LCOV - code coverage report
Current view: top level - src/csg - CSGBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31782 (38bc22) with base 7edd10 Lines: 242 242 100.0 %
Date: 2025-11-11 16:14:25 Functions: 30 30 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             : 
      12             : namespace CSG
      13             : {
      14             : 
      15         115 : CSGBase::CSGBase()
      16         115 :   : _surface_list(CSGSurfaceList()), _cell_list(CSGCellList()), _universe_list(CSGUniverseList())
      17             : {
      18         115 : }
      19             : 
      20          11 : CSGBase::CSGBase(const CSGBase & other_base)
      21          11 :   : _surface_list(other_base.getSurfaceList()),
      22          11 :     _cell_list(CSGCellList()),
      23          11 :     _universe_list(CSGUniverseList())
      24             : {
      25             :   // Iterate through all cell references from the other CSGBase instance and
      26             :   // create new CSGCell pointers based on these references. This is done
      27             :   // recursively to properly handle cells with universe fills
      28          53 :   for (const auto & [name, cell] : other_base.getCellList().getCellListMap())
      29          42 :     addCellToList(*cell);
      30             : 
      31             :   // Link all cells in other_base root universe to current root universe
      32          33 :   for (auto & root_cell : other_base.getRootUniverse().getAllCells())
      33             :   {
      34          22 :     const auto & list_cell = _cell_list.getCell(root_cell.get().getName());
      35          22 :     addCellToUniverse(getRootUniverse(), list_cell);
      36             :   }
      37             : 
      38             :   // Iterate through all universe references from the other CSGBase instance and
      39             :   // create new CSGUniverse pointers based on these references. This is done in case
      40             :   // any universe exist in the universe list that are not connected to the cell list.
      41          33 :   for (const auto & [name, univ] : other_base.getUniverseList().getUniverseListMap())
      42          22 :     addUniverseToList(*univ);
      43          11 : }
      44             : 
      45         118 : CSGBase::~CSGBase() {}
      46             : 
      47             : const CSGCell &
      48          62 : CSGBase::addCellToList(const CSGCell & cell)
      49             : {
      50             :   // If cell has already been created, we just return a reference to it
      51          62 :   const auto name = cell.getName();
      52          62 :   if (_cell_list.hasCell(name))
      53          20 :     return _cell_list.getCell(name);
      54             : 
      55             :   // Otherwise if the cell has material or void cell, we can create it directly
      56          42 :   const auto fill_type = cell.getFillType();
      57          42 :   const auto region = cell.getRegion();
      58          42 :   if (fill_type == "VOID")
      59          11 :     return _cell_list.addVoidCell(name, region);
      60          31 :   else if (fill_type == "CSG_MATERIAL")
      61             :   {
      62          20 :     const auto mat_name = cell.getFillMaterial();
      63          20 :     return _cell_list.addMaterialCell(name, mat_name, region);
      64          20 :   }
      65             :   // Otherwise if the cell has a universe fill, we need to recursively define
      66             :   // all linked universes and cells first before defining this cell
      67             :   else
      68             :   {
      69          11 :     const auto & univ = addUniverseToList(cell.getFillUniverse());
      70          11 :     return _cell_list.addUniverseCell(name, univ, region);
      71             :   }
      72          62 : }
      73             : 
      74             : const CSGUniverse &
      75          33 : CSGBase::addUniverseToList(const CSGUniverse & univ)
      76             : {
      77             :   // If universe has already been created, we just return a reference to it
      78          33 :   const auto name = univ.getName();
      79          33 :   if (_universe_list.hasUniverse(name))
      80          22 :     return _universe_list.getUniverse(name);
      81             : 
      82             :   // Otherwise we create a new universe based on its associated cells.
      83             :   // addCellToList is called recursively in case associated cells have not
      84             :   // been added to the cell list yet.
      85          11 :   const auto univ_cells = univ.getAllCells();
      86          11 :   std::vector<std::reference_wrapper<const CSGCell>> current_univ_cells;
      87          31 :   for (const auto & univ_cell : univ_cells)
      88          20 :     current_univ_cells.push_back(addCellToList(univ_cell));
      89          11 :   return createUniverse(name, current_univ_cells);
      90          33 : }
      91             : 
      92             : const CSGCell &
      93          55 : CSGBase::createCell(const std::string & name,
      94             :                     const std::string & mat_name,
      95             :                     const CSGRegion & region,
      96             :                     const CSGUniverse * add_to_univ)
      97             : {
      98          55 :   checkRegionSurfaces(region);
      99          55 :   auto & cell = _cell_list.addMaterialCell(name, mat_name, region);
     100          55 :   if (add_to_univ)
     101          22 :     addCellToUniverse(*add_to_univ, cell);
     102             :   else
     103          33 :     addCellToUniverse(getRootUniverse(), cell);
     104          55 :   return cell;
     105             : }
     106             : 
     107             : const CSGCell &
     108          71 : CSGBase::createCell(const std::string & name,
     109             :                     const CSGRegion & region,
     110             :                     const CSGUniverse * add_to_univ)
     111             : {
     112          71 :   checkRegionSurfaces(region);
     113          71 :   auto & cell = _cell_list.addVoidCell(name, region);
     114          69 :   if (add_to_univ)
     115           8 :     addCellToUniverse(*add_to_univ, cell);
     116             :   else
     117          61 :     addCellToUniverse(getRootUniverse(), cell);
     118          69 :   return cell;
     119             : }
     120             : 
     121             : const CSGCell &
     122          19 : CSGBase::createCell(const std::string & name,
     123             :                     const CSGUniverse & fill_univ,
     124             :                     const CSGRegion & region,
     125             :                     const CSGUniverse * add_to_univ)
     126             : {
     127          19 :   checkRegionSurfaces(region);
     128          19 :   if (add_to_univ && (&fill_univ == add_to_univ))
     129           6 :     mooseError("Cell " + name +
     130             :                " cannot be filled with the same universe to which it is being added.");
     131             : 
     132          17 :   auto & cell = _cell_list.addUniverseCell(name, fill_univ, region);
     133          17 :   if (add_to_univ)
     134           2 :     addCellToUniverse(*add_to_univ, cell);
     135             :   else
     136          15 :     addCellToUniverse(getRootUniverse(), cell);
     137          17 :   return cell;
     138             : }
     139             : 
     140             : void
     141          13 : CSGBase::updateCellRegion(const CSGCell & cell, const CSGRegion & region)
     142             : {
     143          13 :   checkRegionSurfaces(region);
     144          13 :   if (!checkCellInBase(cell))
     145          10 :     mooseError("The region of cell with name " + cell.getName() +
     146           4 :                " is being updated that is different " +
     147             :                "from the cell of the same name in the CSGBase instance.");
     148          11 :   auto & list_cell = _cell_list.getCell(cell.getName());
     149          11 :   list_cell.updateRegion(region);
     150          11 : }
     151             : 
     152             : const CSGUniverse &
     153          21 : CSGBase::createUniverse(const std::string & name,
     154             :                         std::vector<std::reference_wrapper<const CSGCell>> & cells)
     155             : {
     156          21 :   auto & univ = _universe_list.addUniverse(name);
     157          21 :   addCellsToUniverse(univ, cells); // performs a check that cells are a part of this base
     158          21 :   return univ;
     159             : }
     160             : 
     161             : void
     162         247 : CSGBase::addCellToUniverse(const CSGUniverse & universe, const CSGCell & cell)
     163             : {
     164             :   // make sure cell is a part of this CSGBase instance
     165         247 :   if (!checkCellInBase(cell))
     166          12 :     mooseError("A cell named " + cell.getName() + " is being added to universe " +
     167           8 :                universe.getName() +
     168             :                " that is different from the cell of the same name in the CSGBase instance.");
     169             :   // make sure universe is a part of this CSGBase instance
     170         245 :   if (!checkUniverseInBase(universe))
     171          10 :     mooseError("Cells are being added to a universe named " + universe.getName() +
     172           4 :                " that is different " +
     173             :                "from the universe of the same name in the CSGBase instance.");
     174         243 :   auto & univ = _universe_list.getUniverse(universe.getName());
     175         243 :   univ.addCell(cell);
     176         243 : }
     177             : 
     178             : void
     179          23 : CSGBase::addCellsToUniverse(const CSGUniverse & universe,
     180             :                             std::vector<std::reference_wrapper<const CSGCell>> & cells)
     181             : {
     182          63 :   for (auto & c : cells)
     183          40 :     addCellToUniverse(universe, c);
     184          23 : }
     185             : 
     186             : void
     187          12 : CSGBase::removeCellFromUniverse(const CSGUniverse & universe, const CSGCell & cell)
     188             : {
     189             :   // make sure cell is a part of this CSGBase instance
     190          12 :   if (!checkCellInBase(cell))
     191          12 :     mooseError("A cell named " + cell.getName() + " is being removed from universe " +
     192           8 :                universe.getName() +
     193             :                " that is different from the cell of the same name in the CSGBase instance.");
     194             :   // make sure universe is a part of this CSGBase instance
     195          10 :   if (!checkUniverseInBase(universe))
     196          10 :     mooseError("Cells are being removed from a universe named " + universe.getName() +
     197           4 :                " that is different " +
     198             :                "from the universe of the same name in the CSGBase instance.");
     199           8 :   auto & univ = _universe_list.getUniverse(universe.getName());
     200           8 :   univ.removeCell(cell.getName());
     201           8 : }
     202             : 
     203             : void
     204           4 : CSGBase::removeCellsFromUniverse(const CSGUniverse & universe,
     205             :                                  std::vector<std::reference_wrapper<const CSGCell>> & cells)
     206             : {
     207          10 :   for (auto & c : cells)
     208           6 :     removeCellFromUniverse(universe, c);
     209           4 : }
     210             : 
     211             : void
     212          20 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base)
     213             : {
     214          20 :   joinSurfaceList(base->getSurfaceList());
     215          20 :   joinCellList(base->getCellList());
     216          20 :   joinUniverseList(base->getUniverseList());
     217          20 : }
     218             : 
     219             : void
     220           2 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base, std::string & new_root_name_join)
     221             : {
     222           2 :   joinSurfaceList(base->getSurfaceList());
     223           2 :   joinCellList(base->getCellList());
     224           2 :   joinUniverseList(base->getUniverseList(), new_root_name_join);
     225           2 : }
     226             : 
     227             : void
     228           2 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base,
     229             :                        const std::string & new_root_name_base,
     230             :                        const std::string & new_root_name_join)
     231             : {
     232           2 :   joinSurfaceList(base->getSurfaceList());
     233           2 :   joinCellList(base->getCellList());
     234           2 :   joinUniverseList(base->getUniverseList(), new_root_name_base, new_root_name_join);
     235           2 : }
     236             : 
     237             : void
     238          24 : CSGBase::joinSurfaceList(CSGSurfaceList & surf_list)
     239             : {
     240             :   // TODO: check if surface is a duplicate (by definition) and skip
     241             :   // adding if duplicate; must update references to the surface in cell
     242             :   // region definitions.
     243          24 :   auto & surf_list_map = surf_list.getSurfaceListMap();
     244          66 :   for (auto & s : surf_list_map)
     245          42 :     _surface_list.addSurface(std::move(s.second));
     246          24 : }
     247             : 
     248             : void
     249          24 : CSGBase::joinCellList(CSGCellList & cell_list)
     250             : {
     251          24 :   auto & cell_list_map = cell_list.getCellListMap();
     252         108 :   for (auto & c : cell_list_map)
     253          84 :     _cell_list.addCell(std::move(c.second));
     254          24 : }
     255             : 
     256             : void
     257          20 : CSGBase::joinUniverseList(CSGUniverseList & univ_list)
     258             : {
     259             :   // case 1: incoming root is joined into existing root; no new universes are created
     260          20 :   auto & univ_list_map = univ_list.getUniverseListMap();
     261          20 :   auto & root = getRootUniverse(); // this root universe
     262          60 :   for (auto & u : univ_list_map)
     263             :   {
     264          40 :     if (u.second->isRoot())
     265             :     {
     266             :       // add existing cells to current root instead of creating new universe
     267          20 :       auto all_cells = u.second->getAllCells();
     268          58 :       for (auto & cell : all_cells)
     269          38 :         addCellToUniverse(root, cell);
     270          20 :     }
     271             :     else // unique non-root universe to add to list
     272          20 :       _universe_list.addUniverse(std::move(u.second));
     273             :   }
     274          20 : }
     275             : 
     276             : void
     277           2 : CSGBase::joinUniverseList(CSGUniverseList & univ_list, const std::string & new_root_name_incoming)
     278             : {
     279             :   // case 2: incoming root is turned into new universe and existing root remains root
     280             : 
     281             :   // add incoming universes to current Base
     282           2 :   auto & all_univs = univ_list.getUniverseListMap();
     283           6 :   for (auto & u : all_univs)
     284             :   {
     285           4 :     if (u.second->isRoot())
     286             :     {
     287             :       // create new universe from incoming root universe
     288           2 :       auto all_cells = u.second->getAllCells();
     289           2 :       createUniverse(new_root_name_incoming, all_cells);
     290           2 :     }
     291             :     else // unique non-root universe to add to list
     292           2 :       _universe_list.addUniverse(std::move(u.second));
     293             :   }
     294           2 : }
     295             : 
     296             : void
     297           2 : CSGBase::joinUniverseList(CSGUniverseList & univ_list,
     298             :                           const std::string & new_root_name_base,
     299             :                           const std::string & new_root_name_incoming)
     300             : {
     301             :   // case 3: each root universe becomes a new universe and a new root is created
     302             : 
     303             :   // make a new universe from the existing root universe
     304           2 :   auto & root = getRootUniverse();
     305           2 :   auto root_cells = root.getAllCells();
     306           2 :   createUniverse(new_root_name_base, root_cells);
     307           2 :   removeCellsFromUniverse(root, root_cells);
     308             : 
     309             :   // add incoming universes to current Base
     310           2 :   auto & all_univs = univ_list.getUniverseListMap();
     311           6 :   for (auto & u : all_univs)
     312             :   {
     313           4 :     if (u.second->isRoot())
     314             :     {
     315             :       // create new universe from incoming root universe
     316           2 :       auto all_cells = u.second->getAllCells();
     317           2 :       createUniverse(new_root_name_incoming, all_cells);
     318           2 :     }
     319             :     else // unique non-root universe to add to list
     320           2 :       _universe_list.addUniverse(std::move(u.second));
     321             :   }
     322           2 : }
     323             : 
     324             : void
     325         160 : CSGBase::checkRegionSurfaces(const CSGRegion & region) const
     326             : {
     327         160 :   auto & surfs = region.getSurfaces();
     328         460 :   for (const CSGSurface & s : surfs)
     329             :   {
     330         302 :     auto sname = s.getName();
     331             :     // if there is no surface by this name at all, there will be an error from getSurface
     332         302 :     const auto & list_surf = _surface_list.getSurface(s.getName());
     333             :     // if there is a surface by the same name, check that it is actually the surface being used
     334             :     // (ie same surface points to same location in memory)
     335         302 :     if (&s != &list_surf)
     336           6 :       mooseError("Region is being set with a surface named " + sname +
     337             :                  " that is different from the surface of the same name in the CSGBase instance.");
     338         302 :   }
     339         158 : }
     340             : 
     341             : bool
     342         272 : CSGBase::checkCellInBase(const CSGCell & cell) const
     343             : {
     344         272 :   auto name = cell.getName();
     345             :   // if no cell by this name exists, an error will be produced by getCell
     346         272 :   auto & list_cell = _cell_list.getCell(name);
     347             :   // return whether that the cell in the list is the same as the cell provided (in memory)
     348         272 :   return &cell == &list_cell;
     349         272 : }
     350             : 
     351             : bool
     352         255 : CSGBase::checkUniverseInBase(const CSGUniverse & universe) const
     353             : {
     354         255 :   auto name = universe.getName();
     355             :   // if no universe by this name exists, an error will be produced by getUniverse
     356         255 :   auto & list_univ = _universe_list.getUniverse(name);
     357             :   // return whether that the cell in the list is the same as the cell provided (in memory)
     358         255 :   return &universe == &list_univ;
     359         255 : }
     360             : 
     361             : void
     362          40 : CSGBase::checkUniverseLinking() const
     363             : {
     364          40 :   std::vector<std::string> linked_universe_names;
     365             : 
     366             :   // Recursively figure out which universe names are linked to root universe
     367          40 :   getLinkedUniverses(getRootUniverse(), linked_universe_names);
     368             : 
     369             :   // Iterate through all universes in universe list and check that they exist in universes linked
     370             :   // to root universe list
     371          98 :   for (const CSGUniverse & univ : getAllUniverses())
     372          60 :     if (std::find(linked_universe_names.begin(), linked_universe_names.end(), univ.getName()) ==
     373         120 :         linked_universe_names.end())
     374          40 :       mooseWarning("Universe with name ", univ.getName(), " is not linked to root universe.");
     375          40 : }
     376             : 
     377             : void
     378          60 : CSGBase::getLinkedUniverses(const CSGUniverse & univ,
     379             :                             std::vector<std::string> & linked_universe_names) const
     380             : {
     381          60 :   linked_universe_names.push_back(univ.getName());
     382          60 :   const auto & univ_cells = univ.getAllCells();
     383         161 :   for (const CSGCell & cell : univ_cells)
     384         101 :     if (cell.getFillType() == "UNIVERSE")
     385          20 :       getLinkedUniverses(cell.getFillUniverse(), linked_universe_names);
     386          60 : }
     387             : 
     388             : nlohmann::json
     389          36 : CSGBase::generateOutput() const
     390             : {
     391             :   // Check that orphaned universes do not exist in universe list of CSGBase object
     392          36 :   checkUniverseLinking();
     393             : 
     394          36 :   nlohmann::json csg_json;
     395             : 
     396          36 :   csg_json["surfaces"] = {};
     397          36 :   csg_json["cells"] = {};
     398          36 :   csg_json["universes"] = {};
     399             : 
     400             :   // get all surfaces information
     401          36 :   auto all_surfs = getAllSurfaces();
     402         198 :   for (const CSGSurface & s : all_surfs)
     403             :   {
     404         162 :     const auto & surf_name = s.getName();
     405         162 :     const auto & coeffs = s.getCoeffs();
     406        1134 :     csg_json["surfaces"][surf_name] = {{"type", s.getSurfaceType()}, {"coefficients", {}}};
     407         810 :     for (const auto & c : coeffs)
     408         648 :       csg_json["surfaces"][surf_name]["coefficients"][c.first] = c.second;
     409         162 :   }
     410             : 
     411             :   // Print out cell information
     412          36 :   auto all_cells = getAllCells();
     413         135 :   for (const CSGCell & c : all_cells)
     414             :   {
     415          99 :     const auto & cell_name = c.getName();
     416          99 :     const auto & cell_region = c.getRegionAsString();
     417          99 :     const auto & cell_filltype = c.getFillType();
     418          99 :     const auto & fill_name = c.getFillName();
     419          99 :     csg_json["cells"][cell_name]["filltype"] = cell_filltype;
     420          99 :     csg_json["cells"][cell_name]["region"] = cell_region;
     421          99 :     csg_json["cells"][cell_name]["fill"] = fill_name;
     422          99 :   }
     423             : 
     424             :   // Print out universe information
     425          36 :   auto all_univs = getAllUniverses();
     426          90 :   for (const CSGUniverse & u : all_univs)
     427             :   {
     428          54 :     const auto & univ_name = u.getName();
     429          54 :     const auto & univ_cells = u.getAllCells();
     430          54 :     csg_json["universes"][univ_name]["cells"] = {};
     431         153 :     for (const CSGCell & c : univ_cells)
     432          99 :       csg_json["universes"][univ_name]["cells"].push_back(c.getName());
     433          54 :     if (u.isRoot())
     434          36 :       csg_json["universes"][univ_name]["root"] = u.isRoot();
     435             :   }
     436             : 
     437          72 :   return csg_json;
     438        1008 : }
     439             : 
     440             : bool
     441           4 : CSGBase::operator==(const CSGBase & other) const
     442             : {
     443           4 :   const auto & surf_list = this->getSurfaceList();
     444           4 :   const auto & other_surf_list = other.getSurfaceList();
     445           4 :   const auto & cell_list = this->getCellList();
     446           4 :   const auto & other_cell_list = other.getCellList();
     447           4 :   const auto & univ_list = this->getUniverseList();
     448           4 :   const auto & other_univ_list = other.getUniverseList();
     449           6 :   return (surf_list == other_surf_list) && (cell_list == other_cell_list) &&
     450           6 :          (univ_list == other_univ_list);
     451             : }
     452             : 
     453             : bool
     454           2 : CSGBase::operator!=(const CSGBase & other) const
     455             : {
     456           2 :   return !(*this == other);
     457             : }
     458             : 
     459             : } // namespace CSG

Generated by: LCOV version 1.14