Line data Source code
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 : 15 40 : CSGHexagonalLattice::CSGHexagonalLattice( 16 : const std::string & name, 17 : Real pitch, 18 : std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes, 19 40 : const std::optional<OuterVariant> & outer) 20 40 : : CSGLattice(name, MooseUtils::prettyCppType<CSGHexagonalLattice>(), outer), _pitch(pitch) 21 : { 22 44 : setUniverses(universes); // this will set _nrow 23 36 : if (_pitch < 0) 24 0 : mooseError("Lattice " + getName() + " must have pitch greater than 0."); 25 44 : } 26 : 27 12 : CSGHexagonalLattice::CSGHexagonalLattice(const std::string & name, 28 : Real pitch, 29 12 : const std::optional<OuterVariant> & outer) 30 12 : : CSGLattice(name, MooseUtils::prettyCppType<CSGHexagonalLattice>(), outer), 31 12 : _pitch(pitch), 32 12 : _nrow(0), 33 24 : _nring(0) 34 : { 35 12 : if (_pitch < 0) 36 6 : mooseError("Lattice " + getName() + " must have pitch greater than 0."); 37 14 : } 38 : 39 : bool 40 44 : CSGHexagonalLattice::isValidUniverseMap( 41 : std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes) const 42 : { 43 44 : if (universes.size() < 1) // need at least one row 44 0 : return false; 45 : 46 44 : if (universes.size() % 2 == 0) // must be odd number of rows 47 2 : return false; 48 : 49 : // each row differs in how many elements are required depending on size of lattice 50 42 : unsigned int num_row = universes.size(); 51 42 : unsigned int center_row = (num_row - 1) / 2; 52 214 : for (unsigned int row_i : index_range(universes)) 53 : { 54 174 : unsigned int n_ele = 55 174 : num_row - ((row_i > center_row) ? (row_i - center_row) : (center_row - row_i)); 56 174 : if (universes[row_i].size() != n_ele) 57 2 : return false; 58 : } 59 : 60 40 : return true; 61 : } 62 : 63 : void 64 44 : CSGHexagonalLattice::setUniverses( 65 : std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> universes) 66 : { 67 : // check for valid map arrangment 68 44 : if (!isValidUniverseMap(universes)) 69 20 : mooseError("Cannot set lattice " + getName() + 70 12 : " 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 40 : _nrow = universes.size(); 73 40 : _nring = nRowToRing(_nrow); 74 40 : _universe_map = universes; 75 40 : buildIndexMap(); 76 40 : } 77 : void 78 4 : CSGHexagonalLattice::setPitch(const Real pitch) 79 : { 80 4 : if (pitch < 0) 81 6 : mooseError("Lattice " + getName() + " must have pitch greater than 0."); 82 2 : _pitch = pitch; 83 2 : } 84 : 85 : std::unordered_map<std::string, AttributeVariant> 86 38 : CSGHexagonalLattice::getAttributes() const 87 : { 88 0 : return {{"nrow", static_cast<unsigned int>(_nrow)}, 89 0 : {"nring", static_cast<unsigned int>(_nring)}, 90 190 : {"pitch", _pitch}}; 91 38 : } 92 : 93 : bool 94 152 : CSGHexagonalLattice::isValidIndex(const std::pair<int, int> index) const 95 : { 96 152 : auto row = index.first; // row index 97 152 : auto ele = index.second; // column index within the row 98 : 99 : // Check if row is valid (0 <= row < _nrow) 100 152 : if (row < 0 || row >= (int)_nrow) 101 6 : return false; 102 : 103 : // Calculate maximum number of elements in this specific row 104 146 : auto center_row = (_nrow - 1) / 2; // center row index 105 146 : int max_ele = _nrow - std::abs((int)(row - center_row)); 106 : 107 : // Check if column index is valid for this row 108 146 : return !(ele < 0 || ele >= max_ele); 109 : } 110 : 111 : bool 112 14 : CSGHexagonalLattice::compareAttributes(const CSGLattice & other) const 113 : { 114 14 : if (other.getType() != this->getType()) 115 0 : return false; 116 : 117 14 : auto this_dims = this->getAttributes(); 118 14 : auto other_dims = other.getAttributes(); 119 56 : if (std::get<unsigned int>(this_dims["nrow"]) != std::get<unsigned int>(other_dims["nrow"])) 120 6 : return false; 121 32 : if (std::get<unsigned int>(this_dims["nring"]) != std::get<unsigned int>(other_dims["nring"])) 122 0 : return false; 123 32 : if (std::get<Real>(this_dims["pitch"]) != std::get<Real>(other_dims["pitch"])) 124 4 : return false; 125 4 : return true; 126 14 : } 127 : 128 : void 129 40 : CSGHexagonalLattice::buildIndexMap() 130 : { 131 144 : for (const auto ring : make_range(_nring)) 132 : { 133 104 : unsigned int num_elements = (ring == _nring - 1) ? 1 : 6 * (_nring - 1 - ring); 134 684 : for (const auto element : make_range(num_elements)) 135 : { 136 580 : std::pair<unsigned int, unsigned int> ring_index = std::make_pair(ring, element); 137 580 : std::pair<unsigned int, unsigned int> row_index = getRowIndexFromRingIndex(ring_index); 138 580 : _row_to_ring_map[row_index] = ring_index; 139 : } 140 : } 141 40 : } 142 : 143 : std::pair<int, int> 144 710 : CSGHexagonalLattice::getRowIndexFromRingIndex(const std::pair<int, int> & ring_ele_index) const 145 : { 146 710 : auto og_ring = ring_ele_index.first; // ring corresponds to the outermost ring as ring 0 147 710 : int ring = _nring - og_ring - 1; // convert to internal indexing (0 as innermost ring) 148 710 : auto element = ring_ele_index.second; 149 : 150 710 : if (og_ring < 0 || og_ring >= (int)_nring) 151 10 : mooseError("Ring " + std::to_string(og_ring) + " is not valid for hexagonal lattice " + 152 2 : getName()); 153 708 : if (element < 0 || element >= (ring == 0 ? 1 : 6 * ring)) 154 16 : mooseError("Position " + std::to_string(element) + " is not valid for ring " + 155 14 : std::to_string(og_ring) + " in hexagonal lattice " + getName()); 156 : 157 : // Calculate the center row and column indices 158 706 : int center_row = (_nrow - 1) / 2; 159 706 : int center_col = center_row; 160 : 161 : // Special case for the center element 162 706 : if (ring == 0) 163 46 : return {center_row, center_col}; 164 : 165 : // Calculate the side length of the hexagon for the given ring 166 660 : int side_length = ring; 167 : 168 : // Determine which side of the hexagon the element is on and get row/col from this 169 660 : int side = element / side_length; 170 660 : 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 330 : 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 660 : switch (side) 187 : { 188 110 : case 0: // bottom right (contains starting position of the ring) 189 110 : row = center_row + offset; 190 110 : col = calc_num_cols_in_row(row) - og_ring - 1; 191 110 : break; 192 110 : case 1: // bottom 193 110 : row = center_row + ring; 194 110 : col = calc_num_cols_in_row(row) - og_ring - 1 - offset; 195 110 : break; 196 110 : case 2: // bottom left 197 110 : row = center_row + (side_length - offset); 198 110 : col = center_col - ring; 199 110 : break; 200 110 : case 3: // top left 201 110 : row = center_row - offset; 202 110 : col = center_col - ring; 203 110 : break; 204 110 : case 4: // top 205 110 : row = center_row - ring; 206 110 : col = center_col - ring + offset; 207 110 : break; 208 110 : case 5: // top right 209 110 : row = center_row - (side_length - offset); 210 110 : col = calc_num_cols_in_row(row) - og_ring - 1; 211 110 : break; 212 0 : default: 213 0 : 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 660 : return {row, col}; 221 : } 222 : 223 : std::pair<int, int> 224 128 : CSGHexagonalLattice::getRingIndexFromRowIndex(const std::pair<int, int> & row_col_index) const 225 : { 226 128 : if (!isValidIndex(row_col_index)) 227 16 : mooseError("Index (" + std::to_string(row_col_index.first) + ", " + 228 12 : std::to_string(row_col_index.second) + 229 : ") is not a valid index for hexagonal " 230 6 : "lattice " + 231 2 : getName()); 232 : 233 126 : return _row_to_ring_map.at(row_col_index); 234 : } 235 : 236 : /// convenience functions for converting between number of rows and number of rings 237 : 238 : unsigned int 239 40 : nRowToRing(int nrow) 240 : { 241 40 : if (nrow == 0) // special case 242 0 : return 0; 243 80 : std::string base_msg = "Cannot convert number of rows " + std::to_string(nrow) + 244 40 : " to number of rings in hexagonal lattice. "; 245 40 : if (nrow < 0) 246 0 : mooseError(base_msg + "Number of rows must be >= 0."); 247 40 : if (nrow % 2 == 0) 248 0 : mooseError(base_msg + "Number of rows must be odd."); 249 40 : return (nrow + 1) / 2; 250 40 : } 251 : 252 : unsigned int 253 0 : nRingToRow(int nring) 254 : { 255 0 : if (nring == 0) // special case 256 0 : return 0; 257 0 : if (nring < 0) 258 0 : 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 0 : return 2 * nring - 1; 261 : } 262 : 263 : } // namespace CSG