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.addParam<Real>("rotation_around_axis",
33  0.,
34  "Rotation angle to apply to the underlying hexagonal lattice (in degrees)");
35 
36  params.addRangeCheckedParam<std::vector<std::vector<unsigned int>>>(
37  "pattern",
38  {},
39  "pattern>=0",
40  "A double-indexed hexagonal-shaped array starting with the upper-left corner. '-1's are not "
41  "selected as positions.");
42  params.addParam<std::vector<unsigned int>>(
43  "include_in_pattern", {}, "A vector of the numbers in the pattern to include");
44  params.addParam<std::vector<std::vector<int>>>(
45  "positions_pattern",
46  {},
47  "A double-indexed hexagonal-shaped array with the index of other Positions objects starting "
48  "with the upper-left corner. These positions objects will be distributed within the "
49  "hexagonal grid. The indexing is given in 'positions_pattern_indexing'. Use '-1' to discard "
50  "a position in the lattice.");
51  params.addParam<std::map<std::string, unsigned int>>(
52  "positions_pattern_indexing",
53  {},
54  "A map from the name of positions objects to their index in the 'positions_pattern'");
55 
56  // Use user-provided ordering
57  params.set<bool>("auto_sort") = false;
58  // All functors defined on all processes for now
59  params.set<bool>("auto_broadcast") = false;
60 
61  return params;
62 }
63 
65  : Positions(parameters),
66  _center(getParam<Point>("center")),
67  _lattice_flat_to_flat(getParam<Real>("lattice_flat_to_flat")),
68  _pin_pitch(getParam<Real>("pin_pitch")),
69  _z_axis_index(MooseEnum("X Y Z", "Z")),
70  _nr(getParam<unsigned int>("nr")),
71  _pattern(getParam<std::vector<std::vector<unsigned int>>>("pattern")),
72  _include_in_pattern(
73  std::set<unsigned int>(getParam<std::vector<unsigned int>>("include_in_pattern").begin(),
74  getParam<std::vector<unsigned int>>("include_in_pattern").end())),
75  _positions_pattern(getParam<std::vector<std::vector<int>>>("positions_pattern")),
76  _positions_pattern_indexing(
77  getParam<std::map<std::string, unsigned int>>("positions_pattern_indexing"))
78 {
79  // Check dimensions
80  if (_nr == 1)
81  {
83  paramError("lattice_flat_to_flat",
84  "For one ring, the lattice flat to flat must be at least the pin pitch");
85  }
86  else
87  {
90  paramError("lattice_flat_to_flat",
91  "Lattice flat to flat distance is less than the minimum (3 * nr - 1) * pin_pitch "
92  "/ sqrt(3) given nr rings with a pitch of pin_pitch");
93  }
94 
95  // Check pattern and include_in_pattern
96  if ((_include_in_pattern.empty() && _pattern.size()) ||
97  (_include_in_pattern.size() && _pattern.empty()))
98  paramError(
99  "include_in_pattern",
100  "The 'pattern' parameter and the 'include_in_pattern' must be both specified or both not "
101  "specified by the user.");
102  for (const auto include : _include_in_pattern)
103  {
104  bool found = false;
105  for (const auto & row : _pattern)
106  if (std::find(row.begin(), row.end(), include) != row.end())
107  found = true;
108  if (!found)
109  paramError("include_in_pattern",
110  "Pattern item '" + std::to_string(include) +
111  "' to include is not present in the pattern");
112  }
113 
114  // Check positions_pattern and positions_pattern_indexing
115  if ((_positions_pattern.empty() && !_positions_pattern_indexing.empty()) ||
116  (!_positions_pattern.empty() && _positions_pattern_indexing.empty()))
117  paramError("positions_pattern_indexing",
118  "The 'positions_pattern' parameter and the 'positions_pattern_indexing' must be "
119  "both specified or both not specified by the user.");
120  for (const auto & [pos_name, index] : _positions_pattern_indexing)
121  {
122  bool found = false;
123  for (const auto & row : _positions_pattern)
124  if (std::find(row.begin(), row.end(), index) != row.end())
125  found = true;
126  if (!found)
127  paramError("include_in_pattern",
128  "Pattern item '" + pos_name + "' with index '" + std::to_string(index) +
129  "' to include is not present in the pattern");
130  }
131 
132  // Check incompatible parameters
133  if (((_positions_pattern.size() && _positions_pattern[0].size()) ||
134  _positions_pattern_indexing.size()) &&
135  ((_pattern.size() && _pattern[0].size()) || _include_in_pattern.size()))
136  paramError("positions_pattern",
137  "'pattern'/'include_in_pattern' are not supported in combination with "
138  "'positions_pattern/positions_pattern_indexing'. Only one pattern is supported");
139 
140  // Obtain the positions by unrolling the patterns
141  initialize();
142  // Sort if needed (user-specified)
143  finalize();
144 }
145 
146 void
148 {
149  clearPositions();
150 
151  // We make very large pins so they cover the entire position
152  _hex_latt = std::make_unique<HexagonalLatticeUtils>(_lattice_flat_to_flat,
153  _pin_pitch,
154  _pin_pitch,
155  0.,
156  1.,
157  _nr,
159  getParam<Real>("rotation_around_axis"));
160 
161  if (!isParamSetByUser("positions_pattern"))
162  {
163  // Unroll pattern
164  std::vector<int> pattern_unrolled;
165 
166  if (_pattern.size())
167  {
168  // Check number of pins in pattern
169  std::size_t pattern_size = 0;
170  for (const auto & row : _pattern)
171  pattern_size += row.size();
172  if (_pattern.size() != cast_int<std::size_t>(2 * _nr - 1))
173  mooseError("Number of rows in pattern (",
174  _pattern.size(),
175  ") should be equal to twice the number of hexagonal rings minus one");
176  if (pattern_size != _hex_latt->totalPins(_nr))
177  mooseError("Pattern size (",
178  pattern_size,
179  ") does not match the number of pins with ",
180  _nr,
181  " rings: ",
182  _hex_latt->totalPins(_nr));
183 
184  pattern_unrolled.resize(_hex_latt->totalPins(_nr));
185  unsigned int i = 0;
186  for (const auto r_i : make_range(_nr))
187  for (const auto a_i : make_range(_hex_latt->pins(r_i + 1)))
188  {
189  libmesh_ignore(a_i);
190  unsigned int row_i, within_row_i;
191  _hex_latt->get2DInputPatternIndex(i, row_i, within_row_i);
192  pattern_unrolled[i++] = _pattern[row_i][within_row_i];
193  }
194  }
195  // just needs to be the right size
196  else
197  pattern_unrolled.resize(_hex_latt->totalPins(_nr), 0);
198 
199  // Count the number of positions we do not need to include
200  unsigned int n_exclusions = 0;
201  if (_include_in_pattern.size())
202  for (const auto patt : pattern_unrolled)
203  if (_include_in_pattern.count(patt) == 0)
204  n_exclusions++;
205 
206  // Size array, remove the '-1' / not included positions
207  const auto n_positions = cast_int<std::size_t>(_hex_latt->totalPins(_nr) - n_exclusions);
208  _positions.resize(n_positions);
209 
210  // Fill the positions by retrieving the pin centers at indices included in the pattern (if
211  // specified)
212  unsigned int pos_i = 0;
213  for (const auto patt_i : index_range(pattern_unrolled))
214  if (!_pattern.size() || !_include_in_pattern.size() ||
215  _include_in_pattern.count(pattern_unrolled[patt_i]))
216  _positions[pos_i++] = _hex_latt->pinCenters()[patt_i];
217  }
218  else
219  {
220  // Unroll pattern into positions array
221  const bool initial = _fe_problem.getCurrentExecuteOnFlag() == EXEC_INITIAL;
222 
223  // Check number of positions in pattern of nested positions
224  unsigned pattern_size = 0;
225  for (const auto & row : _positions_pattern)
226  pattern_size += row.size();
227  if (_positions_pattern.size() != cast_int<std::size_t>(2 * _nr - 1))
228  mooseError("Number of rows in 'positions_pattern' (",
229  _pattern.size(),
230  ") should be equal to twice the number of hexagonal rings minus one");
231  if (pattern_size != _hex_latt->totalPins(_nr))
232  mooseError("Pattern size ",
233  pattern_size,
234  " does not match the number of pins with ",
235  _nr,
236  " rings: ",
237  _hex_latt->totalPins(_nr));
238 
239  // Check that all the positions names are valid
240  unsigned num_pos = 0;
241  for (const auto & [pos_name, index] : _positions_pattern_indexing)
242  if (_fe_problem.hasUserObject(pos_name))
243  num_pos += _fe_problem.getPositionsObject(pos_name).getNumPositions(initial);
244  _positions.reserve(num_pos);
245 
246  // Invert map from positions to indices
247  std::map<unsigned int, PositionsName> index_to_pos;
248  for (const auto & [pos_name, index] : _positions_pattern_indexing)
249  index_to_pos[index] = pos_name;
250 
251  // Unroll pattern : the positions vector is 1D and should be
252  std::vector<PositionsName> pattern_unrolled;
253  pattern_unrolled.resize(_hex_latt->totalPins(_nr));
254  unsigned int i = 0;
255  for (const auto r_i : make_range(_nr))
256  for (const auto a_i : make_range(_hex_latt->pins(r_i + 1)))
257  {
258  libmesh_ignore(a_i);
259  unsigned int row_i, within_row_i;
260  _hex_latt->get2DInputPatternIndex(i, row_i, within_row_i);
261  const auto pos_index = _positions_pattern[row_i][within_row_i];
262  if (auto it = index_to_pos.find(cast_int<unsigned int>(pos_index));
263  it != index_to_pos.end())
264  pattern_unrolled[i++] = it->second;
265  else if (pos_index != -1)
266  paramError("positions_pattern",
267  "Index '" + std::to_string(pos_index) +
268  "' in pattern is not found in 'positions_pattern_indexing'");
269  else
270  pattern_unrolled[i++] = "-1";
271  }
272 
273  // Now place the positions in the _positions array with the offset from the parent lattice index
274  for (const auto patt_i : index_range(pattern_unrolled))
275  {
276  const auto & pos_name = pattern_unrolled[patt_i];
277  if (pos_name != "-1")
278  for (const auto & pos : _fe_problem.getPositionsObject(pos_name).getPositions(initial))
279  _positions.push_back(_hex_latt->pinCenters()[patt_i] + pos);
280  }
281  }
282 
283  _initialized = true;
284 }
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 paramError(const std::string &param, Args... args) const
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
const std::vector< Point > & getPositions(bool initial) 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)
bool isParamSetByUser(const std::string &name) const
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.