https://mooseframework.inl.gov
CSGHexagonalLattice.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "CSGHexagonalLattice.h"
11 
12 namespace CSG
13 {
14 
16  const std::string & name,
17  Real pitch,
18  std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes,
19  const std::optional<OuterVariant> & outer)
20  : CSGLattice(name, MooseUtils::prettyCppType<CSGHexagonalLattice>(), outer), _pitch(pitch)
21 {
22  setUniverses(universes); // this will set _nrow
23  if (_pitch < 0)
24  mooseError("Lattice " + getName() + " must have pitch greater than 0.");
25 }
26 
28  Real pitch,
29  const std::optional<OuterVariant> & outer)
31  _pitch(pitch),
32  _nrow(0),
33  _nring(0)
34 {
35  if (_pitch < 0)
36  mooseError("Lattice " + getName() + " must have pitch greater than 0.");
37 }
38 
39 bool
41  std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes) const
42 {
43  if (universes.size() < 1) // need at least one row
44  return false;
45 
46  if (universes.size() % 2 == 0) // must be odd number of rows
47  return false;
48 
49  // each row differs in how many elements are required depending on size of lattice
50  unsigned int num_row = universes.size();
51  unsigned int center_row = (num_row - 1) / 2;
52  for (unsigned int row_i : index_range(universes))
53  {
54  unsigned int n_ele =
55  num_row - ((row_i > center_row) ? (row_i - center_row) : (center_row - row_i));
56  if (universes[row_i].size() != n_ele)
57  return false;
58  }
59 
60  return true;
61 }
62 
63 void
65  std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes)
66 {
67  // check for valid map arrangment
68  if (!isValidUniverseMap(universes))
69  mooseError("Cannot set lattice " + getName() +
70  " with universes. Does not have valid dimensions for lattice type " + getType());
71  // set attributes based on universe map (in case they differ from original values)
72  _nrow = universes.size();
74  _universe_map = universes;
75  buildIndexMap();
76 }
77 void
79 {
80  if (pitch < 0)
81  mooseError("Lattice " + getName() + " must have pitch greater than 0.");
82  _pitch = pitch;
83 }
84 
85 std::unordered_map<std::string, AttributeVariant>
87 {
88  return {{"nrow", static_cast<unsigned int>(_nrow)},
89  {"nring", static_cast<unsigned int>(_nring)},
90  {"pitch", _pitch}};
91 }
92 
93 bool
94 CSGHexagonalLattice::isValidIndex(const std::pair<int, int> index) const
95 {
96  auto row = index.first; // row index
97  auto ele = index.second; // column index within the row
98 
99  // Check if row is valid (0 <= row < _nrow)
100  if (row < 0 || row >= (int)_nrow)
101  return false;
102 
103  // Calculate maximum number of elements in this specific row
104  auto center_row = (_nrow - 1) / 2; // center row index
105  int max_ele = _nrow - std::abs((int)(row - center_row));
106 
107  // Check if column index is valid for this row
108  return !(ele < 0 || ele >= max_ele);
109 }
110 
111 bool
113 {
114  if (other.getType() != this->getType())
115  return false;
116 
117  auto this_dims = this->getAttributes();
118  auto other_dims = other.getAttributes();
119  if (std::get<unsigned int>(this_dims["nrow"]) != std::get<unsigned int>(other_dims["nrow"]))
120  return false;
121  if (std::get<unsigned int>(this_dims["nring"]) != std::get<unsigned int>(other_dims["nring"]))
122  return false;
123  if (std::get<Real>(this_dims["pitch"]) != std::get<Real>(other_dims["pitch"]))
124  return false;
125  return true;
126 }
127 
128 void
130 {
131  for (const auto ring : make_range(_nring))
132  {
133  unsigned int num_elements = (ring == _nring - 1) ? 1 : 6 * (_nring - 1 - ring);
134  for (const auto element : make_range(num_elements))
135  {
136  std::pair<unsigned int, unsigned int> ring_index = std::make_pair(ring, element);
137  std::pair<unsigned int, unsigned int> row_index = getRowIndexFromRingIndex(ring_index);
138  _row_to_ring_map[row_index] = ring_index;
139  }
140  }
141 }
142 
143 std::pair<int, int>
144 CSGHexagonalLattice::getRowIndexFromRingIndex(const std::pair<int, int> & ring_ele_index) const
145 {
146  auto og_ring = ring_ele_index.first; // ring corresponds to the outermost ring as ring 0
147  int ring = _nring - og_ring - 1; // convert to internal indexing (0 as innermost ring)
148  auto element = ring_ele_index.second;
149 
150  if (og_ring < 0 || og_ring >= (int)_nring)
151  mooseError("Ring " + std::to_string(og_ring) + " is not valid for hexagonal lattice " +
152  getName());
153  if (element < 0 || element >= (ring == 0 ? 1 : 6 * ring))
154  mooseError("Position " + std::to_string(element) + " is not valid for ring " +
155  std::to_string(og_ring) + " in hexagonal lattice " + getName());
156 
157  // Calculate the center row and column indices
158  int center_row = (_nrow - 1) / 2;
159  int center_col = center_row;
160 
161  // Special case for the center element
162  if (ring == 0)
163  return {center_row, center_col};
164 
165  // Calculate the side length of the hexagon for the given ring
166  int side_length = ring;
167 
168  // Determine which side of the hexagon the element is on and get row/col from this
169  int side = element / side_length;
170  int offset = element % side_length; // position within the side moving counter-clockwise
171  int row, col;
172 
173  // lamba to calculate the number of columns in any given row
174  auto calc_num_cols_in_row = [&](int r) { return _nrow - std::abs(center_row - r); };
175 
176  // diagram of side numbers:
177  // 4
178  // _______
179  // / \*
180  // 3 / \ 5
181  // / \*
182  // \ /
183  // 2 \ / 0
184  // \ _______ /
185  // 1
186  switch (side)
187  {
188  case 0: // bottom right (contains starting position of the ring)
189  row = center_row + offset;
190  col = calc_num_cols_in_row(row) - og_ring - 1;
191  break;
192  case 1: // bottom
193  row = center_row + ring;
194  col = calc_num_cols_in_row(row) - og_ring - 1 - offset;
195  break;
196  case 2: // bottom left
197  row = center_row + (side_length - offset);
198  col = center_col - ring;
199  break;
200  case 3: // top left
201  row = center_row - offset;
202  col = center_col - ring;
203  break;
204  case 4: // top
205  row = center_row - ring;
206  col = center_col - ring + offset;
207  break;
208  case 5: // top right
209  row = center_row - (side_length - offset);
210  col = calc_num_cols_in_row(row) - og_ring - 1;
211  break;
212  default:
213  mooseError("Invalid side ID calculation in hexagonal lattice " + getName());
214  }
215 
216  mooseAssert(isValidIndex(std::make_pair(row, col)),
217  "Calculated index (" + std::to_string(row) + ", " + std::to_string(col) +
218  ") is not valid for hexagonal lattice " + getName());
219 
220  return {row, col};
221 }
222 
223 std::pair<int, int>
224 CSGHexagonalLattice::getRingIndexFromRowIndex(const std::pair<int, int> & row_col_index) const
225 {
226  if (!isValidIndex(row_col_index))
227  mooseError("Index (" + std::to_string(row_col_index.first) + ", " +
228  std::to_string(row_col_index.second) +
229  ") is not a valid index for hexagonal "
230  "lattice " +
231  getName());
232 
233  return _row_to_ring_map.at(row_col_index);
234 }
235 
237 
238 unsigned int
239 nRowToRing(int nrow)
240 {
241  if (nrow == 0) // special case
242  return 0;
243  std::string base_msg = "Cannot convert number of rows " + std::to_string(nrow) +
244  " to number of rings in hexagonal lattice. ";
245  if (nrow < 0)
246  mooseError(base_msg + "Number of rows must be >= 0.");
247  if (nrow % 2 == 0)
248  mooseError(base_msg + "Number of rows must be odd.");
249  return (nrow + 1) / 2;
250 }
251 
252 unsigned int
253 nRingToRow(int nring)
254 {
255  if (nring == 0) // special case
256  return 0;
257  if (nring < 0)
258  mooseError("Cannot convert number of rings " + std::to_string(nring) +
259  " to number of rows in hexagonal lattice. Number of rings must be >= 0.");
260  return 2 * nring - 1;
261 }
262 
263 } // namespace CSG
std::string name(const ElemQuality q)
void setPitch(Real pitch)
set the pitch of the lattice
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Definition: EigenADReal.h:50
unsigned int _nring
number of rings in the hexagonal lattice, should be consistent with the number of rows ...
virtual bool compareAttributes(const CSGLattice &other) const override
compare the attributes returned in getAttributes of this lattice to another lattice ...
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
const std::string & getType() const
Get the lattice type.
Definition: CSGLattice.h:69
const std::string & getName() const
Get the name of lattice.
Definition: CSGLattice.h:62
CSGLattice is the abstract class for defining lattices.
Definition: CSGLattice.h:34
std::map< std::pair< unsigned int, unsigned int >, std::pair< unsigned int, unsigned int > > _row_to_ring_map
map of row-column indices to ring-position indices for quick conversion and look-up ...
std::pair< int, int > getRingIndexFromRowIndex(const std::pair< int, int > &row_col_index) const
Given an index in row-column form, get the corresponding ring-position index.
std::vector< std::vector< std::reference_wrapper< const CSGUniverse > > > _universe_map
Universes in the arrangement of how they appear in the lattice; dimensions depends on lattice type...
Definition: CSGLattice.h:225
CSGHexagonalLattice is the class for constructing hexagonal lattices of CSGUniverses arranged in conc...
virtual bool isValidUniverseMap(std::vector< std::vector< std::reference_wrapper< const CSGUniverse >>> universes) const override
check if the arrangement of the provided universes is valid for the hexagonal lattice given the numbe...
unsigned int nRowToRing(int nrow)
methods to help convert between number of rows and rings get the total number of rings from the numbe...
Real _pitch
lattice pitch (flat-to-flat distance between adjacent hex elements)
virtual std::unordered_map< std::string, AttributeVariant > getAttributes() const =0
Get attributes that define the lattice (excluding the universe map).
virtual std::unordered_map< std::string, AttributeVariant > getAttributes() const override
Get attributes that define the lattice (excluding the universe map).
void buildIndexMap()
build a mapping of row-column indices to ring-position indices for quick conversion and look-up...
unsigned int nRingToRow(int nring)
get the total number of rows from the number of rings
virtual bool isValidIndex(const std::pair< int, int > index) const override
check if provided index in row-column form is valid for the given hexagonal lattice ...
IntRange< T > make_range(T beg, T end)
unsigned int _nrow
number of rows in the hexagonal lattice (must be odd), should be consistent with the number of rings ...
virtual void setUniverses(std::vector< std::vector< std::reference_wrapper< const CSGUniverse >>> universes) override
set the universes that define the lattice layout
std::pair< int, int > getRowIndexFromRingIndex(const std::pair< int, int > &row_col_index) const
Given an index in ring-position form, get the corresponding row-column index.
auto index_range(const T &sizable)
CSGHexagonalLattice(const std::string &name, Real pitch, std::vector< std::vector< std::reference_wrapper< const CSGUniverse >>> universes, const std::optional< OuterVariant > &outer=std::nullopt)
Construct a new CSGHexagonalLattice from a map of universes.
std::string prettyCppType(const std::string &cpp_type)
Definition: MooseUtils.C:1140