https://mooseframework.inl.gov
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
SCMDetailedTriAssemblyMeshGenerator Class Reference

Mesh generator that builds a 3D mesh representing triangular subchannels and pins. More...

#include <SCMDetailedTriAssemblyMeshGenerator.h>

Inheritance diagram for SCMDetailedTriAssemblyMeshGenerator:
[legend]

Public Types

typedef DataFileName DataFileParameterType
 

Public Member Functions

 SCMDetailedTriAssemblyMeshGenerator (const InputParameters &parameters)
 
virtual std::unique_ptr< MeshBase > generate () override
 
std::unique_ptr< CSG::CSGBasegenerateInternalCSG ()
 
std::unique_ptr< MeshBase > generateInternal ()
 
const std::set< MeshGeneratorName > & getRequestedMeshGenerators () const
 
const std::set< MeshGeneratorName > & getRequestedMeshGeneratorsForSub () const
 
void addParentMeshGenerator (const MeshGenerator &mg, const AddParentChildKey)
 
void addChildMeshGenerator (const MeshGenerator &mg, const AddParentChildKey)
 
const std::set< const MeshGenerator *, Comparator > & getParentMeshGenerators () const
 
const std::set< const MeshGenerator *, Comparator > & getChildMeshGenerators () const
 
const std::set< const MeshGenerator *, Comparator > & getSubMeshGenerators () const
 
bool isParentMeshGenerator (const MeshGeneratorName &name, const bool direct=true) const
 
bool isChildMeshGenerator (const MeshGeneratorName &name, const bool direct=true) const
 
bool isNullMeshName (const MeshGeneratorName &name) const
 
bool hasSaveMesh () const
 
bool hasOutput () const
 
const std::string & getSavedMeshName () const
 
bool hasGenerateData () const
 
bool hasGenerateCSG () const
 
bool isDataOnly () const
 
virtual bool enabled () const
 
std::shared_ptr< MooseObjectgetSharedPtr ()
 
std::shared_ptr< const MooseObjectgetSharedPtr () const
 
bool isKokkosObject () const
 
MooseAppgetMooseApp () const
 
const std::string & type () const
 
const std::string & name () const
 
std::string typeAndName () const
 
MooseObjectParameterName uniqueParameterName (const std::string &parameter_name) const
 
MooseObjectName uniqueName () const
 
const InputParametersparameters () const
 
const hit::Node * getHitNode () const
 
bool hasBase () const
 
const std::string & getBase () const
 
const TgetParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const TqueryParam (const std::string &name) const
 
const TgetRenamedParam (const std::string &old_name, const std::string &new_name) const
 
T getCheckedPointerParam (const std::string &name, const std::string &error_string="") const
 
bool haveParameter (const std::string &name) const
 
bool isParamValid (const std::string &name) const
 
bool isParamSetByUser (const std::string &name) const
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void paramError (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramInfo (const std::string &param, Args... args) const
 
std::string messagePrefix (const bool hit_prefix=true) const
 
std::string errorPrefix (const std::string &) const
 
void mooseError (Args &&... args) const
 
void mooseDocumentedError (const std::string &repo_name, const unsigned int issue_num, Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecatedNoTrace (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
void callMooseError (std::string msg, const bool with_prefix, const hit::Node *node=nullptr, const bool show_trace=true) const
 
std::string getDataFileName (const std::string &param) const
 
std::string getDataFileNameByName (const std::string &relative_path) const
 
std::string getDataFilePath (const std::string &relative_path) const
 
const Parallel::Communicator & comm () const
 
processor_id_type n_processors () const
 
processor_id_type processor_id () const
 

Static Public Member Functions

static InputParameters validParams ()
 
static bool hasGenerateData (const InputParameters &params)
 
static bool hasGenerateCSG (const InputParameters &params)
 
static void callMooseError (MooseApp *const app, const InputParameters &params, std::string msg, const bool with_prefix, const hit::Node *node, const bool show_trace=true)
 
static void setHasGenerateData (InputParameters &params)
 
static void setHasGenerateCSG (InputParameters &params)
 

Public Attributes

 usingCombinedWarningSolutionWarnings
 
const ConsoleStream _console
 

Static Public Attributes

static const std::string data_only_param
 
static const std::string type_param
 
static const std::string name_param
 
static const std::string unique_name_param
 
static const std::string app_param
 
static const std::string moose_base_param
 
static const std::string kokkos_object_param
 
static constexpr auto SYSTEM
 
static constexpr auto NAME
 

Protected Member Functions

EChannelType getSubchannelType (unsigned int index) const
 returns the type of the subchannel given the index More...
 
Point rotatePoint (Point b, Real theta)
 rotate a point by theta radians about the origin More...
 
void generatePin (std::unique_ptr< MeshBase > &mesh_base, const Point &center)
 Generate one detailed fuel pin volume centered at the supplied point. More...
 
Point getPinPosition (unsigned int i)
 returns the position of pin given pin index More...
 
std::vector< RealgetSubchannelPosition (unsigned int i)
 returns the position of subchannel given pin index More...
 
std::vector< unsigned intgetSubChannelPins (unsigned int i)
 returns the index of neighboring pins given subchannel index More...
 
virtual void generateData ()
 
virtual std::unique_ptr< CSG::CSGBasegenerateCSG ()
 
TcopyMeshProperty (const std::string &target_data_name, const std::string &source_data_name, const std::string &source_mesh)
 
TcopyMeshProperty (const std::string &source_data_name, const std::string &source_mesh)
 
std::unique_ptr< MeshBase > & getMesh (const std::string &param_name, const bool allow_invalid=false)
 
std::vector< std::unique_ptr< MeshBase > *> getMeshes (const std::string &param_name)
 
std::unique_ptr< MeshBase > & getMeshByName (const MeshGeneratorName &mesh_generator_name)
 
std::vector< std::unique_ptr< MeshBase > *> getMeshesByName (const std::vector< MeshGeneratorName > &mesh_generator_names)
 
std::unique_ptr< CSG::CSGBase > & getCSGBase (const std::string &param_name)
 
std::unique_ptr< CSG::CSGBase > & getCSGBaseByName (const MeshGeneratorName &mesh_generator_name)
 
std::vector< std::unique_ptr< CSG::CSGBase > *> getCSGBases (const std::string &param_name)
 
std::vector< std::unique_ptr< CSG::CSGBase > *> getCSGBasesByName (const std::vector< MeshGeneratorName > &mesh_generator_names)
 
void declareMeshForSub (const std::string &param_name)
 
void declareMeshesForSub (const std::string &param_name)
 
void declareMeshForSubByName (const MeshGeneratorName &mesh_generator_name)
 
void declareMeshesForSubByName (const std::vector< MeshGeneratorName > &mesh_generator_names)
 
std::unique_ptr< MeshBase > buildMeshBaseObject (unsigned int dim=libMesh::invalid_uint)
 
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh (unsigned int dim=libMesh::invalid_uint)
 
std::unique_ptr< DistributedMesh > buildDistributedMesh (unsigned int dim=libMesh::invalid_uint)
 
void addMeshSubgenerator (const std::string &type, const std::string &name, Ts... extra_input_parameters)
 
void addMeshSubgenerator (const std::string &type, const std::string &name, InputParameters params)
 
void declareNullMeshName (const MeshGeneratorName &name)
 
void flagInvalidSolutionInternal (const InvalidSolutionID invalid_solution_id) const
 
InvalidSolutionID registerInvalidSolutionInternal (const std::string &message, const bool warning) const
 
const TgetMeshProperty (const std::string &data_name, const std::string &prefix)
 
const TgetMeshProperty (const std::string &data_name)
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name) const
 
bool hasMeshProperty (const std::string &data_name) const
 
std::string meshPropertyName (const std::string &data_name) const
 
TdeclareMeshProperty (const std::string &data_name, Args &&... args)
 
TdeclareMeshProperty (const std::string &data_name, const T &data_value)
 
TdeclareMeshProperty (const std::string &data_name, Args &&... args)
 
TdeclareMeshProperty (const std::string &data_name, const T &data_value)
 
TsetMeshProperty (const std::string &data_name, Args &&... args)
 
TsetMeshProperty (const std::string &data_name, const T &data_value)
 
TsetMeshProperty (const std::string &data_name, Args &&... args)
 
TsetMeshProperty (const std::string &data_name, const T &data_value)
 

Static Protected Member Functions

static std::string meshPropertyName (const std::string &data_name, const std::string &prefix)
 

Protected Attributes

const Real _unheated_length_entry
 unheated length of the fuel Pin at the entry of the assembly More...
 
const Real _heated_length
 heated length of the fuel Pin More...
 
const Real _unheated_length_exit
 unheated length of the fuel Pin at the exit of the assembly More...
 
std::vector< Real_z_grid
 axial location of nodes More...
 
const Real _pitch
 Distance between the neighbor fuel pins, pitch. More...
 
const Real _pin_diameter
 fuel Pin diameter More...
 
const unsigned int _n_rings
 Number of rings in the geometry. More...
 
const Real _flat_to_flat
 Half of gap between adjacent assemblies. More...
 
const unsigned int _num_sectors
 Number of azimuthal sectors used to discretize each circular pin cross section. More...
 
std::vector< EChannelType_subch_type
 Subchannel type. More...
 
std::vector< Point > _pin_position
 x,y coordinates of the fuel pins More...
 
std::vector< std::vector< Real > > _subchannel_position
 x,y coordinates of the subchannels More...
 
const unsigned int _subchannel_block_id
 Subchannel subdomain ID. More...
 
const unsigned int _pin_block_id
 Pin subdomain ID. More...
 
const unsigned int _n_cells
 Number of cells in the axial direction. More...
 
unsigned int _nrods
 Number of pins. More...
 
std::vector< std::vector< unsigned int > > _pins_in_rings
 fuel pins that are belonging to each ring More...
 
std::map< unsigned int, Real_orientation_map
 map inner and outer rings More...
 
unsigned int _n_channels
 number of subchannels More...
 
std::vector< std::vector< unsigned int > > _chan_to_pin_map
 stores the fuel pins belonging to each subchannel More...
 
const bool _verbose
 Flag to print out the detailed mesh assembly and coordinates. More...
 
dof_id_type _elem_id
 counter for element numbering More...
 
MooseMesh *const _mesh
 
const bool & _enabled
 
MooseApp_app
 
Factory_factory
 
ActionFactory_action_factory
 
const std::string & _type
 
const std::string & _name
 
const InputParameters_pars
 
const Parallel::Communicator & _communicator
 

Detailed Description

Mesh generator that builds a 3D mesh representing triangular subchannels and pins.

Definition at line 18 of file SCMDetailedTriAssemblyMeshGenerator.h.

Constructor & Destructor Documentation

◆ SCMDetailedTriAssemblyMeshGenerator()

SCMDetailedTriAssemblyMeshGenerator::SCMDetailedTriAssemblyMeshGenerator ( const InputParameters parameters)

Definition at line 65 of file SCMDetailedTriAssemblyMeshGenerator.C.

68  _unheated_length_entry(getParam<Real>("unheated_length_entry")),
69  _heated_length(getParam<Real>("heated_length")),
70  _unheated_length_exit(getParam<Real>("unheated_length_exit")),
71  _pitch(getParam<Real>("pitch")),
72  _pin_diameter(getParam<Real>("pin_diameter")),
73  _n_rings(getParam<unsigned int>("nrings")),
74  _flat_to_flat(getParam<Real>("flat_to_flat")),
75  _num_sectors(getParam<unsigned int>("num_sectors")),
76  _subchannel_block_id(getParam<unsigned int>("subchannel_block_id")),
77  _pin_block_id(getParam<unsigned int>("pin_block_id")),
78  _n_cells(getParam<unsigned int>("n_cells")),
79  _nrods(0),
80  _n_channels(0),
81  _verbose(getParam<bool>("verbose_flag")),
82  _elem_id(0)
83 {
85 
86  if (_n_rings < 2)
87  paramError("nrings",
88  "'nrings' must be at least 2. In this mesh generator, the center pin counts as "
89  "the first ring, so a 7-pin bundle uses nrings = 2.");
90 
91  if (_n_cells == 0)
92  paramError("n_cells", "The number of axial cells must be greater than zero");
93 
94  if (L <= 0.0)
95  mooseError("Total bundle length must be greater than zero");
96 
97  Real dz = L / _n_cells;
98  for (unsigned int i = 0; i < _n_cells + 1; i++)
99  _z_grid.push_back(dz * i);
100 
101  // x coordinate for the first position
102  Real x0 = 0.0;
103  // y coordinate for the first position
104  Real y0 = 0.0;
105  // x coordinate for the second position
106  Real x1 = 0.0;
107  // y coordinate for the second position dummy variable
108  Real y1 = 0.0;
109  // dummy variable
110  Real a1 = 0.0;
111  // dummy variable
112  Real a2 = 0.0;
113  // average x coordinate
114  Real avg_coor_x = 0.0;
115  // average y coordinate
116  Real avg_coor_y = 0.0;
117  // distance between two points
118  Real dist = 0.0;
119  // distance between two points
120  Real dist0 = 0.0;
121  // the indicator used while setting _gap_to_chan_map array
122  std::vector<std::pair<unsigned int, unsigned int>> gap_fill;
124  _nrods = _pin_position.size();
125  // assign the pins to the corresponding rings
126  unsigned int k = 0; // initialize the fuel Pin counter index
127  _pins_in_rings.resize(_n_rings);
128  _pins_in_rings[0].push_back(k++);
129  for (unsigned int i = 1; i < _n_rings; i++)
130  for (unsigned int j = 0; j < i * 6; j++)
131  _pins_in_rings[i].push_back(k++);
132  // Given the number of pins and number of fuel Pin rings, the number of subchannels can be
133  // computed as follows:
134  unsigned int chancount = 0;
135  // Summing internal channels
136  for (unsigned int j = 0; j < _n_rings - 1; j++)
137  chancount += j * 6;
138  // Adding external channels to the total count
139  _n_channels = chancount + _nrods - 1 + (_n_rings - 1) * 6 + 6;
140 
141  // Utils for building the mesh
143  _subch_type.resize(_n_channels);
145 
146  for (unsigned int i = 0; i < _n_channels; i++)
147  {
148  _subchannel_position[i].reserve(3);
149  for (unsigned int j = 0; j < 3; j++)
150  {
151  _subchannel_position.at(i).push_back(0.0);
152  }
153  }
154 
155  // create the subchannels
156  k = 0; // initialize the subchannel counter index
157  for (unsigned int i = 1; i < _n_rings; i++)
158  {
159  // find the closest Pin at back ring
160  for (unsigned int j = 0; j < _pins_in_rings[i].size(); j++)
161  {
162  if (j == _pins_in_rings[i].size() - 1)
163  {
164  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
165  _chan_to_pin_map[k].push_back(_pins_in_rings[i][0]);
166  avg_coor_x =
167  0.5 * (_pin_position[_pins_in_rings[i][j]](0) + _pin_position[_pins_in_rings[i][0]](0));
168  avg_coor_y =
169  0.5 * (_pin_position[_pins_in_rings[i][j]](1) + _pin_position[_pins_in_rings[i][0]](1));
170  }
171  else
172  {
173  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
174  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j + 1]);
175  avg_coor_x = 0.5 * (_pin_position[_pins_in_rings[i][j]](0) +
176  _pin_position[_pins_in_rings[i][j + 1]](0));
177  avg_coor_y = 0.5 * (_pin_position[_pins_in_rings[i][j]](1) +
178  _pin_position[_pins_in_rings[i][j + 1]](1));
179  }
180  dist0 = 1.0e+5;
181  _chan_to_pin_map[k].push_back(_pins_in_rings[i - 1][0]);
182  for (unsigned int l = 0; l < _pins_in_rings[i - 1].size(); l++)
183  {
184  dist = std::sqrt(pow(_pin_position[_pins_in_rings[i - 1][l]](0) - avg_coor_x, 2) +
185  pow(_pin_position[_pins_in_rings[i - 1][l]](1) - avg_coor_y, 2));
186 
187  if (dist < dist0)
188  {
189  _chan_to_pin_map[k][2] = _pins_in_rings[i - 1][l];
190  dist0 = dist;
191  }
192  }
194  _orientation_map.insert(std::make_pair(k, 0.0));
195  k = k + 1;
196  }
197 
198  // find the closest Pin at front ring
199  for (unsigned int j = 0; j < _pins_in_rings[i].size(); j++)
200  {
201  if (j == _pins_in_rings[i].size() - 1)
202  {
203  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
204  _chan_to_pin_map[k].push_back(_pins_in_rings[i][0]);
205  avg_coor_x =
206  0.5 * (_pin_position[_pins_in_rings[i][j]](0) + _pin_position[_pins_in_rings[i][0]](0));
207  avg_coor_y =
208  0.5 * (_pin_position[_pins_in_rings[i][j]](1) + _pin_position[_pins_in_rings[i][0]](1));
209  }
210  else
211  {
212  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
213  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j + 1]);
214  avg_coor_x = 0.5 * (_pin_position[_pins_in_rings[i][j]](0) +
215  _pin_position[_pins_in_rings[i][j + 1]](0));
216  avg_coor_y = 0.5 * (_pin_position[_pins_in_rings[i][j]](1) +
217  _pin_position[_pins_in_rings[i][j + 1]](1));
218  }
219  // if the outermost ring, set the edge subchannels first... then the corner subchannels
220  if (i == _n_rings - 1)
221  {
222  // add edges
223  _subch_type[k] = EChannelType::EDGE; // an edge subchannel is created
224  k = k + 1;
225  if (j % i == 0)
226  {
227  // corner subchannel
228  _chan_to_pin_map[k].push_back(_pins_in_rings[i][j]);
230  k = k + 1;
231  }
232  // if not the outer most ring
233  }
234  else
235  {
236  dist0 = 1.0e+5;
237  _chan_to_pin_map[k].push_back(_pins_in_rings[i + 1][0]);
238  for (unsigned int l = 0; l < _pins_in_rings[i + 1].size(); l++)
239  {
240  dist = std::sqrt(pow(_pin_position[_pins_in_rings[i + 1][l]](0) - avg_coor_x, 2) +
241  pow(_pin_position[_pins_in_rings[i + 1][l]](1) - avg_coor_y, 2));
242  if (dist < dist0)
243  {
244  _chan_to_pin_map[k][2] = _pins_in_rings[i + 1][l];
245  dist0 = dist;
246  }
247  }
249  _orientation_map.insert(std::make_pair(k, libMesh::pi));
250  k = k + 1;
251  }
252  }
253  }
254 
255  for (auto & pin : _chan_to_pin_map)
256  pin.shrink_to_fit();
257 
258  // set the subchannel positions
259  Real _duct_to_pin_gap =
260  0.5 * (_flat_to_flat - (_n_rings - 1) * _pitch * std::sqrt(3.0) - _pin_diameter);
261  for (unsigned int i = 0; i < _n_channels; i++)
262  {
264  {
265  _subchannel_position[i][0] =
267  _pin_position[_chan_to_pin_map[i][2]](0)) /
268  3.0;
269  _subchannel_position[i][1] =
271  _pin_position[_chan_to_pin_map[i][2]](1)) /
272  3.0;
273  }
274  else if (_subch_type[i] == EChannelType::EDGE)
275  {
276  for (unsigned int j = 0; j < _n_channels; j++)
277  {
279  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][0] &&
280  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][1]) ||
281  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][1] &&
282  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][0])))
283  {
284  x0 = _pin_position[_chan_to_pin_map[j][2]](0);
285  y0 = _pin_position[_chan_to_pin_map[j][2]](1);
286  }
287  else if (_subch_type[j] == EChannelType::CENTER &&
288  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][0] &&
289  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][2]) ||
290  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][2] &&
291  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][0])))
292  {
293  x0 = _pin_position[_chan_to_pin_map[j][1]](0);
294  y0 = _pin_position[_chan_to_pin_map[j][1]](1);
295  }
296  else if (_subch_type[j] == EChannelType::CENTER &&
297  ((_chan_to_pin_map[i][0] == _chan_to_pin_map[j][1] &&
298  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][2]) ||
299  (_chan_to_pin_map[i][0] == _chan_to_pin_map[j][2] &&
300  _chan_to_pin_map[i][1] == _chan_to_pin_map[j][1])))
301  {
302  x0 = _pin_position[_chan_to_pin_map[j][0]](0);
303  y0 = _pin_position[_chan_to_pin_map[j][0]](1);
304  }
305  x1 = 0.5 *
307  y1 = 0.5 *
309  a1 = _pin_diameter / 2.0 + _duct_to_pin_gap / 2.0;
310  a2 = std::sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) + a1;
311  _subchannel_position[i][0] = (a2 * x1 - a1 * x0) / (a2 - a1);
312  _subchannel_position[i][1] = (a2 * y1 - a1 * y0) / (a2 - a1);
313  } // j
314  }
315  else if (_subch_type[i] == EChannelType::CORNER)
316  {
317  x0 = _pin_position[0](0);
318  y0 = _pin_position[0](1);
319  x1 = _pin_position[_chan_to_pin_map[i][0]](0);
320  y1 = _pin_position[_chan_to_pin_map[i][0]](1);
321  a1 = _pin_diameter / 2.0 + _duct_to_pin_gap / 2.0;
322  a2 = std::sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) + a1;
323  _subchannel_position[i][0] = (a2 * x1 - a1 * x0) / (a2 - a1);
324  _subchannel_position[i][1] = (a2 * y1 - a1 * y0) / (a2 - a1);
325  }
326  }
327 }
const unsigned int _pin_block_id
Pin subdomain ID.
dof_id_type _elem_id
counter for element numbering
std::vector< Point > _pin_position
x,y coordinates of the fuel pins
void paramError(const std::string &param, Args... args) const
const unsigned int _num_sectors
Number of azimuthal sectors used to discretize each circular pin cross section.
const unsigned int _n_cells
Number of cells in the axial direction.
const InputParameters & parameters() const
const Real _pitch
Distance between the neighbor fuel pins, pitch.
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 ...
MeshGenerator(const InputParameters &parameters)
std::vector< std::vector< unsigned int > > _pins_in_rings
fuel pins that are belonging to each ring
const Real _flat_to_flat
Half of gap between adjacent assemblies.
const Real _unheated_length_entry
unheated length of the fuel Pin at the entry of the assembly
std::vector< EChannelType > _subch_type
Subchannel type.
const Real _heated_length
heated length of the fuel Pin
const unsigned int _subchannel_block_id
Subchannel subdomain ID.
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const bool _verbose
Flag to print out the detailed mesh assembly and coordinates.
std::vector< std::vector< Real > > _subchannel_position
x,y coordinates of the subchannels
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void mooseError(Args &&... args) const
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::vector< std::vector< unsigned int > > _chan_to_pin_map
stores the fuel pins belonging to each subchannel
static const std::string k
Definition: NS.h:134
const Real _unheated_length_exit
unheated length of the fuel Pin at the exit of the assembly
const unsigned int _n_rings
Number of rings in the geometry.
std::vector< Real > _z_grid
axial location of nodes
std::map< unsigned int, Real > _orientation_map
map inner and outer rings
const Real pi

Member Function Documentation

◆ generate()

std::unique_ptr< MeshBase > SCMDetailedTriAssemblyMeshGenerator::generate ( )
overridevirtual

Implements MeshGenerator.

Definition at line 373 of file SCMDetailedTriAssemblyMeshGenerator.C.

374 {
375  auto mesh_base = buildMeshBaseObject();
376  BoundaryInfo & boundary_info = mesh_base->get_boundary_info();
377  mesh_base->set_spatial_dimension(3);
378  // Define the resolution (the number of points used to represent a circle).
379  // This must be divisible by 4.
380  const unsigned int theta_res_triangle = 24; // TODO: parameterize
381  const unsigned int theta_res_square = 24; // TODO: parameterize
382  // Compute the number of points needed to represent one sixth and quadrant of a circle.
383  const unsigned int points_per_sixth = theta_res_triangle / 6 + 1;
384  const unsigned int points_per_quadrant = theta_res_square / 4 + 1;
385 
386  // Compute the points needed to represent one axial cross-flow of a subchannel.
387  // For the center subchannel (sc) there is one center point plus the points from 3 side
388  // circles.
389  const unsigned int points_per_center = points_per_sixth * 3 + 1;
390  // For the corner sc there is one center point plus the points from 1 side circle plus 3
391  // corners
392  const unsigned int points_per_corner = points_per_sixth * 1 + 1 + 3;
393  // For the side sc there is one center point plus the points from 2 intersecting circles plus 2
394  // corners
395  const unsigned int points_per_side = points_per_quadrant * 2 + 1 + 2;
396 
397  if (_verbose)
398  {
399  _console << "Points per center: " << points_per_center << std::endl;
400  _console << "Points per side: " << points_per_side << std::endl;
401  _console << "Points per corner: " << points_per_corner << std::endl;
402  }
403 
404  // Compute the number of elements (Prism6) which combined base creates the sub-channel
405  // cross-section
406  const unsigned int elems_per_center = theta_res_triangle * 3 / 6 + 3; // TODO: check
407  const unsigned int elems_per_corner = theta_res_triangle / 6 + 4;
408  const unsigned int elems_per_side = 2 * theta_res_square / 4 + 4;
409  if (_verbose)
410  {
411  _console << "Elems per center: " << elems_per_center << std::endl;
412  _console << "Elems per side: " << elems_per_side << std::endl;
413  _console << "Elems per corner: " << elems_per_corner << std::endl;
414  }
415 
416  // specify number and type of sub-channel
417  unsigned int n_corner = 6;
418  unsigned int n_side = (_n_rings - 1) * 6;
419  unsigned int n_center = _n_channels - n_side - n_corner;
420  if (_verbose)
421  {
422  _console << "Centers: " << n_center << std::endl;
423  _console << "Sides: " << n_side << std::endl;
424  _console << "Corners: " << n_corner << std::endl;
425  }
426 
427  // Compute the total number of points and elements.
428  const unsigned int points_per_level =
429  n_corner * points_per_corner + n_side * points_per_side + n_center * points_per_center;
430  const unsigned int elems_per_level =
431  n_corner * elems_per_corner + n_side * elems_per_side + n_center * elems_per_center;
432  if (_verbose)
433  {
434  _console << "Points per level: " << points_per_level << std::endl;
435  _console << "Elements per level: " << elems_per_level << std::endl;
436  }
437  const unsigned int n_points = points_per_level * (_n_cells + 1);
438  const unsigned int n_elems = elems_per_level * _n_cells;
439  const unsigned int n_pins = _pin_position.size();
440  const unsigned int pin_points = n_pins > 0 ? (_n_cells + 1) * (_num_sectors + 1) * n_pins : 0;
441  const unsigned int pin_elems = n_pins > 0 ? _n_cells * _num_sectors * n_pins : 0;
442  if (_verbose)
443  {
444  _console << "Number of points: " << n_points << std::endl;
445  _console << "Number of elements: " << n_elems << std::endl;
446  }
447  mesh_base->reserve_nodes(n_points + pin_points);
448  mesh_base->reserve_elem(n_elems + pin_elems);
449  // Build an array of points arranged in a circle on the xy-plane. (last and first node overlap)
450  // We build for both the square discretization in the edges and the triangular discretization
451  // within the mesh
452  const Real radius = _pin_diameter / 2.0;
453  std::array<Point, theta_res_square + 1> circle_points_square;
454  {
455  Real theta = 0;
456  for (unsigned int i = 0; i < theta_res_square + 1; i++)
457  {
458  circle_points_square[i](0) = radius * std::cos(theta);
459  circle_points_square[i](1) = radius * std::sin(theta);
460  theta += 2.0 * libMesh::pi / theta_res_square;
461  }
462  }
463  std::array<Point, theta_res_triangle + 1> circle_points_triangle;
464  {
465  Real theta = 0;
466  for (unsigned int i = 0; i < theta_res_triangle + 1; i++)
467  {
468  circle_points_triangle[i](0) = radius * std::cos(theta);
469  circle_points_triangle[i](1) = radius * std::sin(theta);
470  theta += 2.0 * libMesh::pi / theta_res_triangle;
471  }
472  }
473  // Define "quadrant center" reference points. These will be the centers of
474  // the 3 circles that represent the fuel pins. These centers are
475  // offset a little bit so that in the final mesh, there is a tiny gap between
476  // neighboring subchannel cells. That allows us to easily map a solution to
477  // this detailed mesh with a nearest-neighbor search.
478  const Real shrink_factor = 0.99999;
479  // Quadrants are used only for the side and corner subchannels
480  Real _duct_to_pin_gap =
481  0.5 * (_flat_to_flat - (_n_rings - 1) * _pitch * std::sqrt(3.0) - _pin_diameter);
482  std::array<Point, 2> quadrant_centers_sides;
483  quadrant_centers_sides[0] = Point(
484  -_pitch * 0.5 * shrink_factor, -(_duct_to_pin_gap + _pin_diameter) * 0.5 * shrink_factor, 0);
485  quadrant_centers_sides[1] = Point(
486  _pitch * 0.5 * shrink_factor, -(_duct_to_pin_gap + _pin_diameter) * 0.5 * shrink_factor, 0);
487  std::array<Point, 1> quadrant_centers_corner;
488  quadrant_centers_corner[0] =
489  Point(-(_duct_to_pin_gap + _pin_diameter) * 0.5 * std::sin(libMesh::pi / 6) * shrink_factor,
490  -(_duct_to_pin_gap + _pin_diameter) * 0.5 * std::cos(libMesh::pi / 6) * shrink_factor,
491  0);
492  // Triangles are used for all center subchannels
493  std::array<Point, 3> triangle_centers;
494  triangle_centers[0] = Point(0, _pitch * std::cos(libMesh::pi / 6) * 2 / 3 * shrink_factor, 0);
495  triangle_centers[1] = Point(-_pitch * 0.5 * shrink_factor,
496  -_pitch * std::cos(libMesh::pi / 6) * 1 / 3 * shrink_factor,
497  0);
498  triangle_centers[2] = Point(
499  _pitch * 0.5 * shrink_factor, -_pitch * std::cos(libMesh::pi / 6) * 1 / 3 * shrink_factor, 0);
500 
501  const unsigned int m_sixth = theta_res_triangle / 6;
502  const unsigned int m_quarter = theta_res_square / 4;
503  // Build an array of points that represent a cross section of a center subchannel
504  // cell. The points are ordered in this fashion:
505  // 3 1
506  // 2
507  // 0
508  // 4 5 8 9
509  // 6 7
510  std::array<Point, points_per_center> center_points{};
511  center_points[0] = Point(0, 0, 0);
512  {
513  unsigned int start;
514  for (unsigned int i = 0; i < 3; i++)
515  {
516  if (i == 0)
517  start = 5 * (m_sixth);
518  if (i == 1)
519  start = 1 * (m_sixth);
520  if (i == 2)
521  start = 3 * (m_sixth);
522  for (unsigned int ii = 0; ii < points_per_sixth; ii++)
523  {
524  auto c_pt = circle_points_triangle[start - ii];
525  center_points[i * points_per_sixth + ii + 1] = triangle_centers[i] + c_pt;
526  }
527  }
528  }
529 
530  // Build an array of points that represent a cross section of a top left corner subchannel
531  // cell. The points are ordered in this fashion (x direction towards point 4, y direction towards
532  // point 6):
533  // 5 6
534  //
535  // 0
536  // 4 2 3
537  // 1
538  std::array<Point, points_per_corner> corner_points{};
539  corner_points[0] = Point(0, 0, 0);
540  {
541  for (unsigned int ii = 0; ii < points_per_sixth; ii++)
542  {
543  auto c_pt = circle_points_triangle[1 * m_quarter - ii];
544  corner_points[ii + 1] = quadrant_centers_corner[0] + c_pt;
545  }
546  Real side_short = (_duct_to_pin_gap + _pin_diameter) * 0.5;
547  Real side_long = (2.0 * _duct_to_pin_gap + _pin_diameter) * 0.5;
548  Real side_length = std::sqrt(std::pow(side_short, 2) + std::pow(side_long, 2) -
549  2 * side_short * side_long * std::cos(libMesh::pi / 6));
550  Real angle =
551  libMesh::pi - libMesh::pi / 3 -
552  std::acos((-std::pow(side_long, 2) + std::pow(side_short, 2) + std::pow(side_length, 2)) /
553  (2 * side_short * side_length));
554  corner_points[points_per_sixth + 1] = Point(side_length * std::cos(angle) * shrink_factor,
555  -side_length * std::sin(angle) * shrink_factor,
556  0);
557  corner_points[points_per_sixth + 2] =
558  Point(side_length * std::sin(libMesh::pi / 2 - angle - libMesh::pi / 6) * shrink_factor *
559  std::tan(libMesh::pi / 6),
560  side_length * std::sin(libMesh::pi / 2 - angle - libMesh::pi / 6) * shrink_factor,
561  0);
562  corner_points[points_per_sixth + 3] =
563  Point(-side_length * std::cos(libMesh::pi / 2 - angle - libMesh::pi / 6) * shrink_factor,
564  side_length * std::sin(libMesh::pi / 2 - angle - libMesh::pi / 6) * shrink_factor,
565  0);
566  }
567 
568  // Build an array of points that represent a cross-section of a top side subchannel
569  // cell. The points are ordered in this fashion:
570  // 8 7
571  //
572  // 0
573  // 1 2 5 6
574  // 3 4
575  std::array<Point, points_per_side> side_points{};
576  side_points[0] = Point(0, 0, 0);
577  {
578  for (unsigned int ii = 0; ii < points_per_quadrant; ii++)
579  {
580  auto c_pt = circle_points_square[m_quarter - ii];
581  side_points[ii + 1] = quadrant_centers_sides[0] + c_pt;
582  }
583  for (unsigned int ii = 0; ii < points_per_quadrant; ii++)
584  {
585  auto c_pt = circle_points_square[2 * m_quarter - ii];
586  side_points[points_per_quadrant + ii + 1] = quadrant_centers_sides[1] + c_pt;
587  }
588  side_points[2 * points_per_quadrant + 1] =
589  Point(_pitch * 0.5 * shrink_factor, 0.5 * _duct_to_pin_gap * shrink_factor, 0);
590  side_points[2 * points_per_quadrant + 2] =
591  Point(-_pitch * 0.5 * shrink_factor, 0.5 * _duct_to_pin_gap * shrink_factor, 0);
592  }
593 
594  int point_counter = 0;
595  unsigned int node_id = 0;
596  for (unsigned int i = 0; i < _n_channels; i++)
597  {
598  // Real offset_x = _flat_to_flat / 2.0;
599  // Real offset_y = _flat_to_flat / 2.0;
600 
602  {
603  for (auto z : _z_grid)
604  {
605  // Get height
606  Point z0{0, 0, z};
607 
608  // Get suchannel position and assign to point
609  auto loc_position = getSubchannelPosition(i);
610  Point p0{loc_position[0], loc_position[1], 0};
611 
612  // Determine orientation of current subchannel
613  auto subchannel_pins = getSubChannelPins(i);
614  Point subchannel_side =
615  getPinPosition(subchannel_pins[0]) + getPinPosition(subchannel_pins[1]);
616  Point base_center_orientation = {0, -1};
617 
618  // Get rotation angle for current subchannel
619  Real dot_prod = 0;
620  for (unsigned int lp = 0; lp < 2; lp++)
621  dot_prod += base_center_orientation(lp) * subchannel_side(lp);
622  auto theta =
623  std::acos(dot_prod / (base_center_orientation.norm() * subchannel_side.norm()));
624  if (subchannel_side(0) < 0)
625  theta = 2.0 * libMesh::pi - theta;
626 
627  // Real distance_side = subchannel_side.norm();
628  // Real distance_top = getPinPosition(subchannel_pins[2]).norm();
629  // if (distance_top > distance_side)
630  // theta += libMesh::pi * 0.0;
631 
632  theta += _orientation_map[i];
633 
634  theta = trunc((theta + (libMesh::pi / 6.0)) / (libMesh::pi / 3.0)) * libMesh::pi / 3.0;
635 
636  if (_verbose)
637  {
638  if (z == 0)
639  {
640  _console << "Subchannel Position: " << p0 << std::endl;
641  auto pins = getSubChannelPins(i);
642  for (auto r : pins)
643  _console << r << " ";
644  _console << std::endl;
645  _console << "Theta: " << theta / libMesh::pi * 180. << std::endl;
646  }
647  }
648 
649  // Assigning points for center channels
650  for (unsigned int i = 0; i < points_per_center; i++)
651  {
652  auto new_point = rotatePoint(center_points[i], theta) + p0 + z0;
653  if (_verbose)
654  {
655  if (z == 0)
656  _console << i << " - " << new_point << std::endl;
657  }
658  mesh_base->add_point(new_point, node_id++);
659  point_counter += 1;
660  }
661  }
662  }
663  else if (getSubchannelType(i) == EChannelType::EDGE)
664  {
665  for (auto z : _z_grid)
666  {
667  // Get height
668  Point z0{0, 0, z};
669 
670  // Get suchannel position and assign to point
671  auto loc_position = getSubchannelPosition(i);
672  Point p0{loc_position[0], loc_position[1], 0};
673 
674  // Determine orientation of current subchannel
675  auto subchannel_pins = getSubChannelPins(i);
676  Point subchannel_side =
677  getPinPosition(subchannel_pins[0]) + getPinPosition(subchannel_pins[1]);
678  Point base_center_orientation = {0, 1};
679 
680  // Get rotation angle for current subchannel
681  Real dot_prod = 0;
682  for (unsigned int lp = 0; lp < 2; lp++)
683  dot_prod += base_center_orientation(lp) * subchannel_side(lp);
684  auto theta =
685  std::acos(dot_prod / (base_center_orientation.norm() * subchannel_side.norm()));
686  if (subchannel_side(0) > 0)
687  theta = 2. * libMesh::pi - theta;
688  theta = trunc((theta + (libMesh::pi / 6.0)) / (libMesh::pi / 3.0)) * libMesh::pi / 3.0;
689 
690  if (_verbose)
691  {
692  if (z == 0)
693  {
694  _console << "Subchannel Position: " << p0 << std::endl;
695  auto pins = getSubChannelPins(i);
696  for (auto r : pins)
697  _console << r << " ";
698  _console << std::endl;
699  _console << "Theta: " << theta * 180 / libMesh::pi << std::endl;
700  }
701  }
702 
703  // Assigning points for center channels
704  for (unsigned int i = 0; i < points_per_side; i++)
705  {
706  auto new_point = rotatePoint(side_points[i], theta) + p0 + z0;
707  if (_verbose)
708  {
709  if (z == 0)
710  _console << i << " - " << new_point << std::endl;
711  }
712  mesh_base->add_point(new_point, node_id++);
713  point_counter += 1;
714  }
715  }
716  }
717  else // getSubchannelType(i) == EChannelType::CORNER
718  {
719  for (auto z : _z_grid)
720  {
721  // Get height
722  Point z0{0, 0, z};
723 
724  // Get suchannel position and assign to point
725  auto loc_position = getSubchannelPosition(i);
726  Point p0{loc_position[0], loc_position[1], 0};
727 
728  // Determine orientation of current subchannel
729  auto subchannel_pins = getSubChannelPins(i);
730  Point subchannel_side = getPinPosition(subchannel_pins[0]);
731  Point base_center_orientation = {1, 1};
732 
733  // Get rotation angle for current subchannel
734  Real dot_prod = 0;
735  for (unsigned int lp = 0; lp < 2; lp++)
736  dot_prod += base_center_orientation(lp) * subchannel_side(lp);
737  auto theta =
738  std::acos(dot_prod / (base_center_orientation.norm() * subchannel_side.norm()));
739  if (subchannel_side(0) > 0)
740  theta = 2. * libMesh::pi - theta;
741  theta = trunc((theta + (libMesh::pi / 6.0)) / (libMesh::pi / 3.0)) * libMesh::pi / 3.0;
742 
743  if (_verbose)
744  {
745  if (z == 0)
746  {
747  _console << "Subchannel Position: " << p0 << std::endl;
748  auto pins = getSubChannelPins(i);
749  for (auto r : pins)
750  _console << r << " ";
751  _console << std::endl;
752  _console << "Theta: " << theta * 180 / libMesh::pi << std::endl;
753  }
754  }
755 
756  // Assigning points for center channels
757  for (unsigned int i = 0; i < points_per_corner; i++)
758  {
759  auto new_point = rotatePoint(corner_points[i], theta) + p0 + z0;
760  if (_verbose)
761  {
762  if (z == 0)
763  _console << i << " - " << new_point << std::endl;
764  }
765  mesh_base->add_point(new_point, node_id++);
766  point_counter += 1;
767  }
768  }
769  }
770  } // i
771  if (_verbose)
772  _console << "Point counter: " << point_counter << std::endl;
773 
774  int element_counter = 0;
775  unsigned int elem_id = 0;
776  unsigned int number_of_corner = 0;
777  unsigned int number_of_side = 0;
778  unsigned int number_of_center = 0;
779  unsigned int elems_per_channel = 0;
780  unsigned int points_per_channel = 0;
781  for (unsigned int i = 0; i < _n_channels; i++)
782  {
783  auto subch_type = getSubchannelType(i);
784  if (subch_type == EChannelType::CORNER)
785  {
786  number_of_corner++;
787  elems_per_channel = elems_per_corner;
788  points_per_channel = points_per_corner;
789  if (_verbose)
790  _console << "Corner" << std::endl;
791  }
792  else if (subch_type == EChannelType::EDGE)
793  {
794  number_of_side++;
795  elems_per_channel = elems_per_side;
796  points_per_channel = points_per_side;
797  if (_verbose)
798  _console << "Edge" << std::endl;
799  }
800  else if (subch_type == EChannelType::CENTER)
801  {
802  number_of_center++;
803  elems_per_channel = elems_per_center;
804  points_per_channel = points_per_center;
805  if (_verbose)
806  _console << "Center" << std::endl;
807  }
808  for (unsigned int iz = 0; iz < _n_cells; iz++)
809  {
810  unsigned int elapsed_points = number_of_corner * points_per_corner * (_n_cells + 1) +
811  number_of_side * points_per_side * (_n_cells + 1) +
812  number_of_center * points_per_center * (_n_cells + 1) -
813  points_per_channel * (_n_cells + 1);
814  // index of the central node at base of cell
815  unsigned int indx1 = iz * points_per_channel + elapsed_points;
816  // index of the central node at top of cell
817  unsigned int indx2 = (iz + 1) * points_per_channel + elapsed_points;
818 
819  for (unsigned int i = 0; i < elems_per_channel; i++)
820  {
821  Elem * elem = mesh_base->add_elem(std::make_unique<Prism6>());
822  elem->subdomain_id() = _subchannel_block_id;
823  elem->set_id(elem_id++);
824 
825  if (_verbose)
826  _console << "Node 0: " << *mesh_base->node_ptr(indx1) << std::endl;
827 
828  elem->set_node(0, mesh_base->node_ptr(indx1));
829  elem->set_node(1, mesh_base->node_ptr(indx1 + i + 1));
830  if (i != elems_per_channel - 1)
831  elem->set_node(2, mesh_base->node_ptr(indx1 + i + 2));
832  else
833  elem->set_node(2, mesh_base->node_ptr(indx1 + 1));
834 
835  elem->set_node(3, mesh_base->node_ptr(indx2));
836  elem->set_node(4, mesh_base->node_ptr(indx2 + i + 1));
837  if (i != elems_per_channel - 1)
838  elem->set_node(5, mesh_base->node_ptr(indx2 + i + 2));
839  else
840  elem->set_node(5, mesh_base->node_ptr(indx2 + 1));
841 
842  if (iz == 0)
843  boundary_info.add_side(elem, 0, 0);
844  if (iz == _n_cells - 1)
845  boundary_info.add_side(elem, 4, 1);
846 
847  element_counter += 1;
848  }
849  }
850  }
851  if (_verbose)
852  _console << "Element counter: " << element_counter << std::endl;
853  boundary_info.sideset_name(0) = "inlet";
854  boundary_info.sideset_name(1) = "outlet";
855  mesh_base->subdomain_name(_subchannel_block_id) = "subchannel";
856  if (n_pins > 0)
857  {
858  _elem_id = mesh_base->n_elem();
859  for (auto & ctr : _pin_position)
860  generatePin(mesh_base, ctr);
861  }
862  if (n_pins > 0)
863  mesh_base->subdomain_name(_pin_block_id) = "fuel_pins";
864  if (_verbose)
865  _console << "Mesh assembly done" << std::endl;
866  mesh_base->prepare_for_use();
867 
868  return mesh_base;
869 }
const unsigned int _pin_block_id
Pin subdomain ID.
dof_id_type _elem_id
counter for element numbering
std::vector< Point > _pin_position
x,y coordinates of the fuel pins
const unsigned int _num_sectors
Number of azimuthal sectors used to discretize each circular pin cross section.
const unsigned int _n_cells
Number of cells in the axial direction.
const Real _pitch
Distance between the neighbor fuel pins, pitch.
EChannelType getSubchannelType(unsigned int index) const
returns the type of the subchannel given the index
const Real _flat_to_flat
Half of gap between adjacent assemblies.
std::vector< Real > getSubchannelPosition(unsigned int i)
returns the position of subchannel given pin index
const unsigned int _subchannel_block_id
Subchannel subdomain ID.
void generatePin(std::unique_ptr< MeshBase > &mesh_base, const Point &center)
Generate one detailed fuel pin volume centered at the supplied point.
const bool _verbose
Flag to print out the detailed mesh assembly and coordinates.
Point rotatePoint(Point b, Real theta)
rotate a point by theta radians about the origin
const double radius
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Point getPinPosition(unsigned int i)
returns the position of pin given pin index
const ConsoleStream _console
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
std::vector< unsigned int > getSubChannelPins(unsigned int i)
returns the index of neighboring pins given subchannel index
MooseUnits pow(const MooseUnits &, int)
const unsigned int _n_rings
Number of rings in the geometry.
std::vector< Real > _z_grid
axial location of nodes
std::map< unsigned int, Real > _orientation_map
map inner and outer rings
const Real pi

◆ generatePin()

void SCMDetailedTriAssemblyMeshGenerator::generatePin ( std::unique_ptr< MeshBase > &  mesh_base,
const Point &  center 
)
protected

Generate one detailed fuel pin volume centered at the supplied point.

Definition at line 330 of file SCMDetailedTriAssemblyMeshGenerator.C.

Referenced by generate().

332 {
333  const Real dalpha = 360. / _num_sectors;
334  const Real radius = _pin_diameter / 2.;
335 
336  // Add a center node and radial boundary nodes on each axial level so each pin is discretized into
337  // triangular prism sectors.
338  std::vector<std::vector<Node *>> nodes;
339  nodes.resize(_n_cells + 1);
340  for (unsigned int k = 0; k < _n_cells + 1; k++)
341  {
342  const Real elev = _z_grid[k];
343  nodes[k].push_back(mesh_base->add_point(Point(center(0), center(1), elev)));
344  Real alpha = 0.;
345  for (unsigned int i = 0; i < _num_sectors; i++, alpha += dalpha)
346  {
347  const Real dx = radius * std::cos(alpha * M_PI / 180.);
348  const Real dy = radius * std::sin(alpha * M_PI / 180.);
349  nodes[k].push_back(mesh_base->add_point(Point(center(0) + dx, center(1) + dy, elev)));
350  }
351  }
352 
353  // Add the pin volume elements, linking matching radial sectors between adjacent axial levels.
354  for (unsigned int k = 0; k < _n_cells; k++)
355  for (unsigned int i = 0; i < _num_sectors; i++)
356  {
357  Elem * elem = mesh_base->add_elem(std::make_unique<Prism6>());
358  elem->subdomain_id() = _pin_block_id;
359  elem->set_id(_elem_id++);
360  const unsigned int ctr_idx = 0;
361  const unsigned int idx1 = (i % _num_sectors) + 1;
362  const unsigned int idx2 = ((i + 1) % _num_sectors) + 1;
363  elem->set_node(0, nodes[k][ctr_idx]);
364  elem->set_node(1, nodes[k][idx1]);
365  elem->set_node(2, nodes[k][idx2]);
366  elem->set_node(3, nodes[k + 1][ctr_idx]);
367  elem->set_node(4, nodes[k + 1][idx1]);
368  elem->set_node(5, nodes[k + 1][idx2]);
369  }
370 }
const unsigned int _pin_block_id
Pin subdomain ID.
dof_id_type _elem_id
counter for element numbering
const unsigned int _num_sectors
Number of azimuthal sectors used to discretize each circular pin cross section.
const unsigned int _n_cells
Number of cells in the axial direction.
const double radius
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string alpha
Definition: NS.h:138
static const std::string k
Definition: NS.h:134
static const std::string center
Definition: NS.h:29
std::vector< Real > _z_grid
axial location of nodes

◆ getPinPosition()

Point SCMDetailedTriAssemblyMeshGenerator::getPinPosition ( unsigned int  i)
inlineprotected

returns the position of pin given pin index

Definition at line 32 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

32 { return _pin_position[i]; }
std::vector< Point > _pin_position
x,y coordinates of the fuel pins

◆ getSubChannelPins()

std::vector<unsigned int> SCMDetailedTriAssemblyMeshGenerator::getSubChannelPins ( unsigned int  i)
inlineprotected

returns the index of neighboring pins given subchannel index

Definition at line 36 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

36 { return _chan_to_pin_map[i]; }
std::vector< std::vector< unsigned int > > _chan_to_pin_map
stores the fuel pins belonging to each subchannel

◆ getSubchannelPosition()

std::vector<Real> SCMDetailedTriAssemblyMeshGenerator::getSubchannelPosition ( unsigned int  i)
inlineprotected

returns the position of subchannel given pin index

Definition at line 34 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

34 { return _subchannel_position[i]; }
std::vector< std::vector< Real > > _subchannel_position
x,y coordinates of the subchannels

◆ getSubchannelType()

EChannelType SCMDetailedTriAssemblyMeshGenerator::getSubchannelType ( unsigned int  index) const
inlineprotected

returns the type of the subchannel given the index

Definition at line 26 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

26 { return _subch_type[index]; }
std::vector< EChannelType > _subch_type
Subchannel type.

◆ rotatePoint()

Point SCMDetailedTriAssemblyMeshGenerator::rotatePoint ( Point  b,
Real  theta 
)
protected

rotate a point by theta radians about the origin

Definition at line 872 of file SCMDetailedTriAssemblyMeshGenerator.C.

Referenced by generate().

873 {
874  std::vector<std::vector<Real>> A(3, std::vector<Real>(3));
875 
876  A[0] = {std::cos(theta), -std::sin(theta), 0.0};
877  A[1] = {std::sin(theta), std::cos(theta), 0.0};
878  A[2] = {0.0, 0.0, 1.0};
879 
880  Point rotated_vector = Point(0.0, 0.0, 0.0);
881  for (unsigned int i = 0; i < 3; i++)
882  for (unsigned int j = 0; j < 3; j++)
883  rotated_vector(i) += A[i][j] * b(j);
884 
885  return rotated_vector;
886 }
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")

◆ validParams()

InputParameters SCMDetailedTriAssemblyMeshGenerator::validParams ( )
static

Definition at line 37 of file SCMDetailedTriAssemblyMeshGenerator.C.

38 {
40  params.addClassDescription(
41  "Creates a detailed mesh of subchannels and pins in a triangular lattice arrangement");
42  params.addRequiredParam<Real>("pitch", "Pitch [m]");
43  params.addRequiredParam<Real>("pin_diameter", "Rod diameter [m]");
44  params.addParam<Real>("unheated_length_entry", 0.0, "Unheated length at entry [m]");
45  params.addRequiredParam<Real>("heated_length", "Heated length [m]");
46  params.addParam<Real>("unheated_length_exit", 0.0, "Unheated length at exit [m]");
47  params.addRequiredParam<unsigned int>(
48  "nrings",
49  "Number of fuel-pin rings per assembly, counting the center pin as the first ring [-]");
50  params.addRequiredParam<Real>("flat_to_flat",
51  "Flat to flat distance for the hexagonal assembly [m]");
52  params.addRequiredParam<unsigned int>("n_cells", "The number of cells in the axial direction");
53  params.addRangeCheckedParam<unsigned int>("num_sectors",
54  16,
55  "num_sectors>=4",
56  "Number of azimuthal sectors used to discretize each "
57  "circular pin cross section.");
58  params.addParam<unsigned int>("block_id", 0, "Subchannel block id.");
59  params.deprecateParam("block_id", "subchannel_block_id", "07/01/2027");
60  params.addParam<unsigned int>("pin_block_id", 1, "Fuel pin block id.");
61  params.addParam<bool>("verbose_flag", false, "Flag to print out the mesh coordinates.");
62  return params;
63 }
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void deprecateParam(const std::string &old_name, const std::string &new_name, const std::string &removal_date)
static InputParameters validParams()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)

Member Data Documentation

◆ _chan_to_pin_map

std::vector<std::vector<unsigned int> > SCMDetailedTriAssemblyMeshGenerator::_chan_to_pin_map
protected

stores the fuel pins belonging to each subchannel

Definition at line 77 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by getSubChannelPins(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _elem_id

dof_id_type SCMDetailedTriAssemblyMeshGenerator::_elem_id
protected

counter for element numbering

Definition at line 81 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and generatePin().

◆ _flat_to_flat

const Real SCMDetailedTriAssemblyMeshGenerator::_flat_to_flat
protected

Half of gap between adjacent assemblies.

Definition at line 53 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _heated_length

const Real SCMDetailedTriAssemblyMeshGenerator::_heated_length
protected

heated length of the fuel Pin

Definition at line 41 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by SCMDetailedTriAssemblyMeshGenerator().

◆ _n_cells

const unsigned int SCMDetailedTriAssemblyMeshGenerator::_n_cells
protected

Number of cells in the axial direction.

Definition at line 67 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), generatePin(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _n_channels

unsigned int SCMDetailedTriAssemblyMeshGenerator::_n_channels
protected

number of subchannels

Definition at line 75 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _n_rings

const unsigned int SCMDetailedTriAssemblyMeshGenerator::_n_rings
protected

Number of rings in the geometry.

Definition at line 51 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _nrods

unsigned int SCMDetailedTriAssemblyMeshGenerator::_nrods
protected

Number of pins.

Definition at line 69 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by SCMDetailedTriAssemblyMeshGenerator().

◆ _num_sectors

const unsigned int SCMDetailedTriAssemblyMeshGenerator::_num_sectors
protected

Number of azimuthal sectors used to discretize each circular pin cross section.

Definition at line 55 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and generatePin().

◆ _orientation_map

std::map<unsigned int, Real> SCMDetailedTriAssemblyMeshGenerator::_orientation_map
protected

map inner and outer rings

Definition at line 73 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _pin_block_id

const unsigned int SCMDetailedTriAssemblyMeshGenerator::_pin_block_id
protected

Pin subdomain ID.

Definition at line 65 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and generatePin().

◆ _pin_diameter

const Real SCMDetailedTriAssemblyMeshGenerator::_pin_diameter
protected

fuel Pin diameter

Definition at line 49 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), generatePin(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _pin_position

std::vector<Point> SCMDetailedTriAssemblyMeshGenerator::_pin_position
protected

x,y coordinates of the fuel pins

Definition at line 59 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), getPinPosition(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _pins_in_rings

std::vector<std::vector<unsigned int> > SCMDetailedTriAssemblyMeshGenerator::_pins_in_rings
protected

fuel pins that are belonging to each ring

Definition at line 71 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by SCMDetailedTriAssemblyMeshGenerator().

◆ _pitch

const Real SCMDetailedTriAssemblyMeshGenerator::_pitch
protected

Distance between the neighbor fuel pins, pitch.

Definition at line 47 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _subch_type

std::vector<EChannelType> SCMDetailedTriAssemblyMeshGenerator::_subch_type
protected

Subchannel type.

Definition at line 57 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by getSubchannelType(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _subchannel_block_id

const unsigned int SCMDetailedTriAssemblyMeshGenerator::_subchannel_block_id
protected

Subchannel subdomain ID.

Definition at line 63 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

◆ _subchannel_position

std::vector<std::vector<Real> > SCMDetailedTriAssemblyMeshGenerator::_subchannel_position
protected

x,y coordinates of the subchannels

Definition at line 61 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by getSubchannelPosition(), and SCMDetailedTriAssemblyMeshGenerator().

◆ _unheated_length_entry

const Real SCMDetailedTriAssemblyMeshGenerator::_unheated_length_entry
protected

unheated length of the fuel Pin at the entry of the assembly

Definition at line 39 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by SCMDetailedTriAssemblyMeshGenerator().

◆ _unheated_length_exit

const Real SCMDetailedTriAssemblyMeshGenerator::_unheated_length_exit
protected

unheated length of the fuel Pin at the exit of the assembly

Definition at line 43 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by SCMDetailedTriAssemblyMeshGenerator().

◆ _verbose

const bool SCMDetailedTriAssemblyMeshGenerator::_verbose
protected

Flag to print out the detailed mesh assembly and coordinates.

Definition at line 79 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate().

◆ _z_grid

std::vector<Real> SCMDetailedTriAssemblyMeshGenerator::_z_grid
protected

axial location of nodes

Definition at line 45 of file SCMDetailedTriAssemblyMeshGenerator.h.

Referenced by generate(), generatePin(), and SCMDetailedTriAssemblyMeshGenerator().


The documentation for this class was generated from the following files: