https://mooseframework.inl.gov
HexagonalGridPositions.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 "HexagonalGridPositions.h"
11 #include "HexagonalLatticeUtils.h"
12 
14 
17 {
19  params.addClassDescription(
20  "Create positions along a hexagonal grid. Numbering of positions increases first "
21  "counterclockwise, then expanding outwards from the inner ring. "
22  "Inner-numbering is within a radial ring.");
23 
24  params.addRequiredParam<Point>("center", "Center of the hexagonal grid");
26  "lattice_flat_to_flat",
27  "lattice_flat_to_flat>0",
28  "Distance between two (inner) opposite sides of a lattice. Also known as bundle pitch or "
29  "inner flat-to-flat distance");
30  params.addRequiredRangeCheckedParam<Real>("pin_pitch", "pin_pitch>0", "Distance between pins");
31  params.addRequiredRangeCheckedParam<unsigned int>("nr", "nr>0", "Number of hexagonal rings");
32  params.addRangeCheckedParam<std::vector<std::vector<unsigned int>>>(
33  "pattern",
34  {},
35  "pattern>=0",
36  "A double-indexed hexagonal-shaped array starting with the upper-left corner. '-1's are not "
37  "selected as positions.");
38  params.addParam<std::vector<unsigned int>>(
39  "include_in_pattern", {}, "A vector of the numbers in the pattern to include");
40  params.addParam<std::vector<std::vector<int>>>(
41  "positions_pattern",
42  {},
43  "A double-indexed hexagonal-shaped array with the index of other Positions objects starting "
44  "with the upper-left corner. These positions objects will be distributed within the "
45  "hexagonal grid. The indexing is given in 'positions_pattern_indexing'. Use '-1' to discard "
46  "a position in the lattice.");
47  params.addParam<std::map<std::string, unsigned int>>(
48  "positions_pattern_indexing",
49  {},
50  "A map from the name of positions objects to their index in the 'positions_pattern'");
51 
52  // Use user-provided ordering
53  params.set<bool>("auto_sort") = false;
54  // All functors defined on all processes for now
55  params.set<bool>("auto_broadcast") = false;
56 
57  return params;
58 }
59 
61  : Positions(parameters),
62  _center(getParam<Point>("center")),
63  _lattice_flat_to_flat(getParam<Real>("lattice_flat_to_flat")),
64  _pin_pitch(getParam<Real>("pin_pitch")),
65  _z_axis_index(MooseEnum("X Y Z", "Z")),
66  _nr(getParam<unsigned int>("nr")),
67  _pattern(getParam<std::vector<std::vector<unsigned int>>>("pattern")),
68  _include_in_pattern(
69  std::set<unsigned int>(getParam<std::vector<unsigned int>>("include_in_pattern").begin(),
70  getParam<std::vector<unsigned int>>("include_in_pattern").end())),
71  _positions_pattern(getParam<std::vector<std::vector<int>>>("positions_pattern")),
72  _positions_pattern_indexing(
73  getParam<std::map<std::string, unsigned int>>("positions_pattern_indexing"))
74 {
75  // Check dimensions
76  if (_nr == 1)
77  {
79  paramError("lattice_flat_to_flat",
80  "For one ring, the lattice flat to flat must be at least the pin pitch");
81  }
82  else
83  {
86  paramError("lattice_flat_to_flat",
87  "Lattice flat to flat distance is less than the minimum (3 * nr - 1) * pin_pitch "
88  "/ sqrt(3) given nr rings with a pitch of pin_pitch");
89  }
90 
91  // Check pattern and include_in_pattern
92  if ((_include_in_pattern.empty() && _pattern.size()) ||
93  (_include_in_pattern.size() && _pattern.empty()))
94  paramError(
95  "include_in_pattern",
96  "The 'pattern' parameter and the 'include_in_pattern' must be both specified or both not "
97  "specified by the user.");
98  for (const auto include : _include_in_pattern)
99  {
100  bool found = false;
101  for (const auto & row : _pattern)
102  if (std::find(row.begin(), row.end(), include) != row.end())
103  found = true;
104  if (!found)
105  paramError("include_in_pattern",
106  "Pattern item '" + std::to_string(include) +
107  "' to include is not present in the pattern");
108  }
109 
110  // Check positions_pattern and positions_pattern_indexing
111  if ((_positions_pattern.empty() && !_positions_pattern_indexing.empty()) ||
112  (!_positions_pattern.empty() && _positions_pattern_indexing.empty()))
113  paramError("positions_pattern_indexing",
114  "The 'positions_pattern' parameter and the 'positions_pattern_indexing' must be "
115  "both specified or both not specified by the user.");
116  for (const auto & [pos_name, index] : _positions_pattern_indexing)
117  {
118  bool found = false;
119  for (const auto & row : _positions_pattern)
120  if (std::find(row.begin(), row.end(), index) != row.end())
121  found = true;
122  if (!found)
123  paramError("include_in_pattern",
124  "Pattern item '" + pos_name + "' with index '" + std::to_string(index) +
125  "' to include is not present in the pattern");
126  }
127 
128  // Check incompatible parameters
129  if (((_positions_pattern.size() && _positions_pattern[0].size()) ||
130  _positions_pattern_indexing.size()) &&
131  ((_pattern.size() && _pattern[0].size()) || _include_in_pattern.size()))
132  paramError("positions_pattern",
133  "'pattern'/'include_in_pattern' are not supported in combination with "
134  "'positions_pattern/positions_pattern_indexing'. Only one pattern is supported");
135 
136  // Obtain the positions by unrolling the patterns
137  initialize();
138  // Sort if needed (user-specified)
139  finalize();
140 }
141 
142 void
144 {
145  clearPositions();
146 
147  // We make very large pins so they cover the entire position
148  _hex_latt = std::make_unique<HexagonalLatticeUtils>(
150 
151  if (!isParamSetByUser("positions_pattern"))
152  {
153  // Unroll pattern
154  std::vector<int> pattern_unrolled;
155 
156  if (_pattern.size())
157  {
158  // Check number of pins in pattern
159  std::size_t pattern_size = 0;
160  for (const auto & row : _pattern)
161  pattern_size += row.size();
162  if (_pattern.size() != cast_int<std::size_t>(2 * _nr - 1))
163  mooseError("Number of rows in pattern (",
164  _pattern.size(),
165  ") should be equal to twice the number of hexagonal rings minus one");
166  if (pattern_size != _hex_latt->totalPins(_nr))
167  mooseError("Pattern size (",
168  pattern_size,
169  ") does not match the number of pins with ",
170  _nr,
171  " rings: ",
172  _hex_latt->totalPins(_nr));
173 
174  pattern_unrolled.resize(_hex_latt->totalPins(_nr));
175  unsigned int i = 0;
176  for (const auto r_i : make_range(_nr))
177  for (const auto a_i : make_range(_hex_latt->pins(r_i + 1)))
178  {
179  libmesh_ignore(a_i);
180  unsigned int row_i, within_row_i;
181  _hex_latt->get2DInputPatternIndex(i, row_i, within_row_i);
182  pattern_unrolled[i++] = _pattern[row_i][within_row_i];
183  }
184  }
185  // just needs to be the right size
186  else
187  pattern_unrolled.resize(_hex_latt->totalPins(_nr), 0);
188 
189  // Count the number of positions we do not need to include
190  unsigned int n_exclusions = 0;
191  if (_include_in_pattern.size())
192  for (const auto patt : pattern_unrolled)
193  if (_include_in_pattern.count(patt) == 0)
194  n_exclusions++;
195 
196  // Size array, remove the '-1' / not included positions
197  const auto n_positions = cast_int<std::size_t>(_hex_latt->totalPins(_nr) - n_exclusions);
198  _positions.resize(n_positions);
199 
200  // Fill the positions by retrieving the pin centers at indices included in the pattern (if
201  // specified)
202  unsigned int pos_i = 0;
203  for (const auto patt_i : index_range(pattern_unrolled))
204  if (!_pattern.size() || !_include_in_pattern.size() ||
205  _include_in_pattern.count(pattern_unrolled[patt_i]))
206  _positions[pos_i++] = _hex_latt->pinCenters()[patt_i];
207  }
208  else
209  {
210  // Unroll pattern into positions array
211  const bool initial = _fe_problem.getCurrentExecuteOnFlag() == EXEC_INITIAL;
212 
213  // Check number of positions in pattern of nested positions
214  unsigned pattern_size = 0;
215  for (const auto & row : _positions_pattern)
216  pattern_size += row.size();
217  if (_positions_pattern.size() != cast_int<std::size_t>(2 * _nr - 1))
218  mooseError("Number of rows in 'positions_pattern' (",
219  _pattern.size(),
220  ") should be equal to twice the number of hexagonal rings minus one");
221  if (pattern_size != _hex_latt->totalPins(_nr))
222  mooseError("Pattern size ",
223  pattern_size,
224  " does not match the number of pins with ",
225  _nr,
226  " rings: ",
227  _hex_latt->totalPins(_nr));
228 
229  // Check that all the positions names are valid
230  unsigned num_pos = 0;
231  for (const auto & [pos_name, index] : _positions_pattern_indexing)
232  if (_fe_problem.hasUserObject(pos_name))
233  num_pos += _fe_problem.getPositionsObject(pos_name).getNumPositions(initial);
234  _positions.reserve(num_pos);
235 
236  // Invert map from positions to indices
237  std::map<unsigned int, PositionsName> index_to_pos;
238  for (const auto & [pos_name, index] : _positions_pattern_indexing)
239  index_to_pos[index] = pos_name;
240 
241  // Unroll pattern : the positions vector is 1D and should be
242  std::vector<PositionsName> pattern_unrolled;
243  pattern_unrolled.resize(_hex_latt->totalPins(_nr));
244  unsigned int i = 0;
245  for (const auto r_i : make_range(_nr))
246  for (const auto a_i : make_range(_hex_latt->pins(r_i + 1)))
247  {
248  libmesh_ignore(a_i);
249  unsigned int row_i, within_row_i;
250  _hex_latt->get2DInputPatternIndex(i, row_i, within_row_i);
251  const auto pos_index = _positions_pattern[row_i][within_row_i];
252  if (auto it = index_to_pos.find(cast_int<unsigned int>(pos_index));
253  it != index_to_pos.end())
254  pattern_unrolled[i++] = it->second;
255  else if (pos_index != -1)
256  paramError("positions_pattern",
257  "Index '" + std::to_string(pos_index) +
258  "' in pattern is not found in 'positions_pattern_indexing'");
259  else
260  pattern_unrolled[i++] = "-1";
261  }
262 
263  // Now place the positions in the _positions array with the offset from the parent lattice index
264  for (const auto patt_i : index_range(pattern_unrolled))
265  {
266  const auto & pos_name = pattern_unrolled[patt_i];
267  if (pos_name != "-1")
268  for (const auto & pos : _fe_problem.getPositionsObject(pos_name).getPositions(initial))
269  _positions.push_back(_hex_latt->pinCenters()[patt_i] + pos);
270  }
271  }
272 
273  _initialized = true;
274 }
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
static InputParameters validParams()
const Real _pin_pitch
Pitch between fuel pins.
std::map< std::string, unsigned int > _positions_pattern_indexing
Indexing of the positions objects in the pattern.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const ExecFlagType & getCurrentExecuteOnFlag() const
void clearPositions()
const Real _lattice_flat_to_flat
Distance from one side to the one facing it of the lattice.
T & set(const std::string &name, bool quiet_mode=false)
if(subdm)
Creates positions (points) following an hexagonal grid.
bool hasUserObject(const std::string &name) const
const Positions & getPositionsObject(const std::string &name) const
std::vector< std::vector< int > > _positions_pattern
List of positions objects, the positions of which are translated in the parent hexagonal pattern...
std::set< unsigned int > _include_in_pattern
List of the pattern locations to include. Include all if empty.
void addRequiredParam(const std::string &name, const std::string &doc_string)
bool _initialized
HexagonalGridPositions(const InputParameters &parameters)
void libmesh_ignore(const Args &...)
const MooseEnum _z_axis_index
Axial component for the Z axis.
std::unique_ptr< HexagonalLatticeUtils > _hex_latt
Hexagonal lattice utility object.
registerMooseObject("ReactorApp", HexagonalGridPositions)
std::vector< Point > & _positions
unsigned int getNumPositions(bool initial=false) const
void paramError(const std::string &param, Args... args) const
const std::vector< Point > & getPositions(bool initial) const
bool isParamSetByUser(const std::string &nm) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template * sqrt(_arg)) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(tanh
FEProblemBase & _fe_problem
IntRange< T > make_range(T beg, T end)
virtual void finalize() override
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static InputParameters validParams()
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::vector< std::vector< unsigned int > > _pattern
2D pattern of the pins to select (if specified)
void ErrorVector unsigned int
auto index_range(const T &sizable)
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
const ExecFlagType EXEC_INITIAL
const unsigned int _nr
Number of rings in the radial direction.