CSGBase
CSGBase
is the main class developers should interact with when implementing the generateCSG
method for any mesh generator. This framework class acts as a container and driver for all methods necessary for creating a constructive solid geometry (CSG) representation such as generating surfaces, cells, and universes of the mesh generator under consideration.
Throughout this documentation, csg_obj
will be used in example code blocks to refer to a CSGBase
instance.
Declaring that a mesh generator supports the generation of CSG
In order to call generateCSG
, the setHasGenerateCSG
method must be called on the mesh generator to declare that the method has been implemented.
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)How to implement the generateCSG
routine
This section will describe the various components developers should implement into the generateCSG
method for a given MeshGenerator. This method will return a unique pointer to the CSGBase
object that was created or modified by the mesh generator in the generateCSG
method.
Initialization
A new CSGBase
object can be initialized with:
auto csg_obj = std::make_unique<CSG::CSGBase>();
(moose/test/src/csg/ExampleCSGInfiniteSquareMeshGenerator.C)Once initialized, surfaces, cells, and universes can be created and manipulated. The following sections explain in detail how to do this as a part of the generateCSG
method.
Surfaces
Surfaces are used to define the spatial extent of the region of a CSGCell
. To create a CSGSurface
object, the surface constructor must be called directly to create a unique pointer. This pointer then has to be passed to the current CSGBase
instance with addSurface
which will then return a const reference to that generated surface (const & CSGSurface
). The syntax to do this is as follows, where SurfaceType
should be replaced with the specific type of surface being created (e.g., CSG::CSGPlane
):
// the unique surface pointer is made first, creating the surface object
std::unique_ptr<CSG::CSGSurface> surf_ptr = std::make_unique<SurfaceType>(arguments);
// and then it is explicitly passed to this CSGBase instance, which holds the memory ownership for the object
const auto & surface = csg_obj->addSurface(std::move(surf_ptr));
Surfaces need to be added to the CSGBase instance with addSurface
as described above. If this is not done and these surfaces are referenced in regions used to define cells within the CSGBase instance, an error will occur.
The CSG
framework in MOOSE provides various classes for creating basic surfaces (see table below). Information about how to define new types of surfaces can be found in CSGSurface.
Surface Type | Class | Description |
---|---|---|
Plane | CSGPlane | create a plane defined by 3 points or from coefficients a , b , c , and d for the equation ax + by + cz = d |
Sphere | CSGSphere | creates a sphere of radius r at an optionally specified center point (default is (0, 0, 0) ) |
Cylinder | CSGXCylinder | creates a cylinder aligned with the x-axis at the specified center location (y , z ) |
Cylinder | CSGYCylinder | creates a cylinder aligned with the y-axis at the specified center location (x , z ) |
Cylinder | CSGZCylinder | creates a cylinder aligned with the z-axis at the specified center location (x , y ) |
Example:
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)In order to define a surface, the header file for that surface type must be included in the MeshGenerator.C
file (i.e., #include "CSGPlane.h"
to create planes).
The CSGSurface
objects can then be accessed or updated with the following methods from CSGBase
:
addSurface
: add a unique pointer to aCSGSurface
object to thisCSGBase
instancegetAllSurfaces
: retrieve a list of const references to eachCSGSurface
object in theCSGBase
instancegetSurfaceByName
: retrieve a const reference to theCSGSurface
of the specified namerenameSurface
: change the name of theCSGSurface
Regions
A region is a space defined by boolean operations applied to surfaces and other regions. Half-space regions are defined as the positive and negative space separated by a surface. These regions can be unionized, intersected, or the complement taken to further define more complex regions. Series of operations can be defined using parentheses (
)
to indicate which operations to perform first. The types of operators available to define a CSGRegion
using CSGSurface
objects are:
Operator | Description | Example Use |
---|---|---|
+ | positive half-space | +surf |
- | negative half-space | -surf |
& | intersection | -surfA & +surfB |
| | union | -surfA | +surfB |
~ | complement | ~(-surfA & +surfB) |
&= | update existing region with an intersection | region1 &= -surfA |
| = | update existing region with a union | region1 | = +surfB |
The following is an example of using a combination of all operators to define the space outside a cylinder of a finite height that is topped with a half-sphere. Each of the half-spaces associated with each surface are shown in Figure 1. The cylinder and planes are then combined via intersection to form the region inside a finite cylinder, and the space above the top plane is intersected with the sphere to define a half sphere (Figure 2). These two regions are unionized as shown in Figure 3. The complement of the previous combination then defines the final region ~((-cylinder_surf & -top_plane & +bottom_plane) | (+top_plane & -sphere_surf))
, as shown in blue in Figure 4.

Figure 1: Four different surfaces: an infinite cylinder (blue), a top plane (orange), a bottom plane (red), and a sphere (green)

Figure 2: Two separate regions both defined as intersections of half-spaces.

Figure 3: One region defined by the union of two other regions.

Figure 4: A region defined as the complement of an existing region.
Cells
A cell is an object defined by a region and a fill. To create any CSGCell
, use the method createCell
from CSGBase
which will return a const reference to the CSGCell
object that is created (const CSGCell &
). At the time of calling createCell
, a unique cell name, the cell region (CSGRegion
), and an indicator of the fill must be provided. The CSGRegion
is defined by boolean combinations of CSGSurfaces
as described below. Three types of cell fills are currently supported: void, material, and universe. If creating a void cell, no fill has to be passed to the creation method. To create a cell with a material fill, simply provide it with a name of a material as a string. For a cell with a CSGUniverse
fill, pass it a shared pointer to the CSGUniverse
. Some examples of creating the different types of cells are shown below:
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
(moose/unit/src/CSGBaseTest.C) // create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
(moose/unit/src/CSGBaseTest.C) // create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
(moose/unit/src/CSGBaseTest.C)A cell with a material fill is not connected to a MOOSE material definition at this time. The "material" is currently just a string to represent the name of a CSG material or other type of fill that is otherwise undefined.
The CSGCell
objects can then be accessed or updated with the following methods from CSGBase
:
getAllCells
: retrieve a list of const references to eachCSGCell
object in theCSGBase
instancegetCellByName
: retrieve a const reference to theCSGCell
object of the specified namerenameCell
: change the name of theCSGCell
objectupdateCellRegion
: change the region of the cell; if used, allCSGSurface
objects used to define the newCSGRegion
must also be a part of the currentCSGBase
Universes
A universe is a collection of cells and is created by calling createUniverse
from CSGBase
which will return a const reference to the CSGUniverse
object (const CSGUniverse &
). A CSGUniverse
can be initialized as an empty universe, or by passing a vector of shared pointers to CSGCell
objects. Any CSGUniverse
object can be renamed (including the root universe) with renameUniverse
.
The CSGUniverse
objects can then be accessed or updated with the following methods from CSGBase
:
getAllUniverses
: retrieve a list of const references to eachCSGUniverse
object in theCSGBase
instancegetUniverseByName
: retrieve a const reference to theCSGUniverse
of the specified namerenameUniverse
: change the name of theCSGUniverse
Examples:
auto new_univ = csg_obj->createUniverse("new_univ");
(moose/unit/src/CSGBaseTest.C) // create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
(moose/unit/src/CSGBaseTest.C)Root Universe
All universes in a model should be able to be traced back, through the hierarchical tree of cells and universes, to a singular overarching universe known as the root universe. Because universes are a collection of cells and cells can be filled with universe, a tree of universes can be constructed such that the root universe contains the collection of all cells in the model. When a CSGBase
object is first initialized, a root CSGUniverse
called ROOT_UNIVERSE
is created by default. Every CSGCell
that is created will be added to the root universe unless otherwise specified (as described below). The root universe exists by default, and which universe is set as the root cannot be changed, except when joining CSGBase
objects, as described below. However, the name of the root universe can be updated and cells can be manually added or removed using the same methods described above.
Methods available for managing the root universe:
getRootUniverse
: returns a const reference to the root universe of theCSGBase
instancerenameRootUniverse
: change the name of the root universe
Adding or Removing Cells
There are multiple ways in which cells can be added to a universe:
At the time of universe creation, a vector of references to
CSGCell
objects can be passed intocreateUniverse
(as described above). Example:
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
(moose/unit/src/CSGBaseTest.C)When a
CSGCell
is created withcreateCell
, a pointer to aCSGUniverse
can be passed as the final argument to indicate that the cell will be created and added directly to that specified universe. In this case, the cell will not be added to the root universe. A cell that has a universe fill type cannot be added to the same universe that is being used for the fill. For example, the two snippets below come from the same file where a new universe is initialized and passed by reference to the cell when it is created:
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
(moose/unit/src/CSGBaseTest.C) // create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
(moose/unit/src/CSGBaseTest.C)A cell or list of cells can be added to an existing universe with the
addCellToUniverse
andaddCellsToUniverse
methods. In this case, if aCSGCell
exists in anotherCSGUniverse
(such as the root universe), it will not be removed when being added to another (i.e. if the same behavior as option 2 above is desired, the cell will have to be manually removed from the root universe, as described below). The following is an example where the list of cells is collected first and then added at one time to the existing universe, but this could also be accomplished by usingaddCellToUniverse
in a for-loop after each cell is initially created.
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
(moose/unit/src/CSGBaseTest.C)Cells can also be removed from a universe in the same way as method 3 above by using the removeCellFromUniverse
and removeCellsFromUniverse
methods. An example is shown above where the cells are removed from the root universe after they are added to the new universe. Doing this in multiple steps has the same outcome as that of method 2 for adding cells to a universe at the time of cell creation.
When adding and removing cells to/from universes, it is important to maintain the connectivity of all universes meaning all universes should be nested under the root universe at the end of the generation process, in order to have a consistent model.
Updating Existing CSGBase Objects
An empty CSGBase
object can be initialized on its own in each generateCSG
method for each mesh generator. However, in most cases, it is necessary to update an existing CSGBase
object from a previous MeshGenerator
or join multiple CSGBase
together such that only one CSGBase
object is ultimately produced at the end of the mesh/CSG generation process. There are two main ways to handle this: passing and joining.
Passing between Mesh Generators
CSGBase
objects from other mesh generators can be accessed through methods that parallel those available for accessing other MeshGenerator objects. For all methods listed below, a unique pointer to the CSGBase
object(s) created by generateCSG
for the specified MeshGenerator names are returned.
getCSGBase
: get theCSGBase
object given a parameter name represented as astd::string
that stores the mesh generator namegetCSGBases
: get theCSGBase
objects given a parameter name represented as astd::string
that stores a list of mesh generator namesgetCSGBaseByName
: get theCSGBase
object given aMeshGeneratorName
getCSGBasesByName
: get allCSGBase
objects given a list ofMeshGeneratorName
s
For example:
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)A MeshGenerator object(s) can be passed to another mesh generator as input by providing InputParameters
of type MeshGeneratorName
. See the ExampleAxialSurfaceMeshGenerator
implementation below for an example of this.
Joining Bases
When two or more existing CSGBase
objects need to be combined to continue to use and update, the joinOtherBase
method should be used. This method is called from another CSGBase
and at a minimum takes a different existing CSGBase
object as input. There are 3 different behaviors for joining bases that are supported depending on the additional arguments that are passed:
No additional arguments: All cells that are in the root universe of the incoming
CSGBase
object will be added to the existing root universe of the current base object, and the root universe from the incoming base will no longer exist.
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
(moose/unit/src/CSGBaseTest.C)One new root universe name (
new_root_name_join
): All cells in the root universe of the incoming base will be used to create a new universe of the name specified by thenew_root_name_join
parameter. These cells will not be added to the existing root universe, which will remain unchanged. This new universe will be added as a new non-root universe in the existing base object. This newly created universe will not be connected to the root universe of the existingCSGBase
object by default.
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
(moose/unit/src/CSGBaseTest.C)Two new root universe names (
new_root_name_base
andnew_root_name_join
): The cells in the root universe of the currentCSGBase
object will be used to create a new non-root universe of the name specified by thenew_root_name_base
parameter, and the cells in the root universe of the incomingCSGBase
object will be used to create a separate non-root universe of the name specified by thenew_root_name_join
parameter. At the end of this join method, the root universe of the current base object will be empty and neither of the two new non-root universes will be connected to the root universe by default.
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
(moose/unit/src/CSGBaseTest.C)For all of these join methods, any non-root universes will remain unchanged and simply added to the list of universes for the current CSGBase
object. Similarly, all incoming cells and surfaces are added alongside existing cells and surfaces.
It is very important when using the joinOtherBase
method that all CSGSurfaces
, CSGCells
, and CSGSurfaces
are uniquely named so that errors are not encountered when combining sets of objects. An error will be produced during the join process if an object of the same type and name already exists. See recommendations for naming below.
Accessing CSG-related Methods
All CSG methods related to creating or changing a CSG object must be called through CSGBase
. Calls that retrieve information only but do not manipulate an object (such as getName
methods) can be called on the object directly. For example, if a cell were to be created, the current name and region could be retrieved directly from the CSGCell
object, but if the name or region needed to be changed, that would need to be handled through CSGBase
.
This ensures proper accounting of all CSG-related objects in the CSGBase
instance. Consult the Doxygen documentation for information on all object-specific methods.
Object Naming Recommendations
For each new CSG element (CSGSurface
, CSGCell
, and CSGUniverse
) that is created, a unique name identifier (of type std::string
) must be provided (name
parameter for all creation methods). A recommended best practice is to include the mesh generator name (which can be accessed with this->getName()
in any MeshGenerator class) as a part of that object name. This name
is used as the unique identifier within the CSGBase
instance. Methods for renaming objects are available as described in the above sections to help prevent issues and errors.
Example Implementation
Provided here is an example implementation of the generateCSG
method for a simple example MeshGenerator that creates an infinite rectangular prism given an input parameter for side_length
. The code snippets provided here correspond to the .C
file.
InputParameters
ExampleCSGInfiniteSquareMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
params.addRequiredParam<Real>("side_length", "Side length of infinite square.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
ExampleCSGInfiniteSquareMeshGenerator::ExampleCSGInfiniteSquareMeshGenerator(
const InputParameters & params)
: MeshGenerator(params), _side_length(getParam<Real>("side_length"))
{
}
std::unique_ptr<MeshBase>
ExampleCSGInfiniteSquareMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
ExampleCSGInfiniteSquareMeshGenerator::generateCSG()
{
// name of the current mesh generator to use for naming generated objects
auto mg_name = this->name();
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// Add surfaces and halfspaces corresponding to 4 planes of infinite square
std::vector<std::vector<Point>> points_on_planes{{Point(1. * _side_length / 2., 0., 0.),
Point(1. * _side_length / 2., 1., 0.),
Point(1. * _side_length / 2., 0., 1.)},
{Point(-1. * _side_length / 2., 0., 0.),
Point(-1. * _side_length / 2., 1., 0.),
Point(-1. * _side_length / 2., 0., 1.)},
{Point(0., 1. * _side_length / 2., 0.),
Point(1., 1. * _side_length / 2., 0.),
Point(0., 1. * _side_length / 2., 1.)},
{Point(0., -1. * _side_length / 2., 0.),
Point(1., -1. * _side_length / 2., 0.),
Point(0., -1. * _side_length / 2., 1.)}};
std::vector<std::string> surf_names{"plus_x", "minus_x", "plus_y", "minus_y"};
// initialize cell region to be updated
CSG::CSGRegion region;
// set the center of the prism to be used for determining half-spaces
const auto centroid = Point(0, 0, 0);
for (unsigned int i = 0; i < points_on_planes.size(); ++i)
{
// object name includes the mesh generator name for uniqueness
const auto surf_name = mg_name + "_surf_" + surf_names[i];
// create the plane for one face of the prism
std::unique_ptr<CSG::CSGSurface> plane_ptr = std::make_unique<CSG::CSGPlane>(
surf_name, points_on_planes[i][0], points_on_planes[i][1], points_on_planes[i][2]);
auto & csg_plane = csg_obj->addSurface(std::move(plane_ptr));
// determine where the plane is in relation to the centroid to be able to set the half-space
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
// half-space is either positive (+plane_ptr) or negative (-plane_ptr)
// depending on the direction to the centroid
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// check if this is the first half-space to be added to the region,
// if not, update the existing region with the intersection of the regions (&=)
if (region.getRegionType() == CSG::CSGRegion::RegionType::EMPTY)
region = halfspace;
else
region &= halfspace;
}
// create the cell defined by the surfaces and region just created
const auto cell_name = mg_name + "_square_cell";
const auto material_name = "square_material";
csg_obj->createCell(cell_name, material_name, region);
return csg_obj;
}
(moose/test/src/csg/ExampleCSGInfiniteSquareMeshGenerator.C)The following example builds on the infinite prism example above by taking a MeshGeneratorName
for an existing ExampleCSGInfiniteSquareMeshGenerator
as input and adding planes to create a finite rectangular prism.
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
TestCSGAxialSurfaceMeshGenerator::TestCSGAxialSurfaceMeshGenerator(const InputParameters & params)
: MeshGenerator(params),
_mesh_ptr(getMesh("input")),
_axial_height(getParam<Real>("axial_height"))
{
}
std::unique_ptr<MeshBase>
TestCSGAxialSurfaceMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
TestCSGAxialSurfaceMeshGenerator::generateCSG()
{
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
// get the names of the current mesh generator and the input mesh generator
// so that unique object naming can be enforced
auto mg_name = this->name();
auto inp_name = getParam<MeshGeneratorName>("input");
// get the expected existing cell
const auto cell_name = inp_name + "_square_cell";
const auto & csg_cell = csg_obj->getCellByName(cell_name);
// get the existing cell region to update
auto cell_region = csg_cell.getRegion();
// centroid used to determine direction for half-space
const auto centroid = Point(0, 0, 0);
// setting a default surface name purely for testing purposes
const auto default_surf_name = "default_surf";
// Add surfaces and halfspaces corresponding to top and bottom axial planes
std::vector<std::string> surf_names{"plus_z", "minus_z"};
std::vector<Real> coeffs{0.5 * _axial_height, -0.5 * _axial_height};
for (unsigned int i = 0; i < coeffs.size(); ++i)
{
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
// Rename surface so that it has a unique surface name based on the mesh generator
const auto surf_name = mg_name + "_surf_" + surf_names[i];
csg_obj->renameSurface(csg_plane, surf_name);
// determine the half-space to add as an updated intersection
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// update the existing region with a half-space
cell_region &= halfspace;
}
// set the new region for the existing cell
csg_obj->updateCellRegion(csg_cell, cell_region);
// Rename cell as it now defines a box region instead of an infinite square region
csg_obj->renameCell(csg_cell, mg_name + "_box_cell");
return csg_obj;
}
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)If the above methods were to be used, the following input would generate the corresponding JSON output below.
Example Input:
[Mesh<<<{"href": "../../syntax/Mesh/index.html"}>>>]
[inf_square]
type = ExampleCSGInfiniteSquareMeshGenerator
side_length = 4
[]
[cube]
type = TestCSGAxialSurfaceMeshGenerator
input = inf_square
axial_height = 5
[]
[]
(moose/test/tests/csg/csg_only_chained.i)Example Output:
{
"cells": {
"cube_box_cell": {
"fill": "square_material",
"filltype": "CSG_MATERIAL",
"region":
"(+inf_square_surf_plus_x & -inf_square_surf_minus_x & -inf_square_surf_plus_y & +inf_square_surf_minus_y & -cube_surf_plus_z & +cube_surf_minus_z)"
}
},
"surfaces": {
"inf_square_surf_minus_x": {
"coefficients": {
"a": -1.0,
"b": 0.0,
"c": 0.0,
"d": 2.0
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_minus_y": {
"coefficients": {
"a": 0.0,
"b": 1.0,
"c": 0.0,
"d": -2.0
},
"type": "CSG::CSGPlane"
},
"cube_surf_minus_z": {
"coefficients": {
"a": 0.0,
"b": 0.0,
"c": 1.0,
"d": -2.5
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_plus_x": {
"coefficients": {
"a": -1.0,
"b": 0.0,
"c": 0.0,
"d": -2.0
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_plus_y": {
"coefficients": {
"a": 0.0,
"b": 1.0,
"c": 0.0,
"d": 2.0
},
"type": "CSG::CSGPlane"
},
"cube_surf_plus_z": {
"coefficients": {
"a": 0.0,
"b": 0.0,
"c": 1.0,
"d": 2.5
},
"type": "CSG::CSGPlane"
}
},
"universes": {
"ROOT_UNIVERSE": {
"cells": [
"cube_box_cell"
],
"root": true
}
}
}
(moose/test/tests/csg/gold/csg_only_chained_out_csg.json)To run the above example, use --allow-test-objects
:
./moose_test-opt --allow-test-objects --csg-only -i tests/csg/csg_only_chained.i
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "TestCSGAxialSurfaceMeshGenerator.h"
#include "MeshGenerator.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", TestCSGAxialSurfaceMeshGenerator);
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
TestCSGAxialSurfaceMeshGenerator::TestCSGAxialSurfaceMeshGenerator(const InputParameters & params)
: MeshGenerator(params),
_mesh_ptr(getMesh("input")),
_axial_height(getParam<Real>("axial_height"))
{
}
std::unique_ptr<MeshBase>
TestCSGAxialSurfaceMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
TestCSGAxialSurfaceMeshGenerator::generateCSG()
{
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
// get the names of the current mesh generator and the input mesh generator
// so that unique object naming can be enforced
auto mg_name = this->name();
auto inp_name = getParam<MeshGeneratorName>("input");
// get the expected existing cell
const auto cell_name = inp_name + "_square_cell";
const auto & csg_cell = csg_obj->getCellByName(cell_name);
// get the existing cell region to update
auto cell_region = csg_cell.getRegion();
// centroid used to determine direction for half-space
const auto centroid = Point(0, 0, 0);
// setting a default surface name purely for testing purposes
const auto default_surf_name = "default_surf";
// Add surfaces and halfspaces corresponding to top and bottom axial planes
std::vector<std::string> surf_names{"plus_z", "minus_z"};
std::vector<Real> coeffs{0.5 * _axial_height, -0.5 * _axial_height};
for (unsigned int i = 0; i < coeffs.size(); ++i)
{
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
// Rename surface so that it has a unique surface name based on the mesh generator
const auto surf_name = mg_name + "_surf_" + surf_names[i];
csg_obj->renameSurface(csg_plane, surf_name);
// determine the half-space to add as an updated intersection
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// update the existing region with a half-space
cell_region &= halfspace;
}
// set the new region for the existing cell
csg_obj->updateCellRegion(csg_cell, cell_region);
// Rename cell as it now defines a box region instead of an infinite square region
csg_obj->renameCell(csg_cell, mg_name + "_box_cell");
return csg_obj;
}
(moose/test/src/csg/ExampleCSGInfiniteSquareMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "ExampleCSGInfiniteSquareMeshGenerator.h"
#include "CSGBase.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", ExampleCSGInfiniteSquareMeshGenerator);
InputParameters
ExampleCSGInfiniteSquareMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
params.addRequiredParam<Real>("side_length", "Side length of infinite square.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
ExampleCSGInfiniteSquareMeshGenerator::ExampleCSGInfiniteSquareMeshGenerator(
const InputParameters & params)
: MeshGenerator(params), _side_length(getParam<Real>("side_length"))
{
}
std::unique_ptr<MeshBase>
ExampleCSGInfiniteSquareMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
ExampleCSGInfiniteSquareMeshGenerator::generateCSG()
{
// name of the current mesh generator to use for naming generated objects
auto mg_name = this->name();
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// Add surfaces and halfspaces corresponding to 4 planes of infinite square
std::vector<std::vector<Point>> points_on_planes{{Point(1. * _side_length / 2., 0., 0.),
Point(1. * _side_length / 2., 1., 0.),
Point(1. * _side_length / 2., 0., 1.)},
{Point(-1. * _side_length / 2., 0., 0.),
Point(-1. * _side_length / 2., 1., 0.),
Point(-1. * _side_length / 2., 0., 1.)},
{Point(0., 1. * _side_length / 2., 0.),
Point(1., 1. * _side_length / 2., 0.),
Point(0., 1. * _side_length / 2., 1.)},
{Point(0., -1. * _side_length / 2., 0.),
Point(1., -1. * _side_length / 2., 0.),
Point(0., -1. * _side_length / 2., 1.)}};
std::vector<std::string> surf_names{"plus_x", "minus_x", "plus_y", "minus_y"};
// initialize cell region to be updated
CSG::CSGRegion region;
// set the center of the prism to be used for determining half-spaces
const auto centroid = Point(0, 0, 0);
for (unsigned int i = 0; i < points_on_planes.size(); ++i)
{
// object name includes the mesh generator name for uniqueness
const auto surf_name = mg_name + "_surf_" + surf_names[i];
// create the plane for one face of the prism
std::unique_ptr<CSG::CSGSurface> plane_ptr = std::make_unique<CSG::CSGPlane>(
surf_name, points_on_planes[i][0], points_on_planes[i][1], points_on_planes[i][2]);
auto & csg_plane = csg_obj->addSurface(std::move(plane_ptr));
// determine where the plane is in relation to the centroid to be able to set the half-space
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
// half-space is either positive (+plane_ptr) or negative (-plane_ptr)
// depending on the direction to the centroid
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// check if this is the first half-space to be added to the region,
// if not, update the existing region with the intersection of the regions (&=)
if (region.getRegionType() == CSG::CSGRegion::RegionType::EMPTY)
region = halfspace;
else
region &= halfspace;
}
// create the cell defined by the surfaces and region just created
const auto cell_name = mg_name + "_square_cell";
const auto material_name = "square_material";
csg_obj->createCell(cell_name, material_name, region);
return csg_obj;
}
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "TestCSGAxialSurfaceMeshGenerator.h"
#include "MeshGenerator.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", TestCSGAxialSurfaceMeshGenerator);
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
TestCSGAxialSurfaceMeshGenerator::TestCSGAxialSurfaceMeshGenerator(const InputParameters & params)
: MeshGenerator(params),
_mesh_ptr(getMesh("input")),
_axial_height(getParam<Real>("axial_height"))
{
}
std::unique_ptr<MeshBase>
TestCSGAxialSurfaceMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
TestCSGAxialSurfaceMeshGenerator::generateCSG()
{
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
// get the names of the current mesh generator and the input mesh generator
// so that unique object naming can be enforced
auto mg_name = this->name();
auto inp_name = getParam<MeshGeneratorName>("input");
// get the expected existing cell
const auto cell_name = inp_name + "_square_cell";
const auto & csg_cell = csg_obj->getCellByName(cell_name);
// get the existing cell region to update
auto cell_region = csg_cell.getRegion();
// centroid used to determine direction for half-space
const auto centroid = Point(0, 0, 0);
// setting a default surface name purely for testing purposes
const auto default_surf_name = "default_surf";
// Add surfaces and halfspaces corresponding to top and bottom axial planes
std::vector<std::string> surf_names{"plus_z", "minus_z"};
std::vector<Real> coeffs{0.5 * _axial_height, -0.5 * _axial_height};
for (unsigned int i = 0; i < coeffs.size(); ++i)
{
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
// Rename surface so that it has a unique surface name based on the mesh generator
const auto surf_name = mg_name + "_surf_" + surf_names[i];
csg_obj->renameSurface(csg_plane, surf_name);
// determine the half-space to add as an updated intersection
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// update the existing region with a half-space
cell_region &= halfspace;
}
// set the new region for the existing cell
csg_obj->updateCellRegion(csg_cell, cell_region);
// Rename cell as it now defines a box region instead of an infinite square region
csg_obj->renameCell(csg_cell, mg_name + "_box_cell");
return csg_obj;
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "TestCSGAxialSurfaceMeshGenerator.h"
#include "MeshGenerator.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", TestCSGAxialSurfaceMeshGenerator);
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
TestCSGAxialSurfaceMeshGenerator::TestCSGAxialSurfaceMeshGenerator(const InputParameters & params)
: MeshGenerator(params),
_mesh_ptr(getMesh("input")),
_axial_height(getParam<Real>("axial_height"))
{
}
std::unique_ptr<MeshBase>
TestCSGAxialSurfaceMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
TestCSGAxialSurfaceMeshGenerator::generateCSG()
{
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
// get the names of the current mesh generator and the input mesh generator
// so that unique object naming can be enforced
auto mg_name = this->name();
auto inp_name = getParam<MeshGeneratorName>("input");
// get the expected existing cell
const auto cell_name = inp_name + "_square_cell";
const auto & csg_cell = csg_obj->getCellByName(cell_name);
// get the existing cell region to update
auto cell_region = csg_cell.getRegion();
// centroid used to determine direction for half-space
const auto centroid = Point(0, 0, 0);
// setting a default surface name purely for testing purposes
const auto default_surf_name = "default_surf";
// Add surfaces and halfspaces corresponding to top and bottom axial planes
std::vector<std::string> surf_names{"plus_z", "minus_z"};
std::vector<Real> coeffs{0.5 * _axial_height, -0.5 * _axial_height};
for (unsigned int i = 0; i < coeffs.size(); ++i)
{
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
// Rename surface so that it has a unique surface name based on the mesh generator
const auto surf_name = mg_name + "_surf_" + surf_names[i];
csg_obj->renameSurface(csg_plane, surf_name);
// determine the half-space to add as an updated intersection
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// update the existing region with a half-space
cell_region &= halfspace;
}
// set the new region for the existing cell
csg_obj->updateCellRegion(csg_cell, cell_region);
// Rename cell as it now defines a box region instead of an infinite square region
csg_obj->renameCell(csg_cell, mg_name + "_box_cell");
return csg_obj;
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/unit/src/CSGBaseTest.C)
// This file is part of the MOOSE framework
// https://mooseframework.inl.gov
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "gtest/gtest.h"
#include "CSGBase.h"
#include "CSGSphere.h"
#include "MooseUnitUtils.h"
namespace CSG
{
/**
* Tests associated with CSGSurfaceList functionality as called through CSGBase
*/
/// tests CSG[Base/SurfaceList]::addSurface() and CSG[Base/SurfaceList]::getSurfaceByName()
TEST(CSGBaseTest, testAddGetSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces that have the same name
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf", 2.0);
// add one surface to base initially
const auto & added_surf = csg_obj->addSurface(std::move(surf_ptr1));
// assert surface is present after adding by successfully using getSurfaceByName
{
// public method, returns const
ASSERT_TRUE(added_surf == csg_obj->getSurfaceByName("surf"));
// private method, returns non-const
ASSERT_TRUE(added_surf == csg_obj->getSurface("surf"));
}
// try to add surface that already exists of the same name, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj, &surf_ptr2]()
{ csg_obj->addSurface(std::move(surf_ptr2)); },
"Surface with name surf already exists in geometry.");
}
// try to get surface that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getSurfaceByName("fake_name"); },
"No surface by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/SurfaceList]::getAllSurfaces
TEST(CSGBaseTest, testGetAllSurfaces)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
csg_obj->addSurface(std::move(surf_ptr1));
csg_obj->addSurface(std::move(surf_ptr2));
auto all_surfs = csg_obj->getAllSurfaces();
ASSERT_EQ(2, all_surfs.size());
}
/// tests CSG[Base/SurfaceList]::renameSurface
TEST(CSGBaseTest, testRenameSurface)
{
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// make two surfaces to add to base
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("surf2", 2.0);
const auto & s1 = csg_obj->addSurface(std::move(surf_ptr1));
const auto & s2 = csg_obj->addSurface(std::move(surf_ptr2));
// successfully rename surface
{
csg_obj->renameSurface(s1, "george");
ASSERT_EQ("george", s1.getName());
}
// error should be raised if try to rename to a name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj, &s2]() { csg_obj->renameSurface(s2, "george"); },
"Surface with name george already exists in geometry");
}
// error should be raised if trying to rename a surface that is not a part of this instance
{
// initialize a new CSGBase object
auto csg_obj_new = std::make_unique<CSG::CSGBase>();
// make new surface to add to new base
std::unique_ptr<CSG::CSGSphere> surf_ptr3 = std::make_unique<CSG::CSGSphere>("surf3", 1.0);
const auto & s3 = csg_obj_new->addSurface(std::move(surf_ptr3));
// try to rename s3 via original base where it was not added
Moose::UnitUtils::assertThrows([&csg_obj, &s3]() { csg_obj->renameSurface(s3, "ringo"); },
"cannot be renamed to ringo as it does not exist");
}
}
/// tests CSGBase::checkRegionSurfaces
TEST(CSGBaseTest, testCheckRegionSurfaces)
{
// make two sets of surfaces that are identical but different base ownership
// create a region from surfaces in base 1 and make sure that base 2 recognizes the surfaces as
// not available in that base even though names exist
auto csg_obj1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
const auto & s1 = csg_obj1->addSurface(std::move(surf1));
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf", 1.0);
csg_obj2->addSurface(std::move(surf2));
auto reg1 = +s1; // uses surfaces from base 1
// expect error when surfaces are checked in base2
Moose::UnitUtils::assertThrows([&csg_obj2, ®1]() { csg_obj2->checkRegionSurfaces(reg1); },
"Region is being set with a surface named surf that is different "
"from the surface of the same name in the CSGBase instance.");
}
/**
* Tests associated with CSGCellList or CSGCell functionality as called through CSGBase
*/
/// tests CSG[Base/CellList]::createCell
TEST(CSGBaseTest, testCreateCell)
{
// create each type of cell, each w/ or w/out add_to_univ specified to test universe ownership
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// surfaces for regions for cell
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto reg1 = +s1;
// make a new universe to which the new cells can be added at time of creation
auto & add_to_univ = csg_obj->createUniverse("add_univ");
// root universe to check in tests
auto & root_univ = csg_obj->getRootUniverse();
// make void cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "void_cell1";
// create a void cell with name cname1 and defined by region reg1
csg_obj->createCell(cname1, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "void_cell2";
csg_obj->createCell(cname2, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make material cells and check universe ownership
{
// create cell to be auto added to root universe
std::string cname1 = "mat_cell1";
// create a material-filled cell with name cname1, a fill with material matname,
// and defined by region reg1
csg_obj->createCell(cname1, "matname", reg1);
// create a cell and add to different universe, not root
std::string cname2 = "mat_cell2";
csg_obj->createCell(cname2, "matname", reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// make universe cells and check universe ownership
{
auto new_univ = csg_obj->createUniverse("new_univ");
// create cell to be auto added to root universe
std::string cname1 = "univ_cell1";
// create a universe-filled cell with name cname1, a fill of universe new_univ,
// and defined by region reg1
csg_obj->createCell(cname1, new_univ, reg1);
// create a cell and add to different universe, not root
std::string cname2 = "univ_cell2";
csg_obj->createCell(cname2, new_univ, reg1, &add_to_univ);
// cname1 should exist in root but not the other universe
ASSERT_TRUE(root_univ.hasCell(cname1));
ASSERT_FALSE(add_to_univ.hasCell(cname1));
// cname2 should exist in add_to_univ but not root
ASSERT_TRUE(add_to_univ.hasCell(cname2));
ASSERT_FALSE(root_univ.hasCell(cname2));
}
// expected error: create a universe cell and add it to the same universe
{
Moose::UnitUtils::assertThrows(
[&csg_obj, &add_to_univ, ®1]()
{ csg_obj->createCell("c", add_to_univ, reg1, &add_to_univ); },
"cannot be filled with the same universe to which it is being added");
}
// expect error: create a cell with existing name
{
Moose::UnitUtils::assertThrows([&csg_obj, ®1]() { csg_obj->createCell("void_cell1", reg1); },
"Cell with name void_cell1 already exists");
}
}
/// tests CSG[Base/CellList]::getAllCells
TEST(CSGBaseTest, testGetAllCells)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", +s1);
csg_obj->createCell("c2", -s1);
// expect the 2 cells to be present
auto all_cells = csg_obj->getAllCells();
ASSERT_EQ(2, all_cells.size());
}
/// tests CSGBase::getCellByName / CSGCellList::getCell
TEST(CSGBaseTest, testGetCellByName)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto c1 = csg_obj->createCell("c1", +s1);
// get cell that exists
{
auto c1_get = csg_obj->getCellByName("c1");
ASSERT_EQ(c1, c1_get);
}
// try to get cell that doesn't exist in base, should raise error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getCellByName("fake_name"); },
"No cell by name fake_name exists in the geometry.");
}
}
/// tests CSG[Base/CellList]::renameCell
TEST(CSGBaseTest, testRenameCell)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// rename success
{
csg_obj->renameCell(c1, "paul");
ASSERT_EQ("paul", c1.getName());
}
// rename cell to existing name
{
// make a second cell
auto & c2 = csg_obj->createCell("c2", -s1);
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "paul"); },
"Cell with name paul already exists");
}
// rename cell that does not exist in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
// try to rename from the first base
Moose::UnitUtils::assertThrows([&csg_obj, &c2]() { csg_obj->renameCell(c2, "john"); },
"cannot be renamed to john as it does not exist");
}
}
/// tests CSGBase::updateCellRegion
TEST(CSGBaseTest, testUpdateCellRegion)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
// successfully update cell region to new region
{
csg_obj->updateCellRegion(c1, -s1);
ASSERT_EQ(-s1, c1.getRegion());
}
// try to update cell not in this base
{
// make an identical cell in a different base
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c2 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &c2, &s1]() { csg_obj->updateCellRegion(c2, -s1); },
"is being updated that is different from the cell of the same "
"name in the CSGBase instance.");
}
}
/**
* Tests associated with CSGUniverseList and CSGUniverse functionality as called through CSGBase
*/
/// tests CSGBase::createUniverse
TEST(CSGBaseTest, testCreateUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
// create empty universe
{
auto & univ = csg_obj->createUniverse("thelma");
ASSERT_NO_THROW(csg_obj->getUniverseByName("thelma")); // no throw confirms existence
ASSERT_EQ(0, univ.getAllCells().size()); // confirms empty
}
// create universe from cells
{
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
// create a list of cells to be added to the universe
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
auto & univ = csg_obj->createUniverse("louise", cells);
ASSERT_NO_THROW(csg_obj->getUniverseByName("louise")); // no throw confirms existence
ASSERT_EQ(2, univ.getAllCells().size()); // confirms has cells
}
// create universe for name that already exists
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->createUniverse("louise"); },
"Universe with name louise already exists in geometry.");
}
}
/// tests CSG[Base/UniverseList]::renameUniverse and CSGBase::renameRootUniverse
TEST(CSGBaseTest, renameUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & root = csg_obj->getRootUniverse();
std::string new_name_1 = "simon";
std::string new_name_2 = "alvin";
std::string new_name_3 = "theo";
// rename root through root-specific function
{
csg_obj->renameRootUniverse(new_name_1);
ASSERT_EQ(new_name_1, root.getName());
}
// rename root by passing to method explicitly
{
csg_obj->renameUniverse(root, new_name_2);
ASSERT_EQ(new_name_2, root.getName());
}
// rename a different universe to name that already exists, should raise error
{
auto & univ = csg_obj->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_2]()
{ csg_obj->renameUniverse(univ, new_name_2); },
"Universe with name " + new_name_2 + " already exists");
}
// rename a universe that doesn't exist in the current base
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj2->createUniverse("new_univ");
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &new_name_3]()
{ csg_obj->renameUniverse(univ, new_name_3); },
"cannot be renamed to " + new_name_3 + " as it does not exist");
}
}
/// tests CSGBase::addCell[s]ToUniverse
TEST(CSGBaseTest, testAddCellToUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
auto & univ = csg_obj->createUniverse("univ");
// add a list of cells to an existing universe
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2};
csg_obj->addCellsToUniverse(univ, cells);
ASSERT_EQ(2, univ.getAllCells().size());
}
// add individual cell
{
csg_obj->addCellToUniverse(univ, c3);
ASSERT_EQ(3, univ.getAllCells().size());
}
// add cell that is not in current base but has the same name and attributes, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->addCellToUniverse(univ, c4); },
"is being added to universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// add cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->addCellToUniverse(univ_new, c1); },
"Cells are being added to a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::removeCell[s]FromUniverse
TEST(CSGBaseTest, testRemoveCellFromUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
auto & c1 = csg_obj->createCell("c1", +s1);
auto & c2 = csg_obj->createCell("c2", -s1);
auto & c3 = csg_obj->createCell("c3", -s1 | +s1);
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells = {c1, c2, c3};
auto & univ = csg_obj->createUniverse("univ", cells);
// remove inidividual cell
{
csg_obj->removeCellFromUniverse(univ, c1);
ASSERT_EQ(2, univ.getAllCells().size());
}
// remove list of cells
{
std::vector<std::reference_wrapper<const CSG::CSGCell>> cells_remove = {c2, c3};
csg_obj->removeCellsFromUniverse(univ, cells_remove);
ASSERT_EQ(0, univ.getAllCells().size());
}
// remove cell that is not in current base but has the same name and attributes, should raise
// error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf2 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s2 = csg_obj2->addSurface(std::move(surf2));
auto & c4 = csg_obj2->createCell("c1", +s2);
Moose::UnitUtils::assertThrows([&csg_obj, &univ, &c4]()
{ csg_obj->removeCellFromUniverse(univ, c4); },
"is being removed from universe univ that is different from the "
"cell of the same name in the CSGBase instance.");
}
// remove cell that is in the base a universe that is not in the base, should raise error
{
auto csg_obj2 = std::make_unique<CSG::CSGBase>();
auto & univ_new = csg_obj2->createUniverse("univ");
Moose::UnitUtils::assertThrows(
[&csg_obj, &univ_new, &c1]() { csg_obj->removeCellFromUniverse(univ_new, c1); },
"Cells are being removed from a universe named univ that is different "
"from the universe of the same name in the CSGBase instance.");
}
}
/// tests CSGBase::get*Universe* methods
TEST(CSGBaseTest, testGetUniverse)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ = csg_obj->createUniverse("harry");
// get root
{
auto & root = csg_obj->getRootUniverse();
ASSERT_TRUE(root.isRoot());
}
// successful getUniverseByName call
{
auto & univ_get = csg_obj->getUniverseByName("harry");
ASSERT_EQ(univ, univ_get);
}
// get universe for name that does not exist, expect error
{
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->getUniverseByName("potter"); },
"No universe by name potter exists in the geometry.");
}
// getAllUniverses
{
// two universes expected: ROOT_UNIVERSE and harry
auto all_univs = csg_obj->getAllUniverses();
ASSERT_EQ(2, all_univs.size());
}
}
/**
* CSGBase::joinOtherBase methods
*/
/// test CSGBase::joinOtherBase no passed name
TEST(CSGBaseTest, joinOtherBaseJoinRoot)
{
// Case 1: Create two CSGBase objects to join together into a single root
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: two universes will remain
// base1 ROOT_UNIVERSE will gain all cells from base2 ROOT_UNIVERSE
// base2 ROOT_UNIVERSE will not exist as a separate universe
// the "extra_univ" in base2 will remain a separate universe
base1->joinOtherBase(std::move(base2));
// expect 2 universes: root and extra
// 3 cells: 2 owned by root, 1 owned by extra
ASSERT_EQ(2, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
ASSERT_EQ(2, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
ASSERT_TRUE(root.hasCell(c2.getName()));
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase one passed name
TEST(CSGBaseTest, joinOtherBaseOneNewRoot)
{
// Case 2: Create two CSGBase objects to join together but keep incoming root separate
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: three universes will remain
// base1 ROOT_UNIVERSE will remain untouched
// all cells from ROOT_UNIVERSE in base2 create new universe called "new_univ"
// the "extra_univ" in base2 will remain a separate universe
std::string new_root_name = "new_univ";
base1->joinOtherBase(std::move(base2), new_root_name);
// expect 3 universes: root, extra, and new
// 3 cells: 1 owned by root, 1 owned by new, 1 owned by extra
ASSERT_EQ(3, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have c1 from original root
ASSERT_EQ(1, root.getAllCells().size());
ASSERT_TRUE(root.hasCell(c1.getName()));
// new_univ should have c2 from root of base 2
auto new_univ = base1->getUniverseByName(new_root_name);
ASSERT_EQ(1, new_univ.getAllCells().size());
ASSERT_TRUE(new_univ.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_EQ(1, new_extra.getAllCells().size());
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::joinOtherBase two passed names
TEST(CSGBaseTest, joinOtherBaseTwoNewRoot)
{
// Case 3: Create two CSGBase objects to join together with each root becoming a new universe
// CSGBase 1: only one cell, which lives in the ROOT_UNIVERSE
std::unique_ptr<CSGBase> base1 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr1 = std::make_unique<CSG::CSGSphere>("s1", 1.0);
const auto & surf1 = base1->addSurface(std::move(surf_ptr1));
auto & c1 = base1->createCell("c1", +surf1);
// CSGBase 2: two total unverses (ROOT_UNIVERSE and extra_univ) with a cell in each
std::unique_ptr<CSGBase> base2 = std::make_unique<CSG::CSGBase>();
std::unique_ptr<CSG::CSGSphere> surf_ptr2 = std::make_unique<CSG::CSGSphere>("s2", 1.0);
const auto & surf2 = base2->addSurface(std::move(surf_ptr2));
auto & c2 = base2->createCell("c2", +surf2);
auto & extra_univ = base2->createUniverse("extra_univ");
auto & c3 = base2->createCell("c3", -surf2, &extra_univ);
// Joining: four universes will remain
// all cells from base1 ROOT_UNIVERSE will be moved to a new universe called "new_univ1"
// all cells from base2 ROOT_UNIVERSE will be moved to a new universe called "new_univ2"
// base1 ROOT_UNIVERSE will be empty
// the "extra_univ" in base2 will remain a separate universe
std::string new_name1 = "new_univ1";
std::string new_name2 = "new_univ2";
base1->joinOtherBase(std::move(base2), new_name1, new_name2);
// expect 4 universes: root, extra, new1 and new2
// 3 cells: 0 owned by root, 1 owned by new1, 1 owned by new2, 1 owned by extra
ASSERT_EQ(4, base1->getAllUniverses().size());
auto & root = base1->getRootUniverse();
ASSERT_EQ(3, base1->getAllCells().size());
// root should have 0 cells since all were moved
ASSERT_EQ(0, root.getAllCells().size());
// new_univ1 should have c1 from original root of base 1
auto new_univ1 = base1->getUniverseByName(new_name1);
ASSERT_TRUE(new_univ1.hasCell(c1.getName()));
// new_univ2 should have c2 from original root of base 2
auto new_univ2 = base1->getUniverseByName(new_name2);
ASSERT_TRUE(new_univ2.hasCell(c2.getName()));
// original existing extra universe should still only have c3
auto & new_extra = base1->getUniverseByName("extra_univ");
ASSERT_TRUE(new_extra.hasCell(c3.getName()));
ASSERT_EQ(1, new_extra.getAllCells().size());
// expect 2 surfaces
ASSERT_EQ(2, base1->getAllSurfaces().size());
}
/// test CSGBase::checkUniverseLinking / getLinkedUniverses
TEST(CSGBaseTest, testUniverseLinking)
{
auto csg_obj = std::make_unique<CSG::CSGBase>();
auto & univ1 = csg_obj->createUniverse("univ1");
// new universe is not inherently linked to ROOT_UNIVERSE, should raise warning when checked
Moose::UnitUtils::assertThrows([&csg_obj]() { csg_obj->checkUniverseLinking(); },
"Universe with name univ1 is not linked to root universe.");
// link the universe by adding it to a cell that is created in root
std::unique_ptr<CSG::CSGSphere> surf1 = std::make_unique<CSG::CSGSphere>("surf1", 1.0);
const auto & s1 = csg_obj->addSurface(std::move(surf1));
csg_obj->createCell("c1", univ1, +s1);
// no warning should be raised because it is a part of c1, which is a part of root
// linking tree: ROOT_UNIVERSE -> c1 -> univ1
ASSERT_NO_THROW(csg_obj->checkUniverseLinking());
}
}
(moose/test/src/csg/ExampleCSGInfiniteSquareMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "ExampleCSGInfiniteSquareMeshGenerator.h"
#include "CSGBase.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", ExampleCSGInfiniteSquareMeshGenerator);
InputParameters
ExampleCSGInfiniteSquareMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
params.addRequiredParam<Real>("side_length", "Side length of infinite square.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
ExampleCSGInfiniteSquareMeshGenerator::ExampleCSGInfiniteSquareMeshGenerator(
const InputParameters & params)
: MeshGenerator(params), _side_length(getParam<Real>("side_length"))
{
}
std::unique_ptr<MeshBase>
ExampleCSGInfiniteSquareMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
ExampleCSGInfiniteSquareMeshGenerator::generateCSG()
{
// name of the current mesh generator to use for naming generated objects
auto mg_name = this->name();
// initialize a CSGBase object
auto csg_obj = std::make_unique<CSG::CSGBase>();
// Add surfaces and halfspaces corresponding to 4 planes of infinite square
std::vector<std::vector<Point>> points_on_planes{{Point(1. * _side_length / 2., 0., 0.),
Point(1. * _side_length / 2., 1., 0.),
Point(1. * _side_length / 2., 0., 1.)},
{Point(-1. * _side_length / 2., 0., 0.),
Point(-1. * _side_length / 2., 1., 0.),
Point(-1. * _side_length / 2., 0., 1.)},
{Point(0., 1. * _side_length / 2., 0.),
Point(1., 1. * _side_length / 2., 0.),
Point(0., 1. * _side_length / 2., 1.)},
{Point(0., -1. * _side_length / 2., 0.),
Point(1., -1. * _side_length / 2., 0.),
Point(0., -1. * _side_length / 2., 1.)}};
std::vector<std::string> surf_names{"plus_x", "minus_x", "plus_y", "minus_y"};
// initialize cell region to be updated
CSG::CSGRegion region;
// set the center of the prism to be used for determining half-spaces
const auto centroid = Point(0, 0, 0);
for (unsigned int i = 0; i < points_on_planes.size(); ++i)
{
// object name includes the mesh generator name for uniqueness
const auto surf_name = mg_name + "_surf_" + surf_names[i];
// create the plane for one face of the prism
std::unique_ptr<CSG::CSGSurface> plane_ptr = std::make_unique<CSG::CSGPlane>(
surf_name, points_on_planes[i][0], points_on_planes[i][1], points_on_planes[i][2]);
auto & csg_plane = csg_obj->addSurface(std::move(plane_ptr));
// determine where the plane is in relation to the centroid to be able to set the half-space
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
// half-space is either positive (+plane_ptr) or negative (-plane_ptr)
// depending on the direction to the centroid
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// check if this is the first half-space to be added to the region,
// if not, update the existing region with the intersection of the regions (&=)
if (region.getRegionType() == CSG::CSGRegion::RegionType::EMPTY)
region = halfspace;
else
region &= halfspace;
}
// create the cell defined by the surfaces and region just created
const auto cell_name = mg_name + "_square_cell";
const auto material_name = "square_material";
csg_obj->createCell(cell_name, material_name, region);
return csg_obj;
}
(moose/test/src/csg/TestCSGAxialSurfaceMeshGenerator.C)
// This file is part of the MOOSE framework
// https://www.mooseframework.org
//
// All rights reserved, see COPYRIGHT for full restrictions
// https://github.com/idaholab/moose/blob/master/COPYRIGHT
//
// Licensed under LGPL 2.1, please see LICENSE for details
// https://www.gnu.org/licenses/lgpl-2.1.html
#include "TestCSGAxialSurfaceMeshGenerator.h"
#include "MeshGenerator.h"
#include "CSGPlane.h"
registerMooseObject("MooseTestApp", TestCSGAxialSurfaceMeshGenerator);
InputParameters
TestCSGAxialSurfaceMeshGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
// input parameter that is an existing mesh generator
params.addRequiredParam<MeshGeneratorName>("input", "The input MeshGenerator.");
// additional params for this specific mesh generator
params.addRequiredParam<Real>("axial_height", "Axial height of the model.");
// Declare that this generator has a generateCSG method
MeshGenerator::setHasGenerateCSG(params);
return params;
}
TestCSGAxialSurfaceMeshGenerator::TestCSGAxialSurfaceMeshGenerator(const InputParameters & params)
: MeshGenerator(params),
_mesh_ptr(getMesh("input")),
_axial_height(getParam<Real>("axial_height"))
{
}
std::unique_ptr<MeshBase>
TestCSGAxialSurfaceMeshGenerator::generate()
{
auto null_mesh = nullptr;
return null_mesh;
}
std::unique_ptr<CSG::CSGBase>
TestCSGAxialSurfaceMeshGenerator::generateCSG()
{
// get the existing CSGBase associated with the input mesh generator
// this is the CSGBase object that will be updated
std::unique_ptr<CSG::CSGBase> csg_obj = std::move(getCSGBase("input"));
// get the names of the current mesh generator and the input mesh generator
// so that unique object naming can be enforced
auto mg_name = this->name();
auto inp_name = getParam<MeshGeneratorName>("input");
// get the expected existing cell
const auto cell_name = inp_name + "_square_cell";
const auto & csg_cell = csg_obj->getCellByName(cell_name);
// get the existing cell region to update
auto cell_region = csg_cell.getRegion();
// centroid used to determine direction for half-space
const auto centroid = Point(0, 0, 0);
// setting a default surface name purely for testing purposes
const auto default_surf_name = "default_surf";
// Add surfaces and halfspaces corresponding to top and bottom axial planes
std::vector<std::string> surf_names{"plus_z", "minus_z"};
std::vector<Real> coeffs{0.5 * _axial_height, -0.5 * _axial_height};
for (unsigned int i = 0; i < coeffs.size(); ++i)
{
// create a plane using the coefficients for the equation of a plane
// z plane equation: 0.0*x + 0.0*y + 1.0*z = (+/-)0.5 * axial_height
std::unique_ptr<CSG::CSGSurface> surface_ptr =
std::make_unique<CSG::CSGPlane>(default_surf_name, 0.0, 0.0, 1.0, coeffs[i]);
auto & csg_plane = csg_obj->addSurface(std::move(surface_ptr));
// Rename surface so that it has a unique surface name based on the mesh generator
const auto surf_name = mg_name + "_surf_" + surf_names[i];
csg_obj->renameSurface(csg_plane, surf_name);
// determine the half-space to add as an updated intersection
const auto region_direction = csg_plane.getHalfspaceFromPoint(centroid);
auto halfspace =
((region_direction == CSG::CSGSurface::Halfspace::POSITIVE) ? +csg_plane : -csg_plane);
// update the existing region with a half-space
cell_region &= halfspace;
}
// set the new region for the existing cell
csg_obj->updateCellRegion(csg_cell, cell_region);
// Rename cell as it now defines a box region instead of an infinite square region
csg_obj->renameCell(csg_cell, mg_name + "_box_cell");
return csg_obj;
}
(moose/test/tests/csg/csg_only_chained.i)
[Mesh]
[inf_square]
type = ExampleCSGInfiniteSquareMeshGenerator
side_length = 4
[]
[cube]
type = TestCSGAxialSurfaceMeshGenerator
input = inf_square
axial_height = 5
[]
[]
(moose/test/tests/csg/gold/csg_only_chained_out_csg.json)
{
"cells": {
"cube_box_cell": {
"fill": "square_material",
"filltype": "CSG_MATERIAL",
"region":
"(+inf_square_surf_plus_x & -inf_square_surf_minus_x & -inf_square_surf_plus_y & +inf_square_surf_minus_y & -cube_surf_plus_z & +cube_surf_minus_z)"
}
},
"surfaces": {
"inf_square_surf_minus_x": {
"coefficients": {
"a": -1.0,
"b": 0.0,
"c": 0.0,
"d": 2.0
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_minus_y": {
"coefficients": {
"a": 0.0,
"b": 1.0,
"c": 0.0,
"d": -2.0
},
"type": "CSG::CSGPlane"
},
"cube_surf_minus_z": {
"coefficients": {
"a": 0.0,
"b": 0.0,
"c": 1.0,
"d": -2.5
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_plus_x": {
"coefficients": {
"a": -1.0,
"b": 0.0,
"c": 0.0,
"d": -2.0
},
"type": "CSG::CSGPlane"
},
"inf_square_surf_plus_y": {
"coefficients": {
"a": 0.0,
"b": 1.0,
"c": 0.0,
"d": 2.0
},
"type": "CSG::CSGPlane"
},
"cube_surf_plus_z": {
"coefficients": {
"a": 0.0,
"b": 0.0,
"c": 1.0,
"d": 2.5
},
"type": "CSG::CSGPlane"
}
},
"universes": {
"ROOT_UNIVERSE": {
"cells": [
"cube_box_cell"
],
"root": true
}
}
}