LCOV - code coverage report
Current view: top level - src/csg - CSGHexagonalLattice.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 130 147 88.4 %
Date: 2026-05-29 20:35:17 Functions: 13 14 92.9 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14