From 57dfa151eb0bccda917779a545e544439d48aa13 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Wed, 24 Jul 2024 23:31:20 -0400 Subject: [PATCH 1/9] First pass at flexible assembly stitching in RGMB --- .../FlexiblePatternGenerator.md | 2 +- .../meshgenerators/AssemblyMeshGenerator.h | 3 + .../meshgenerators/CoreMeshGenerator.h | 3 + .../include/meshgenerators/PinMeshGenerator.h | 3 + .../ReactorGeometryMeshBuilderBase.h | 2 + .../meshgenerators/AssemblyMeshGenerator.C | 58 +++++++- .../src/meshgenerators/CoreMeshGenerator.C | 81 +++++++++- .../meshgenerators/FlexiblePatternGenerator.C | 19 ++- .../src/meshgenerators/PinMeshGenerator.C | 138 +++++++++++++++--- .../src/meshgenerators/ReactorMeshParams.C | 9 ++ 10 files changed, 287 insertions(+), 31 deletions(-) diff --git a/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md b/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md index 2aa0b66df2cf..b27f083e3a88 100644 --- a/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md +++ b/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md @@ -10,7 +10,7 @@ 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. 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 and name for the external boundary by using [!param](/Mesh/FlexiblePatternGenerator/external_boundary_id) and [!param](/Mesh/FlexiblePatternGenerator/external_boundary_name), respectively. 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). diff --git a/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h b/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h index 6778783f89cf..2b627785e49b 100644 --- a/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h @@ -25,6 +25,9 @@ class AssemblyMeshGenerator : public ReactorGeometryMeshBuilderBase std::unique_ptr 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(); diff --git a/modules/reactor/include/meshgenerators/CoreMeshGenerator.h b/modules/reactor/include/meshgenerators/CoreMeshGenerator.h index 9009221f9d34..b77f90e5d283 100644 --- a/modules/reactor/include/meshgenerators/CoreMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/CoreMeshGenerator.h @@ -29,6 +29,9 @@ 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 _inputs; diff --git a/modules/reactor/include/meshgenerators/PinMeshGenerator.h b/modules/reactor/include/meshgenerators/PinMeshGenerator.h index cc637f71a57a..1eabd48bb73d 100644 --- a/modules/reactor/include/meshgenerators/PinMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/PinMeshGenerator.h @@ -25,6 +25,9 @@ class PinMeshGenerator : public ReactorGeometryMeshBuilderBase std::unique_ptr 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(); diff --git a/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h b/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h index 05706ed462ec..2a67079a09e1 100644 --- a/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h +++ b/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h @@ -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"; diff --git a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C index 8389c9f1095f..5341b8f37011 100644 --- a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C @@ -361,6 +361,14 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params); } + // Modify outermost mesh interval to enable flexible assembly stitching + auto use_flexible_stitching = getReactorParam(RGMB::flexible_assembly_stitching); + if (use_flexible_stitching) + { + generateFlexibleAssemblyBoundaries(); + build_mesh_name = name() + "_fpg_delbds"; + } + for (auto pinMG : _inputs) { std::map>> region_id_map = @@ -386,7 +394,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) { auto params = _app.getFactory().getValidParams("AdvancedExtruderGenerator"); - params.set("input") = name() + "_delbds"; + params.set("input") = build_mesh_name; params.set("direction") = Point(0, 0, 1); params.set>("num_layers") = getReactorParam>(RGMB::axial_mesh_intervals); @@ -487,6 +495,54 @@ 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>("block") = {block_to_delete}; + params.set("input") = name() + "_delbds"; + + addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params); + } + { + // Invoke FlexiblePatternGenerator to triangulate deleted mesh interval + auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator"); + + params.set>("inputs") = {name() + "_del_outer"}; + params.set>("extra_positions") = {libMesh::Point(0, 0, 0)}; + params.set>("extra_positions_mg_indices") = {0}; + params.set("use_auto_area_func") = true; + params.set("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN"; + params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); + params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); + params.set("external_boundary_id") = _assembly_boundary_id; + params.set("external_boundary_name") = _assembly_boundary_name; + params.set("background_subdomain_name") = block_to_delete + "_TRI"; + params.set("background_subdomain_id") = 19999; + + addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params); + } + { + // Delete extra boundary created by FlexiblePatternGenerator + auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator"); + + params.set("input") = name() + "_fpg"; + params.set>("boundary_names") = {std::to_string(1)}; + + addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params); + } +} + std::unique_ptr AssemblyMeshGenerator::generate() { diff --git a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C index ee37bfca584f..8b01fbe211a2 100644 --- a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C @@ -190,12 +190,9 @@ CoreMeshGenerator::CoreMeshGenerator(const InputParameters & parameters) if (getMeshProperty(RGMB::reactor_params_name, _inputs[i]) != reactor_params) mooseError("The name of all reactor_params objects should be identical across all pins in " "the input assemblies.\n"); - if (getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) + if ((getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) && !getMeshProperty(RGMB::flexible_assembly_stitching, reactor_params)) mooseError( - "All assemblies in the core must be homogenized if assembly homogenization is used\n"); - if (getMeshProperty(RGMB::is_single_pin, _inputs[i]) != pin_as_assembly) - mooseWarning("Not all assemblies in the core are defined as a single pin by setting " - "`PinMeshGenerator/use_as_assembly` to true\n"); + "In order to stitch heterogeneous assemblies with homogeneous assemblies in CoreMeshGenerator, ReactorMeshParams/flexible_assembly_stitching should be set to true\n"); // Check assembly_types across constituent assemblies are uniquely defined const auto assembly_type = getMeshProperty(RGMB::assembly_type, _inputs[i]); @@ -280,6 +277,10 @@ CoreMeshGenerator::CoreMeshGenerator(const InputParameters & parameters) // No subgenerators will be called if option to bypass mesh generators is enabled if (!getReactorParam(RGMB::bypass_meshgen)) { + // Check whether flexible stitching should be used for constituent assemblies and throw a warning if flexible stitching option is not enabled + if (!getReactorParam(RGMB::flexible_assembly_stitching) && constituentAssembliesNeedFlexibleStiching()) + mooseWarning("Constituent assemblies do not share the same number of nodes at the outer boundary. In order to ensure that output mesh does not having hanging nodes, a flexible stitching approach should be used by setting ReactorMeshParams/flexible_assembly_stitching = true."); + // Declare that all of the meshes in the "inputs" parameter are to be used by // a sub mesh generator. declareMeshesForSub("inputs"); @@ -619,6 +620,76 @@ CoreMeshGenerator::generateMetadata() printReactorMetadata("core", name()); } +bool +CoreMeshGenerator::constituentAssembliesNeedFlexibleStiching() +{ + MeshGeneratorName first_nondummy_assembly = ""; + bool assembly_homogenization = false; + bool pin_as_assembly = false; + unsigned int n_constituent_pins = 0; + unsigned int n_pin_sectors = 0; + + // Loop through all non-dummy input assemblies. Flexible assembly stitching is needed if one of the following criteria are met: + // 1. The number of constituent pins within the assembly does not match with another assembly + // 2. The value of is_single_pin and is_homogenized metadata do not agree with another assembly + // 3. The number of sectors of the constituent pins of an assembly do not match with the constituent pins of another assembly + for (const auto i : index_range(_inputs)) + { + // Skip if assembly name is equal to dummy assembly name + if (_inputs[i] == _empty_key) + continue; + + // Compute total number of constituent pins in assembly, as well as the number of sectors per side for each pin + // Note: number of sectors per side is defined uniformly across constituent pins of an assembly, so only first one needs to be checked + unsigned int total_pins = 0; + unsigned int pin_sectors_per_side = 0; + if (!getMeshProperty(RGMB::is_single_pin, _inputs[i])) + { + const auto first_pin_name = getMeshProperty>(RGMB::pin_names, _inputs[i])[0]; + pin_sectors_per_side = getMeshProperty>("num_sectors_per_side_meta", first_pin_name + "_2D")[0]; + const auto pin_lattice = getMeshProperty>>(RGMB::pin_lattice, _inputs[i]); + for (const auto i : index_range(pin_lattice)) + total_pins += pin_lattice[i].size(); + } + else + { + if (getMeshProperty(RGMB::is_homogenized, _inputs[i])) + { + // Homogenized assembly + total_pins = 0; + pin_sectors_per_side = 0; + } + else + { + // Assembly with single constituent pin + total_pins = 1; + pin_sectors_per_side = getMeshProperty>("num_sectors_per_side_meta", _inputs[i] + "_2D")[0]; + } + } + + if (first_nondummy_assembly == "") + { + first_nondummy_assembly = MeshGeneratorName(_inputs[i]); + assembly_homogenization = getMeshProperty(RGMB::is_homogenized, _inputs[i]); + pin_as_assembly = getMeshProperty(RGMB::is_single_pin, _inputs[i]); + n_constituent_pins = total_pins; + n_pin_sectors = pin_sectors_per_side; + } + else + { + if (getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) + return true; + if (getMeshProperty(RGMB::is_single_pin, _inputs[i]) != pin_as_assembly) + return true; + if (total_pins != n_constituent_pins) + return true; + if (pin_sectors_per_side != n_pin_sectors) + return true; + } + } + return false; +} + std::unique_ptr CoreMeshGenerator::generate() { diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 737a51ec2fac..1fbd6d9ebd6f 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -122,6 +122,8 @@ FlexiblePatternGenerator::validParams() params.addParam( "external_boundary_id", "The boundary id of the external boundary in addition to the default 10000."); + params.addParam( + "external_boundary_name", std::string(), "Optional boundary name for the external boundary."); params.addParam("delete_default_external_boundary_from_inputs", true, @@ -146,7 +148,7 @@ FlexiblePatternGenerator::validParams() "auto_area_function_num_points auto_area_function_power", "Background Area Delaunay"); params.addParamNamesToGroup("boundary_type boundary_mesh boundary_sectors boundary_size " - "delete_default_external_boundary_from_inputs external_boundary_id", + "delete_default_external_boundary_from_inputs external_boundary_id external_boundary_name", "Boundary"); return params; @@ -553,9 +555,20 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param std::unique_ptr FlexiblePatternGenerator::generate() { - if (isParamValid("external_boundary_id")) + const auto external_boundary_id = isParamValid("external_boundary_id") ? getParam("external_boundary_id") : 0; + const auto external_boundary_name = isParamValid("external_boundary_name") ? getParam("external_boundary_name") : ""; + if (external_boundary_id > 0) MooseMesh::changeBoundaryId( - **_build_mesh, OUTER_SIDESET_ID, getParam("external_boundary_id"), false); + **_build_mesh, OUTER_SIDESET_ID, external_boundary_id, false); + if (!external_boundary_name.empty()) + { + (*_build_mesh)->get_boundary_info().sideset_name( + external_boundary_id > 0 ? external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) = + external_boundary_name; + (*_build_mesh)->get_boundary_info().nodeset_name( + external_boundary_id > 0 ? external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) = + external_boundary_name; + } (*_build_mesh)->find_neighbors(); (*_build_mesh)->set_isnt_prepared(); return std::move(*_build_mesh); diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index 4fd1e10477fb..228ec68cc66e 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -195,6 +195,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) // Use special block id to designate TRI elements subdomain_id_type pin_block_id_tri = pin_block_id_start - 1; + const auto use_flexible_stitching = getReactorParam(RGMB::flexible_assembly_stitching); std::string build_mesh_name; // No subgenerators will be called if option to bypass mesh generators is enabled @@ -202,6 +203,10 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) { if (_homogenized) { + // If flexible assembly stitching is invoked and this is a homogeneous assembly mesh, do not call mesh subgenerators here + // The homogeneous assembly mesh should be created entirely in generateFlexibleAssemblyBoundaries() + bool skip_assembly_generation = _is_assembly && use_flexible_stitching; + auto params = _app.getFactory().getValidParams("SimpleHexagonGenerator"); params.set("hexagon_size") = _pitch / 2.0; @@ -213,12 +218,15 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) : pin_block_id_tri}; params.set("element_type") = _quad_center ? "QUAD" : "TRI"; auto block_name = "RGMB_PIN" + std::to_string(_pin_type) + "_R0"; - if (_quad_center) + if (!_quad_center) block_name += "_TRI"; params.set>("block_name") = {block_name}; - build_mesh_name = name() + "_2D"; - addMeshSubgenerator("SimpleHexagonGenerator", build_mesh_name, params); + if (!skip_assembly_generation) + { + build_mesh_name = name() + "_2D"; + addMeshSubgenerator("SimpleHexagonGenerator", build_mesh_name, params); + } } else { @@ -313,6 +321,10 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) } } + // If flexible assembly stitching is invoked and this is an assembly mesh with only a background region, do not call mesh subgenerators here + // This assembly mesh should be created entirely in generateFlexibleAssemblyBoundaries() + bool skip_assembly_generation = _is_assembly && use_flexible_stitching && _intervals.size() == 1; + // Generate Cartesian/hex pin using PolygonConcentricCircleMeshGenerator { // Get and assign parameters for the main geometry feature of the Pin @@ -356,7 +368,8 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) params.set>("duct_intervals") = duct_intervals; } - addMeshSubgenerator("PolygonConcentricCircleMeshGenerator", name() + "_2D", params); + if (!skip_assembly_generation) + addMeshSubgenerator("PolygonConcentricCircleMeshGenerator", name() + "_2D", params); } // Remove extra sidesets created by PolygonConcentricCircleMeshGenerator @@ -372,17 +385,32 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) {std::to_string(10001 + i), std::to_string(15001 + i)}); params.set>("boundary_names") = boundaries_to_delete; - build_mesh_name = name() + "_del_bds"; - addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params); + if (!skip_assembly_generation) + { + build_mesh_name = name() + "_delbds"; + addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params); + } } } + // For pin acting as assembly, modify outermost mesh interval to enable flexible assembly stitching + if (_is_assembly && use_flexible_stitching) + { + generateFlexibleAssemblyBoundaries(); + build_mesh_name = name() + "_fpg_delbds"; + } + // Pass mesh meta-data defined in subgenerator constructor to this MeshGenerator - copyMeshProperty("pitch_meta", name() + "_2D"); - copyMeshProperty>("num_sectors_per_side_meta", name() + "_2D"); - copyMeshProperty("max_radius_meta", name() + "_2D"); - copyMeshProperty("background_intervals_meta", name() + "_2D"); - copyMeshProperty("node_id_background_meta", name() + "_2D"); + if (hasMeshProperty("pitch_meta", name() + "_2D")) + copyMeshProperty("pitch_meta", name() + "_2D"); + if (hasMeshProperty>("num_sectors_per_side_meta", name() + "_2D")) + copyMeshProperty>("num_sectors_per_side_meta", name() + "_2D"); + if (hasMeshProperty("max_radius_meta", name() + "_2D")) + copyMeshProperty("max_radius_meta", name() + "_2D"); + if (hasMeshProperty("background_intervals_meta", name() + "_2D")) + copyMeshProperty("background_intervals_meta", name() + "_2D"); + if (hasMeshProperty("node_id_background_meta", name() + "_2D")) + copyMeshProperty("node_id_background_meta", name() + "_2D"); if (_is_assembly) declareMeshProperty("pattern_pitch_meta", getReactorParam(RGMB::assembly_pitch)); @@ -399,8 +427,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) { auto params = _app.getFactory().getValidParams("AdvancedExtruderGenerator"); - params.set("input") = - _homogenized ? name() + "_2D" : name() + "_del_bds"; + params.set("input") = build_mesh_name; params.set("direction") = Point(0, 0, 1); params.set>("num_layers") = getReactorParam>(RGMB::axial_mesh_intervals); @@ -446,6 +473,72 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) generateMetadata(); } +void +PinMeshGenerator::generateFlexibleAssemblyBoundaries() +{ + SubdomainName outermost_block_name; + bool has_single_mesh_interval; + + // Assemblies that invoke this method are either homogenized or have a single pin. First check if the assembly only has a single region. + // Otherwise, determine the outermost region for deletion + if (_homogenized || (_intervals.size() == 1)) + { + outermost_block_name = "RGMB_PIN" + std::to_string(_pin_type)+ "_R0"; + has_single_mesh_interval = true; + } + else + { + outermost_block_name = "RGMB_PIN" + std::to_string(_pin_type)+ "_R" + std::to_string(_intervals.size() - 1); + has_single_mesh_interval = false; + + // Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly + auto params = _app.getFactory().getValidParams("BlockDeletionGenerator"); + + params.set>("block") = {outermost_block_name}; + params.set("input") = _homogenized ? name() + "_2D" : name() + "_delbds"; + + addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params); + } + + { + // Invoke FlexiblePatternGenerator to triangulate deleted mesh interval + auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator"); + + if (has_single_mesh_interval) + params.set>("inputs") = {}; + else + { + params.set>("inputs") = {name() + "_del_outer"}; + params.set>("extra_positions") = {libMesh::Point(0, 0, 0)}; + params.set>("extra_positions_mg_indices") = {0}; + } + params.set("use_auto_area_func") = true; + params.set("boundary_type") = (_mesh_geometry == "Hex") ? "HEXAGON" : "CARTESIAN"; + params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); + params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); + params.set("external_boundary_id") = 20000 + _pin_type; + params.set("external_boundary_name") = "outer_assembly_" + std::to_string(_pin_type); + params.set("background_subdomain_name") = outermost_block_name + "_TRI"; + // Allocate block ID 9998 for triangulated outer region, since 9999 is reserved for tri elements when + // quad_center_elements is false + params.set("background_subdomain_id") = 9998; + + addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params); + } + { + // Delete extra boundary created by FlexiblePatternGenerator + auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator"); + + params.set("input") = name() + "_fpg"; + std::vector boundaries_to_delete = {}; + if (!has_single_mesh_interval) + boundaries_to_delete.push_back(std::to_string(1)); + params.set>("boundary_names") = boundaries_to_delete; + + addMeshSubgenerator("BoundaryDeletionGenerator", name() + "_fpg_delbds", params); + } +} + void PinMeshGenerator::generateMetadata() { @@ -544,14 +637,17 @@ PinMeshGenerator::generate() // Update metadata at this point since values for these metadata only get set by PCCMG // at generate() stage - const auto max_radius_meta = getMeshProperty("max_radius_meta", name() + "_2D"); - setMeshProperty("max_radius_meta", max_radius_meta); - const auto background_intervals_meta = - getMeshProperty("background_intervals_meta", name() + "_2D"); - setMeshProperty("background_intervals_meta", background_intervals_meta); - const auto node_id_background_meta = - getMeshProperty("node_id_background_meta", name() + "_2D"); - setMeshProperty("node_id_background_meta", node_id_background_meta); + if (hasMeshProperty("max_radius_meta", name() + "_2D")) + { + const auto max_radius_meta = getMeshProperty("max_radius_meta", name() + "_2D"); + setMeshProperty("max_radius_meta", max_radius_meta); + const auto background_intervals_meta = + getMeshProperty("background_intervals_meta", name() + "_2D"); + setMeshProperty("background_intervals_meta", background_intervals_meta); + const auto node_id_background_meta = + getMeshProperty("node_id_background_meta", name() + "_2D"); + setMeshProperty("node_id_background_meta", node_id_background_meta); + } // This generate() method will be called once the subgenerators that we depend on // have been called. This is where we reassign subdomain ids/names according to what diff --git a/modules/reactor/src/meshgenerators/ReactorMeshParams.C b/modules/reactor/src/meshgenerators/ReactorMeshParams.C index cac9eedd4202..56ed46a6ec88 100644 --- a/modules/reactor/src/meshgenerators/ReactorMeshParams.C +++ b/modules/reactor/src/meshgenerators/ReactorMeshParams.C @@ -44,6 +44,8 @@ ReactorMeshParams::validParams() "axial_mesh_intervals", "Number of elements in the Z direction for each axial region"); params.addParam("region_id_as_block_name", false, "Set block names based on region id"); + params.addParam("flexible_assembly_stitching", false, "Use FlexiblePatternGenerator for stitching dissimilar assemblies together"); + params.addRangeCheckedParam("num_sectors_at_flexible_boundary", 6, "num_sectors_at_flexible_boundary>2", "Number of sectors to use at assembly boundary interface when flexible patterning is used (Defaults to 6)"); params.addClassDescription("This ReactorMeshParams object acts as storage for persistent " "information about the reactor geometry."); @@ -84,6 +86,13 @@ ReactorMeshParams::ReactorMeshParams(const InputParameters & parameters) this->declareMeshProperty(RGMB::region_id_as_block_name, getParam(RGMB::region_id_as_block_name)); + const bool flexible_assembly_stitching = getParam(RGMB::flexible_assembly_stitching); + this->declareMeshProperty(RGMB::flexible_assembly_stitching, flexible_assembly_stitching); + if (flexible_assembly_stitching) + this->declareMeshProperty(RGMB::num_sectors_flexible_stitching, getParam("num_sectors_at_flexible_boundary")); + if (parameters.isParamSetByUser("num_sectors_at_flexible_boundary") && !flexible_assembly_stitching) + paramWarning("num_sectors_at_flexible_boundary", "This parameter is only relevant when ReactorMeshParams/flexible_assembly_stitching is set to true. This value will be ignored"); + // Option to bypass mesh generation is controlled by presence of Mesh/data_driven_generator // and whether the current generator is in data only mode const auto & moose_mesh = _app.actionWarehouse().getMesh(); From 1fe197c45de11431c18cd05fa9b5eca907887ac6 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Thu, 25 Jul 2024 15:37:49 -0400 Subject: [PATCH 2/9] Add unit tests and documentation, refs #28230 --- large_media | 2 +- .../meshgenerators/CoreMeshGenerator.md | 16 ++ .../meshgenerators/ReactorMeshParams.md | 2 +- .../meshgenerators/AssemblyMeshGenerator.h | 3 +- .../meshgenerators/CoreMeshGenerator.h | 3 +- .../include/meshgenerators/PinMeshGenerator.h | 3 +- .../meshgenerators/AssemblyMeshGenerator.C | 12 +- .../src/meshgenerators/CoreMeshGenerator.C | 42 +++-- .../meshgenerators/FlexiblePatternGenerator.C | 28 +-- .../src/meshgenerators/PinMeshGenerator.C | 35 ++-- .../src/meshgenerators/ReactorMeshParams.C | 23 ++- .../core_flexible_assembly_stitching_cart.i | 147 ++++++++++++++++ .../core_flexible_assembly_stitching_hex.i | 160 ++++++++++++++++++ ...e_flexible_assembly_stitching_cart_out.csv | 2 + ...re_flexible_assembly_stitching_hex_out.csv | 2 + .../gold/core_hex_2d_datadriven_out.json | 4 + .../gold/core_hex_datadriven_out.json | 4 + .../gold/core_square_datadriven_out.json | 4 + .../meshgenerators/core_mesh_generator/tests | 28 ++- 19 files changed, 464 insertions(+), 56 deletions(-) create mode 100644 modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_cart.i create mode 100644 modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_hex.i create mode 100644 modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_cart_out.csv create mode 100644 modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_hex_out.csv diff --git a/large_media b/large_media index 2fe4657bc59b..547732eca85f 160000 --- a/large_media +++ b/large_media @@ -1 +1 @@ -Subproject commit 2fe4657bc59b93eb8179d22fa1b3ba137361b6b3 +Subproject commit 547732eca85f14cf545ebc86875535afc38121c5 diff --git a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md index 4703e9e39727..6b5cc8c41984 100644 --- a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md +++ b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md @@ -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 situtations 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 of 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 provided 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. diff --git a/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md b/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md index 1d16a5e99115..2dc4c33d7f5e 100644 --- a/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md +++ b/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md @@ -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) 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). 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 diff --git a/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h b/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h index 2b627785e49b..64c3c74b8d62 100644 --- a/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/AssemblyMeshGenerator.h @@ -25,7 +25,8 @@ class AssemblyMeshGenerator : public ReactorGeometryMeshBuilderBase std::unique_ptr generate() override; protected: - // Delete outermost mesh interval of assembly and replace with triangulated mesh with fixed number of nodes at outer boundary + // 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 diff --git a/modules/reactor/include/meshgenerators/CoreMeshGenerator.h b/modules/reactor/include/meshgenerators/CoreMeshGenerator.h index b77f90e5d283..07821211fe86 100644 --- a/modules/reactor/include/meshgenerators/CoreMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/CoreMeshGenerator.h @@ -29,7 +29,8 @@ 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 + // 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 diff --git a/modules/reactor/include/meshgenerators/PinMeshGenerator.h b/modules/reactor/include/meshgenerators/PinMeshGenerator.h index 1eabd48bb73d..c2e8bbd7ec5f 100644 --- a/modules/reactor/include/meshgenerators/PinMeshGenerator.h +++ b/modules/reactor/include/meshgenerators/PinMeshGenerator.h @@ -25,7 +25,8 @@ class PinMeshGenerator : public ReactorGeometryMeshBuilderBase std::unique_ptr 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 + // 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 diff --git a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C index 5341b8f37011..42ed71ef94fd 100644 --- a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C @@ -498,12 +498,15 @@ AssemblyMeshGenerator::generateMetadata() void AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries() { - // Assemblies that invoke this method have constituent pin lattice, delete outermost background or duct region (if present) + // 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."); + 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); + 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 @@ -523,7 +526,8 @@ AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries() params.set>("extra_positions_mg_indices") = {0}; params.set("use_auto_area_func") = true; params.set("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN"; - params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); + params.set("boundary_sectors") = + getReactorParam(RGMB::num_sectors_flexible_stitching); params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); params.set("external_boundary_id") = _assembly_boundary_id; params.set("external_boundary_name") = _assembly_boundary_name; diff --git a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C index 8b01fbe211a2..1d34e7186748 100644 --- a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C @@ -190,9 +190,11 @@ CoreMeshGenerator::CoreMeshGenerator(const InputParameters & parameters) if (getMeshProperty(RGMB::reactor_params_name, _inputs[i]) != reactor_params) mooseError("The name of all reactor_params objects should be identical across all pins in " "the input assemblies.\n"); - if ((getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) && !getMeshProperty(RGMB::flexible_assembly_stitching, reactor_params)) - mooseError( - "In order to stitch heterogeneous assemblies with homogeneous assemblies in CoreMeshGenerator, ReactorMeshParams/flexible_assembly_stitching should be set to true\n"); + if ((getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) && + !getMeshProperty(RGMB::flexible_assembly_stitching, reactor_params)) + mooseError("In order to stitch heterogeneous assemblies with homogeneous assemblies in " + "CoreMeshGenerator, ReactorMeshParams/flexible_assembly_stitching should be set " + "to true\n"); // Check assembly_types across constituent assemblies are uniquely defined const auto assembly_type = getMeshProperty(RGMB::assembly_type, _inputs[i]); @@ -277,9 +279,14 @@ CoreMeshGenerator::CoreMeshGenerator(const InputParameters & parameters) // No subgenerators will be called if option to bypass mesh generators is enabled if (!getReactorParam(RGMB::bypass_meshgen)) { - // Check whether flexible stitching should be used for constituent assemblies and throw a warning if flexible stitching option is not enabled - if (!getReactorParam(RGMB::flexible_assembly_stitching) && constituentAssembliesNeedFlexibleStiching()) - mooseWarning("Constituent assemblies do not share the same number of nodes at the outer boundary. In order to ensure that output mesh does not having hanging nodes, a flexible stitching approach should be used by setting ReactorMeshParams/flexible_assembly_stitching = true."); + // Check whether flexible stitching should be used for constituent assemblies and throw a + // warning if flexible stitching option is not enabled + if (!getReactorParam(RGMB::flexible_assembly_stitching) && + constituentAssembliesNeedFlexibleStiching()) + mooseWarning("Constituent assemblies do not share the same number of nodes at the outer " + "boundary. In order to ensure that output mesh does not having hanging nodes, a " + "flexible stitching approach should be used by setting " + "ReactorMeshParams/flexible_assembly_stitching = true."); // Declare that all of the meshes in the "inputs" parameter are to be used by // a sub mesh generator. @@ -629,25 +636,31 @@ CoreMeshGenerator::constituentAssembliesNeedFlexibleStiching() unsigned int n_constituent_pins = 0; unsigned int n_pin_sectors = 0; - // Loop through all non-dummy input assemblies. Flexible assembly stitching is needed if one of the following criteria are met: + // Loop through all non-dummy input assemblies. Flexible assembly stitching is needed if one of + // the following criteria are met: // 1. The number of constituent pins within the assembly does not match with another assembly // 2. The value of is_single_pin and is_homogenized metadata do not agree with another assembly - // 3. The number of sectors of the constituent pins of an assembly do not match with the constituent pins of another assembly + // 3. The number of sectors of the constituent pins of an assembly do not match with the + // constituent pins of another assembly for (const auto i : index_range(_inputs)) { // Skip if assembly name is equal to dummy assembly name if (_inputs[i] == _empty_key) continue; - // Compute total number of constituent pins in assembly, as well as the number of sectors per side for each pin - // Note: number of sectors per side is defined uniformly across constituent pins of an assembly, so only first one needs to be checked + // Compute total number of constituent pins in assembly, as well as the number of sectors per + // side for each pin Note: number of sectors per side is defined uniformly across constituent + // pins of an assembly, so only first one needs to be checked unsigned int total_pins = 0; unsigned int pin_sectors_per_side = 0; if (!getMeshProperty(RGMB::is_single_pin, _inputs[i])) { - const auto first_pin_name = getMeshProperty>(RGMB::pin_names, _inputs[i])[0]; - pin_sectors_per_side = getMeshProperty>("num_sectors_per_side_meta", first_pin_name + "_2D")[0]; - const auto pin_lattice = getMeshProperty>>(RGMB::pin_lattice, _inputs[i]); + const auto first_pin_name = + getMeshProperty>(RGMB::pin_names, _inputs[i])[0]; + pin_sectors_per_side = getMeshProperty>("num_sectors_per_side_meta", + first_pin_name + "_2D")[0]; + const auto pin_lattice = + getMeshProperty>>(RGMB::pin_lattice, _inputs[i]); for (const auto i : index_range(pin_lattice)) total_pins += pin_lattice[i].size(); } @@ -663,7 +676,8 @@ CoreMeshGenerator::constituentAssembliesNeedFlexibleStiching() { // Assembly with single constituent pin total_pins = 1; - pin_sectors_per_side = getMeshProperty>("num_sectors_per_side_meta", _inputs[i] + "_2D")[0]; + pin_sectors_per_side = getMeshProperty>( + "num_sectors_per_side_meta", _inputs[i] + "_2D")[0]; } } diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 1fbd6d9ebd6f..8a850815653e 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -147,9 +147,10 @@ FlexiblePatternGenerator::validParams() "auto_area_func_default_size auto_area_func_default_size_dist " "auto_area_function_num_points auto_area_function_power", "Background Area Delaunay"); - params.addParamNamesToGroup("boundary_type boundary_mesh boundary_sectors boundary_size " - "delete_default_external_boundary_from_inputs external_boundary_id external_boundary_name", - "Boundary"); + params.addParamNamesToGroup( + "boundary_type boundary_mesh boundary_sectors boundary_size " + "delete_default_external_boundary_from_inputs external_boundary_id external_boundary_name", + "Boundary"); return params; } @@ -555,18 +556,23 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param std::unique_ptr FlexiblePatternGenerator::generate() { - const auto external_boundary_id = isParamValid("external_boundary_id") ? getParam("external_boundary_id") : 0; - const auto external_boundary_name = isParamValid("external_boundary_name") ? getParam("external_boundary_name") : ""; + const auto external_boundary_id = + isParamValid("external_boundary_id") ? getParam("external_boundary_id") : 0; + const auto external_boundary_name = + isParamValid("external_boundary_name") ? getParam("external_boundary_name") : ""; if (external_boundary_id > 0) - MooseMesh::changeBoundaryId( - **_build_mesh, OUTER_SIDESET_ID, external_boundary_id, false); + MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, external_boundary_id, false); if (!external_boundary_name.empty()) { - (*_build_mesh)->get_boundary_info().sideset_name( - external_boundary_id > 0 ? external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) = + (*_build_mesh) + ->get_boundary_info() + .sideset_name(external_boundary_id > 0 ? external_boundary_id + : (boundary_id_type)OUTER_SIDESET_ID) = external_boundary_name; - (*_build_mesh)->get_boundary_info().nodeset_name( - external_boundary_id > 0 ? external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) = + (*_build_mesh) + ->get_boundary_info() + .nodeset_name(external_boundary_id > 0 ? external_boundary_id + : (boundary_id_type)OUTER_SIDESET_ID) = external_boundary_name; } (*_build_mesh)->find_neighbors(); diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index 228ec68cc66e..80bfc416b087 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -203,8 +203,9 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) { if (_homogenized) { - // If flexible assembly stitching is invoked and this is a homogeneous assembly mesh, do not call mesh subgenerators here - // The homogeneous assembly mesh should be created entirely in generateFlexibleAssemblyBoundaries() + // If flexible assembly stitching is invoked and this is a homogeneous assembly mesh, do not + // call mesh subgenerators here The homogeneous assembly mesh should be created entirely in + // generateFlexibleAssemblyBoundaries() bool skip_assembly_generation = _is_assembly && use_flexible_stitching; auto params = _app.getFactory().getValidParams("SimpleHexagonGenerator"); @@ -321,9 +322,11 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) } } - // If flexible assembly stitching is invoked and this is an assembly mesh with only a background region, do not call mesh subgenerators here - // This assembly mesh should be created entirely in generateFlexibleAssemblyBoundaries() - bool skip_assembly_generation = _is_assembly && use_flexible_stitching && _intervals.size() == 1; + // If flexible assembly stitching is invoked and this is an assembly mesh with only a + // background region, do not call mesh subgenerators here This assembly mesh should be created + // entirely in generateFlexibleAssemblyBoundaries() + bool skip_assembly_generation = + _is_assembly && use_flexible_stitching && _intervals.size() == 1; // Generate Cartesian/hex pin using PolygonConcentricCircleMeshGenerator { @@ -393,7 +396,8 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) } } - // For pin acting as assembly, modify outermost mesh interval to enable flexible assembly stitching + // For pin acting as assembly, modify outermost mesh interval to enable flexible assembly + // stitching if (_is_assembly && use_flexible_stitching) { generateFlexibleAssemblyBoundaries(); @@ -479,16 +483,17 @@ PinMeshGenerator::generateFlexibleAssemblyBoundaries() SubdomainName outermost_block_name; bool has_single_mesh_interval; - // Assemblies that invoke this method are either homogenized or have a single pin. First check if the assembly only has a single region. - // Otherwise, determine the outermost region for deletion + // Assemblies that invoke this method are either homogenized or have a single pin. First check if + // the assembly only has a single region. Otherwise, determine the outermost region for deletion if (_homogenized || (_intervals.size() == 1)) { - outermost_block_name = "RGMB_PIN" + std::to_string(_pin_type)+ "_R0"; + outermost_block_name = "RGMB_PIN" + std::to_string(_pin_type) + "_R0"; has_single_mesh_interval = true; } else { - outermost_block_name = "RGMB_PIN" + std::to_string(_pin_type)+ "_R" + std::to_string(_intervals.size() - 1); + outermost_block_name = + "RGMB_PIN" + std::to_string(_pin_type) + "_R" + std::to_string(_intervals.size() - 1); has_single_mesh_interval = false; // Invoke BlockDeletionGenerator to delete outermost mesh interval of assembly @@ -514,13 +519,15 @@ PinMeshGenerator::generateFlexibleAssemblyBoundaries() } params.set("use_auto_area_func") = true; params.set("boundary_type") = (_mesh_geometry == "Hex") ? "HEXAGON" : "CARTESIAN"; - params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); + params.set("boundary_sectors") = + getReactorParam(RGMB::num_sectors_flexible_stitching); params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); params.set("external_boundary_id") = 20000 + _pin_type; - params.set("external_boundary_name") = "outer_assembly_" + std::to_string(_pin_type); + params.set("external_boundary_name") = + "outer_assembly_" + std::to_string(_pin_type); params.set("background_subdomain_name") = outermost_block_name + "_TRI"; - // Allocate block ID 9998 for triangulated outer region, since 9999 is reserved for tri elements when - // quad_center_elements is false + // Allocate block ID 9998 for triangulated outer region, since 9999 is reserved for tri elements + // when quad_center_elements is false params.set("background_subdomain_id") = 9998; addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params); diff --git a/modules/reactor/src/meshgenerators/ReactorMeshParams.C b/modules/reactor/src/meshgenerators/ReactorMeshParams.C index 56ed46a6ec88..e9a106791e8d 100644 --- a/modules/reactor/src/meshgenerators/ReactorMeshParams.C +++ b/modules/reactor/src/meshgenerators/ReactorMeshParams.C @@ -44,8 +44,16 @@ ReactorMeshParams::validParams() "axial_mesh_intervals", "Number of elements in the Z direction for each axial region"); params.addParam("region_id_as_block_name", false, "Set block names based on region id"); - params.addParam("flexible_assembly_stitching", false, "Use FlexiblePatternGenerator for stitching dissimilar assemblies together"); - params.addRangeCheckedParam("num_sectors_at_flexible_boundary", 6, "num_sectors_at_flexible_boundary>2", "Number of sectors to use at assembly boundary interface when flexible patterning is used (Defaults to 6)"); + params.addParam( + "flexible_assembly_stitching", + false, + "Use FlexiblePatternGenerator for stitching dissimilar assemblies together"); + params.addRangeCheckedParam( + "num_sectors_at_flexible_boundary", + 6, + "num_sectors_at_flexible_boundary>2", + "Number of sectors to use at assembly boundary interface when flexible patterning is used " + "(Defaults to 6)"); params.addClassDescription("This ReactorMeshParams object acts as storage for persistent " "information about the reactor geometry."); @@ -89,9 +97,14 @@ ReactorMeshParams::ReactorMeshParams(const InputParameters & parameters) const bool flexible_assembly_stitching = getParam(RGMB::flexible_assembly_stitching); this->declareMeshProperty(RGMB::flexible_assembly_stitching, flexible_assembly_stitching); if (flexible_assembly_stitching) - this->declareMeshProperty(RGMB::num_sectors_flexible_stitching, getParam("num_sectors_at_flexible_boundary")); - if (parameters.isParamSetByUser("num_sectors_at_flexible_boundary") && !flexible_assembly_stitching) - paramWarning("num_sectors_at_flexible_boundary", "This parameter is only relevant when ReactorMeshParams/flexible_assembly_stitching is set to true. This value will be ignored"); + this->declareMeshProperty(RGMB::num_sectors_flexible_stitching, + getParam("num_sectors_at_flexible_boundary")); + if (parameters.isParamSetByUser("num_sectors_at_flexible_boundary") && + !flexible_assembly_stitching) + paramWarning( + "num_sectors_at_flexible_boundary", + "This parameter is only relevant when ReactorMeshParams/flexible_assembly_stitching is set " + "to true. This value will be ignored"); // Option to bypass mesh generation is controlled by presence of Mesh/data_driven_generator // and whether the current generator is in data only mode diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_cart.i b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_cart.i new file mode 100644 index 000000000000..f64f700c8b93 --- /dev/null +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_cart.i @@ -0,0 +1,147 @@ +[Mesh] + [rmp] + type = ReactorMeshParams + dim = 3 + geom = "Square" + assembly_pitch = 20 + flexible_assembly_stitching = true + radial_boundary_id = 200 + top_boundary_id = 201 + bottom_boundary_id = 202 + axial_regions = 1.0 + axial_mesh_intervals = 1 + region_id_as_block_name = true + [] + [het_pin_1] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 1 + pitch = 1.0 + num_sectors = 2 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '1 2' + quad_center_elements = false + [] + [het_assembly_1] + type = AssemblyMeshGenerator + assembly_type = 1 + background_intervals = 1 + background_region_id = '3' + inputs = 'het_pin_1' + pattern = '0 0; + 0 0' + [] + + [het_pin_2] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 2 + pitch = 1.0 + num_sectors = 2 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '5 6' + quad_center_elements = false + [] + [het_assembly_2] + type = AssemblyMeshGenerator + assembly_type = 2 + background_intervals = 1 + background_region_id = '7' + inputs = 'het_pin_2' + pattern = '0 0 0; + 0 0 0; + 0 0 0' + [] + + [het_pin_3] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 3 + pitch = 1.0 + num_sectors = 4 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '9 10' + quad_center_elements = false + [] + [het_assembly_3] + type = AssemblyMeshGenerator + assembly_type = 3 + background_intervals = 1 + background_region_id = '11' + inputs = 'het_pin_3' + pattern = '0 0; + 0 0' + [] + [hom_assembly] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 4 + pitch = 20 + num_sectors = 2 + mesh_intervals = '1' + region_ids = '13' + use_as_assembly = true + quad_center_elements = false + [] + [hom_assembly_single_pin] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 5 + pitch = 20 + num_sectors = 2 + ring_radii = '2' + mesh_intervals = '1 1' # Fuel, background + region_ids = '14 15' + use_as_assembly = true + quad_center_elements = false + [] + [core] + type = CoreMeshGenerator + inputs = 'het_assembly_1 het_assembly_2 het_assembly_3 hom_assembly hom_assembly_single_pin dummy' + dummy_assembly_name = dummy + pattern = '5 1 5; + 3 0 2; + 5 4 5' + extrude = true + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + num_steps = 1 +[] + +[Postprocessors] + [area_reg3] + type = VolumePostprocessor + block = "RGMB_CORE_REG3_TRI" + [] + [area_reg7] + type = VolumePostprocessor + block = "RGMB_CORE_REG7_TRI" + [] + [area_reg11] + type = VolumePostprocessor + block = "RGMB_CORE_REG11_TRI" + [] + [area_reg13] + type = VolumePostprocessor + block = "RGMB_CORE_REG13_TRI" + [] + [area_reg15] + type = VolumePostprocessor + block = "RGMB_CORE_REG15_TRI" + [] +[] + +[Outputs] + csv = true + execute_on = 'FINAL' +[] diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_hex.i b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_hex.i new file mode 100644 index 000000000000..b75f519a0dc0 --- /dev/null +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/core_flexible_assembly_stitching_hex.i @@ -0,0 +1,160 @@ +[Mesh] + [rmp] + type = ReactorMeshParams + dim = 3 + geom = "Hex" + assembly_pitch = 20 + flexible_assembly_stitching = true + radial_boundary_id = 200 + top_boundary_id = 201 + bottom_boundary_id = 202 + axial_regions = 1.0 + axial_mesh_intervals = 1 + region_id_as_block_name = true + [] + [het_pin_1] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 1 + pitch = 1.0 + num_sectors = 2 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '1 2' + quad_center_elements = false + [] + [het_assembly_1] + type = AssemblyMeshGenerator + assembly_type = 1 + background_intervals = 1 + background_region_id = '3' + duct_halfpitch = '9' + duct_intervals = '1' + duct_region_ids = '4' + inputs = 'het_pin_1' + pattern = '0 0; + 0 0 0; + 0 0' + [] + + [het_pin_2] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 2 + pitch = 1.0 + num_sectors = 2 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '5 6' + quad_center_elements = false + [] + [het_assembly_2] + type = AssemblyMeshGenerator + assembly_type = 2 + background_intervals = 1 + background_region_id = '7' + duct_halfpitch = '9' + duct_intervals = '1' + duct_region_ids = '8' + inputs = 'het_pin_2' + pattern = '0 0 0; + 0 0 0 0; + 0 0 0 0 0; + 0 0 0 0; + 0 0 0' + [] + + [het_pin_3] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 3 + pitch = 1.0 + num_sectors = 4 + ring_radii = '0.4' + mesh_intervals = '1 1' # Fuel, background + region_ids = '9 10' + quad_center_elements = false + [] + [het_assembly_3] + type = AssemblyMeshGenerator + assembly_type = 3 + background_intervals = 1 + background_region_id = '11' + duct_halfpitch = '9' + duct_intervals = '1' + duct_region_ids = '12' + inputs = 'het_pin_3' + pattern = '0 0; + 0 0 0; + 0 0' + [] + [hom_assembly] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 4 + pitch = 20 + region_ids = '13' + homogenized = true + use_as_assembly = true + quad_center_elements = false + [] + [hom_assembly_single_pin] + type = PinMeshGenerator + reactor_params = rmp + pin_type = 5 + pitch = 20 + num_sectors = 2 + ring_radii = '2' + mesh_intervals = '1 1' # Fuel, background + region_ids = '14 15' + use_as_assembly = true + quad_center_elements = false + [] + [core] + type = CoreMeshGenerator + inputs = 'het_assembly_1 het_assembly_2 het_assembly_3 hom_assembly hom_assembly_single_pin dummy' + dummy_assembly_name = dummy + pattern = ' + 1 2; + 5 0 3; + 5 4' + extrude = true + [] +[] + +[Problem] + solve = false +[] + +[Executioner] + type = Transient + num_steps = 1 +[] + +[Postprocessors] + [area_reg4] + type = VolumePostprocessor + block = "RGMB_CORE_REG4_TRI" + [] + [area_reg9] + type = VolumePostprocessor + block = "RGMB_CORE_REG9_TRI" + [] + [area_reg12] + type = VolumePostprocessor + block = "RGMB_CORE_REG12_TRI" + [] + [area_reg13] + type = VolumePostprocessor + block = "RGMB_CORE_REG13_TRI" + [] + [area_reg15] + type = VolumePostprocessor + block = "RGMB_CORE_REG15_TRI" + [] +[] + +[Outputs] + csv = true + execute_on = 'FINAL' +[] diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_cart_out.csv b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_cart_out.csv new file mode 100644 index 000000000000..05944b4ac4b0 --- /dev/null +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_cart_out.csv @@ -0,0 +1,2 @@ +time,area_reg11,area_reg13,area_reg15,area_reg3,area_reg7 +1,396,400,387.43362938564,396,391 diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_hex_out.csv b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_hex_out.csv new file mode 100644 index 000000000000..1f8c6237ed84 --- /dev/null +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_flexible_assembly_stitching_hex_out.csv @@ -0,0 +1,2 @@ +time,area_reg12,area_reg13,area_reg15,area_reg4,area_reg9 +1,65.817930687617,346.41016151378,333.84379089942,65.817930687617,3.5185837720206 diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_2d_datadriven_out.json b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_2d_datadriven_out.json index 5bc23c9b8989..0bd2b6aa10e9 100644 --- a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_2d_datadriven_out.json +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_2d_datadriven_out.json @@ -211,6 +211,10 @@ "type": "bool", "value": true }, + "MeshMetaData/rmp/flexible_assembly_stitching": { + "type": "bool", + "value": false + }, "MeshMetaData/rmp/mesh_dimensions": { "type": "int", "value": 2 diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_datadriven_out.json b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_datadriven_out.json index 82a5475697cb..dcf804568440 100644 --- a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_datadriven_out.json +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_hex_datadriven_out.json @@ -503,6 +503,10 @@ "type": "bool", "value": true }, + "MeshMetaData/rmp/flexible_assembly_stitching": { + "type": "bool", + "value": false + }, "MeshMetaData/rmp/mesh_dimensions": { "type": "int", "value": 3 diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_square_datadriven_out.json b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_square_datadriven_out.json index 131513862151..8abe8cbf885d 100644 --- a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_square_datadriven_out.json +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/gold/core_square_datadriven_out.json @@ -405,6 +405,10 @@ "type": "bool", "value": true }, + "MeshMetaData/rmp/flexible_assembly_stitching": { + "type": "bool", + "value": false + }, "MeshMetaData/rmp/mesh_dimensions": { "type": "int", "value": 3 diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests index 449e1f73b4f1..cd69cd553941 100755 --- a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests @@ -36,7 +36,7 @@ Outputs/json_out/file_base=core_square_datadriven_out' jsondiff = 'core_square_datadriven_out.json' # Ignoring data that is only generated when the mesh is actually constructed, to compare with data-driven - ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries' + ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries|flexible_assembly_stitching' recover = false allow_test_objects = true [] @@ -155,7 +155,7 @@ Outputs/json_out/file_base=core_hex_datadriven_out' jsondiff = 'core_hex_datadriven_out.json' # Ignoring data that is only generated when the mesh is actually constructed, to compare with data-driven - ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries' + ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries|flexible_assembly_stitching' recover = false allow_test_objects = true [] @@ -252,7 +252,7 @@ Outputs/json_out/file_base=core_hex_2d_datadriven_out' jsondiff = 'core_hex_2d_datadriven_out.json' # Ignoring data that is only generated when the mesh is actually constructed, to compare with data-driven - ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries' + ignored_regex_items = '.*/.*/.*_meta|flat_side_up|control_drum_angles|control_drum_positions|quad_center_block_id|pin_block_name_map|pin_region_id_map|position_file_name|peripheral_modifier_compatible|pattern_size|.*_trimmability|name_id_map|bypass_meshgen|interface_boundary_ids|interface_boundaries|flexible_assembly_stitching' recover = false allow_test_objects = true [] @@ -316,4 +316,26 @@ exodiff = 'core_hex_depl_pin_type_in.e' recover = false [] + [flexible_stitching_hex] + requirement = 'The system shall generate a 3D hexagonal core mesh with flexible assembly patterning that avoids hanging nodes at assembly interfaces' + type = 'CSVDiff' + input = 'core_flexible_assembly_stitching_hex.i' + csvdiff = 'core_flexible_assembly_stitching_hex_out.csv' + recover = false + [] + [flexible_stitching_cart] + requirement = 'The system shall generate a 3D Cartesian core mesh with flexible assembly patterning that avoids hanging nodes at assembly interfaces' + type = 'CSVDiff' + input = 'core_flexible_assembly_stitching_cart.i' + csvdiff = 'core_flexible_assembly_stitching_cart_out.csv' + recover = false + [] + [flexible_stitching_modify_num_sectors] + requirement = 'The system shall generate a 3D core mesh with the number of sectors at the assembly boundary being set by the user' + type = 'CSVDiff' + input = 'core_flexible_assembly_stitching_hex.i' + cli_args = "Mesh/rmp/num_sectors_at_flexible_boundary=3" + csvdiff = 'core_flexible_assembly_stitching_hex_out.csv' + recover = false + [] [] From 76527dd5b166733a8956b64c4d5972b92279fd19 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 10:03:49 -0400 Subject: [PATCH 3/9] Change external boundary variables into class attributes --- .../meshgenerators/FlexiblePatternGenerator.h | 5 +++ .../meshgenerators/FlexiblePatternGenerator.C | 41 +++++++++++-------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/modules/reactor/include/meshgenerators/FlexiblePatternGenerator.h b/modules/reactor/include/meshgenerators/FlexiblePatternGenerator.h index 4cc100f0b7fe..c6250331ab10 100644 --- a/modules/reactor/include/meshgenerators/FlexiblePatternGenerator.h +++ b/modules/reactor/include/meshgenerators/FlexiblePatternGenerator.h @@ -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 * _build_mesh; diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 8a850815653e..79e8364ba259 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -206,7 +206,14 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param ? getParam("background_subdomain_name") : SubdomainName()), _delete_default_external_boundary_from_inputs( - getParam("delete_default_external_boundary_from_inputs")) + getParam("delete_default_external_boundary_from_inputs")), + _external_boundary_id(isParamValid("external_boundary_id") + ? getParam("external_boundary_id") + : OUTER_SIDESET_ID), + _external_boundary_name(isParamValid("external_boundary_name") + ? getParam("external_boundary_name") + : "") + { declareMeshesForSub("inputs"); @@ -556,24 +563,22 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param std::unique_ptr FlexiblePatternGenerator::generate() { - const auto external_boundary_id = - isParamValid("external_boundary_id") ? getParam("external_boundary_id") : 0; - const auto external_boundary_name = - isParamValid("external_boundary_name") ? getParam("external_boundary_name") : ""; - if (external_boundary_id > 0) - MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, external_boundary_id, false); - if (!external_boundary_name.empty()) + MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false); + if (!_external_boundary_name.empty()) { - (*_build_mesh) - ->get_boundary_info() - .sideset_name(external_boundary_id > 0 ? external_boundary_id - : (boundary_id_type)OUTER_SIDESET_ID) = - external_boundary_name; - (*_build_mesh) - ->get_boundary_info() - .nodeset_name(external_boundary_id > 0 ? external_boundary_id - : (boundary_id_type)OUTER_SIDESET_ID) = - external_boundary_name; + // Check if _external_boundary_name has been assigned to another boundary id + const auto external_id_by_name = + (*_build_mesh)->get_boundary_info().get_id_by_name(_external_boundary_name); + if ((external_id_by_name != Moose::INVALID_BOUNDARY_ID) && + (external_id_by_name != _external_boundary_id)) + mooseError("External boundary name " + _external_boundary_name + " is associated with id " + + std::to_string(external_id_by_name) + ", which differs from " + + std::to_string(_external_boundary_id)); + + (*_build_mesh)->get_boundary_info().sideset_name(_external_boundary_id) = + _external_boundary_name; + (*_build_mesh)->get_boundary_info().nodeset_name(_external_boundary_id) = + _external_boundary_name; } (*_build_mesh)->find_neighbors(); (*_build_mesh)->set_isnt_prepared(); From c2e26677a1ffbf94160d5ecf2ec567ca51a04e4b Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 10:56:20 -0400 Subject: [PATCH 4/9] Minor updates to input parameter datatypes --- .../reactor/src/meshgenerators/AssemblyMeshGenerator.C | 6 +++--- .../reactor/src/meshgenerators/FlexiblePatternGenerator.C | 5 +++-- modules/reactor/src/meshgenerators/PinMeshGenerator.C | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C index 42ed71ef94fd..274cef66dbea 100644 --- a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C @@ -322,7 +322,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) } params.set("external_boundary_id") = _assembly_boundary_id; - params.set("external_boundary_name") = _assembly_boundary_name; + params.set("external_boundary_name") = _assembly_boundary_name; addMeshSubgenerator(patterned_mg_name, name() + "_pattern", params); @@ -528,9 +528,9 @@ AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries() params.set("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN"; params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); - params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); + params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); params.set("external_boundary_id") = _assembly_boundary_id; - params.set("external_boundary_name") = _assembly_boundary_name; + params.set("external_boundary_name") = _assembly_boundary_name; params.set("background_subdomain_name") = block_to_delete + "_TRI"; params.set("background_subdomain_id") = 19999; diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 79e8364ba259..db9969c6daf3 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -122,8 +122,9 @@ FlexiblePatternGenerator::validParams() params.addParam( "external_boundary_id", "The boundary id of the external boundary in addition to the default 10000."); - params.addParam( - "external_boundary_name", std::string(), "Optional boundary name for the external boundary."); + params.addParam("external_boundary_name", + BoundaryName(), + "Optional boundary name for the external boundary."); params.addParam("delete_default_external_boundary_from_inputs", true, diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index 80bfc416b087..3b5b28e1b24a 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -214,7 +214,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) params.set("external_boundary_id") = 20000 + _pin_type; const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) : "outer_pin_" + std::to_string(_pin_type); - params.set("external_boundary_name") = boundary_name; + params.set("external_boundary_name") = boundary_name; params.set>("block_id") = {_quad_center ? pin_block_id_start : pin_block_id_tri}; params.set("element_type") = _quad_center ? "QUAD" : "TRI"; @@ -340,7 +340,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) params.set("external_boundary_id") = 20000 + _pin_type; const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) : "outer_pin_" + std::to_string(_pin_type); - params.set("external_boundary_name") = boundary_name; + params.set("external_boundary_name") = boundary_name; bool flat_side_up = (_mesh_geometry == "Square"); params.set("flat_side_up") = flat_side_up; params.set("create_outward_interface_boundaries") = false; @@ -521,9 +521,9 @@ PinMeshGenerator::generateFlexibleAssemblyBoundaries() params.set("boundary_type") = (_mesh_geometry == "Hex") ? "HEXAGON" : "CARTESIAN"; params.set("boundary_sectors") = getReactorParam(RGMB::num_sectors_flexible_stitching); - params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); + params.set("boundary_size") = getReactorParam(RGMB::assembly_pitch); params.set("external_boundary_id") = 20000 + _pin_type; - params.set("external_boundary_name") = + params.set("external_boundary_name") = "outer_assembly_" + std::to_string(_pin_type); params.set("background_subdomain_name") = outermost_block_name + "_TRI"; // Allocate block ID 9998 for triangulated outer region, since 9999 is reserved for tri elements From a12b84c229134061ff12a535150f07049a07bb07 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 11:11:31 -0400 Subject: [PATCH 5/9] Minor documentation updates --- .../doc/content/source/meshgenerators/CoreMeshGenerator.md | 4 ++-- .../doc/content/source/meshgenerators/ReactorMeshParams.md | 2 +- modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C | 4 ++-- modules/reactor/src/meshgenerators/PinMeshGenerator.C | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md index 6b5cc8c41984..7e0c3386a963 100644 --- a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md +++ b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md @@ -37,13 +37,13 @@ If the core is extruded to three dimensions the top-most boundary ID must be ass ## 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 situtations are identified as scenarios where such hanging nodes can occur between stitched assemblies: +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 of 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 provided above: +`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%; diff --git a/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md b/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md index 2dc4c33d7f5e..a9a6a63b5357 100644 --- a/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md +++ b/modules/reactor/doc/content/source/meshgenerators/ReactorMeshParams.md @@ -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). 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). +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 diff --git a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C index 274cef66dbea..5ddbb3a1159e 100644 --- a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C @@ -362,7 +362,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) } // Modify outermost mesh interval to enable flexible assembly stitching - auto use_flexible_stitching = getReactorParam(RGMB::flexible_assembly_stitching); + const auto use_flexible_stitching = getReactorParam(RGMB::flexible_assembly_stitching); if (use_flexible_stitching) { generateFlexibleAssemblyBoundaries(); @@ -518,7 +518,7 @@ AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries() addMeshSubgenerator("BlockDeletionGenerator", name() + "_del_outer", params); } { - // Invoke FlexiblePatternGenerator to triangulate deleted mesh interval + // Invoke FlexiblePatternGenerator to triangulate deleted mesh region auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator"); params.set>("inputs") = {name() + "_del_outer"}; diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index 3b5b28e1b24a..45fa0ef809e9 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -204,7 +204,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) if (_homogenized) { // If flexible assembly stitching is invoked and this is a homogeneous assembly mesh, do not - // call mesh subgenerators here The homogeneous assembly mesh should be created entirely in + // call mesh subgenerators here. The homogeneous assembly mesh should be created entirely in // generateFlexibleAssemblyBoundaries() bool skip_assembly_generation = _is_assembly && use_flexible_stitching; From c3e88302181f5f1ceb235c66c193770e00861a2e Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 12:17:16 -0400 Subject: [PATCH 6/9] Add descriptions of assembly names if dissimlar assemblies detected --- .../meshgenerators/FlexiblePatternGenerator.md | 4 +++- .../src/meshgenerators/CoreMeshGenerator.C | 17 +++++++++++++---- .../meshgenerators/FlexiblePatternGenerator.C | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md b/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md index b27f083e3a88..1bec42b7bada 100644 --- a/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md +++ b/modules/reactor/doc/content/source/meshgenerators/FlexiblePatternGenerator.md @@ -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 and name for the external boundary by using [!param](/Mesh/FlexiblePatternGenerator/external_boundary_id) and [!param](/Mesh/FlexiblePatternGenerator/external_boundary_name), respectively. +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). diff --git a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C index 1d34e7186748..23b021060a1b 100644 --- a/modules/reactor/src/meshgenerators/CoreMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/CoreMeshGenerator.C @@ -632,7 +632,6 @@ CoreMeshGenerator::constituentAssembliesNeedFlexibleStiching() { MeshGeneratorName first_nondummy_assembly = ""; bool assembly_homogenization = false; - bool pin_as_assembly = false; unsigned int n_constituent_pins = 0; unsigned int n_pin_sectors = 0; @@ -685,20 +684,30 @@ CoreMeshGenerator::constituentAssembliesNeedFlexibleStiching() { first_nondummy_assembly = MeshGeneratorName(_inputs[i]); assembly_homogenization = getMeshProperty(RGMB::is_homogenized, _inputs[i]); - pin_as_assembly = getMeshProperty(RGMB::is_single_pin, _inputs[i]); n_constituent_pins = total_pins; n_pin_sectors = pin_sectors_per_side; } else { if (getMeshProperty(RGMB::is_homogenized, _inputs[i]) != assembly_homogenization) + { + mooseWarning("Detected mix of homogenized and heterogeneous assemblies between " + + first_nondummy_assembly + " and " + _inputs[i]); return true; - if (getMeshProperty(RGMB::is_single_pin, _inputs[i]) != pin_as_assembly) - return true; + } if (total_pins != n_constituent_pins) + { + mooseWarning( + "Detected assemblies with different number of total constituent pins between " + + first_nondummy_assembly + " and " + _inputs[i]); return true; + } if (pin_sectors_per_side != n_pin_sectors) + { + mooseWarning("Constituent pins in " + first_nondummy_assembly + " and " + _inputs[i] + + " differ in terms of number of sectors per side"); return true; + } } } return false; diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index db9969c6daf3..3e321bcbd120 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -210,7 +210,7 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param getParam("delete_default_external_boundary_from_inputs")), _external_boundary_id(isParamValid("external_boundary_id") ? getParam("external_boundary_id") - : OUTER_SIDESET_ID), + : (boundary_id_type)OUTER_SIDESET_ID), _external_boundary_name(isParamValid("external_boundary_name") ? getParam("external_boundary_name") : "") From 0b3da71f17cf9471af6c85b1c41585962ed85319 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 13:07:09 -0400 Subject: [PATCH 7/9] Move default block id values to RGMB base header file --- .../ReactorGeometryMeshBuilderBase.h | 7 +++++ .../meshgenerators/AssemblyMeshGenerator.C | 9 +++---- .../meshgenerators/FlexiblePatternGenerator.C | 2 +- .../src/meshgenerators/PinMeshGenerator.C | 27 +++++++------------ 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h b/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h index 2a67079a09e1..422af947452b 100644 --- a/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h +++ b/modules/reactor/include/meshgenerators/ReactorGeometryMeshBuilderBase.h @@ -59,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; } /** diff --git a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C index 5ddbb3a1159e..288ceb8d6652 100644 --- a/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/AssemblyMeshGenerator.C @@ -290,14 +290,13 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) params.set>>("pattern") = _pattern; params.set("create_outward_interface_boundaries") = false; - unsigned int assembly_block_id_start = 20000; if (_background_intervals > 0) { params.set("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("background_block_id") = background_block_id; params.set("background_block_name") = background_block_name; } @@ -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); } @@ -322,7 +321,7 @@ AssemblyMeshGenerator::AssemblyMeshGenerator(const InputParameters & parameters) } params.set("external_boundary_id") = _assembly_boundary_id; - params.set("external_boundary_name") = _assembly_boundary_name; + params.set("external_boundary_name") = _assembly_boundary_name; addMeshSubgenerator(patterned_mg_name, name() + "_pattern", params); @@ -532,7 +531,7 @@ AssemblyMeshGenerator::generateFlexibleAssemblyBoundaries() params.set("external_boundary_id") = _assembly_boundary_id; params.set("external_boundary_name") = _assembly_boundary_name; params.set("background_subdomain_name") = block_to_delete + "_TRI"; - params.set("background_subdomain_id") = 19999; + params.set("background_subdomain_id") = RGMB::ASSEMBLY_BLOCK_ID_TRI_FLEXIBLE; addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params); } diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 3e321bcbd120..697eb595cca4 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -212,7 +212,7 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param ? getParam("external_boundary_id") : (boundary_id_type)OUTER_SIDESET_ID), _external_boundary_name(isParamValid("external_boundary_name") - ? getParam("external_boundary_name") + ? getParam("external_boundary_name") : "") { diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index 45fa0ef809e9..beae4b3967c7 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -190,11 +190,6 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) else _has_block_names = false; - // Initial block id used to define radial regions of pin - subdomain_id_type pin_block_id_start = 10000; - // Use special block id to designate TRI elements - subdomain_id_type pin_block_id_tri = pin_block_id_start - 1; - const auto use_flexible_stitching = getReactorParam(RGMB::flexible_assembly_stitching); std::string build_mesh_name; @@ -214,9 +209,9 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) params.set("external_boundary_id") = 20000 + _pin_type; const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) : "outer_pin_" + std::to_string(_pin_type); - params.set("external_boundary_name") = boundary_name; - params.set>("block_id") = {_quad_center ? pin_block_id_start - : pin_block_id_tri}; + params.set("external_boundary_name") = boundary_name; + params.set>("block_id") = { + _quad_center ? RGMB::PIN_BLOCK_ID_START : RGMB::PIN_BLOCK_ID_TRI}; params.set("element_type") = _quad_center ? "QUAD" : "TRI"; auto block_name = "RGMB_PIN" + std::to_string(_pin_type) + "_R0"; if (!_quad_center) @@ -245,7 +240,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) for (const auto i : index_range(_intervals)) { const auto block_name = "RGMB_PIN" + std::to_string(_pin_type) + "_R" + std::to_string(i); - const auto block_id = pin_block_id_start + i; + const auto block_id = RGMB::PIN_BLOCK_ID_START + i; if (i < _ring_radii.size()) { @@ -281,7 +276,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) else { const auto block_name = ring_blk_names.front() + "_TRI"; - const auto block_id = pin_block_id_tri; + const auto block_id = RGMB::PIN_BLOCK_ID_TRI; ring_blk_ids.insert(ring_blk_ids.begin(), block_id); ring_blk_names.insert(ring_blk_names.begin(), block_name); } @@ -289,7 +284,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) // Add _TRI suffix if only one radial region and tri center elements else if (!_quad_center) { - ring_blk_ids[0] = pin_block_id_tri; + ring_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI; ring_blk_names[0] += "_TRI"; } } @@ -308,7 +303,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) else { const auto block_name = background_blk_names.front() + "_TRI"; - const auto block_id = pin_block_id_tri; + const auto block_id = RGMB::PIN_BLOCK_ID_TRI; background_blk_ids.insert(background_blk_ids.begin(), block_id); background_blk_names.insert(background_blk_names.begin(), block_name); } @@ -317,7 +312,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) // and no ring regions else if (!_quad_center) { - background_blk_ids[0] = pin_block_id_tri; + background_blk_ids[0] = RGMB::PIN_BLOCK_ID_TRI; background_blk_names[0] += "_TRI"; } } @@ -340,7 +335,7 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) params.set("external_boundary_id") = 20000 + _pin_type; const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) : "outer_pin_" + std::to_string(_pin_type); - params.set("external_boundary_name") = boundary_name; + params.set("external_boundary_name") = boundary_name; bool flat_side_up = (_mesh_geometry == "Square"); params.set("flat_side_up") = flat_side_up; params.set("create_outward_interface_boundaries") = false; @@ -526,9 +521,7 @@ PinMeshGenerator::generateFlexibleAssemblyBoundaries() params.set("external_boundary_name") = "outer_assembly_" + std::to_string(_pin_type); params.set("background_subdomain_name") = outermost_block_name + "_TRI"; - // Allocate block ID 9998 for triangulated outer region, since 9999 is reserved for tri elements - // when quad_center_elements is false - params.set("background_subdomain_id") = 9998; + params.set("background_subdomain_id") = RGMB::PIN_BLOCK_ID_TRI_FLEXIBLE; addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params); } From ba8d53fefe5d3fc71a5a1934c013c583a377fade Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Mon, 29 Jul 2024 19:34:11 -0400 Subject: [PATCH 8/9] Address replicated tests --- .../reactor/src/meshgenerators/FlexiblePatternGenerator.C | 6 +++--- .../test/tests/meshgenerators/core_mesh_generator/tests | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 697eb595cca4..1341e7f4305a 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -123,7 +123,6 @@ FlexiblePatternGenerator::validParams() "external_boundary_id", "The boundary id of the external boundary in addition to the default 10000."); params.addParam("external_boundary_name", - BoundaryName(), "Optional boundary name for the external boundary."); params.addParam("delete_default_external_boundary_from_inputs", @@ -213,7 +212,7 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param : (boundary_id_type)OUTER_SIDESET_ID), _external_boundary_name(isParamValid("external_boundary_name") ? getParam("external_boundary_name") - : "") + : BoundaryName()) { declareMeshesForSub("inputs"); @@ -564,7 +563,8 @@ FlexiblePatternGenerator::FlexiblePatternGenerator(const InputParameters & param std::unique_ptr FlexiblePatternGenerator::generate() { - MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false); + if (_external_boundary_id != OUTER_SIDESET_ID) + MooseMesh::changeBoundaryId(**_build_mesh, OUTER_SIDESET_ID, _external_boundary_id, false); if (!_external_boundary_name.empty()) { // Check if _external_boundary_name has been assigned to another boundary id diff --git a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests index cd69cd553941..2434f5fc56b6 100755 --- a/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests +++ b/modules/reactor/test/tests/meshgenerators/core_mesh_generator/tests @@ -322,6 +322,7 @@ input = 'core_flexible_assembly_stitching_hex.i' csvdiff = 'core_flexible_assembly_stitching_hex_out.csv' recover = false + mesh_mode = REPLICATED [] [flexible_stitching_cart] requirement = 'The system shall generate a 3D Cartesian core mesh with flexible assembly patterning that avoids hanging nodes at assembly interfaces' @@ -329,6 +330,7 @@ input = 'core_flexible_assembly_stitching_cart.i' csvdiff = 'core_flexible_assembly_stitching_cart_out.csv' recover = false + mesh_mode = REPLICATED [] [flexible_stitching_modify_num_sectors] requirement = 'The system shall generate a 3D core mesh with the number of sectors at the assembly boundary being set by the user' @@ -337,5 +339,6 @@ cli_args = "Mesh/rmp/num_sectors_at_flexible_boundary=3" csvdiff = 'core_flexible_assembly_stitching_hex_out.csv' recover = false + mesh_mode = REPLICATED [] [] From 3e3e0c908428a2f205befaaa2b2181f9c98084ad Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Sun, 4 Aug 2024 12:32:25 -0400 Subject: [PATCH 9/9] Move skip_assembly_generation to outer loop --- .../meshgenerators/CoreMeshGenerator.md | 2 +- .../meshgenerators/FlexiblePatternGenerator.C | 8 +- .../src/meshgenerators/PinMeshGenerator.C | 113 +++++++++--------- 3 files changed, 65 insertions(+), 58 deletions(-) diff --git a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md index 7e0c3386a963..a28985f638b6 100644 --- a/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md +++ b/modules/reactor/doc/content/source/meshgenerators/CoreMeshGenerator.md @@ -41,7 +41,7 @@ By default, `CoreMeshGenerator` will stitch assemblies created by [`AssemblyMesh 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 of more pins), and the other assembly is homogenized. +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: diff --git a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C index 1341e7f4305a..a18424721e87 100644 --- a/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C +++ b/modules/reactor/src/meshgenerators/FlexiblePatternGenerator.C @@ -572,9 +572,11 @@ FlexiblePatternGenerator::generate() (*_build_mesh)->get_boundary_info().get_id_by_name(_external_boundary_name); if ((external_id_by_name != Moose::INVALID_BOUNDARY_ID) && (external_id_by_name != _external_boundary_id)) - mooseError("External boundary name " + _external_boundary_name + " is associated with id " + - std::to_string(external_id_by_name) + ", which differs from " + - std::to_string(_external_boundary_id)); + paramError("external_boundary_name", + "External boundary name " + _external_boundary_name + + " is already associated with id " + std::to_string(external_id_by_name) + + ", which differs from the user-specified external_boundary_id " + + std::to_string(_external_boundary_id)); (*_build_mesh)->get_boundary_info().sideset_name(_external_boundary_id) = _external_boundary_name; diff --git a/modules/reactor/src/meshgenerators/PinMeshGenerator.C b/modules/reactor/src/meshgenerators/PinMeshGenerator.C index beae4b3967c7..78ed12e19465 100644 --- a/modules/reactor/src/meshgenerators/PinMeshGenerator.C +++ b/modules/reactor/src/meshgenerators/PinMeshGenerator.C @@ -318,73 +318,72 @@ PinMeshGenerator::PinMeshGenerator(const InputParameters & parameters) } // If flexible assembly stitching is invoked and this is an assembly mesh with only a - // background region, do not call mesh subgenerators here This assembly mesh should be created - // entirely in generateFlexibleAssemblyBoundaries() + // background region, do not call mesh subgenerators here. This assembly mesh should be + // created entirely in generateFlexibleAssemblyBoundaries() bool skip_assembly_generation = _is_assembly && use_flexible_stitching && _intervals.size() == 1; - // Generate Cartesian/hex pin using PolygonConcentricCircleMeshGenerator + if (!skip_assembly_generation) { - // Get and assign parameters for the main geometry feature of the Pin - // which is created with a PolygonConcentricCircleMeshGenerator subgenerator - auto params = _app.getFactory().getValidParams("PolygonConcentricCircleMeshGenerator"); - params.set("preserve_volumes") = true; - params.set("quad_center_elements") = _quad_center; - params.set("polygon_size_style") = "apothem"; - params.set("polygon_size") = _pitch / 2.0; - params.set("external_boundary_id") = 20000 + _pin_type; - const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) - : "outer_pin_" + std::to_string(_pin_type); - params.set("external_boundary_name") = boundary_name; - bool flat_side_up = (_mesh_geometry == "Square"); - params.set("flat_side_up") = flat_side_up; - params.set("create_outward_interface_boundaries") = false; - - const auto num_sides = (_mesh_geometry == "Square") ? 4 : 6; - params.set("num_sides") = num_sides; - params.set>("num_sectors_per_side") = - std::vector(num_sides, _num_sectors); - - if (ring_intervals.size() > 0) + // Generate Cartesian/hex pin using PolygonConcentricCircleMeshGenerator { - params.set>("ring_radii") = _ring_radii; - params.set>("ring_block_ids") = ring_blk_ids; - params.set>("ring_block_names") = ring_blk_names; - params.set>("ring_intervals") = ring_intervals; - } + // Get and assign parameters for the main geometry feature of the Pin + // which is created with a PolygonConcentricCircleMeshGenerator subgenerator + auto params = _app.getFactory().getValidParams("PolygonConcentricCircleMeshGenerator"); + params.set("preserve_volumes") = true; + params.set("quad_center_elements") = _quad_center; + params.set("polygon_size_style") = "apothem"; + params.set("polygon_size") = _pitch / 2.0; + params.set("external_boundary_id") = 20000 + _pin_type; + const auto boundary_name = _is_assembly ? "outer_assembly_" + std::to_string(_pin_type) + : "outer_pin_" + std::to_string(_pin_type); + params.set("external_boundary_name") = boundary_name; + bool flat_side_up = (_mesh_geometry == "Square"); + params.set("flat_side_up") = flat_side_up; + params.set("create_outward_interface_boundaries") = false; + + const auto num_sides = (_mesh_geometry == "Square") ? 4 : 6; + params.set("num_sides") = num_sides; + params.set>("num_sectors_per_side") = + std::vector(num_sides, _num_sectors); + + if (ring_intervals.size() > 0) + { + params.set>("ring_radii") = _ring_radii; + params.set>("ring_block_ids") = ring_blk_ids; + params.set>("ring_block_names") = ring_blk_names; + params.set>("ring_intervals") = ring_intervals; + } - params.set>("background_block_ids") = background_blk_ids; - params.set>("background_block_names") = background_blk_names; - params.set("background_intervals") = background_intervals; + params.set>("background_block_ids") = background_blk_ids; + params.set>("background_block_names") = background_blk_names; + params.set("background_intervals") = background_intervals; - if (duct_intervals.size() > 0) - { - params.set("duct_sizes_style") = "apothem"; - params.set>("duct_sizes") = _duct_halfpitch; - params.set>("duct_block_ids") = duct_blk_ids; - params.set>("duct_block_names") = duct_blk_names; - params.set>("duct_intervals") = duct_intervals; - } + if (duct_intervals.size() > 0) + { + params.set("duct_sizes_style") = "apothem"; + params.set>("duct_sizes") = _duct_halfpitch; + params.set>("duct_block_ids") = duct_blk_ids; + params.set>("duct_block_names") = duct_blk_names; + params.set>("duct_intervals") = duct_intervals; + } - if (!skip_assembly_generation) addMeshSubgenerator("PolygonConcentricCircleMeshGenerator", name() + "_2D", params); - } + } - // Remove extra sidesets created by PolygonConcentricCircleMeshGenerator - { - auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator"); + // Remove extra sidesets created by PolygonConcentricCircleMeshGenerator + { + auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator"); - params.set("input") = name() + "_2D"; + params.set("input") = name() + "_2D"; - auto num_sides = (_mesh_geometry == "Square") ? 4 : 6; - std::vector boundaries_to_delete = {}; - for (const auto i : make_range(num_sides)) - boundaries_to_delete.insert(boundaries_to_delete.end(), - {std::to_string(10001 + i), std::to_string(15001 + i)}); - params.set>("boundary_names") = boundaries_to_delete; + auto num_sides = (_mesh_geometry == "Square") ? 4 : 6; + std::vector boundaries_to_delete = {}; + for (const auto i : make_range(num_sides)) + boundaries_to_delete.insert(boundaries_to_delete.end(), + {std::to_string(10001 + i), std::to_string(15001 + i)}); + params.set>("boundary_names") = boundaries_to_delete; - if (!skip_assembly_generation) - { build_mesh_name = name() + "_delbds"; addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params); } @@ -641,9 +640,15 @@ PinMeshGenerator::generate() { const auto max_radius_meta = getMeshProperty("max_radius_meta", name() + "_2D"); setMeshProperty("max_radius_meta", max_radius_meta); + } + if (hasMeshProperty("background_intervals_meta", name() + "_2D")) + { const auto background_intervals_meta = getMeshProperty("background_intervals_meta", name() + "_2D"); setMeshProperty("background_intervals_meta", background_intervals_meta); + } + if (hasMeshProperty("node_id_background_meta", name() + "_2D")) + { const auto node_id_background_meta = getMeshProperty("node_id_background_meta", name() + "_2D"); setMeshProperty("node_id_background_meta", node_id_background_meta);