Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RGMB option to enable flexible assembly stitching #28231

Merged
merged 9 commits into from
Aug 4, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ The `CoreMeshGenerator` objects automatically assigns boundary information. The

If the core is extruded to three dimensions the top-most boundary ID must be assigned using [!param](/Mesh/ReactorMeshParams/top_boundary_id) and will have the name "top", while the bottom-most boundary must be assigned using [!param](/Mesh/ReactorMeshParams/bottom_boundary_id) and will have the name "bottom".

## Flexible Assembly Stitching

By default, `CoreMeshGenerator` will stitch assemblies created by [`AssemblyMeshGenerator`](AssemblyMeshGenerator.md) together without regard for the number and location of nodes at the exterior boundaries of the assemblies. This works if very similar assemblies are being stitched together. However, this will lead to an output core mesh with hanging nodes if dissimilar assemblies are being stitched together. The following situations are identified as scenarios where such hanging nodes can occur between stitched assemblies:

1. Two assemblies have the same constituent pin geometry but vary in total number of pins in the pin lattice
2. Two assemblies have the same pin lattice structure and geometry, but the constituent pins of each assembly are subdivided into a different number of sectors per side.
3. One assembly is defined as a heterogeneous mesh (contains one or more pins), and the other assembly is homogenized.

`CoreMeshGenerator` will throw a warning if it detects that assembly stitching may lead to hanging nodes. If this happens, the user can regenerate the core mesh by setting [ReactorMeshParams](ReactorMeshParams.md)/[!param](/Mesh/ReactorMeshParams/flexible_assembly_stitching) to `true` to enable flexible assembly stitching. This flexible assembly stitching algorithm deletes the outermost mesh interval and replaces it with a triangulated region using [`FlexiblePatternGenerator`](FlexiblePatternGenerator.md). For a homogeneous assembly, the entire assembly region is triangulated. By doing so, the number of nodes at the outer boundary of each input assembly will be identical and positioned at the same locations, thus enabling stitching of dissimilar assemblies. In order to control the number of sectors at the outer assembly boundary after the triangulation step, the user can set this parameter using [ReactorMeshParams](ReactorMeshParams.md)/[!param](/Mesh/ReactorMeshParams/num_sectors_at_flexible_boundary). The following three images describe how flexible assembly patterning can be used to address the issue of hanging nodes for the three cases listed above:

!media reactor/meshgenerators/rgmb_flexible_stitching_case1.png style=width:70%;

!media reactor/meshgenerators/rgmb_flexible_stitching_case2.png style=width:70%;

!media reactor/meshgenerators/rgmb_flexible_stitching_case3.png style=width:70%;

## Metadata Information

Users may be interested in defining metadata to represent the reactor geometry and region IDs assigned to each geometry zone, which may be useful to users who want mesh geometry and composition information without having to inspect the generated mesh itself. [!param](/Mesh/CoreMeshGenerator/show_rgmb_metadata) can be set to true in order to see the values of these metadata entries as console output.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

Instead of the fixed hexagonal and cartesian background shapes provided respectively by `PatternedHexMeshGenerator` and `PatternedCartesianMeshGenerator`, `FlexiblePatternGenerator` allows adoption of a closed curve of any type, provided by [!param](/Mesh/FlexiblePatternGenerator/boundary_mesh), to be used as the external boundary of the background region, with [!param](/Mesh/FlexiblePatternGenerator/boundary_type) set as `CUSTOM`. The [!param](/Mesh/FlexiblePatternGenerator/boundary_mesh) needs to be a mesh containing a single closed curve that resides in the XY plane and consists of only `EDGE2` elements. Examples of such curve meshes include polygon curves generated by [`PolyLineMeshGenerator`](PolyLineMeshGenerator.md), more generalized curves generated by [`ParsedCurveGenerator`](ParsedCurveGenerator.md), and even externally generated curves through [`FileMeshGenerator`](FileMeshGenerator.md).

If a hexagonal, Cartesian, or circular external boundary are desired, [!param](/Mesh/FlexiblePatternGenerator/boundary_type) should be set as as `HEXAGON`, `CARTESIAN`, and `CIRCLE`, respectively. In that case, [!param](/Mesh/FlexiblePatternGenerator/boundary_size) and [!param](/Mesh/FlexiblePatternGenerator/boundary_sectors) also need to be specified. By default, the external boundary will be assigned an ID of `10000` to be compatible with other Reactor Module tools. Users can also define a custom id for the external boundary using [!param](/Mesh/FlexiblePatternGenerator/external_boundary_id).
If a hexagonal, Cartesian, or circular external boundary are desired, [!param](/Mesh/FlexiblePatternGenerator/boundary_type) should be set as as `HEXAGON`, `CARTESIAN`, and `CIRCLE`, respectively. In that case, [!param](/Mesh/FlexiblePatternGenerator/boundary_size) and [!param](/Mesh/FlexiblePatternGenerator/boundary_sectors) also need to be specified. Users can also define a custom id and name for the external boundary by using [!param](/Mesh/FlexiblePatternGenerator/external_boundary_id) and [!param](/Mesh/FlexiblePatternGenerator/external_boundary_name), respectively. By default, the external boundary will be assigned the following ID to be compatible with other Reactor Module tools:

!listing include/meshgenerators/PolygonMeshGeneratorBase.h line=OUTER_SIDESET_ID =

The background region is meshed by [`XYDelaunayGenerator`](XYDelaunayGenerator.md) through MOOSE's sub-meshgenerator capability. Some key parameters of `XYDelaunayGenerator` (e.g., [!param](/Mesh/FlexiblePatternGenerator/desired_area), [!param](/Mesh/FlexiblePatternGenerator/desired_area_func), [!param](/Mesh/FlexiblePatternGenerator/verify_holes), [!param](/Mesh/XYDelaunayGenerator/use_auto_area_func), [!param](/Mesh/XYDelaunayGenerator/auto_area_func_default_size), [!param](/Mesh/XYDelaunayGenerator/auto_area_func_default_size_dist), [!param](/Mesh/XYDelaunayGenerator/auto_area_function_num_points), and [!param](/Mesh/XYDelaunayGenerator/auto_area_function_power)) can be set here and then directly passed to `XYDelaunayGenerator`. The block id and names can be optionally specified through [!param](/Mesh/FlexiblePatternGenerator/background_subdomain_id) and [!param](/Mesh/FlexiblePatternGenerator/background_subdomain_name).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Overview

The `ReactorMeshParams` object stores persistent mesh information about a reactor's geometry for use with [PinMeshGenerator](/PinMeshGenerator.md), [AssemblyMeshGenerator](/AssemblyMeshGenerator.md), and [CoreMeshGenerator](/CoreMeshGenerator.md). This is where the geometry type ([!param](/Mesh/ReactorMeshParams/geom) as 'Square' or 'Hex' for cartesian and hexagonal definitions respectively) and the number of dimensions of the mesh ([!param](/Mesh/ReactorMeshParams/dim) 2 or 3D) is declared and persistently enforced for the rest of the mesh definition. If the mesh is to be 3-dimensional, this is also where the axial information is declared ([!param](/Mesh/ReactorMeshParams/axial_regions) and [!param](/Mesh/ReactorMeshParams/axial_mesh_intervals)). In addition, the global option to automatically set block names for the output mesh based on the region IDs of the mesh can be selected in this mesh generator, by setting ([!param](/Mesh/ReactorMeshParams/region_id_as_block_name) to `true`. More information about this parameter can be found in the block naming sections of [PinMeshGenerator](/PinMeshGenerator.md), [AssemblyMeshGenerator](/AssemblyMeshGenerator.md), and [CoreMeshGenerator](/CoreMeshGenerator.md).
The `ReactorMeshParams` object stores persistent mesh information about a reactor's geometry for use with [PinMeshGenerator](/PinMeshGenerator.md), [AssemblyMeshGenerator](/AssemblyMeshGenerator.md), and [CoreMeshGenerator](/CoreMeshGenerator.md). This is where the geometry type ([!param](/Mesh/ReactorMeshParams/geom) as 'Square' or 'Hex' for cartesian and hexagonal definitions respectively) and the number of dimensions of the mesh ([!param](/Mesh/ReactorMeshParams/dim) either 2 for 2D or 3 for 3D) is declared and persistently enforced for the rest of the mesh definition. If the mesh is to be 3-dimensional, this is also where the axial information is declared ([!param](/Mesh/ReactorMeshParams/axial_regions) and [!param](/Mesh/ReactorMeshParams/axial_mesh_intervals)). In addition, the global option to automatically set block names for the output mesh based on the region IDs of the mesh can be selected in this mesh generator, by setting ([!param](/Mesh/ReactorMeshParams/region_id_as_block_name) to `true`. More information about this parameter can be found in the block naming sections of [PinMeshGenerator](/PinMeshGenerator.md), [AssemblyMeshGenerator](/AssemblyMeshGenerator.md), and [CoreMeshGenerator](/CoreMeshGenerator.md). In order to enable flexible assembly stitching between [AssemblyMeshGenerator](/AssemblyMeshGenerator.md) objects that do not share the same number of nodes at the outer assembly interface, [!param](/Mesh/ReactorMeshParams/flexible_assembly_stitching) can be set to `true`, and the number of sectors that are created at the flexible assembly boundary interface is controlled by ([!param](/Mesh/ReactorMeshParams/num_sectors_at_flexible_boundary). More information about flexible assembly stitching can be found in [CoreMeshGenerator](/CoreMeshGenerator.md).

## Metadata Information

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class AssemblyMeshGenerator : public ReactorGeometryMeshBuilderBase
std::unique_ptr<MeshBase> generate() override;

protected:
// Delete outermost mesh interval of assembly and replace with triangulated mesh with fixed number
// of nodes at outer boundary
void generateFlexibleAssemblyBoundaries();

// Define metadata associated with AssemblyMeshGenerator
void generateMetadata();

Expand Down
4 changes: 4 additions & 0 deletions modules/reactor/include/meshgenerators/CoreMeshGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class CoreMeshGenerator : public ReactorGeometryMeshBuilderBase
// Define metadata associated with CoreMeshGenerator
void generateMetadata();

// Check constituent assemblies and determine whether they should be stitched into a core using
// flexible stitching
bool constituentAssembliesNeedFlexibleStiching();

///The names of the assemblies that compose the core
const std::vector<MeshGeneratorName> _inputs;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class FlexiblePatternGenerator : public PolygonMeshGeneratorBase
// PolygonMeshGeneratorBase::INTRINSIC_SIDESET_ID::OUTER_SIDESET_ID) from the inputs
const bool _delete_default_external_boundary_from_inputs;

/// Boundary ID of the external boundary
const boundary_id_type _external_boundary_id;
/// Boundary Name of the external boundary
const std::string _external_boundary_name;

/// The final mesh that is generated by the subgenerators;
/// This mesh is generated by the subgenerators with only element and boundary IDs changed.
std::unique_ptr<MeshBase> * _build_mesh;
Expand Down
4 changes: 4 additions & 0 deletions modules/reactor/include/meshgenerators/PinMeshGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class PinMeshGenerator : public ReactorGeometryMeshBuilderBase
std::unique_ptr<MeshBase> generate() override;

protected:
// Delete outermost mesh interval of single-pin / homogenized assembly and replace with
// triangulated mesh with fixed number of nodes at outer boundary
void generateFlexibleAssemblyBoundaries();

// Define metadata associated with PinMeshGenerator
void generateMetadata();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ static const std::string pin_region_ids = "pin_region_ids";
static const std::string pin_block_names = "pin_block_names";
static const std::string pin_region_id_map = "pin_region_id_map";
static const std::string pin_block_name_map = "pin_block_name_map";
static const std::string flexible_assembly_stitching = "flexible_assembly_stitching";
static const std::string num_sectors_flexible_stitching = "num_sectors_flexible_stitching";

// Geometrical quantities
static const std::string pitch = "pitch";
Expand All @@ -57,6 +59,13 @@ static const std::string region_id_as_block_name = "region_id_as_block_name";
// Name of a boolean metadata that indicates whether or not we skipped mesh generation in favor of
// only generating the mesh metadata
static const std::string bypass_meshgen = "bypass_meshgen";

// Default values for setting block IDs of RGMB regions
const subdomain_id_type PIN_BLOCK_ID_START = 10000;
const subdomain_id_type PIN_BLOCK_ID_TRI = 9999;
const subdomain_id_type PIN_BLOCK_ID_TRI_FLEXIBLE = 9998;
const subdomain_id_type ASSEMBLY_BLOCK_ID_START = 20000;
const subdomain_id_type ASSEMBLY_BLOCK_ID_TRI_FLEXIBLE = 19999;
}

/**
Expand Down
67 changes: 63 additions & 4 deletions modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,13 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters)
params.set<std::vector<std::vector<unsigned int>>>("pattern") = _pattern;
params.set<bool>("create_outward_interface_boundaries") = false;

unsigned int assembly_block_id_start = 20000;
if (_background_intervals > 0)
{
params.set<unsigned int>("background_intervals") = _background_intervals;
// Initial block id used to define peripheral regions of assembly

const auto background_block_name = "RGMB_ASSEMBLY" + std::to_string(_assembly_type) + "_R0";
const auto background_block_id = assembly_block_id_start;
const auto background_block_id = RGMB::ASSEMBLY_BLOCK_ID_START;
params.set<subdomain_id_type>("background_block_id") = background_block_id;
params.set<SubdomainName>("background_block_name") = background_block_name;
}
Expand All @@ -310,7 +309,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters)
{
const auto duct_block_name =
"RGMB_ASSEMBLY" + std::to_string(_assembly_type) + "_R" + std::to_string(duct_it + 1);
const auto duct_block_id = assembly_block_id_start + duct_it + 1;
const auto duct_block_id = RGMB::ASSEMBLY_BLOCK_ID_START + duct_it + 1;
duct_block_ids.push_back(duct_block_id);
duct_block_names.push_back(duct_block_name);
}
Expand Down Expand Up @@ -361,6 +360,14 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters)
addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
}

// Modify outermost mesh interval to enable flexible assembly stitching
const auto use_flexible_stitching = getReactorParam<bool>(RGMB::flexible_assembly_stitching);
if (use_flexible_stitching)
{
generateFlexibleAssemblyBoundaries();
build_mesh_name = name() + "_fpg_delbds";
}

for (auto pinMG : _inputs)
{
std::map<subdomain_id_type, std::vector<std::vector<subdomain_id_type>>> region_id_map =
Expand All @@ -386,7 +393,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters)
{
auto params = _app.getFactory().getValidParams("AdvancedExtruderGenerator");

params.set<MeshGeneratorName>("input") = name() + "_delbds";
params.set<MeshGeneratorName>("input") = build_mesh_name;
params.set<Point>("direction") = Point(0, 0, 1);
params.set<std::vector<unsigned int>>("num_layers") =
getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals);
Expand Down Expand Up @@ -487,6 +494,58 @@ AssemblyMeshGenerator::generateMetadata()
printReactorMetadata("assembly", name());
}

void
AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries()
{
// Assemblies that invoke this method have constituent pin lattice, delete outermost background or
// duct region (if present)
SubdomainName block_to_delete = "";
if (_background_region_id.size() == 0)
mooseError("Attempting to use flexible stitching on assembly " + name() +
" that does not have a background region. This is not yet supported.");
const auto radial_index = _duct_region_ids.size() == 0 ? 0 : _duct_region_ids[0].size();
block_to_delete =
"RGMB_ASSEMBLY" + std::to_string(_assembly_type) + "_R" + std::to_string(radial_index);

{
// Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly
auto params = _app.getFactory().getValidParams("BlockDeletionGenerator");

params.set<std::vector<SubdomainName>>("block") = {block_to_delete};
params.set<MeshGeneratorName>("input") = name() + "_delbds";

addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params);
}
{
// Invoke FlexiblePatternGenerator to triangulate deleted mesh region
auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator");

params.set<std::vector<MeshGeneratorName>>("inputs") = {name() + "_del_outer"};
params.set<std::vector<libMesh::Point>>("extra_positions") = {libMesh::Point(0, 0, 0)};
params.set<std::vector<unsigned int>>("extra_positions_mg_indices") = {0};
params.set<bool>("use_auto_area_func") = true;
params.set<MooseEnum>("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN";
params.set<unsigned int>("boundary_sectors") =
getReactorParam<unsigned int>(RGMB::num_sectors_flexible_stitching);
params.set<Real>("boundary_size") = getReactorParam<Real>(RGMB::assembly_pitch);
params.set<boundary_id_type>("external_boundary_id") = _assembly_boundary_id;
params.set<BoundaryName>("external_boundary_name") = _assembly_boundary_name;
params.set<SubdomainName>("background_subdomain_name") = block_to_delete + "_TRI";
params.set<unsigned short>("background_subdomain_id") = RGMB::ASSEMBLY_BLOCK_ID_TRI_FLEXIBLE;

addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params);
}
{
// Delete extra boundary created by FlexiblePatternGenerator
auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");

params.set<MeshGeneratorName>("input") = name() + "_fpg";
params.set<std::vector<BoundaryName>>("boundary_names") = {std::to_string(1)};

addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params);
}
}

std::unique_ptr<MeshBase>
AssemblyMeshGenerator::generate()
{
Expand Down
Loading