https://mooseframework.inl.gov
TriSubChannelMesh.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "TriSubChannelMesh.h"
11 #include <cmath>
12 #include "libmesh/node.h"
13 
14 registerMooseObject("SubChannelApp", TriSubChannelMesh);
15 
18 {
20  params.addClassDescription("Creates an subchannel mesh container for a triangular "
21  "lattice arrangement");
22  return params;
23 }
24 
26 
28  : SubChannelMesh(other_mesh),
29  _n_rings(other_mesh._n_rings),
30  _n_channels(other_mesh._n_channels),
31  _flat_to_flat(other_mesh._flat_to_flat),
32  _dwire(other_mesh._dwire),
33  _hwire(other_mesh._hwire),
34  _duct_to_pin_gap(other_mesh._duct_to_pin_gap),
35  _nodes(other_mesh._nodes),
36  _pin_nodes(other_mesh._pin_nodes),
37  _gap_to_chan_map(other_mesh._gap_to_chan_map),
38  _gap_to_pin_map(other_mesh._gap_to_pin_map),
39  _chan_to_gap_map(other_mesh._chan_to_gap_map),
40  _sign_id_crossflow_map(other_mesh._sign_id_crossflow_map),
41  _gij_map(other_mesh._gij_map),
42  _pin_position(other_mesh._pin_position),
43  _pins_in_rings(other_mesh._pins_in_rings),
44  _chan_to_pin_map(other_mesh._chan_to_pin_map),
45  _npins(other_mesh._npins),
46  _n_gaps(other_mesh._n_gaps),
47  _subch_type(other_mesh._subch_type),
48  _gap_type(other_mesh._gap_type),
49  _gap_pairs_sf(other_mesh._gap_pairs_sf),
50  _chan_pairs_sf(other_mesh._chan_pairs_sf),
51  _pin_to_chan_map(other_mesh._pin_to_chan_map)
52 {
53 }
54 
55 std::unique_ptr<MooseMesh>
57 {
58  return _app.getFactory().copyConstruct(*this);
59 }
60 
61 unsigned int
63 {
65  return this->channelIndex(p);
66 }
67 
68 unsigned int
69 TriSubChannelMesh::channelIndex(const Point & p) const
70 {
75 
76  // Distances to determine the closest subchannel
77  Real distance0 = 1.0e+8; // Dummy distance to keep updating the closes distance found
78  Real distance1; // Distance to be updated with the current subchannel distance
79  unsigned int j = 0; // Index to keep track of the closest point to subchannel
80 
81  // Projecting point into hexahedral coordinated to determine if the point belongs to a center
82  // subchannel
83  Real distance_outer_ring = _flat_to_flat / 2 - _duct_to_pin_gap - _pin_diameter / 2;
84  Real channel_distance = std::sqrt(std::pow(p(0), 2) + std::pow(p(1), 2));
85  Real angle = std::abs(std::atan2(p(1), p(0)));
86  Real projection_angle =
87  angle - libMesh::pi / 6 - std::trunc(angle / (libMesh::pi / 3)) * (libMesh::pi / 3);
88  channel_distance = channel_distance * std::cos(projection_angle);
89 
90  // Projecting point on top edge to determine if the point is a corner or edge subchannel by x
91  // coordinate
92  Real loc_angle = std::atan2(p(1), p(0));
93  if (loc_angle < 0.0)
94  loc_angle += 2 * libMesh::pi;
95  Real rem_ang = std::trunc(loc_angle / (libMesh::pi / 3)) * (libMesh::pi / 3) - libMesh::pi / 3;
96  Real x_coord_new = (std::cos(-rem_ang) * p(0) - std::sin(-rem_ang) * p(1));
97  Real x_lim = (_n_rings - 1) * _pitch / 2.0;
98 
99  // looping over all channels
100  for (unsigned int i = 0; i < _n_channels; i++)
101  {
102  // Distance from the point to subchannel
103  distance1 = std::sqrt(std::pow((p(0) - _subchannel_position[i][0]), 2.0) +
104  std::pow((p(1) - _subchannel_position[i][1]), 2.0));
105 
106  // If subchannel belongs to center ring
107  if (channel_distance < distance_outer_ring)
108  {
109  if ((distance1 < distance0) && (_subch_type[i] == EChannelType::CENTER))
110  {
111  j = i;
112  distance0 = distance1;
113  } // if
114  } // if
115  // If subchannel belongs to outer ring
116  else
117  {
118  if ((distance1 < distance0) &&
120  {
121  if (((x_coord_new > x_lim) || (x_coord_new < -x_lim)) &&
123  {
124  j = i;
125  distance0 = distance1;
126  } // if
127  else if ((x_coord_new <= x_lim && x_coord_new >= -x_lim) &&
129  {
130  j = i;
131  distance0 = distance1;
132  }
133  }
134  }
135  }
136  return j;
137 }
138 
139 void
141 {
142 }
143 
144 void
146 {
147  _assembly_flow_area = 0.0;
150 
151  const Real z = _z_grid.empty() ? 0.0 : _z_grid.front();
152 
153  for (unsigned int i_ch = 0; i_ch < _n_channels; i_ch++)
154  {
157  }
158 
159  if (_assembly_wetted_perimeter == 0.0)
160  mooseError(name(), ": Assembly wetted perimeter is zero; cannot compute hydraulic diameter.");
161 
163 }
164 
165 Real
166 TriSubChannelMesh::getSubchannelFlowArea(unsigned int i_chan, Real z) const
167 {
168  Real standard_area = 0.0;
169  Real rod_area = 0.0;
170  Real wire_area = 0.0;
171 
172  const Real theta =
173  std::acos(_hwire / std::sqrt(std::pow(_hwire, 2) +
175  const auto subch_type = getSubchannelType(i_chan);
176  if (subch_type == EChannelType::CENTER)
177  {
178  standard_area = std::pow(_pitch, 2) * std::sqrt(3.0) / 4.0;
179  rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 8.0;
180  wire_area = libMesh::pi * std::pow(_dwire, 2) / 8.0 / std::cos(theta);
181  }
182  else if (subch_type == EChannelType::EDGE)
183  {
184  standard_area = _pitch * (_pin_diameter / 2.0 + _duct_to_pin_gap);
185  rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 8.0;
186  wire_area = libMesh::pi * std::pow(_dwire, 2) / 8.0 / std::cos(theta);
187  }
188  else
189  {
190  standard_area = 1.0 / std::sqrt(3.0) * std::pow(_pin_diameter / 2.0 + _duct_to_pin_gap, 2);
191  rod_area = libMesh::pi * std::pow(_pin_diameter, 2) / 24.0;
192  wire_area = libMesh::pi * std::pow(_dwire, 2) / 24.0 / std::cos(theta);
193  }
194 
195  Real flow_area = standard_area - rod_area - wire_area;
196 
197  unsigned int blockage_index = 0;
198  for (const auto & i_blockage : _index_blockage)
199  {
200  if (i_chan == i_blockage && z >= _z_blockage.front() && z <= _z_blockage.back())
201  flow_area *= _reduction_blockage[blockage_index];
202  blockage_index++;
203  }
204 
205  return flow_area;
206 }
207 
208 Real
210 {
211  const Real theta =
212  std::acos(_hwire / std::sqrt(std::pow(_hwire, 2) +
214  const Real rod_circumference = libMesh::pi * _pin_diameter;
215  const Real wire_circumference = libMesh::pi * _dwire;
216  const auto subch_type = getSubchannelType(i_chan);
217 
218  if (subch_type == EChannelType::CENTER)
219  return 0.5 * rod_circumference + 0.5 * wire_circumference / std::cos(theta);
220  else if (subch_type == EChannelType::EDGE)
221  return 0.5 * rod_circumference + 0.5 * wire_circumference / std::cos(theta) + _pitch;
222  else
223  return (rod_circumference + wire_circumference / std::cos(theta)) / 6.0 +
224  2.0 / std::sqrt(3.0) * (_pin_diameter / 2.0 + _duct_to_pin_gap);
225 }
226 
227 unsigned int
229 {
231 
232  return this->pinIndex(p);
233 }
234 
235 unsigned int
236 TriSubChannelMesh::pinIndex(const Point & p) const
237 {
239 
240  // Define the current ring
241  Real distance_rod;
242  Real d0 = 1e5;
243  unsigned int current_rod = 0;
244 
245  std::vector<Point> positions;
246  Point center(0, 0);
247  this->pinPositions(positions, _n_rings, _pitch, center);
248  for (unsigned int i = 0; i < _npins; i++)
249  {
250  Real x_dist = positions[i](0) - p(0);
251  Real y_dist = positions[i](1) - p(1);
252  distance_rod = std::sqrt(std::pow(x_dist, 2) + std::pow(y_dist, 2));
253  if (distance_rod < d0)
254  {
255  d0 = distance_rod;
256  current_rod = i;
257  }
258  }
259 
260  return current_rod;
261 }
262 
263 void
264 TriSubChannelMesh::pinPositions(std::vector<Point> & positions,
265  unsigned int nrings,
266  Real pitch,
267  Point center)
268 {
270  // distance: it is the distance to the next Pin
271  //
272  Real theta = 0.0;
273  Real dtheta = 0.0;
274  Real distance = 0.0;
275  Real theta1 = 0.0;
276  Real theta_corrected = 0.0;
277  Real pi = libMesh::pi;
278  unsigned int k = 0;
279  positions.emplace_back(center(0), center(1));
280  for (unsigned int i = 1; i < nrings; i++)
281  {
282  dtheta = 2.0 * pi / (i * 6);
283  theta = 0.0;
284  for (unsigned int j = 0; j < i * 6; j++)
285  {
286  k = k + 1;
287  theta1 = fmod(theta + 1.0e-10, pi / 3.0);
288  distance = std::sqrt((pow(i * pitch, 2) + pow(theta1 / dtheta * pitch, 2) -
289  2.0 * i * pitch * (theta1 / dtheta * pitch) * std::cos(pi / 3.0)));
290  double argument = 1.0 / (i * pitch) / distance / 2.0 *
291  (std::pow(i * pitch, 2.0) + std::pow(distance, 2.0) -
292  std::pow(theta1 / dtheta * pitch, 2.0));
293  // Check if the argument to std::acos() is within the valid range [-1, 1]
294  if (argument >= -1.0 && argument <= 1.0)
295  {
296  theta_corrected = std::acos(argument);
297  }
298  else if (argument > 1.0)
299  {
300  theta_corrected = 0.0;
301  }
302  else
303  {
304  theta_corrected = pi;
305  }
306  if (theta1 < 1.0e-6)
307  {
308  theta_corrected = theta;
309  }
310  else
311  {
312  if (theta > pi / 3.0 && theta <= 2.0 / 3.0 * pi)
313  theta_corrected = theta_corrected + pi / 3.0;
314  else if (theta > 2.0 / 3.0 * pi && theta <= pi)
315  theta_corrected = theta_corrected + 2.0 / 3.0 * pi;
316  else if (theta > pi && theta <= 4.0 / 3.0 * pi)
317  theta_corrected = theta_corrected + pi;
318  else if (theta > 4.0 / 3.0 * pi && theta <= 5.0 / 3.0 * pi)
319  theta_corrected = theta_corrected + 4.0 / 3.0 * pi;
320  else if (theta > 5.0 / 3.0 * pi && theta <= 2.0 * pi)
321  theta_corrected = theta_corrected + 5.0 / 3.0 * pi;
322  }
323  positions.emplace_back(center(0) + distance * std::cos(theta_corrected),
324  center(1) + distance * std::sin(theta_corrected));
325  theta = theta + dtheta;
326  } // j
327  } // i
328 }
std::vector< EChannelType > _subch_type
subchannel type
static InputParameters validParams()
std::vector< Real > _z_grid
axial location of nodes
Real getSubchannelWettedPerimeter(unsigned int i_chan) const override
Return undeformed wetted perimeter for a subchannel.
std::unique_ptr< MooseMesh > safeClone() const override
static void pinPositions(std::vector< Point > &positions, unsigned int nrings, Real pitch, Point center)
Calculates and stores the pin positions/centers for a hexagonal assembly containing the given number ...
unsigned int getSubchannelIndexFromPoint(const Point &p) const override
Return a subchannel index for a given physical point p
TriSubChannelMesh(const InputParameters &parameters)
Real _dwire
wire diameter
void computeAssemblyHydraulicParameters()
Compute undeformed bundle-average inlet hydraulic quantities from generated mesh geometry.
Real _hwire
wire lead length
Real _duct_to_pin_gap
the gap thickness between the duct and peripheral fuel pins
Real distance(const Point &p)
std::vector< std::vector< Real > > _subchannel_position
x,y coordinates of the subchannel centroids
std::unique_ptr< T > copyConstruct(const T &object)
Factory & getFactory()
registerMooseObject("SubChannelApp", TriSubChannelMesh)
void buildMesh() override
unsigned int _n_rings
number of fuel-pin rings, counting the center pin as the first ring
const std::string & name() const
unsigned int channelIndex(const Point &point) const override
static const std::string pitch
Real _flat_to_flat
the distance between flat surfaces of the duct facing each other
Real _assembly_wetted_perimeter
Undeformed bundle inlet wetted perimeter.
std::vector< Real > _z_blockage
axial location of blockage (inlet, outlet) [m]
unsigned int _npins
number of fuel pins
Real _pin_diameter
fuel Pin diameter
std::vector< Real > _reduction_blockage
area reduction of subchannels affected by blockage
unsigned int getPinIndexFromPoint(const Point &p) const override
Return a pin index for a given physical point p
Mesh class for triangular, edge and corner subchannels for hexagonal lattice fuel assemblies...
Real _pitch
Distance between the neighbor fuel pins, pitch.
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
Real _assembly_flow_area
Undeformed bundle inlet flow area.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MooseApp & _app
const Real p
unsigned int pinIndex(const Point &p) const override
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Base class for subchannel meshes.
Real getSubchannelFlowArea(unsigned int i_chan, Real z) const override
Return undeformed flow area for a subchannel at an axial location, including any blockage reduction...
EChannelType getSubchannelType(unsigned int index) const override
Return the type of the subchannel for given subchannel index.
MooseUnits pow(const MooseUnits &, int)
unsigned int _n_channels
number of subchannels
static const std::string k
Definition: NS.h:134
static InputParameters validParams()
Real _assembly_hydraulic_diameter
Undeformed bundle-average hydraulic diameter.
static const std::string center
Definition: NS.h:29
std::vector< unsigned int > _index_blockage
index of subchannels affected by blockage
const Real pi