LCOV - code coverage report
Current view: top level - src/meshgenerators - ControlDrumMeshGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 218 232 94.0 %
Date: 2025-09-04 07:56:24 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "ControlDrumMeshGenerator.h"
      11             : 
      12             : #include "ReactorGeometryMeshBuilderBase.h"
      13             : #include "PolygonalMeshGenerationUtils.h"
      14             : #include "MooseApp.h"
      15             : #include "Factory.h"
      16             : #include "libmesh/elem.h"
      17             : #include "MooseMeshUtils.h"
      18             : #include "PolygonMeshGeneratorBase.h"
      19             : 
      20             : registerMooseObject("ReactorApp", ControlDrumMeshGenerator);
      21             : 
      22             : InputParameters
      23         178 : ControlDrumMeshGenerator::validParams()
      24             : {
      25         178 :   auto params = ReactorGeometryMeshBuilderBase::validParams();
      26             : 
      27         356 :   params.addRequiredParam<MeshGeneratorName>(
      28             :       "reactor_params",
      29             :       "The ReactorMeshParams MeshGenerator that is the basis for this component mesh.");
      30         356 :   params.addRequiredParam<subdomain_id_type>(
      31             :       "assembly_type",
      32             :       "The assembly type integer ID to use for this control drum definition. "
      33             :       "This parameter should be uniquely defined for each ControlDrumMeshGenerator "
      34             :       "and AssemblyMeshGenerator structure in the RGMB workflow.");
      35         356 :   params.addParam<bool>("extrude",
      36         356 :                         false,
      37             :                         "Determines if this is the final step in the geometry construction"
      38             :                         " and extrudes the 2D geometry to 3D. If this is true then this mesh "
      39             :                         "cannot be used in further mesh building in the Reactor workflow");
      40         356 :   params.addRequiredRangeCheckedParam<Real>(
      41             :       "drum_inner_radius", "drum_inner_radius>0", "Inner radius of drum region");
      42         356 :   params.addRequiredRangeCheckedParam<Real>(
      43             :       "drum_outer_radius", "drum_outer_radius>0", "Outer radius of drum region");
      44         534 :   params.addRangeCheckedParam<unsigned int>(
      45             :       "drum_inner_intervals",
      46         356 :       1,
      47             :       "drum_inner_intervals>0",
      48             :       "Number of radial mesh intervals in region up to inner drum radius");
      49         534 :   params.addRangeCheckedParam<unsigned int>(
      50         356 :       "drum_intervals", 1, "drum_intervals>0", "Number of radial mesh intervals in drum region");
      51         356 :   params.addRangeCheckedParam<Real>("pad_start_angle",
      52             :                                     "pad_start_angle>=0 & pad_start_angle < 360",
      53             :                                     "Starting angle of drum pad region");
      54         356 :   params.addRangeCheckedParam<Real>(
      55             :       "pad_end_angle", "pad_end_angle>0 & pad_end_angle < 720", "Ending angle of drum pad region");
      56         356 :   params.addRequiredRangeCheckedParam<unsigned int>(
      57             :       "num_azimuthal_sectors",
      58             :       "num_azimuthal_sectors>2",
      59             :       "Number of azimuthal sectors to sub-divide the drum region into");
      60         356 :   params.addRequiredParam<std::vector<std::vector<subdomain_id_type>>>(
      61             :       "region_ids",
      62             :       "IDs for each radial and axial zone for assignment of region_id extra element "
      63             :       "id. "
      64             :       "Inner indexing is radial zones (drum inner/drum/drum outer), outer indexing is axial");
      65         356 :   params.addParam<std::vector<std::vector<std::string>>>(
      66             :       "block_names",
      67             :       "Block names for each radial and axial zone. "
      68             :       "Inner indexing is radial zones (drum inner/drum/drum outer), outer indexing is axial");
      69         356 :   params.addParam<Real>("azimuthal_node_tolerance",
      70         356 :                         0.1,
      71             :                         "(in degrees) The absolute tolerance for which to shift an azimuthal node "
      72             :                         "to match the pad start/end angles");
      73             : 
      74         356 :   params.addParamNamesToGroup("region_ids assembly_type", "ID assigment");
      75         356 :   params.addParamNamesToGroup("drum_inner_radius drum_outer_radius drum_inner_intervals "
      76             :                               "drum_intervals num_azimuthal_sectors",
      77             :                               "Drum specifications");
      78         356 :   params.addParamNamesToGroup("pad_start_angle pad_end_angle azimuthal_node_tolerance",
      79             :                               "Control pad specifications");
      80             : 
      81         178 :   params.addClassDescription(
      82             :       "This ControlDrumMeshGenerator object is designed to generate "
      83             :       "drum-like structures, with IDs, from a reactor geometry. "
      84             :       "These structures can be used directly within CoreMeshGenerator to stitch"
      85             :       "control drums into a core lattice alongside AssemblyMeshGenerator structures");
      86             :   // depletion id generation params are added
      87         178 :   addDepletionIDParams(params);
      88             : 
      89         178 :   return params;
      90           0 : }
      91             : 
      92         105 : ControlDrumMeshGenerator::ControlDrumMeshGenerator(const InputParameters & parameters)
      93             :   : ReactorGeometryMeshBuilderBase(parameters),
      94         210 :     _assembly_type(getParam<subdomain_id_type>("assembly_type")),
      95         210 :     _drum_inner_radius(getParam<Real>("drum_inner_radius")),
      96         210 :     _drum_outer_radius(getParam<Real>("drum_outer_radius")),
      97         210 :     _extrude(getParam<bool>("extrude")),
      98         420 :     _region_ids(getParam<std::vector<std::vector<subdomain_id_type>>>("region_ids"))
      99             : {
     100             :   // Initialize ReactorMeshParams object
     101         315 :   initializeReactorMeshParams(getParam<MeshGeneratorName>("reactor_params"));
     102             : 
     103             :   // Flexible stitching needs to be invoked in order to create control drum mesh
     104         105 :   if (!getReactorParam<bool>(RGMB::flexible_assembly_stitching))
     105           2 :     mooseError("'flexible_assembly_stitching' needs to be set to true in ReactorMeshParams in "
     106             :                "order to use ControlDrumMeshGenerator");
     107             : 
     108         103 :   _geom_type = getReactorParam<std::string>(RGMB::mesh_geometry);
     109         103 :   _mesh_dimensions = getReactorParam<unsigned int>(RGMB::mesh_dimensions);
     110             : 
     111         206 :   const auto drum_inner_intervals = getParam<unsigned int>("drum_inner_intervals");
     112         206 :   const auto drum_intervals = getParam<unsigned int>("drum_intervals");
     113         206 :   const auto num_sectors = getParam<unsigned int>("num_azimuthal_sectors");
     114         103 :   const auto assembly_pitch = getReactorParam<Real>(RGMB::assembly_pitch);
     115             : 
     116             :   // Check drum pad parameters
     117         206 :   if (isParamSetByUser("pad_start_angle"))
     118             :   {
     119         146 :     _pad_start_angle = getParam<Real>("pad_start_angle");
     120         146 :     if (!isParamSetByUser("pad_end_angle"))
     121           2 :       paramError("pad_start_angle",
     122             :                  "If 'pad_start_angle' is set, 'pad_end_angle' needs to also be set.");
     123         142 :     _pad_end_angle = getParam<Real>("pad_end_angle");
     124             : 
     125          71 :     if ((_pad_end_angle - _pad_start_angle >= 360) || (_pad_end_angle - _pad_start_angle <= 0))
     126           4 :       paramError("pad_start_angle",
     127             :                  "The difference between 'pad_end_angle' and 'pad_start_angle' must be between 0 "
     128             :                  "and 360 exclusive.");
     129          67 :     _has_pad_region = true;
     130             :   }
     131             :   else
     132             :   {
     133          60 :     if (isParamSetByUser("pad_end_angle"))
     134           2 :       paramError("pad_end_angle",
     135             :                  "If 'pad_end_angle' is set, 'pad_start_angle' needs to also be set.");
     136          28 :     _has_pad_region = false;
     137             :   }
     138             : 
     139             :   // Error checking for azimuthal node tolerance
     140         190 :   const auto azimuthal_node_tolerance = getParam<Real>("azimuthal_node_tolerance");
     141         151 :   if (!_has_pad_region && isParamSetByUser("azimuthal_node_tolerance"))
     142           0 :     paramError("azimuthal_node_tolerance",
     143             :                "This parameter is relevant only when pad start and end angles are defined");
     144          95 :   if (_has_pad_region && MooseUtils::absoluteFuzzyGreaterEqual(2. * azimuthal_node_tolerance,
     145          67 :                                                                360. / (Real)num_sectors))
     146           2 :     paramError("azimuthal_node_tolerance",
     147             :                "Azimuthal node tolerance should be smaller than half the azimuthal interval size "
     148             :                "as defined by 'num_azimuthal_sectors'");
     149          93 :   if (_has_pad_region && MooseUtils::absoluteFuzzyGreaterEqual(2. * azimuthal_node_tolerance,
     150          65 :                                                                _pad_end_angle - _pad_start_angle))
     151           2 :     paramError("azimuthal_node_tolerance",
     152             :                "Azimuthal node tolerance should be smaller than half the difference of the pad "
     153             :                "angle range");
     154             : 
     155             :   // Check region IDs have correct size
     156          91 :   const unsigned int n_radial_regions = _has_pad_region ? 4 : 3;
     157             :   unsigned int n_axial_levels =
     158          91 :       (_mesh_dimensions == 3)
     159             :           ? getReactorParam<std::vector<unsigned int>>(RGMB::axial_mesh_intervals).size()
     160         127 :           : 1;
     161          91 :   if (_region_ids.size() != n_axial_levels)
     162           2 :     mooseError("The size of region IDs must be equal to the number of axial levels as defined in "
     163             :                "the ReactorMeshParams object");
     164          89 :   if (_region_ids[0].size() != n_radial_regions)
     165             :   {
     166             :     std::string err_msg =
     167           4 :         "'region_ids' parameter does not have the correct number of elements per axial zone. ";
     168           4 :     err_msg += _has_pad_region
     169             :                    ? "For control drums with a pad region, 4 radial IDs need to be provided per "
     170             :                      "axial zone (drum inner, drum pad, drum ex-pad, and drum outer)"
     171             :                    : "For control drums with no pad region, 3 radial IDs need to be provided per "
     172           4 :                      "axial zone (drum inner, drum, and drum outer)";
     173           4 :     paramError("region_ids", err_msg);
     174             :   }
     175             : 
     176             :   // Check block names have the correct size
     177         170 :   if (isParamValid("block_names"))
     178             :   {
     179           6 :     if (getReactorParam<bool>(RGMB::region_id_as_block_name))
     180           2 :       paramError("block_names",
     181             :                  "If ReactorMeshParams/region_id_as_block_name is set, block_names should not be "
     182             :                  "specified in ControlDrumMeshGenerator");
     183           4 :     _has_block_names = true;
     184          12 :     _block_names = getParam<std::vector<std::vector<std::string>>>("block_names");
     185           4 :     if (_region_ids.size() != _block_names.size())
     186           2 :       mooseError("The size of block_names must match the size of region_ids");
     187           2 :     for (const auto i : index_range(_region_ids))
     188           2 :       if (_region_ids[i].size() != _block_names[i].size())
     189           2 :         mooseError("The size of block_names must match the size of region_ids");
     190             :   }
     191             :   else
     192          79 :     _has_block_names = false;
     193             : 
     194             :   // Check extrusion parameters
     195          79 :   if (_extrude && _mesh_dimensions != 3)
     196           2 :     paramError("extrude",
     197             :                "In order to extrude this mesh, ReactorMeshParams/dim needs to be set to 3\n");
     198         156 :   if (_extrude && (!hasReactorParam<boundary_id_type>(RGMB::top_boundary_id) ||
     199          77 :                    !hasReactorParam<boundary_id_type>(RGMB::bottom_boundary_id)))
     200           2 :     mooseError("Both top_boundary_id and bottom_boundary_id must be provided in ReactorMeshParams "
     201             :                "if using extruded geometry");
     202             : 
     203             :   // Define azimuthal angles explicitly based on num_azimuthal_sectors and manually add pad start
     204             :   // angle and end angle if they are not contained within these angle intervals
     205             :   std::vector<Real> azimuthal_angles;
     206          75 :   const auto custom_start_angle = _has_pad_region ? _pad_start_angle : 0.;
     207          75 :   const auto custom_end_angle =
     208          75 :       _has_pad_region ? ((_pad_end_angle > 360) ? _pad_end_angle - 360. : _pad_end_angle) : 0.;
     209        7941 :   for (unsigned int i = 0; i < num_sectors; ++i)
     210             :   {
     211        7866 :     Real current_azim_angle = (Real)i * 360. / (Real)num_sectors;
     212        7866 :     Real next_azim_angle = (Real)(i + 1) * 360. / (Real)num_sectors;
     213        7866 :     if (!_has_pad_region)
     214        2172 :       azimuthal_angles.push_back(current_azim_angle);
     215             :     else
     216             :     {
     217             :       // When pad regions are involved, check if the current azimuthal node angle coincides with
     218             :       // pad start/end angle to within tolerance. If it does, then shift the azimuthal node location
     219             :       // to match the pad angle location. If it does not and the pad angle falls within the
     220             :       // azimuthal sector, then create an additional node for the pad location
     221        5694 :       if (MooseUtils::absoluteFuzzyLessEqual(std::abs(current_azim_angle - custom_start_angle),
     222             :                                              azimuthal_node_tolerance))
     223             :       {
     224          56 :         azimuthal_angles.push_back(custom_start_angle);
     225             :       }
     226        5638 :       else if (MooseUtils::absoluteFuzzyLessEqual(std::abs(current_azim_angle - custom_end_angle),
     227             :                                                   azimuthal_node_tolerance))
     228             :       {
     229          61 :         azimuthal_angles.push_back(custom_end_angle);
     230             :       }
     231        5577 :       else if (MooseUtils::absoluteFuzzyGreaterThan(custom_start_angle - current_azim_angle,
     232        5577 :                                                     azimuthal_node_tolerance) &&
     233        1426 :                MooseUtils::absoluteFuzzyGreaterThan(next_azim_angle - custom_start_angle,
     234             :                                                     azimuthal_node_tolerance))
     235             :       {
     236           5 :         mooseWarning("pad_start_angle not contained within drum azimuthal discretization so "
     237             :                      "additional azimuthal nodes are created to align mesh with this angle");
     238           5 :         azimuthal_angles.push_back(current_azim_angle);
     239           5 :         azimuthal_angles.push_back(custom_start_angle);
     240             :       }
     241        5572 :       else if (MooseUtils::absoluteFuzzyGreaterThan(custom_end_angle - current_azim_angle,
     242        5572 :                                                     azimuthal_node_tolerance) &&
     243        2786 :                MooseUtils::absoluteFuzzyGreaterThan(next_azim_angle - custom_end_angle,
     244             :                                                     azimuthal_node_tolerance))
     245             :       {
     246           0 :         mooseWarning("pad_end_angle not contained within drum azimuthal discretization so "
     247             :                      "additional azimuthal nodes are created to align mesh with this angle");
     248           0 :         azimuthal_angles.push_back(current_azim_angle);
     249           0 :         azimuthal_angles.push_back(custom_end_angle);
     250             :       }
     251             :       else
     252        5572 :         azimuthal_angles.push_back(current_azim_angle);
     253             :     }
     254             :   }
     255             : 
     256             :   // Check drum radius parameters
     257          75 :   if (_drum_inner_radius >= _drum_outer_radius)
     258           2 :     paramError("drum_outer_radius", "Drum outer radius must be larger than the inner radius");
     259             :   // Check if volume preserved radius of outer radius exceeds assembly halfpitch. In data driven
     260             :   // mode, radius is assumed not to need volume preservation
     261             :   auto radius_corrfac =
     262          73 :       getReactorParam<bool>(RGMB::bypass_meshgen)
     263          73 :           ? 1.0
     264          64 :           : PolygonalMeshGenerationUtils::radiusCorrectionFactor(azimuthal_angles);
     265          73 :   if (_drum_outer_radius * radius_corrfac >= assembly_pitch / 2.)
     266           2 :     paramError("drum_outer_radius",
     267             :                "Volume-corrected outer radius of drum region must be smaller than half the "
     268             :                "assembly pitch as "
     269             :                "defined by 'ReactorMeshParams/assembly_pitch'");
     270             : 
     271             :   // No subgenerators will be called if option to bypass mesh generators is enabled
     272          71 :   if (!getReactorParam<bool>(RGMB::bypass_meshgen))
     273             :   {
     274             :     const std::string block_name_prefix =
     275          62 :         RGMB::DRUM_BLOCK_NAME_PREFIX + std::to_string(_assembly_type);
     276             : 
     277             :     {
     278             :       // Invoke AdvancedConcentricCircleGenerator to define drum mesh without background region
     279          62 :       auto params = _app.getFactory().getValidParams("AdvancedConcentricCircleGenerator");
     280             : 
     281          62 :       params.set<std::vector<Real>>("customized_azimuthal_angles") = azimuthal_angles;
     282          62 :       params.set<std::vector<double>>("ring_radii") = {_drum_inner_radius, _drum_outer_radius};
     283          62 :       params.set<std::vector<unsigned int>>("ring_intervals") = {drum_inner_intervals,
     284         124 :                                                                  drum_intervals};
     285          62 :       if (drum_inner_intervals > 1)
     286             :       {
     287          62 :         params.set<std::vector<subdomain_id_type>>("ring_block_ids") = {
     288             :             RGMB::CONTROL_DRUM_BLOCK_ID_INNER_TRI,
     289             :             RGMB::CONTROL_DRUM_BLOCK_ID_INNER,
     290         124 :             RGMB::CONTROL_DRUM_BLOCK_ID_PAD};
     291         124 :         params.set<std::vector<SubdomainName>>("ring_block_names") = {
     292         620 :             block_name_prefix + "_R0_TRI", block_name_prefix + "_R0", block_name_prefix + "_R1"};
     293             :       }
     294             :       else
     295             :       {
     296           0 :         params.set<std::vector<subdomain_id_type>>("ring_block_ids") = {
     297           0 :             RGMB::CONTROL_DRUM_BLOCK_ID_INNER, RGMB::CONTROL_DRUM_BLOCK_ID_PAD};
     298           0 :         params.set<std::vector<SubdomainName>>("ring_block_names") = {block_name_prefix + "_R0",
     299           0 :                                                                       block_name_prefix + "_R1"};
     300             :       }
     301          62 :       params.set<bool>("create_outward_interface_boundaries") = false;
     302             : 
     303         124 :       addMeshSubgenerator("AdvancedConcentricCircleGenerator", name() + "_accg", params);
     304          62 :     }
     305             :     {
     306             :       // Invoke FlexiblePatternGenerator to triangulate drum background region
     307         124 :       auto params = _app.getFactory().getValidParams("FlexiblePatternGenerator");
     308             : 
     309         310 :       params.set<std::vector<MeshGeneratorName>>("inputs") = {name() + "_accg"};
     310          62 :       params.set<std::vector<libMesh::Point>>("extra_positions") = {libMesh::Point(0, 0, 0)};
     311          62 :       params.set<std::vector<unsigned int>>("extra_positions_mg_indices") = {0};
     312          62 :       params.set<bool>("use_auto_area_func") = true;
     313             :       // `verify_holes` is set to false to prevent false positive instances of points outside of
     314             :       // defined holes, which can create test failures on certain dev environments
     315          62 :       params.set<bool>("verify_holes") = false;
     316         139 :       params.set<MooseEnum>("boundary_type") = (_geom_type == "Hex") ? "HEXAGON" : "CARTESIAN";
     317          62 :       params.set<unsigned int>("boundary_sectors") =
     318          62 :           getReactorParam<unsigned int>(RGMB::num_sectors_flexible_stitching);
     319          62 :       params.set<Real>("boundary_size") = assembly_pitch;
     320          62 :       params.set<boundary_id_type>("external_boundary_id") =
     321          62 :           RGMB::ASSEMBLY_BOUNDARY_ID_START + _assembly_type;
     322         124 :       params.set<BoundaryName>("external_boundary_name") =
     323          62 :           RGMB::ASSEMBLY_BOUNDARY_NAME_PREFIX + std::to_string(_assembly_type);
     324         186 :       params.set<SubdomainName>("background_subdomain_name") = block_name_prefix + "_R2_TRI";
     325          62 :       params.set<subdomain_id_type>("background_subdomain_id") = RGMB::CONTROL_DRUM_BLOCK_ID_OUTER;
     326             : 
     327         124 :       addMeshSubgenerator("FlexiblePatternGenerator", name() + "_fpg", params);
     328             : 
     329             :       // Pass mesh meta-data defined in subgenerator constructor to this MeshGenerator
     330         124 :       copyMeshProperty<bool>("is_control_drum_meta", name() + "_fpg");
     331         124 :       copyMeshProperty<Real>("pattern_pitch_meta", name() + "_fpg");
     332          62 :     }
     333          62 :     std::string build_mesh_name = name() + "_delbds";
     334             :     {
     335             :       // Invoke BoundaryDeletionGenerator to delete extra sidesets created by
     336             :       // AdvancedConcentricCircleGenerator
     337         124 :       auto params = _app.getFactory().getValidParams("BoundaryDeletionGenerator");
     338             : 
     339         248 :       params.set<MeshGeneratorName>("input") = name() + "_fpg";
     340         248 :       params.set<std::vector<BoundaryName>>("boundary_names") = {"0", "2"};
     341             : 
     342         124 :       addMeshSubgenerator("BoundaryDeletionGenerator", build_mesh_name, params);
     343          62 :     }
     344          62 :     if (_extrude && _mesh_dimensions == 3)
     345           0 :       build_mesh_name = callExtrusionMeshSubgenerators(build_mesh_name);
     346             : 
     347             :     // Store final mesh subgenerator
     348          62 :     _build_mesh = &getMeshByName(build_mesh_name);
     349             :   }
     350             : 
     351          71 :   generateMetadata();
     352          71 : }
     353             : 
     354             : void
     355          71 : ControlDrumMeshGenerator::generateMetadata()
     356             : {
     357             :   // Declare metadata for use in downstream mesh generators
     358          71 :   declareMeshProperty(RGMB::assembly_type, _assembly_type);
     359             :   declareMeshProperty(RGMB::pitch, getReactorParam<Real>(RGMB::assembly_pitch));
     360         142 :   declareMeshProperty(RGMB::extruded, _extrude && _mesh_dimensions == 3);
     361          71 :   declareMeshProperty(RGMB::is_control_drum, true);
     362          71 :   declareMeshProperty(RGMB::drum_region_ids, _region_ids);
     363          71 :   declareMeshProperty(RGMB::drum_block_names, _block_names);
     364             :   std::vector<Real> drum_pad_angles =
     365          81 :       _has_pad_region ? std::vector<Real>({_pad_start_angle, _pad_end_angle}) : std::vector<Real>();
     366             :   declareMeshProperty(RGMB::drum_pad_angles, drum_pad_angles);
     367          71 :   std::vector<Real> drum_radii = std::vector<Real>({_drum_inner_radius, _drum_outer_radius});
     368             :   declareMeshProperty(RGMB::drum_radii, drum_radii);
     369          71 :   declareMeshProperty(RGMB::is_homogenized, false);
     370          71 :   declareMeshProperty(RGMB::is_single_pin, false);
     371          71 : }
     372             : 
     373             : std::unique_ptr<MeshBase>
     374          62 : ControlDrumMeshGenerator::generate()
     375             : {
     376             :   // Must be called to free the ReactorMeshParams mesh
     377          62 :   freeReactorMeshParams();
     378             : 
     379             :   // If bypass_mesh is true, return a null mesh. In this mode, an output mesh is not
     380             :   // generated and only metadata is defined on the generator, so logic related to
     381             :   // generation of output mesh will not be called
     382          62 :   if (getReactorParam<bool>(RGMB::bypass_meshgen))
     383             :   {
     384             :     auto null_mesh = nullptr;
     385             :     return null_mesh;
     386             :   }
     387             : 
     388             :   // This generate() method will be called once the subgenerators that we depend on are
     389             :   // called. This is where we reassign subdomain ids/name in case they were merged when
     390             :   // stitching pins into an assembly. This is also where we set region_id and
     391             :   // assembly_type_id element integers.
     392             : 
     393             :   // Define all extra element names and integers
     394          62 :   std::string plane_id_name = "plane_id";
     395          62 :   std::string region_id_name = "region_id";
     396          62 :   std::string pin_type_id_name = "pin_type_id";
     397          62 :   std::string assembly_type_id_name = "assembly_type_id";
     398             :   const std::string default_block_name =
     399          62 :       RGMB::DRUM_BLOCK_NAME_PREFIX + std::to_string(_assembly_type);
     400             : 
     401          62 :   auto pin_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), pin_type_id_name);
     402          62 :   auto region_id_int = getElemIntegerFromMesh(*(*_build_mesh), region_id_name);
     403          62 :   auto assembly_type_id_int = getElemIntegerFromMesh(*(*_build_mesh), assembly_type_id_name);
     404             : 
     405             :   unsigned int plane_id_int = 0;
     406          62 :   if (_extrude)
     407           0 :     plane_id_int = getElemIntegerFromMesh(*(*_build_mesh), plane_id_name, true);
     408             : 
     409             :   // Get next free block ID in mesh in case subdomain ids need to be remapped
     410          62 :   auto next_block_id = MooseMeshUtils::getNextFreeSubdomainID(*(*(_build_mesh)));
     411             :   std::map<std::string, SubdomainID> rgmb_name_id_map;
     412             : 
     413             :   // Loop through all mesh elements and set region ids and reassign block IDs/names
     414             :   // if they were merged during pin stitching
     415      246272 :   for (auto & elem : (*_build_mesh)->active_element_ptr_range())
     416             :   {
     417      123074 :     elem->set_extra_integer(assembly_type_id_int, _assembly_type);
     418      123074 :     const dof_id_type z_id = _extrude ? elem->get_extra_integer(plane_id_int) : 0;
     419             : 
     420             :     // Assembly peripheral element (background / duct), set subdomains according
     421             :     // to user preferences and set pin type id to RGMB::MAX_PIN_TYPE_ID - peripheral index
     422             :     // Region id is inferred from z_id and peripheral_idx
     423      123074 :     const auto base_block_id = elem->subdomain_id();
     424      123074 :     const auto base_block_name = (*_build_mesh)->subdomain_name(base_block_id);
     425             : 
     426             :     // Check if block name has correct prefix
     427      246148 :     std::string prefix = RGMB::DRUM_BLOCK_NAME_PREFIX + std::to_string(_assembly_type) + "_R";
     428      123074 :     if (!(base_block_name.find(prefix, 0) == 0))
     429             :       continue;
     430             : 
     431             :     // Radial index is integer value of substring after prefix
     432      246148 :     const unsigned int radial_idx = std::stoi(base_block_name.substr(prefix.length()));
     433             : 
     434             :     // Drum index distinguishes between elements in pad and ex-pad regions that have the same radial
     435             :     // index
     436             :     const unsigned int drum_idx =
     437      123074 :         getDrumIdxFromRadialIdx(radial_idx, elem->true_centroid()(0), elem->true_centroid()(1));
     438      123074 :     subdomain_id_type pin_type = RGMB::MAX_PIN_TYPE_ID - drum_idx;
     439      123074 :     elem->set_extra_integer(pin_type_id_int, pin_type);
     440             : 
     441      123074 :     const auto elem_rid = _region_ids[z_id][drum_idx];
     442      123074 :     elem->set_extra_integer(region_id_int, elem_rid);
     443             : 
     444             :     // Set element block name and block id
     445      123074 :     auto elem_block_name = default_block_name;
     446      123074 :     if (getReactorParam<bool>(RGMB::region_id_as_block_name))
     447      246148 :       elem_block_name += "_REG" + std::to_string(elem_rid);
     448           0 :     else if (_has_block_names)
     449           0 :       elem_block_name += "_" + _block_names[z_id][drum_idx];
     450      123074 :     if (elem->type() == TRI3 || elem->type() == PRISM6)
     451             :       elem_block_name += RGMB::TRI_BLOCK_NAME_SUFFIX;
     452      246148 :     updateElementBlockNameId(
     453      123074 :         *(*_build_mesh), elem, rgmb_name_id_map, elem_block_name, next_block_id);
     454          62 :   }
     455             : 
     456         124 :   if (getParam<bool>("generate_depletion_id"))
     457             :   {
     458          14 :     const MooseEnum option = getParam<MooseEnum>("depletion_id_type");
     459           7 :     addDepletionId(*(*_build_mesh), option, DepletionIDGenerationLevel::Drum, _extrude);
     460           5 :   }
     461             : 
     462             :   // Mark mesh as not prepared, as block ID's were re-assigned in this method
     463          60 :   (*_build_mesh)->set_isnt_prepared();
     464             : 
     465             :   return std::move(*_build_mesh);
     466             : }
     467             : 
     468             : unsigned int
     469      123074 : ControlDrumMeshGenerator::getDrumIdxFromRadialIdx(const unsigned int radial_idx,
     470             :                                                   const Real elem_x,
     471             :                                                   const Real elem_y)
     472             : {
     473             :   // By default, drum index will match radial index unless a pad region is defined
     474             :   unsigned int drum_idx = radial_idx;
     475      123074 :   if (_has_pad_region)
     476             :   {
     477       89206 :     if (radial_idx == 1)
     478             :     {
     479             :       // This is an element in the drum region, use drum angle to determine whether it belongs to
     480             :       // pad or ex-pad region Note: drum angle of 0 degrees starts in positive y-direction and
     481             :       // increments in clockwise direction, which is consistent
     482             :       //       with how AdvancedConcentricCircleMeshGenerator defines azimuthal angles
     483        5375 :       Real drum_angle = std::atan2(elem_x, elem_y) * 180. / M_PI;
     484        5375 :       if (drum_angle < 0)
     485        2685 :         drum_angle += 360;
     486             : 
     487             :       // If _pad_end_angle does not exceed 360 degrees, check if drum angle lies within
     488             :       // _pad_start_angle and _pad_end_angle. Drum index needs to be incremented if element in
     489             :       // ex-pad region
     490        5375 :       if (_pad_end_angle <= 360)
     491             :       {
     492        5375 :         if ((drum_angle < _pad_start_angle) || (drum_angle > _pad_end_angle))
     493             :           ++drum_idx;
     494             :       }
     495             :       else
     496             :       {
     497             :         // If _pad_end_angle exceeds 360 degrees, check two intervals - _pad_start_angle to 360, and
     498             :         // 0 to _pad_end_angle - 360 Drum index needs to be incremented if element in ex-pad region
     499           0 :         if ((drum_angle < _pad_start_angle) && (drum_angle > _pad_end_angle - 360.))
     500             :           ++drum_idx;
     501             :       }
     502             :     }
     503       83831 :     else if (radial_idx == 2)
     504             :     {
     505             :       // Element is in outer drum region, drum index needs to be incremented to account for presence
     506             :       // of ex-pad region
     507             :       ++drum_idx;
     508             :     }
     509             :   }
     510      123074 :   return drum_idx;
     511             : }

Generated by: LCOV version 1.14