LCOV - code coverage report
Current view: top level - src/csg - CSGBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: fa5e60 Lines: 593 629 94.3 %
Date: 2026-06-24 08:03:36 Functions: 60 60 100.0 %
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 "CSGBase.h"
      11             : #include "CSGUtils.h"
      12             : #include "JsonIO.h"
      13             : 
      14             : namespace CSG
      15             : {
      16             : 
      17         280 : CSGBase::CSGBase()
      18         280 :   : _surface_list(CSGSurfaceList()),
      19         280 :     _cell_list(CSGCellList()),
      20         280 :     _universe_list(CSGUniverseList()),
      21         280 :     _lattice_list(CSGLatticeList())
      22             : {
      23         280 : }
      24             : 
      25          36 : CSGBase::CSGBase(const CSGBase & other_base)
      26          36 :   : _surface_list(other_base.getSurfaceList()),
      27          36 :     _cell_list(CSGCellList()),
      28          36 :     _universe_list(CSGUniverseList()),
      29          36 :     _lattice_list(CSGLatticeList())
      30             : {
      31             :   // Iterate through all cell references from the other CSGBase instance and
      32             :   // create new CSGCell pointers based on these references. This is done
      33             :   // recursively to properly handle cells with universe fills
      34         118 :   for (const auto & [name, cell] : other_base.getCellList().getCellListMap())
      35          82 :     addCellToList(*cell);
      36             : 
      37             :   // Link all cells in other_base root universe to current root universe
      38          70 :   for (auto & root_cell : other_base.getRootUniverse().getAllCells())
      39             :   {
      40          34 :     const auto & list_cell = _cell_list.getCell(root_cell.get().getName());
      41          34 :     addCellToUniverse(getRootUniverse(), list_cell);
      42             :   }
      43             : 
      44             :   // Iterate through all universe references from the other CSGBase instance and
      45             :   // create new CSGUniverse pointers based on these references. This is done in case
      46             :   // any universe exist in the universe list that are not connected to the cell list.
      47         146 :   for (const auto & [name, univ] : other_base.getUniverseList().getUniverseListMap())
      48         110 :     addUniverseToList(*univ);
      49             : 
      50             :   // Iterate through all lattice references from the other CSGBase instance and
      51             :   // create new CSGLattice pointers based on these references.
      52          54 :   for (const auto & [name, lattice] : other_base.getLatticeList().getLatticeListMap())
      53          18 :     addLatticeToList(*lattice);
      54          36 : }
      55             : 
      56         310 : CSGBase::~CSGBase() {}
      57             : 
      58             : void
      59           6 : CSGBase::deleteSurface(const CSGSurface & surface)
      60             : {
      61           6 :   if (!checkSurfaceInBase(surface))
      62           0 :     mooseError("Surface with name ",
      63           0 :                surface.getName(),
      64             :                " cannot be deleted as it is different from the surface of the same name in the "
      65             :                "CSGBase instance.");
      66             : 
      67             :   // Check if surface is used in region definition of existing cells
      68           6 :   for (const auto & cell_ref : _cell_list.getAllCells())
      69             :   {
      70           2 :     const auto & cell = cell_ref.get();
      71           2 :     const auto & cell_region = cell.getRegion();
      72           2 :     const auto & region_surfaces = cell_region.getSurfaces();
      73           2 :     for (const auto & region_surf : region_surfaces)
      74           2 :       if (region_surf.get() == surface)
      75           2 :         mooseError("Cannot delete surface with name ",
      76           2 :                    surface.getName(),
      77             :                    " as it is used in region definition of cell with name ",
      78           2 :                    cell.getName());
      79           8 :   }
      80             : 
      81           4 :   _surface_list.getSurfaceListMap().erase(surface.getName());
      82           4 : }
      83             : 
      84             : const CSGCell &
      85         130 : CSGBase::addCellToList(const CSGCell & cell)
      86             : {
      87             :   // If cell has already been created, we just return a reference to it
      88         130 :   const auto name = cell.getName();
      89         130 :   if (_cell_list.hasCell(name))
      90          48 :     return _cell_list.getCell(name);
      91             : 
      92             :   // Otherwise if the cell has material or void cell, we can create it directly
      93          82 :   const auto fill_type = cell.getFillType();
      94          82 :   const auto region = cell.getRegion();
      95          82 :   if (fill_type == "VOID")
      96          14 :     return _cell_list.addVoidCell(name, region);
      97          68 :   else if (fill_type == "CSG_MATERIAL")
      98             :   {
      99          26 :     const auto mat_name = cell.getFillMaterial();
     100          26 :     return _cell_list.addMaterialCell(name, mat_name, region);
     101          26 :   }
     102          42 :   else if (fill_type == "LATTICE")
     103             :   {
     104             :     // add lattice recursively to capture all linked universes in the lattice
     105          18 :     const CSGLattice & lattice = addLatticeToList(cell.getFillLattice());
     106          18 :     return _cell_list.addLatticeCell(name, lattice, region);
     107             :   }
     108             :   // Otherwise if the cell has a universe fill, we need to recursively define
     109             :   // all linked universes and cells first before defining this cell
     110          24 :   else if (fill_type == "UNIVERSE")
     111             :   {
     112          24 :     const auto & univ = addUniverseToList(cell.getFillUniverse());
     113          24 :     return _cell_list.addUniverseCell(name, univ, region);
     114             :   }
     115             :   else
     116           0 :     mooseError("Cell " + name + " has unrecognized fill type " + fill_type);
     117         130 : }
     118             : 
     119             : const CSGUniverse &
     120         194 : CSGBase::addUniverseToList(const CSGUniverse & univ)
     121             : {
     122             :   // If universe has already been created, we just return a reference to it
     123         194 :   const auto name = univ.getName();
     124         194 :   if (_universe_list.hasUniverse(name))
     125         120 :     return _universe_list.getUniverse(name);
     126             : 
     127             :   // Otherwise we create a new universe based on its associated cells.
     128             :   // addCellToList is called recursively in case associated cells have not
     129             :   // been added to the cell list yet.
     130          74 :   const auto univ_cells = univ.getAllCells();
     131          74 :   std::vector<std::reference_wrapper<const CSGCell>> current_univ_cells;
     132         122 :   for (const auto & univ_cell : univ_cells)
     133          48 :     current_univ_cells.push_back(addCellToList(univ_cell));
     134          74 :   return createUniverse(name, current_univ_cells);
     135         194 : }
     136             : 
     137             : const CSGLattice &
     138          36 : CSGBase::addLatticeToList(const CSGLattice & lattice)
     139             : {
     140             :   // If lattice has already been created, we just return a reference to it
     141          36 :   const auto name = lattice.getName();
     142          36 :   if (_lattice_list.hasLattice(name))
     143          18 :     return _lattice_list.getLattice(name);
     144             : 
     145             :   // Clone the lattice (associated universes need to be transferred and set)
     146          18 :   auto cloned_lattice = lattice.clone();
     147             : 
     148             :   // If lattice has associated universes, we need to add them to this CSGBase instance as well.
     149             :   // addUniverseToList is called recursively in case associated universes have not been added to
     150             :   // the universe list yet.
     151          18 :   std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> current_univ_map;
     152          44 :   for (const auto & univ_list : lattice.getUniverses())
     153             :   {
     154          26 :     std::vector<std::reference_wrapper<const CSGUniverse>> current_univ_list;
     155          68 :     for (const auto & univ_ref : univ_list)
     156          42 :       current_univ_list.push_back(addUniverseToList(univ_ref.get()));
     157          26 :     current_univ_map.push_back(current_univ_list);
     158          44 :   }
     159             : 
     160             :   // Set universes only if lattice has universes defined
     161          18 :   if (current_univ_map.size() > 0)
     162          18 :     cloned_lattice->setUniverses(current_univ_map);
     163             : 
     164             :   // Update reference to outer universe if it exists
     165          18 :   if (lattice.getOuterType() == "UNIVERSE")
     166             :   {
     167          18 :     const auto & outer_univ_ref = addUniverseToList(lattice.getOuterUniverse());
     168          18 :     cloned_lattice->updateOuter(outer_univ_ref);
     169             :   }
     170             : 
     171             :   // Use addLattice to add the cloned lattice
     172          18 :   return addLattice(std::move(cloned_lattice));
     173          36 : }
     174             : 
     175             : void
     176          10 : CSGBase::deleteLattice(const CSGLattice & lattice)
     177             : {
     178          10 :   if (!checkLatticeInBase(lattice))
     179           0 :     mooseError("Lattice with name ",
     180           0 :                lattice.getName(),
     181             :                " cannot be deleted as it is different from the lattice of the same name in the "
     182             :                "CSGBase instance.");
     183             : 
     184             :   // Check if lattice is used as fill in existing cells
     185          12 :   for (const auto & cell_ref : _cell_list.getAllCells())
     186             :   {
     187           4 :     const auto & cell = cell_ref.get();
     188           4 :     if ((cell.getFillType() == "LATTICE") && (cell.getFillLattice() == lattice))
     189           2 :       mooseError("Cannot delete lattice with name ",
     190           2 :                  lattice.getName(),
     191             :                  " as it is used as the fill of cell with name ",
     192           2 :                  cell.getName());
     193          10 :   }
     194             : 
     195           8 :   _lattice_list.getLatticeListMap().erase(lattice.getName());
     196           8 : }
     197             : 
     198             : const CSGCell &
     199         115 : CSGBase::createCell(const std::string & name,
     200             :                     const std::string & mat_name,
     201             :                     const CSGRegion & region,
     202             :                     const CSGUniverse * add_to_univ)
     203             : {
     204         115 :   checkRegionSurfaces(region);
     205         115 :   auto & cell = _cell_list.addMaterialCell(name, mat_name, region);
     206         115 :   if (add_to_univ)
     207          28 :     addCellToUniverse(*add_to_univ, cell);
     208             :   else
     209          87 :     addCellToUniverse(getRootUniverse(), cell);
     210         115 :   return cell;
     211             : }
     212             : 
     213             : const CSGCell &
     214          86 : CSGBase::createCell(const std::string & name,
     215             :                     const CSGRegion & region,
     216             :                     const CSGUniverse * add_to_univ)
     217             : {
     218          86 :   checkRegionSurfaces(region);
     219          86 :   auto & cell = _cell_list.addVoidCell(name, region);
     220          84 :   if (add_to_univ)
     221          10 :     addCellToUniverse(*add_to_univ, cell);
     222             :   else
     223          74 :     addCellToUniverse(getRootUniverse(), cell);
     224          84 :   return cell;
     225             : }
     226             : 
     227             : const CSGCell &
     228          24 : CSGBase::createCell(const std::string & name,
     229             :                     const CSGUniverse & fill_univ,
     230             :                     const CSGRegion & region,
     231             :                     const CSGUniverse * add_to_univ)
     232             : {
     233          24 :   checkRegionSurfaces(region);
     234          24 :   if (add_to_univ && (&fill_univ == add_to_univ))
     235           6 :     mooseError("Cell " + name +
     236             :                " cannot be filled with the same universe to which it is being added.");
     237             : 
     238          22 :   auto & cell = _cell_list.addUniverseCell(name, fill_univ, region);
     239          22 :   if (add_to_univ)
     240          12 :     addCellToUniverse(*add_to_univ, cell);
     241             :   else
     242          10 :     addCellToUniverse(getRootUniverse(), cell);
     243          22 :   return cell;
     244             : }
     245             : 
     246             : const CSGCell &
     247          60 : CSGBase::createCell(const std::string & name,
     248             :                     const CSGLattice & fill_lattice,
     249             :                     const CSGRegion & region,
     250             :                     const CSGUniverse * add_to_univ)
     251             : {
     252          60 :   checkRegionSurfaces(region);
     253             : 
     254             :   // check that cell is not being added to a universe that exists in the lattice itself
     255          60 :   if (add_to_univ)
     256          10 :     for (auto univ_list : fill_lattice.getUniverses())
     257          12 :       for (const auto & univ_ref : univ_list)
     258             :       {
     259           8 :         const CSGUniverse & univ_in_lattice = univ_ref.get();
     260           8 :         if (&univ_in_lattice == add_to_univ)
     261           6 :           mooseError("Cell " + name +
     262             :                      " cannot be filled with a lattice containing the same universe to which it is "
     263             :                      "being added.");
     264          12 :       }
     265             : 
     266          58 :   auto & cell = _cell_list.addLatticeCell(name, fill_lattice, region);
     267          58 :   if (add_to_univ)
     268           4 :     addCellToUniverse(*add_to_univ, cell);
     269             :   else
     270          54 :     addCellToUniverse(getRootUniverse(), cell);
     271          58 :   return cell;
     272             : }
     273             : 
     274             : void
     275          20 : CSGBase::deleteCell(const CSGCell & cell)
     276             : {
     277          20 :   if (!checkCellInBase(cell))
     278           0 :     mooseError("Cell with name ",
     279           0 :                cell.getName(),
     280             :                " cannot be deleted as it is different from the cell of the same name in the "
     281             :                "CSGBase instance.");
     282             : 
     283             :   // Check if cell exists in any existing universes. Cell will be removed from these universes
     284          40 :   for (const auto & univ_ref : _universe_list.getAllUniverses())
     285             :   {
     286          22 :     const auto & univ = univ_ref.get();
     287          22 :     const auto & univ_cells = univ.getAllCells();
     288          32 :     for (const auto & univ_cell : univ_cells)
     289          12 :       if (cell == univ_cell.get() && univ != getRootUniverse())
     290             :       {
     291           2 :         mooseWarning("Removing cell ",
     292           2 :                      cell.getName(),
     293             :                      " from universe with name ",
     294           2 :                      univ.getName(),
     295             :                      " before cell deletion.");
     296           0 :         auto & univ_to_modify = _universe_list.getUniverse(univ.getName());
     297           0 :         univ_to_modify.removeCell(cell.getName());
     298             :       }
     299          20 :   }
     300             : 
     301          18 :   _cell_list.getCellListMap().erase(cell.getName());
     302          18 : }
     303             : 
     304             : void
     305          20 : CSGBase::updateCellRegion(const CSGCell & cell, const CSGRegion & region)
     306             : {
     307          20 :   checkRegionSurfaces(region);
     308          20 :   if (!checkCellInBase(cell))
     309          10 :     mooseError("The region of cell with name " + cell.getName() +
     310           4 :                " that is being updated is different " +
     311             :                "from the cell of the same name in the CSGBase instance.");
     312          18 :   auto & list_cell = _cell_list.getCell(cell.getName());
     313          18 :   list_cell.updateRegion(region);
     314          18 : }
     315             : 
     316             : void
     317           6 : CSGBase::resetCellFill(const CSGCell & cell)
     318             : {
     319           6 :   if (!checkCellInBase(cell))
     320           0 :     mooseError("The fill of cell with name " + cell.getName() +
     321           0 :                " that is being updated is different " +
     322             :                "from the cell of the same name in the CSGBase instance.");
     323           6 :   auto & list_cell = _cell_list.getCell(cell.getName());
     324           6 :   list_cell.resetCellFill();
     325           6 : }
     326             : 
     327             : void
     328           2 : CSGBase::updateCellFill(const CSGCell & cell, const std::string & mat_name)
     329             : {
     330           2 :   if (!checkCellInBase(cell))
     331           0 :     mooseError("The region of cell with name " + cell.getName() +
     332           0 :                " that is being updated is different " +
     333             :                "from the cell of the same name in the CSGBase instance.");
     334           2 :   auto & list_cell = _cell_list.getCell(cell.getName());
     335           2 :   list_cell.updateCellFill(mat_name);
     336           2 : }
     337             : 
     338             : void
     339           2 : CSGBase::updateCellFill(const CSGCell & cell, const CSGUniverse * univ)
     340             : {
     341           2 :   if (!checkUniverseInBase(*univ))
     342           0 :     mooseError("Universe with name ",
     343           0 :                univ->getName(),
     344             :                " is being used as a cell fill that is different from the universe of the same name "
     345             :                "in the CSGBase instance.");
     346           2 :   if (!checkCellInBase(cell))
     347           0 :     mooseError("The fill of cell with name " + cell.getName() +
     348           0 :                " that is being updated is different " +
     349             :                "from the cell of the same name in the CSGBase instance.");
     350           2 :   auto & list_cell = _cell_list.getCell(cell.getName());
     351           2 :   list_cell.updateCellFill(univ);
     352           2 : }
     353             : 
     354             : void
     355           2 : CSGBase::updateCellFill(const CSGCell & cell, const CSGLattice * lattice)
     356             : {
     357           2 :   if (!checkLatticeInBase(*lattice))
     358           0 :     mooseError("Lattice with name ",
     359           0 :                lattice->getName(),
     360             :                " is being used as a cell fill that is different from the lattice of the same name "
     361             :                "in the CSGBase instance.");
     362           2 :   if (!checkCellInBase(cell))
     363           0 :     mooseError("The fill of cell with name " + cell.getName() +
     364           0 :                " that is being updated is different " +
     365             :                "from the cell of the same name in the CSGBase instance.");
     366           2 :   auto & list_cell = _cell_list.getCell(cell.getName());
     367           2 :   list_cell.updateCellFill(lattice);
     368           2 : }
     369             : 
     370             : const CSGUniverse &
     371         150 : CSGBase::createUniverse(const std::string & name,
     372             :                         std::vector<std::reference_wrapper<const CSGCell>> & cells)
     373             : {
     374         150 :   auto & univ = _universe_list.addUniverse(name);
     375         150 :   addCellsToUniverse(univ, cells); // performs a check that cells are a part of this base
     376         150 :   return univ;
     377             : }
     378             : 
     379             : void
     380          28 : CSGBase::deleteUniverse(const CSGUniverse & univ)
     381             : {
     382          28 :   if (!checkUniverseInBase(univ))
     383           0 :     mooseError("Universe with name ",
     384           0 :                univ.getName(),
     385             :                " cannot be deleted as it is different from the universe of the same name in the "
     386             :                "CSGBase instance.");
     387             : 
     388             :   // Check if universe is the root universe
     389          28 :   if (univ == getRootUniverse())
     390           2 :     mooseError("Cannot delete root universe from CSGBase instance");
     391             : 
     392             :   // Check if universe is used in any existing lattices
     393          26 :   for (const auto & lat : _lattice_list.getAllLattices())
     394             :   {
     395           4 :     const auto & lattice_univs = lat.get().getUniqueUniverses();
     396           6 :     for (const auto & lat_univ : lattice_univs)
     397           4 :       if (univ == lat_univ.get())
     398           2 :         mooseError("Cannot delete universe with name ",
     399           2 :                    univ.getName(),
     400             :                    " as it is used in lattice with name ",
     401           2 :                    lat.get().getName());
     402           2 :     if ((lat.get().getOuterType() == "UNIVERSE") && (lat.get().getOuterUniverse() == univ))
     403           2 :       mooseError("Cannot delete universe with name ",
     404           2 :                  univ.getName(),
     405             :                  " as it is used as the outer universe of lattice with name ",
     406           2 :                  lat.get().getName());
     407          30 :   }
     408             : 
     409             :   // Check if universe is used as fill in existing cells
     410          34 :   for (const auto & cell_ref : _cell_list.getAllCells())
     411             :   {
     412          14 :     const auto & cell = cell_ref.get();
     413          14 :     if ((cell.getFillType() == "UNIVERSE") && (cell.getFillUniverse() == univ))
     414           2 :       mooseError("Cannot delete universe with name ",
     415           2 :                  univ.getName(),
     416             :                  " as it is used as the fill of cell with name ",
     417           2 :                  cell.getName());
     418          22 :   }
     419             : 
     420          20 :   _universe_list.getUniverseListMap().erase(univ.getName());
     421          20 : }
     422             : 
     423             : void
     424         493 : CSGBase::addCellToUniverse(const CSGUniverse & universe, const CSGCell & cell)
     425             : {
     426             :   // make sure cell is a part of this CSGBase instance
     427         493 :   if (!checkCellInBase(cell))
     428          12 :     mooseError("A cell named " + cell.getName() + " is being added to universe " +
     429           8 :                universe.getName() +
     430             :                " that is different from the cell of the same name in the CSGBase instance.");
     431             :   // make sure universe is a part of this CSGBase instance
     432         491 :   if (!checkUniverseInBase(universe))
     433          10 :     mooseError("Cells are being added to a universe named " + universe.getName() +
     434           4 :                " that is different " +
     435             :                "from the universe of the same name in the CSGBase instance.");
     436         489 :   auto & univ = _universe_list.getUniverse(universe.getName());
     437         489 :   univ.addCell(cell);
     438         489 : }
     439             : 
     440             : void
     441         152 : CSGBase::addCellsToUniverse(const CSGUniverse & universe,
     442             :                             std::vector<std::reference_wrapper<const CSGCell>> & cells)
     443             : {
     444         286 :   for (auto & c : cells)
     445         134 :     addCellToUniverse(universe, c);
     446         152 : }
     447             : 
     448             : void
     449          14 : CSGBase::removeCellFromUniverse(const CSGUniverse & universe, const CSGCell & cell)
     450             : {
     451             :   // make sure cell is a part of this CSGBase instance
     452          14 :   if (!checkCellInBase(cell))
     453          12 :     mooseError("A cell named " + cell.getName() + " is being removed from universe " +
     454           8 :                universe.getName() +
     455             :                " that is different from the cell of the same name in the CSGBase instance.");
     456             :   // make sure universe is a part of this CSGBase instance
     457          12 :   if (!checkUniverseInBase(universe))
     458          10 :     mooseError("Cells are being removed from a universe named " + universe.getName() +
     459           4 :                " that is different " +
     460             :                "from the universe of the same name in the CSGBase instance.");
     461          10 :   auto & univ = _universe_list.getUniverse(universe.getName());
     462          10 :   univ.removeCell(cell.getName());
     463          10 : }
     464             : 
     465             : void
     466           4 : CSGBase::removeCellsFromUniverse(const CSGUniverse & universe,
     467             :                                  std::vector<std::reference_wrapper<const CSGCell>> & cells)
     468             : {
     469          10 :   for (auto & c : cells)
     470           6 :     removeCellFromUniverse(universe, c);
     471           4 : }
     472             : 
     473             : void
     474           2 : CSGBase::setLatticeOuter(const CSGLattice & lattice, const std::string & outer_name)
     475             : {
     476           2 :   auto name = lattice.getName();
     477           2 :   if (!checkLatticeInBase(lattice))
     478           0 :     mooseError("Cannot set outer for lattice " + name +
     479             :                ". Lattice is different from the lattice of the same name in the "
     480             :                "CSGBase instance.");
     481           2 :   _lattice_list.getLattice(name).updateOuter(outer_name);
     482           2 : }
     483             : 
     484             : void
     485          20 : CSGBase::setLatticeOuter(const CSGLattice & lattice, const CSGUniverse & outer_univ)
     486             : {
     487          20 :   auto name = lattice.getName();
     488          20 :   if (!checkLatticeInBase(lattice))
     489           0 :     mooseError("Cannot set outer universe for lattice " + name +
     490             :                ". Lattice is different from the lattice of the same name in the "
     491             :                "CSGBase instance.");
     492          20 :   if (!checkUniverseInBase(outer_univ))
     493          12 :     mooseError("Cannot set outer universe for lattice " + name + ". Outer universe " +
     494           8 :                outer_univ.getName() + " is not in the CSGBase instance.");
     495          18 :   _lattice_list.getLattice(name).updateOuter(outer_univ);
     496          20 : }
     497             : 
     498             : void
     499           4 : CSGBase::resetLatticeOuter(const CSGLattice & lattice)
     500             : {
     501           4 :   auto name = lattice.getName();
     502           4 :   if (!checkLatticeInBase(lattice))
     503           0 :     mooseError("Cannot reset outer for lattice " + name +
     504             :                ". Lattice is different from the lattice of the same name in the "
     505             :                "CSGBase instance.");
     506           4 :   _lattice_list.getLattice(name).resetOuter();
     507           4 : }
     508             : 
     509             : void
     510           4 : CSGBase::setUniverseAtLatticeIndex(const CSGLattice & lattice,
     511             :                                    const CSGUniverse & universe,
     512             :                                    std::pair<int, int> index)
     513             : {
     514           4 :   auto name = lattice.getName();
     515           4 :   if (!checkLatticeInBase(lattice))
     516           0 :     mooseError("Cannot set universe at index for lattice " + name +
     517             :                ". Lattice is different from the lattice of the same name in the "
     518             :                "CSGBase instance.");
     519           4 :   if (!checkUniverseInBase(universe))
     520          10 :     mooseError("Cannot add universe " + universe.getName() + " to lattice " + lattice.getName() +
     521             :                ". Universe is not in the CSGBase instance.");
     522           2 :   _lattice_list.getLattice(name).setUniverseAtIndex(universe, index);
     523           4 : }
     524             : 
     525             : void
     526           8 : CSGBase::setLatticeUniverses(
     527             :     const CSGLattice & lattice,
     528             :     std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> & universes)
     529             : {
     530           8 :   auto name = lattice.getName();
     531           8 :   if (!checkLatticeInBase(lattice))
     532           0 :     mooseError("Cannot set universes for lattice " + name +
     533             :                ". Lattice is different from the lattice of the same name in the "
     534             :                "CSGBase instance.");
     535             :   // make sure all universes are a part of this base instance
     536          20 :   for (auto univ_list : universes)
     537          26 :     for (const CSGUniverse & univ : univ_list)
     538          14 :       if (!checkUniverseInBase(univ))
     539          10 :         mooseError("Cannot set universes for lattice " + name + ". Universe " + univ.getName() +
     540          14 :                    " is not in the CSGBase instance.");
     541           6 :   _lattice_list.getLattice(name).setUniverses(universes);
     542           8 : }
     543             : 
     544             : void
     545         126 : CSGBase::addTransformation(const CSGObjectVariant & csg_object,
     546             :                            TransformationType type,
     547             :                            const std::tuple<Real, Real, Real> & values)
     548             : {
     549             :   // Use std::visit to handle each type in the variant
     550         126 :   std::visit(
     551         252 :       [&](const auto & obj)
     552             :       {
     553             :         using T = std::decay_t<decltype(obj.get())>;
     554             : 
     555             :         // Handle each CSG object type differently because each needs to check that it exists in
     556             :         // this base instance
     557             :         if constexpr (std::is_same_v<T, CSGCell>)
     558             :         {
     559          42 :           const CSGCell & cell = obj.get();
     560          42 :           if (!checkCellInBase(cell))
     561           2 :             mooseError("Cannot apply transformation to cell ",
     562           2 :                        cell.getName(),
     563             :                        " that is not in this CSGBase instance.");
     564             : 
     565             :           // Get non-const reference and apply transformation
     566          40 :           CSGCell & mutable_cell = _cell_list.getCell(cell.getName());
     567             :           mooseAssert(mutable_cell == cell, "Mutable cell does not match const cell passed in.");
     568          40 :           mutable_cell.addTransformation(type, values);
     569             :         }
     570             :         else if constexpr (std::is_same_v<T, CSGSurface>)
     571             :         {
     572          34 :           const CSGSurface & surface = obj.get();
     573          34 :           if (!checkSurfaceInBase(surface))
     574           2 :             mooseError("Cannot apply transformation to surface ",
     575           2 :                        surface.getName(),
     576             :                        " that is not in this CSGBase instance.");
     577             : 
     578             :           // Get non-const reference and apply transformation
     579          32 :           CSGSurface & mutable_surface = _surface_list.getSurface(surface.getName());
     580             :           mooseAssert(mutable_surface == surface,
     581             :                       "Mutable surface does not match const surface passed in.");
     582          32 :           mutable_surface.addTransformation(type, values);
     583             :         }
     584             :         else if constexpr (std::is_same_v<T, CSGUniverse>)
     585             :         {
     586          18 :           const CSGUniverse & universe = obj.get();
     587          18 :           if (!checkUniverseInBase(universe))
     588           2 :             mooseError("Cannot apply transformation to universe ",
     589           2 :                        universe.getName(),
     590             :                        " that is not in this CSGBase instance.");
     591             : 
     592             :           // Get non-const reference and apply transformation
     593          16 :           CSGUniverse & mutable_universe = _universe_list.getUniverse(universe.getName());
     594             :           mooseAssert(mutable_universe == universe,
     595             :                       "Mutable universe does not match const universe passed in.");
     596          16 :           mutable_universe.addTransformation(type, values);
     597             :         }
     598             :         else if constexpr (std::is_same_v<T, CSGLattice>)
     599             :         {
     600          16 :           const CSGLattice & lattice = obj.get();
     601          16 :           if (!checkLatticeInBase(lattice))
     602           2 :             mooseError("Cannot apply transformation to lattice ",
     603           2 :                        lattice.getName(),
     604             :                        " that is not in this CSGBase instance.");
     605             : 
     606             :           // Get non-const reference and apply transformation
     607          14 :           CSGLattice & mutable_lattice = _lattice_list.getLattice(lattice.getName());
     608             :           mooseAssert(mutable_lattice == lattice,
     609             :                       "Mutable lattice does not match const lattice passed in.");
     610          14 :           mutable_lattice.addTransformation(type, values);
     611             :         }
     612             :         else if constexpr (std::is_same_v<T, CSGRegion>)
     613             :         {
     614             :           // iterate on the surfaces of the region and apply the transformation to those surfaces
     615          16 :           const CSGRegion & region = obj.get();
     616          16 :           const auto surfaces = region.getSurfaces();
     617          30 :           for (const CSGSurface & surface : surfaces)
     618             :           {
     619          16 :             if (!checkSurfaceInBase(surface))
     620           2 :               mooseError("Cannot apply transformation to region with surface ",
     621           2 :                          surface.getName(),
     622             :                          " that is not in this CSGBase instance.");
     623          14 :             addTransformation(surface, type, values);
     624             :           }
     625          16 :         }
     626             :         else
     627             :           mooseError("Transformation not implemented for this object type: ", typeid(T).name());
     628         114 :       },
     629             :       csg_object);
     630         114 : }
     631             : 
     632             : void
     633          56 : CSGBase::applyAxisRotation(const CSGObjectVariant & csg_object,
     634             :                            RotationAxisType axis,
     635             :                            const Real angle)
     636             : {
     637             :   // convert to the Euler angles (phi, theta, psi) based on axis
     638          56 :   Real phi = 0.0;
     639          56 :   Real theta = 0.0;
     640          56 :   Real psi = 0.0;
     641             : 
     642          56 :   switch (axis)
     643             :   {
     644          20 :     case RotationAxisType::X:
     645          20 :       theta = angle;
     646          20 :       break;
     647          10 :     case RotationAxisType::Y:
     648          10 :       phi = 90.0;
     649          10 :       theta = angle;
     650          10 :       psi = -90.0;
     651          10 :       break;
     652          26 :     case RotationAxisType::Z:
     653          26 :       phi = angle;
     654          26 :       break;
     655           0 :     default:
     656           0 :       mooseError("Invalid axis type provided for axis rotation.");
     657             :   }
     658             : 
     659          56 :   addTransformation(csg_object, TransformationType::ROTATION, std::make_tuple(phi, theta, psi));
     660          46 : }
     661             : 
     662             : void
     663          76 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base, const bool ignore_identical_components)
     664             : {
     665             :   // If we are ignoring identical incoming CSG components, we need to update any references
     666             :   // stored by these components to point to the references of the pre-existing CSGBase object
     667          76 :   if (ignore_identical_components)
     668          18 :     updateIncomingCSGReferences(*base);
     669          76 :   joinSurfaceList(base->getSurfaceList(), ignore_identical_components);
     670          72 :   joinCellList(base->getCellList(), ignore_identical_components);
     671          66 :   joinLatticeList(base->getLatticeList(), ignore_identical_components);
     672          62 :   joinUniverseList(base->getUniverseList(), ignore_identical_components);
     673          58 : }
     674             : 
     675             : void
     676          58 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base,
     677             :                        const bool ignore_identical_components,
     678             :                        const std::string & new_root_name_join)
     679             : {
     680             :   // If we are ignoring identical incoming CSG components, we need to update any references
     681             :   // stored by these components to point to the references of the pre-existing CSGBase object
     682          58 :   if (ignore_identical_components)
     683           0 :     updateIncomingCSGReferences(*base);
     684          58 :   joinSurfaceList(base->getSurfaceList(), ignore_identical_components);
     685          58 :   joinCellList(base->getCellList(), ignore_identical_components);
     686          58 :   joinLatticeList(base->getLatticeList(), ignore_identical_components);
     687          58 :   joinUniverseList(base->getUniverseList(), ignore_identical_components, new_root_name_join);
     688          58 : }
     689             : 
     690             : void
     691           2 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base,
     692             :                        const bool ignore_identical_components,
     693             :                        const std::string & new_root_name_base,
     694             :                        const std::string & new_root_name_join)
     695             : {
     696             :   // If we are ignoring identical incoming CSG components, we need to update any references
     697             :   // stored by these components to point to the references of the pre-existing CSGBase object
     698           2 :   if (ignore_identical_components)
     699           0 :     updateIncomingCSGReferences(*base);
     700           2 :   joinSurfaceList(base->getSurfaceList(), ignore_identical_components);
     701           2 :   joinCellList(base->getCellList(), ignore_identical_components);
     702           2 :   joinLatticeList(base->getLatticeList(), ignore_identical_components);
     703           2 :   joinUniverseList(
     704             :       base->getUniverseList(), ignore_identical_components, new_root_name_base, new_root_name_join);
     705           2 : }
     706             : 
     707             : void
     708          18 : CSGBase::updateIncomingCSGReferences(CSGBase & incoming_base)
     709             : {
     710             :   // Iterate through all incoming surfaces and track which ones have names already
     711             :   // defined within this CSGSurfaceList object
     712          18 :   std::map<std::string, std::reference_wrapper<const CSGSurface>> identical_surface_refs;
     713          18 :   auto & surf_list_map = incoming_base.getSurfaceList().getSurfaceListMap();
     714          22 :   for (const auto & [surf_name, surf_ptr] : surf_list_map)
     715           4 :     if (hasSurface(surf_name))
     716           4 :       identical_surface_refs.insert({surf_name, getSurfaceByName(surf_name)});
     717             : 
     718             :   // Iterate through all incoming cells and track which ones have names already
     719             :   // defined within this CSGCellList object
     720          18 :   std::map<std::string, std::reference_wrapper<const CSGCell>> identical_cell_refs;
     721          18 :   auto & cell_list_map = incoming_base.getCellList().getCellListMap();
     722          36 :   for (const auto & [cell_name, cell_ptr] : cell_list_map)
     723          18 :     if (hasCell(cell_name))
     724          12 :       identical_cell_refs.insert({cell_name, getCellByName(cell_name)});
     725             : 
     726             :   // Iterate through all incoming universes and track which ones have names already
     727             :   // defined within this CSGUniverseList object
     728          18 :   std::map<std::string, std::reference_wrapper<const CSGUniverse>> identical_universe_refs;
     729          18 :   auto & universe_list_map = incoming_base.getUniverseList().getUniverseListMap();
     730          66 :   for (const auto & [univ_name, univ_ptr] : universe_list_map)
     731          48 :     if (hasUniverse(univ_name))
     732          34 :       identical_universe_refs.insert({univ_name, getUniverseByName(univ_name)});
     733             : 
     734             :   // Iterate through all incoming lattices and track which ones have names already
     735             :   // defined within this CSGLatticeList object
     736          18 :   std::map<std::string, std::reference_wrapper<const CSGLattice>> identical_lattice_refs;
     737          18 :   auto & lattice_list_map = incoming_base.getLatticeList().getLatticeListMap();
     738          24 :   for (const auto & [lat_name, lat_ptr] : lattice_list_map)
     739           6 :     if (hasLattice(lat_name))
     740           6 :       identical_lattice_refs.insert({lat_name, getLatticeByName(lat_name)});
     741             : 
     742             :   // Update all surface, cell, universe, and lattice references of incoming base to those of this
     743             :   // base
     744          18 :   if (!identical_surface_refs.empty())
     745           4 :     replaceSurfaceRefsByName(identical_surface_refs, incoming_base);
     746             : 
     747          18 :   if (!identical_cell_refs.empty())
     748          12 :     replaceCellRefsByName(identical_cell_refs, incoming_base);
     749             : 
     750          18 :   if (!identical_universe_refs.empty())
     751          18 :     replaceUniverseRefsByName(identical_universe_refs, incoming_base);
     752             : 
     753          18 :   if (!identical_lattice_refs.empty())
     754           6 :     replaceLatticeRefsByName(identical_lattice_refs, incoming_base);
     755          18 : }
     756             : 
     757             : void
     758           4 : CSGBase::replaceSurfaceRefsByName(
     759             :     std::map<std::string, std::reference_wrapper<const CSGSurface>> & identical_surface_refs,
     760             :     CSGBase & base)
     761             : {
     762             :   // Update surface references of cell regions to those of this base
     763           8 :   for (auto & [cell_name, cell_ptr] : base.getCellList().getCellListMap())
     764           4 :     cell_ptr->updateCellRegionSurfaces(identical_surface_refs);
     765           4 : }
     766             : 
     767             : void
     768          12 : CSGBase::replaceCellRefsByName(
     769             :     std::map<std::string, std::reference_wrapper<const CSGCell>> & identical_cell_refs,
     770             :     CSGBase & base)
     771             : {
     772             :   // Update cell references of universes to those of this base
     773          52 :   for (auto & [univ_name, univ_ptr] : base.getUniverseList().getUniverseListMap())
     774          80 :     for (auto & [cell_name, cell_ref] : identical_cell_refs)
     775          40 :       if (univ_ptr->hasCell(cell_name))
     776             :       {
     777          12 :         univ_ptr->removeCell(cell_name);
     778          12 :         univ_ptr->addCell(cell_ref);
     779             :       }
     780          12 : }
     781             : 
     782             : void
     783          18 : CSGBase::replaceUniverseRefsByName(
     784             :     std::map<std::string, std::reference_wrapper<const CSGUniverse>> & identical_universe_refs,
     785             :     CSGBase & base)
     786             : {
     787             :   // Update universe references of cells to those of this base
     788          36 :   for (auto & [cell_name, cell_ptr] : base.getCellList().getCellListMap())
     789             :   {
     790          18 :     const auto fill_type = cell_ptr->getFillType();
     791          18 :     const auto fill_name = cell_ptr->getFillName();
     792          26 :     if ((fill_type == "UNIVERSE") &&
     793          26 :         (identical_universe_refs.find(fill_name) != identical_universe_refs.end()))
     794             :     {
     795           8 :       const CSGUniverse * univ_ptr = &identical_universe_refs.at(fill_name).get();
     796           8 :       cell_ptr->updateCellFill(univ_ptr);
     797             :     }
     798          18 :   }
     799             : 
     800             :   // Update universe references of lattices to those of this base
     801          24 :   for (auto & [lat_name, lat_ptr] : base.getLatticeList().getLatticeListMap())
     802          20 :     for (auto & [univ_name, univ_ref] : identical_universe_refs)
     803             :     {
     804             :       // Check if universe belongs to lattice
     805          14 :       if (lat_ptr->hasUniverse(univ_name))
     806             :       {
     807             :         // If so, replace all instances of this universe in the lattice
     808           4 :         const auto univ_indices = lat_ptr->getUniverseIndices(univ_name);
     809           8 :         for (const auto & index : univ_indices)
     810           4 :           lat_ptr->setUniverseAtIndex(univ_ref, index);
     811           4 :       }
     812             :       // Check if universe belongs to lattice outer
     813          28 :       if ((lat_ptr->getOuterType() == "UNIVERSE") &&
     814          14 :           (lat_ptr->getOuterUniverse().getName() == univ_name))
     815           4 :         lat_ptr->updateOuter(univ_ref);
     816             :     }
     817          18 : }
     818             : 
     819             : void
     820           6 : CSGBase::replaceLatticeRefsByName(
     821             :     std::map<std::string, std::reference_wrapper<const CSGLattice>> & identical_lattice_refs,
     822             :     CSGBase & base)
     823             : {
     824             :   // Update lattice references of cells to those of this base
     825          12 :   for (auto & [cell_name, cell_ptr] : base.getCellList().getCellListMap())
     826             :   {
     827           6 :     const auto fill_type = cell_ptr->getFillType();
     828           6 :     const auto fill_name = cell_ptr->getFillName();
     829          12 :     if ((fill_type == "LATTICE") &&
     830          12 :         (identical_lattice_refs.find(fill_name) != identical_lattice_refs.end()))
     831             :     {
     832           6 :       const CSGLattice * lat_ptr = &identical_lattice_refs.at(fill_name).get();
     833           6 :       cell_ptr->updateCellFill(lat_ptr);
     834             :     }
     835           6 :   }
     836           6 : }
     837             : 
     838             : void
     839         136 : CSGBase::joinSurfaceList(CSGSurfaceList & surf_list, const bool ignore_identical_surfaces)
     840             : {
     841         136 :   auto & surf_list_map = surf_list.getSurfaceListMap();
     842         688 :   for (auto & s : surf_list_map)
     843         560 :     _surface_list.addSurface(std::move(s.second), ignore_identical_surfaces);
     844         132 : }
     845             : 
     846             : void
     847         132 : CSGBase::joinCellList(CSGCellList & cell_list, const bool ignore_identical_cells)
     848             : {
     849         132 :   auto & cell_list_map = cell_list.getCellListMap();
     850         376 :   for (auto & c : cell_list_map)
     851         256 :     _cell_list.addCell(std::move(c.second), ignore_identical_cells);
     852         126 : }
     853             : 
     854             : void
     855         126 : CSGBase::joinLatticeList(CSGLatticeList & lattice_list, const bool ignore_identical_lattices)
     856             : {
     857         126 :   auto & lat_list_map = lattice_list.getLatticeListMap();
     858         192 :   for (auto & lat : lat_list_map)
     859          74 :     _lattice_list.addLattice(std::move(lat.second), ignore_identical_lattices);
     860         122 : }
     861             : 
     862             : void
     863          62 : CSGBase::joinUniverseList(CSGUniverseList & univ_list, const bool ignore_identical_universes)
     864             : {
     865             :   // case 1: incoming root is joined into existing root; no new universes are created
     866          62 :   auto & univ_list_map = univ_list.getUniverseListMap();
     867          62 :   auto & root = getRootUniverse(); // this root universe
     868         238 :   for (auto & u : univ_list_map)
     869             :   {
     870         180 :     if (u.second->isRoot())
     871             :     {
     872             :       // add existing cells to current root instead of creating new universe
     873          58 :       auto all_cells = u.second->getAllCells();
     874          96 :       for (auto & cell : all_cells)
     875          38 :         addCellToUniverse(root, cell);
     876          58 :     }
     877             :     else // unique non-root universe to add to list
     878         126 :       _universe_list.addUniverse(std::move(u.second), ignore_identical_universes);
     879             :   }
     880          58 : }
     881             : 
     882             : void
     883          58 : CSGBase::joinUniverseList(CSGUniverseList & univ_list,
     884             :                           const bool ignore_identical_universes,
     885             :                           const std::string & new_root_name_incoming)
     886             : {
     887             :   // case 2: incoming root is turned into new universe and existing root remains root
     888             : 
     889             :   // add incoming universes to current Base
     890          58 :   auto & all_univs = univ_list.getUniverseListMap();
     891         126 :   for (auto & u : all_univs)
     892             :   {
     893          68 :     if (u.second->isRoot())
     894             :     {
     895             :       // create new universe from incoming root universe
     896          58 :       auto all_cells = u.second->getAllCells();
     897          58 :       createUniverse(new_root_name_incoming, all_cells);
     898          58 :     }
     899             :     else // unique non-root universe to add to list
     900          10 :       _universe_list.addUniverse(std::move(u.second), ignore_identical_universes);
     901             :   }
     902          58 : }
     903             : 
     904             : void
     905           2 : CSGBase::joinUniverseList(CSGUniverseList & univ_list,
     906             :                           const bool ignore_identical_universes,
     907             :                           const std::string & new_root_name_base,
     908             :                           const std::string & new_root_name_incoming)
     909             : {
     910             :   // case 3: each root universe becomes a new universe and a new root is created
     911             : 
     912             :   // make a new universe from the existing root universe
     913           2 :   auto & root = getRootUniverse();
     914           2 :   auto root_cells = root.getAllCells();
     915           2 :   createUniverse(new_root_name_base, root_cells);
     916           2 :   removeCellsFromUniverse(root, root_cells);
     917             : 
     918             :   // add incoming universes to current Base
     919           2 :   auto & all_univs = univ_list.getUniverseListMap();
     920           6 :   for (auto & u : all_univs)
     921             :   {
     922           4 :     if (u.second->isRoot())
     923             :     {
     924             :       // create new universe from incoming root universe
     925           2 :       auto all_cells = u.second->getAllCells();
     926           2 :       createUniverse(new_root_name_incoming, all_cells);
     927           2 :     }
     928             :     else // unique non-root universe to add to list
     929           2 :       _universe_list.addUniverse(std::move(u.second), ignore_identical_universes);
     930             :   }
     931           2 : }
     932             : 
     933             : void
     934         307 : CSGBase::checkRegionSurfaces(const CSGRegion & region) const
     935             : {
     936         307 :   const auto surfs = region.getSurfaces();
     937        1041 :   for (const CSGSurface & s : surfs)
     938             :   {
     939         736 :     if (!checkSurfaceInBase(s))
     940           6 :       mooseError("Region is being set with a surface named " + s.getName() +
     941             :                  " that is different from the surface of the same name in the CSGBase instance.");
     942             :   }
     943         307 : }
     944             : 
     945             : bool
     946         792 : CSGBase::checkSurfaceInBase(const CSGSurface & surface) const
     947             : {
     948         792 :   auto name = surface.getName();
     949             :   // if no surface by this name exists, an error will be produced by getSurface
     950         792 :   auto & list_surf = _surface_list.getSurface(name);
     951             :   // return whether that the surface in the list is the same as the surface provided (in memory)
     952         792 :   return &surface == &list_surf;
     953         792 : }
     954             : 
     955             : bool
     956         601 : CSGBase::checkCellInBase(const CSGCell & cell) const
     957             : {
     958         601 :   auto name = cell.getName();
     959             :   // if no cell by this name exists, an error will be produced by getCell
     960         601 :   auto & list_cell = _cell_list.getCell(name);
     961             :   // return whether that the cell in the list is the same as the cell provided (in memory)
     962         601 :   return &cell == &list_cell;
     963         601 : }
     964             : 
     965             : bool
     966        1011 : CSGBase::checkUniverseInBase(const CSGUniverse & universe) const
     967             : {
     968        1011 :   auto name = universe.getName();
     969             :   // if no universe by this name exists, an error will be produced by getUniverse
     970        1011 :   auto & list_univ = _universe_list.getUniverse(name);
     971             :   // return whether that the universe in the list is the same as the universe provided (in memory)
     972        1011 :   return &universe == &list_univ;
     973        1011 : }
     974             : 
     975             : bool
     976          66 : CSGBase::checkLatticeInBase(const CSGLattice & lattice) const
     977             : {
     978          66 :   auto name = lattice.getName();
     979             :   // if no lattice by this name exists, an error will be produced by getLattice
     980          66 :   auto & list_lattice = _lattice_list.getLattice(name);
     981             :   // return whether that the lattice in the list is the same as the lattice provided (in memory)
     982          66 :   return &lattice == &list_lattice;
     983          66 : }
     984             : 
     985             : void
     986          78 : CSGBase::checkUniverseLinking() const
     987             : {
     988          78 :   std::vector<std::string> linked_universe_names;
     989          78 :   std::vector<std::string> linked_cell_names;
     990             : 
     991             :   // Recursively figure out which universe names are linked to root universe
     992          78 :   getLinkedUniverses(getRootUniverse(), linked_universe_names, linked_cell_names);
     993             : 
     994             :   // Iterate through all universes in universe list and check that they exist in universes linked
     995             :   // to root universe
     996         266 :   for (const CSGUniverse & univ : getAllUniverses())
     997         194 :     if (std::find(linked_universe_names.begin(), linked_universe_names.end(), univ.getName()) ==
     998         388 :         linked_universe_names.end())
     999          78 :       mooseWarning("Universe with name ", univ.getName(), " is not linked to root universe.");
    1000             : 
    1001             :   // Iterate through all cells in cell list and check that they exist in cells linked
    1002             :   // to root universe
    1003         284 :   for (const CSGCell & cell : getAllCells())
    1004         214 :     if (std::find(linked_cell_names.begin(), linked_cell_names.end(), cell.getName()) ==
    1005         428 :         linked_cell_names.end())
    1006          72 :       mooseWarning("Cell with name ", cell.getName(), " is not linked to root universe.");
    1007          86 : }
    1008             : 
    1009             : void
    1010         790 : CSGBase::getLinkedUniverses(const CSGUniverse & univ,
    1011             :                             std::vector<std::string> & linked_universe_names,
    1012             :                             std::vector<std::string> & linked_cell_names) const
    1013             : {
    1014         790 :   linked_universe_names.push_back(univ.getName());
    1015         790 :   const auto & univ_cells = univ.getAllCells();
    1016        1698 :   for (const CSGCell & cell : univ_cells)
    1017             :   {
    1018         908 :     linked_cell_names.push_back(cell.getName());
    1019         908 :     if (cell.getFillType() == "UNIVERSE")
    1020          76 :       getLinkedUniverses(cell.getFillUniverse(), linked_universe_names, linked_cell_names);
    1021         832 :     else if (cell.getFillType() == "LATTICE")
    1022             :     {
    1023         118 :       const auto & lattice = cell.getFillLattice();
    1024         380 :       for (const auto & univ_list : lattice.getUniverses())
    1025         876 :         for (const auto & univ_ref : univ_list)
    1026             :         {
    1027         614 :           const CSGUniverse & lattice_univ = univ_ref.get();
    1028         614 :           getLinkedUniverses(lattice_univ, linked_universe_names, linked_cell_names);
    1029         118 :         }
    1030             : 
    1031         118 :       if (lattice.getOuterType() == "UNIVERSE")
    1032             :       {
    1033          22 :         const CSGUniverse & outer_univ = lattice.getOuterUniverse();
    1034          22 :         getLinkedUniverses(outer_univ, linked_universe_names, linked_cell_names);
    1035             :       }
    1036             :     }
    1037             :   }
    1038         790 : }
    1039             : 
    1040             : nlohmann::json
    1041          64 : CSGBase::generateOutput() const
    1042             : {
    1043             :   // Check that orphaned universes do not exist in universe list of CSGBase object
    1044          64 :   checkUniverseLinking();
    1045             : 
    1046          64 :   nlohmann::json csg_json;
    1047             : 
    1048          64 :   csg_json["surfaces"] = {};
    1049          64 :   csg_json["cells"] = {};
    1050          64 :   csg_json["universes"] = {};
    1051             : 
    1052             :   // get all surfaces information
    1053          64 :   auto all_surfs = getAllSurfaces();
    1054         560 :   for (const CSGSurface & s : all_surfs)
    1055             :   {
    1056         496 :     const auto & surf_name = s.getName();
    1057         496 :     const auto & coeffs = s.getCoeffs();
    1058        3472 :     csg_json["surfaces"][surf_name] = {{"type", s.getSurfaceType()}, {"coefficients", {}}};
    1059        2480 :     for (const auto & c : coeffs)
    1060        1984 :       csg_json["surfaces"][surf_name]["coefficients"][c.first] = c.second;
    1061             :     // include any information about transformations if present
    1062         496 :     if (s.getTransformations().size() > 0)
    1063           0 :       csg_json["surfaces"][surf_name]["transformations"] = s.getTransformationsAsStrings();
    1064         496 :   }
    1065             : 
    1066             :   // Print out cell information
    1067          64 :   auto all_cells = getAllCells();
    1068         264 :   for (const CSGCell & c : all_cells)
    1069             :   {
    1070         200 :     const auto & cell_name = c.getName();
    1071         200 :     const auto & cell_region_infix = c.getRegion().toInfixJSON();
    1072         200 :     const auto & cell_region_postfix = c.getRegion().toPostfixStringList();
    1073         200 :     const auto & cell_filltype = c.getFillType();
    1074         200 :     const auto & fill_name = c.getFillName();
    1075         200 :     csg_json["cells"][cell_name]["filltype"] = cell_filltype;
    1076         200 :     csg_json["cells"][cell_name]["region_infix"] = cell_region_infix;
    1077         200 :     csg_json["cells"][cell_name]["region_postfix"] = cell_region_postfix;
    1078         200 :     csg_json["cells"][cell_name]["fill"] = fill_name;
    1079             :     // include any information about transformations if present
    1080         200 :     if (c.getTransformations().size())
    1081          16 :       csg_json["cells"][cell_name]["transformations"] = c.getTransformationsAsStrings();
    1082         200 :   }
    1083             : 
    1084             :   // Print out universe information
    1085          64 :   auto all_univs = getAllUniverses();
    1086         224 :   for (const CSGUniverse & u : all_univs)
    1087             :   {
    1088         160 :     const auto & univ_name = u.getName();
    1089         160 :     const auto & univ_cells = u.getAllCells();
    1090         160 :     csg_json["universes"][univ_name]["cells"] = {};
    1091         360 :     for (const CSGCell & c : univ_cells)
    1092         200 :       csg_json["universes"][univ_name]["cells"].push_back(c.getName());
    1093         160 :     if (u.isRoot())
    1094          64 :       csg_json["universes"][univ_name]["root"] = u.isRoot();
    1095             :     // include any information about transformations if present
    1096         160 :     if (u.getTransformations().size())
    1097           0 :       csg_json["universes"][univ_name]["transformations"] = u.getTransformationsAsStrings();
    1098             :   }
    1099             : 
    1100             :   // print out lattice information if lattices exist
    1101          64 :   auto all_lats = getAllLattices();
    1102          64 :   if (all_lats.size())
    1103             :   {
    1104          32 :     csg_json["lattices"] = {};
    1105          80 :     for (const CSGLattice & lat : all_lats)
    1106             :     {
    1107          48 :       const auto & lat_name = lat.getName();
    1108          48 :       csg_json["lattices"][lat_name] = {};
    1109          48 :       csg_json["lattices"][lat_name]["type"] = lat.getType();
    1110          48 :       const auto & outer_type = lat.getOuterType();
    1111          48 :       csg_json["lattices"][lat_name]["outertype"] = outer_type;
    1112          48 :       if (outer_type == "UNIVERSE")
    1113          16 :         csg_json["lattices"][lat_name]["outer"] = lat.getOuterUniverse().getName();
    1114          32 :       else if (outer_type == "CSG_MATERIAL")
    1115           0 :         csg_json["lattices"][lat_name]["outer"] = lat.getOuterMaterial();
    1116             :       // write out any additional attributes
    1117          48 :       csg_json["lattices"][lat_name]["attributes"] = {};
    1118          48 :       const auto & lat_attrs = lat.getAttributes();
    1119         192 :       for (const auto & attr : lat_attrs)
    1120         144 :         csg_json["lattices"][lat_name]["attributes"][attr.first] = attr.second;
    1121             :       // write the map of universe names: list of lists
    1122          48 :       csg_json["lattices"][lat_name]["universes"] = lat.getUniverseNameMap();
    1123             :       // include any information about transformations if present
    1124          48 :       if (lat.getTransformations().size())
    1125           0 :         csg_json["lattices"][lat_name]["transformations"] = lat.getTransformationsAsStrings();
    1126          48 :     }
    1127             :   }
    1128             : 
    1129         128 :   return csg_json;
    1130        3040 : }
    1131             : 
    1132             : bool
    1133           8 : CSGBase::operator==(const CSGBase & other) const
    1134             : {
    1135           8 :   const auto & surf_list = this->getSurfaceList();
    1136           8 :   const auto & other_surf_list = other.getSurfaceList();
    1137           8 :   const auto & cell_list = this->getCellList();
    1138           8 :   const auto & other_cell_list = other.getCellList();
    1139           8 :   const auto & univ_list = this->getUniverseList();
    1140           8 :   const auto & other_univ_list = other.getUniverseList();
    1141           8 :   const auto & lat_list = this->getLatticeList();
    1142           8 :   const auto & other_lat_list = other.getLatticeList();
    1143          14 :   return (surf_list == other_surf_list) && (cell_list == other_cell_list) &&
    1144          14 :          (univ_list == other_univ_list) && (lat_list == other_lat_list);
    1145             : }
    1146             : 
    1147             : bool
    1148           4 : CSGBase::operator!=(const CSGBase & other) const
    1149             : {
    1150           4 :   return !(*this == other);
    1151             : }
    1152             : } // namespace CSG

Generated by: LCOV version 1.14