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 274 : CSGBase::CSGBase()
18 274 : : _surface_list(CSGSurfaceList()),
19 274 : _cell_list(CSGCellList()),
20 274 : _universe_list(CSGUniverseList()),
21 274 : _lattice_list(CSGLatticeList())
22 : {
23 274 : }
24 :
25 12 : CSGBase::CSGBase(const CSGBase & other_base)
26 12 : : _surface_list(other_base.getSurfaceList()),
27 12 : _cell_list(CSGCellList()),
28 12 : _universe_list(CSGUniverseList()),
29 12 : _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 70 : for (const auto & [name, cell] : other_base.getCellList().getCellListMap())
35 58 : addCellToList(*cell);
36 :
37 : // Link all cells in other_base root universe to current root universe
38 36 : for (auto & root_cell : other_base.getRootUniverse().getAllCells())
39 : {
40 24 : const auto & list_cell = _cell_list.getCell(root_cell.get().getName());
41 24 : 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 54 : for (const auto & [name, univ] : other_base.getUniverseList().getUniverseListMap())
48 42 : 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 22 : for (const auto & [name, lattice] : other_base.getLatticeList().getLatticeListMap())
53 10 : addLatticeToList(*lattice);
54 12 : }
55 :
56 280 : 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 92 : CSGBase::addCellToList(const CSGCell & cell)
86 : {
87 : // If cell has already been created, we just return a reference to it
88 92 : const auto name = cell.getName();
89 92 : if (_cell_list.hasCell(name))
90 34 : return _cell_list.getCell(name);
91 :
92 : // Otherwise if the cell has material or void cell, we can create it directly
93 58 : const auto fill_type = cell.getFillType();
94 58 : const auto region = cell.getRegion();
95 58 : if (fill_type == "VOID")
96 12 : return _cell_list.addVoidCell(name, region);
97 46 : 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 20 : else if (fill_type == "LATTICE")
103 : {
104 : // add lattice recursively to capture all linked universes in the lattice
105 10 : const CSGLattice & lattice = addLatticeToList(cell.getFillLattice());
106 10 : 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 10 : else if (fill_type == "UNIVERSE")
111 : {
112 10 : const auto & univ = addUniverseToList(cell.getFillUniverse());
113 10 : return _cell_list.addUniverseCell(name, univ, region);
114 : }
115 : else
116 0 : mooseError("Cell " + name + " has unrecognized fill type " + fill_type);
117 92 : }
118 :
119 : const CSGUniverse &
120 96 : CSGBase::addUniverseToList(const CSGUniverse & univ)
121 : {
122 : // If universe has already been created, we just return a reference to it
123 96 : const auto name = univ.getName();
124 96 : if (_universe_list.hasUniverse(name))
125 66 : 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 30 : const auto univ_cells = univ.getAllCells();
131 30 : std::vector<std::reference_wrapper<const CSGCell>> current_univ_cells;
132 64 : for (const auto & univ_cell : univ_cells)
133 34 : current_univ_cells.push_back(addCellToList(univ_cell));
134 30 : return createUniverse(name, current_univ_cells);
135 96 : }
136 :
137 : const CSGLattice &
138 20 : CSGBase::addLatticeToList(const CSGLattice & lattice)
139 : {
140 : // If lattice has already been created, we just return a reference to it
141 20 : const auto name = lattice.getName();
142 20 : if (_lattice_list.hasLattice(name))
143 10 : return _lattice_list.getLattice(name);
144 :
145 : // Clone the lattice (associated universes need to be transferred and set)
146 10 : 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 10 : std::vector<std::vector<std::reference_wrapper<const CSGUniverse>>> current_univ_map;
152 28 : for (const auto & univ_list : lattice.getUniverses())
153 : {
154 18 : std::vector<std::reference_wrapper<const CSGUniverse>> current_univ_list;
155 52 : for (const auto & univ_ref : univ_list)
156 34 : current_univ_list.push_back(addUniverseToList(univ_ref.get()));
157 18 : current_univ_map.push_back(current_univ_list);
158 28 : }
159 :
160 : // Set universes only if lattice has universes defined
161 10 : if (current_univ_map.size() > 0)
162 10 : cloned_lattice->setUniverses(current_univ_map);
163 :
164 : // Update reference to outer universe if it exists
165 10 : if (lattice.getOuterType() == "UNIVERSE")
166 : {
167 10 : const auto & outer_univ_ref = addUniverseToList(lattice.getOuterUniverse());
168 10 : cloned_lattice->updateOuter(outer_univ_ref);
169 : }
170 :
171 : // Use addLattice to add the cloned lattice
172 10 : return addLattice(std::move(cloned_lattice));
173 20 : }
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 20 : CSGBase::createCell(const std::string & name,
229 : const CSGUniverse & fill_univ,
230 : const CSGRegion & region,
231 : const CSGUniverse * add_to_univ)
232 : {
233 20 : checkRegionSurfaces(region);
234 20 : 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 18 : auto & cell = _cell_list.addUniverseCell(name, fill_univ, region);
239 18 : if (add_to_univ)
240 10 : addCellToUniverse(*add_to_univ, cell);
241 : else
242 8 : addCellToUniverse(getRootUniverse(), cell);
243 18 : return cell;
244 : }
245 :
246 : const CSGCell &
247 58 : CSGBase::createCell(const std::string & name,
248 : const CSGLattice & fill_lattice,
249 : const CSGRegion & region,
250 : const CSGUniverse * add_to_univ)
251 : {
252 58 : checkRegionSurfaces(region);
253 :
254 : // check that cell is not being added to a universe that exists in the lattice itself
255 58 : if (add_to_univ)
256 6 : for (auto univ_list : fill_lattice.getUniverses())
257 8 : for (const auto & univ_ref : univ_list)
258 : {
259 6 : const CSGUniverse & univ_in_lattice = univ_ref.get();
260 6 : 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 8 : }
265 :
266 56 : auto & cell = _cell_list.addLatticeCell(name, fill_lattice, region);
267 56 : if (add_to_univ)
268 2 : addCellToUniverse(*add_to_univ, cell);
269 : else
270 54 : addCellToUniverse(getRootUniverse(), cell);
271 56 : 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 106 : CSGBase::createUniverse(const std::string & name,
372 : std::vector<std::reference_wrapper<const CSGCell>> & cells)
373 : {
374 106 : auto & univ = _universe_list.addUniverse(name);
375 106 : addCellsToUniverse(univ, cells); // performs a check that cells are a part of this base
376 106 : 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 461 : CSGBase::addCellToUniverse(const CSGUniverse & universe, const CSGCell & cell)
425 : {
426 : // make sure cell is a part of this CSGBase instance
427 461 : 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 459 : 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 457 : auto & univ = _universe_list.getUniverse(universe.getName());
437 457 : univ.addCell(cell);
438 457 : }
439 :
440 : void
441 108 : CSGBase::addCellsToUniverse(const CSGUniverse & universe,
442 : std::vector<std::reference_wrapper<const CSGCell>> & cells)
443 : {
444 228 : for (auto & c : cells)
445 120 : addCellToUniverse(universe, c);
446 108 : }
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 18 : CSGBase::setLatticeOuter(const CSGLattice & lattice, const CSGUniverse & outer_univ)
486 : {
487 18 : auto name = lattice.getName();
488 18 : 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 18 : 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 16 : _lattice_list.getLattice(name).updateOuter(outer_univ);
496 18 : }
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 120 : 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 120 : std::visit(
551 240 : [&](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 40 : const CSGCell & cell = obj.get();
560 40 : 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 38 : CSGCell & mutable_cell = _cell_list.getCell(cell.getName());
567 : mooseAssert(mutable_cell == cell, "Mutable cell does not match const cell passed in.");
568 38 : mutable_cell.addTransformation(type, values);
569 : }
570 : else if constexpr (std::is_same_v<T, CSGSurface>)
571 : {
572 32 : const CSGSurface & surface = obj.get();
573 32 : 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 30 : CSGSurface & mutable_surface = _surface_list.getSurface(surface.getName());
580 : mooseAssert(mutable_surface == surface,
581 : "Mutable surface does not match const surface passed in.");
582 30 : mutable_surface.addTransformation(type, values);
583 : }
584 : else if constexpr (std::is_same_v<T, CSGUniverse>)
585 : {
586 16 : const CSGUniverse & universe = obj.get();
587 16 : 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 14 : CSGUniverse & mutable_universe = _universe_list.getUniverse(universe.getName());
594 : mooseAssert(mutable_universe == universe,
595 : "Mutable universe does not match const universe passed in.");
596 14 : 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 108 : },
629 : csg_object);
630 108 : }
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 54 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base, const bool ignore_identical_surfaces)
664 : {
665 : // If we are ignoring identical incoming surfaces, we need to update the cell regions to
666 : // point to the references of the pre-existing surfaces
667 54 : if (ignore_identical_surfaces)
668 2 : updateIncomingCellRegions(base->getSurfaceList(), base->getCellList());
669 54 : joinSurfaceList(base->getSurfaceList(), ignore_identical_surfaces);
670 52 : joinCellList(base->getCellList());
671 52 : joinLatticeList(base->getLatticeList());
672 52 : joinUniverseList(base->getUniverseList());
673 52 : }
674 :
675 : void
676 58 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base,
677 : const bool ignore_identical_surfaces,
678 : const std::string & new_root_name_join)
679 : {
680 : // If we are ignoring identical incoming surfaces, we need to update the cell regions to
681 : // point to the references of the pre-existing surfaces
682 58 : if (ignore_identical_surfaces)
683 0 : updateIncomingCellRegions(base->getSurfaceList(), base->getCellList());
684 58 : joinSurfaceList(base->getSurfaceList(), ignore_identical_surfaces);
685 58 : joinCellList(base->getCellList());
686 58 : joinLatticeList(base->getLatticeList());
687 58 : joinUniverseList(base->getUniverseList(), new_root_name_join);
688 58 : }
689 :
690 : void
691 2 : CSGBase::joinOtherBase(std::unique_ptr<CSGBase> base,
692 : const bool ignore_identical_surfaces,
693 : const std::string & new_root_name_base,
694 : const std::string & new_root_name_join)
695 : {
696 : // If we are ignoring identical incoming surfaces, we need to update the cell regions to
697 : // point to the references of the pre-existing surfaces
698 2 : if (ignore_identical_surfaces)
699 0 : updateIncomingCellRegions(base->getSurfaceList(), base->getCellList());
700 2 : joinSurfaceList(base->getSurfaceList(), ignore_identical_surfaces);
701 2 : joinCellList(base->getCellList());
702 2 : joinLatticeList(base->getLatticeList());
703 2 : joinUniverseList(base->getUniverseList(), new_root_name_base, new_root_name_join);
704 2 : }
705 :
706 : void
707 2 : CSGBase::updateIncomingCellRegions(CSGSurfaceList & surf_list, CSGCellList & cell_list)
708 : {
709 : // Iterate through all incoming surfaces and track which ones have names already
710 : // defined within this CSGSurfaceList object
711 2 : std::map<std::string, std::reference_wrapper<const CSGSurface>> identical_surface_refs;
712 2 : auto & surf_list_map = surf_list.getSurfaceListMap();
713 4 : for (const auto & s : surf_list_map)
714 2 : if (hasSurface(s.first))
715 2 : identical_surface_refs.insert({s.first, getSurfaceByName(s.first)});
716 :
717 2 : if (!identical_surface_refs.empty())
718 : {
719 2 : auto & cell_list_map = cell_list.getCellListMap();
720 4 : for (auto & c : cell_list_map)
721 2 : c.second->updateCellRegionSurfaces(identical_surface_refs);
722 : }
723 2 : }
724 :
725 : void
726 114 : CSGBase::joinSurfaceList(CSGSurfaceList & surf_list, const bool ignore_identical_surfaces)
727 : {
728 114 : auto & surf_list_map = surf_list.getSurfaceListMap();
729 666 : for (auto & s : surf_list_map)
730 556 : _surface_list.addSurface(std::move(s.second), ignore_identical_surfaces);
731 112 : }
732 :
733 : void
734 112 : CSGBase::joinCellList(CSGCellList & cell_list)
735 : {
736 112 : auto & cell_list_map = cell_list.getCellListMap();
737 342 : for (auto & c : cell_list_map)
738 230 : _cell_list.addCell(std::move(c.second));
739 112 : }
740 :
741 : void
742 112 : CSGBase::joinLatticeList(CSGLatticeList & lattice_list)
743 : {
744 112 : auto & lat_list_map = lattice_list.getLatticeListMap();
745 176 : for (auto & lat : lat_list_map)
746 64 : _lattice_list.addLattice(std::move(lat.second));
747 112 : }
748 :
749 : void
750 52 : CSGBase::joinUniverseList(CSGUniverseList & univ_list)
751 : {
752 : // case 1: incoming root is joined into existing root; no new universes are created
753 52 : auto & univ_list_map = univ_list.getUniverseListMap();
754 52 : auto & root = getRootUniverse(); // this root universe
755 210 : for (auto & u : univ_list_map)
756 : {
757 158 : if (u.second->isRoot())
758 : {
759 : // add existing cells to current root instead of creating new universe
760 52 : auto all_cells = u.second->getAllCells();
761 88 : for (auto & cell : all_cells)
762 36 : addCellToUniverse(root, cell);
763 52 : }
764 : else // unique non-root universe to add to list
765 106 : _universe_list.addUniverse(std::move(u.second));
766 : }
767 52 : }
768 :
769 : void
770 58 : CSGBase::joinUniverseList(CSGUniverseList & univ_list, const std::string & new_root_name_incoming)
771 : {
772 : // case 2: incoming root is turned into new universe and existing root remains root
773 :
774 : // add incoming universes to current Base
775 58 : auto & all_univs = univ_list.getUniverseListMap();
776 126 : for (auto & u : all_univs)
777 : {
778 68 : if (u.second->isRoot())
779 : {
780 : // create new universe from incoming root universe
781 58 : auto all_cells = u.second->getAllCells();
782 58 : createUniverse(new_root_name_incoming, all_cells);
783 58 : }
784 : else // unique non-root universe to add to list
785 10 : _universe_list.addUniverse(std::move(u.second));
786 : }
787 58 : }
788 :
789 : void
790 2 : CSGBase::joinUniverseList(CSGUniverseList & univ_list,
791 : const std::string & new_root_name_base,
792 : const std::string & new_root_name_incoming)
793 : {
794 : // case 3: each root universe becomes a new universe and a new root is created
795 :
796 : // make a new universe from the existing root universe
797 2 : auto & root = getRootUniverse();
798 2 : auto root_cells = root.getAllCells();
799 2 : createUniverse(new_root_name_base, root_cells);
800 2 : removeCellsFromUniverse(root, root_cells);
801 :
802 : // add incoming universes to current Base
803 2 : auto & all_univs = univ_list.getUniverseListMap();
804 6 : for (auto & u : all_univs)
805 : {
806 4 : if (u.second->isRoot())
807 : {
808 : // create new universe from incoming root universe
809 2 : auto all_cells = u.second->getAllCells();
810 2 : createUniverse(new_root_name_incoming, all_cells);
811 2 : }
812 : else // unique non-root universe to add to list
813 2 : _universe_list.addUniverse(std::move(u.second));
814 : }
815 2 : }
816 :
817 : void
818 301 : CSGBase::checkRegionSurfaces(const CSGRegion & region) const
819 : {
820 301 : const auto surfs = region.getSurfaces();
821 1035 : for (const CSGSurface & s : surfs)
822 : {
823 736 : if (!checkSurfaceInBase(s))
824 6 : mooseError("Region is being set with a surface named " + s.getName() +
825 : " that is different from the surface of the same name in the CSGBase instance.");
826 : }
827 301 : }
828 :
829 : bool
830 790 : CSGBase::checkSurfaceInBase(const CSGSurface & surface) const
831 : {
832 790 : auto name = surface.getName();
833 : // if no surface by this name exists, an error will be produced by getSurface
834 790 : auto & list_surf = _surface_list.getSurface(name);
835 : // return whether that the surface in the list is the same as the surface provided (in memory)
836 790 : return &surface == &list_surf;
837 790 : }
838 :
839 : bool
840 567 : CSGBase::checkCellInBase(const CSGCell & cell) const
841 : {
842 567 : auto name = cell.getName();
843 : // if no cell by this name exists, an error will be produced by getCell
844 567 : auto & list_cell = _cell_list.getCell(name);
845 : // return whether that the cell in the list is the same as the cell provided (in memory)
846 567 : return &cell == &list_cell;
847 567 : }
848 :
849 : bool
850 957 : CSGBase::checkUniverseInBase(const CSGUniverse & universe) const
851 : {
852 957 : auto name = universe.getName();
853 : // if no universe by this name exists, an error will be produced by getUniverse
854 957 : auto & list_univ = _universe_list.getUniverse(name);
855 : // return whether that the universe in the list is the same as the universe provided (in memory)
856 957 : return &universe == &list_univ;
857 957 : }
858 :
859 : bool
860 64 : CSGBase::checkLatticeInBase(const CSGLattice & lattice) const
861 : {
862 64 : auto name = lattice.getName();
863 : // if no lattice by this name exists, an error will be produced by getLattice
864 64 : auto & list_lattice = _lattice_list.getLattice(name);
865 : // return whether that the lattice in the list is the same as the lattice provided (in memory)
866 64 : return &lattice == &list_lattice;
867 64 : }
868 :
869 : void
870 78 : CSGBase::checkUniverseLinking() const
871 : {
872 78 : std::vector<std::string> linked_universe_names;
873 78 : std::vector<std::string> linked_cell_names;
874 :
875 : // Recursively figure out which universe names are linked to root universe
876 78 : getLinkedUniverses(getRootUniverse(), linked_universe_names, linked_cell_names);
877 :
878 : // Iterate through all universes in universe list and check that they exist in universes linked
879 : // to root universe
880 266 : for (const CSGUniverse & univ : getAllUniverses())
881 194 : if (std::find(linked_universe_names.begin(), linked_universe_names.end(), univ.getName()) ==
882 388 : linked_universe_names.end())
883 78 : mooseWarning("Universe with name ", univ.getName(), " is not linked to root universe.");
884 :
885 : // Iterate through all cells in cell list and check that they exist in cells linked
886 : // to root universe
887 284 : for (const CSGCell & cell : getAllCells())
888 214 : if (std::find(linked_cell_names.begin(), linked_cell_names.end(), cell.getName()) ==
889 428 : linked_cell_names.end())
890 72 : mooseWarning("Cell with name ", cell.getName(), " is not linked to root universe.");
891 86 : }
892 :
893 : void
894 790 : CSGBase::getLinkedUniverses(const CSGUniverse & univ,
895 : std::vector<std::string> & linked_universe_names,
896 : std::vector<std::string> & linked_cell_names) const
897 : {
898 790 : linked_universe_names.push_back(univ.getName());
899 790 : const auto & univ_cells = univ.getAllCells();
900 1698 : for (const CSGCell & cell : univ_cells)
901 : {
902 908 : linked_cell_names.push_back(cell.getName());
903 908 : if (cell.getFillType() == "UNIVERSE")
904 76 : getLinkedUniverses(cell.getFillUniverse(), linked_universe_names, linked_cell_names);
905 832 : else if (cell.getFillType() == "LATTICE")
906 : {
907 118 : const auto & lattice = cell.getFillLattice();
908 380 : for (const auto & univ_list : lattice.getUniverses())
909 876 : for (const auto & univ_ref : univ_list)
910 : {
911 614 : const CSGUniverse & lattice_univ = univ_ref.get();
912 614 : getLinkedUniverses(lattice_univ, linked_universe_names, linked_cell_names);
913 118 : }
914 :
915 118 : if (lattice.getOuterType() == "UNIVERSE")
916 : {
917 22 : const CSGUniverse & outer_univ = lattice.getOuterUniverse();
918 22 : getLinkedUniverses(outer_univ, linked_universe_names, linked_cell_names);
919 : }
920 : }
921 : }
922 790 : }
923 :
924 : nlohmann::json
925 64 : CSGBase::generateOutput() const
926 : {
927 : // Check that orphaned universes do not exist in universe list of CSGBase object
928 64 : checkUniverseLinking();
929 :
930 64 : nlohmann::json csg_json;
931 :
932 64 : csg_json["surfaces"] = {};
933 64 : csg_json["cells"] = {};
934 64 : csg_json["universes"] = {};
935 :
936 : // get all surfaces information
937 64 : auto all_surfs = getAllSurfaces();
938 560 : for (const CSGSurface & s : all_surfs)
939 : {
940 496 : const auto & surf_name = s.getName();
941 496 : const auto & coeffs = s.getCoeffs();
942 3472 : csg_json["surfaces"][surf_name] = {{"type", s.getSurfaceType()}, {"coefficients", {}}};
943 2480 : for (const auto & c : coeffs)
944 1984 : csg_json["surfaces"][surf_name]["coefficients"][c.first] = c.second;
945 : // include any information about transformations if present
946 496 : if (s.getTransformations().size() > 0)
947 0 : csg_json["surfaces"][surf_name]["transformations"] = s.getTransformationsAsStrings();
948 496 : }
949 :
950 : // Print out cell information
951 64 : auto all_cells = getAllCells();
952 264 : for (const CSGCell & c : all_cells)
953 : {
954 200 : const auto & cell_name = c.getName();
955 200 : const auto & cell_region_infix = c.getRegion().toInfixJSON();
956 200 : const auto & cell_region_postfix = c.getRegion().toPostfixStringList();
957 200 : const auto & cell_filltype = c.getFillType();
958 200 : const auto & fill_name = c.getFillName();
959 200 : csg_json["cells"][cell_name]["filltype"] = cell_filltype;
960 200 : csg_json["cells"][cell_name]["region_infix"] = cell_region_infix;
961 200 : csg_json["cells"][cell_name]["region_postfix"] = cell_region_postfix;
962 200 : csg_json["cells"][cell_name]["fill"] = fill_name;
963 : // include any information about transformations if present
964 200 : if (c.getTransformations().size())
965 16 : csg_json["cells"][cell_name]["transformations"] = c.getTransformationsAsStrings();
966 200 : }
967 :
968 : // Print out universe information
969 64 : auto all_univs = getAllUniverses();
970 224 : for (const CSGUniverse & u : all_univs)
971 : {
972 160 : const auto & univ_name = u.getName();
973 160 : const auto & univ_cells = u.getAllCells();
974 160 : csg_json["universes"][univ_name]["cells"] = {};
975 360 : for (const CSGCell & c : univ_cells)
976 200 : csg_json["universes"][univ_name]["cells"].push_back(c.getName());
977 160 : if (u.isRoot())
978 64 : csg_json["universes"][univ_name]["root"] = u.isRoot();
979 : // include any information about transformations if present
980 160 : if (u.getTransformations().size())
981 0 : csg_json["universes"][univ_name]["transformations"] = u.getTransformationsAsStrings();
982 : }
983 :
984 : // print out lattice information if lattices exist
985 64 : auto all_lats = getAllLattices();
986 64 : if (all_lats.size())
987 : {
988 32 : csg_json["lattices"] = {};
989 80 : for (const CSGLattice & lat : all_lats)
990 : {
991 48 : const auto & lat_name = lat.getName();
992 48 : csg_json["lattices"][lat_name] = {};
993 48 : csg_json["lattices"][lat_name]["type"] = lat.getType();
994 48 : const auto & outer_type = lat.getOuterType();
995 48 : csg_json["lattices"][lat_name]["outertype"] = outer_type;
996 48 : if (outer_type == "UNIVERSE")
997 16 : csg_json["lattices"][lat_name]["outer"] = lat.getOuterUniverse().getName();
998 32 : else if (outer_type == "CSG_MATERIAL")
999 0 : csg_json["lattices"][lat_name]["outer"] = lat.getOuterMaterial();
1000 : // write out any additional attributes
1001 48 : csg_json["lattices"][lat_name]["attributes"] = {};
1002 48 : const auto & lat_attrs = lat.getAttributes();
1003 192 : for (const auto & attr : lat_attrs)
1004 144 : csg_json["lattices"][lat_name]["attributes"][attr.first] = attr.second;
1005 : // write the map of universe names: list of lists
1006 48 : csg_json["lattices"][lat_name]["universes"] = lat.getUniverseNameMap();
1007 : // include any information about transformations if present
1008 48 : if (lat.getTransformations().size())
1009 0 : csg_json["lattices"][lat_name]["transformations"] = lat.getTransformationsAsStrings();
1010 48 : }
1011 : }
1012 :
1013 128 : return csg_json;
1014 3040 : }
1015 :
1016 : bool
1017 8 : CSGBase::operator==(const CSGBase & other) const
1018 : {
1019 8 : const auto & surf_list = this->getSurfaceList();
1020 8 : const auto & other_surf_list = other.getSurfaceList();
1021 8 : const auto & cell_list = this->getCellList();
1022 8 : const auto & other_cell_list = other.getCellList();
1023 8 : const auto & univ_list = this->getUniverseList();
1024 8 : const auto & other_univ_list = other.getUniverseList();
1025 8 : const auto & lat_list = this->getLatticeList();
1026 8 : const auto & other_lat_list = other.getLatticeList();
1027 14 : return (surf_list == other_surf_list) && (cell_list == other_cell_list) &&
1028 14 : (univ_list == other_univ_list) && (lat_list == other_lat_list);
1029 : }
1030 :
1031 : bool
1032 4 : CSGBase::operator!=(const CSGBase & other) const
1033 : {
1034 4 : return !(*this == other);
1035 : }
1036 : } // namespace CSG
|