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
|