LCOV - code coverage report
Current view: top level - src/actioncomponents - CylinderComponent.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 101 131 77.1 %
Date: 2026-05-29 20:35:17 Functions: 4 7 57.1 %
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             : // MOOSE includes
      11             : #include "CylinderComponent.h"
      12             : #include "RotationMatrix.h"
      13             : 
      14             : registerMooseAction("MooseApp", CylinderComponent, "add_mesh_generator");
      15             : // CylinderComponent is an example of ComponentPhysicsInterface
      16             : registerMooseAction("MooseApp", CylinderComponent, "init_component_physics");
      17             : // CylinderComponent is an example of ComponentMaterialPropertyInterface
      18             : registerMooseAction("MooseApp", CylinderComponent, "add_material");
      19             : // CylinderComponent is an example of ComponentInitialConditionInterface
      20             : registerMooseAction("MooseApp", CylinderComponent, "check_integrity");
      21             : registerActionComponent("MooseApp", CylinderComponent);
      22             : 
      23             : InputParameters
      24         424 : CylinderComponent::validParams()
      25             : {
      26         424 :   InputParameters params = ActionComponent::validParams();
      27         424 :   params += ComponentPhysicsInterface::validParams();
      28         424 :   params += ComponentMaterialPropertyInterface::validParams();
      29         424 :   params += ComponentInitialConditionInterface::validParams();
      30         424 :   params += ComponentBoundaryConditionInterface::validParams();
      31         424 :   params += ComponentMeshTransformHelper::validParams();
      32         848 :   params.addClassDescription("Cylindrical component.");
      33        1696 :   MooseEnum dims("0 1 2 3");
      34        1696 :   params.addRequiredParam<MooseEnum>("dimension",
      35             :                                      dims,
      36             :                                      "Dimension of the cylinder. 0 for a point (not implemented), "
      37             :                                      "1 for an (axial) 1D line, 2 for a 2D-RZ cylinder, and 3 for "
      38             :                                      "a 3D cylinder");
      39        1696 :   params.addParam<SubdomainName>("block", "Block name for the cylinder");
      40             : 
      41             :   // Geometry
      42        2544 :   params.addRequiredRangeCheckedParam<Real>("radius", "radius>0", "Radius of the cylinder");
      43        2544 :   params.addRequiredRangeCheckedParam<Real>("length", "length>0", "Length/Height of the cylinder");
      44        1272 :   params.addParam<bool>("position_is_bottom_center",
      45         848 :                         true,
      46             :                         "Whether the 'position' parameter gives the position of the bottom-center "
      47             :                         "of the cylinder. Only used in 3D");
      48             : 
      49             :   // Discretization
      50        3392 :   params.addRangeCheckedParam<std::vector<unsigned int>>(
      51             :       "n_radial",
      52             :       {1},
      53             :       "n_radial > 0",
      54             :       "Number of radial elements (per ring if multiple values specified). All rings are lumped at "
      55             :       "this time.");
      56             :   // TODO: Specify the ring radii and subdomains as well
      57        2544 :   params.addRequiredRangeCheckedParam<unsigned int>(
      58             :       "n_axial", "n_axial>0", "Number of axial elements of the cylinder");
      59        2544 :   params.addRangeCheckedParam<unsigned int>(
      60             :       "n_sectors",
      61             :       "n_sectors>0",
      62             :       "Number of azimuthal sectors in each quadrant of cylinder face. Only used in 3D");
      63        1696 :   params.addParamNamesToGroup("n_radial n_axial n_sectors", "Discretization");
      64             : 
      65             :   // Boundary layers
      66        2544 :   params.addRangeCheckedParam<Real>("boundary_layer_width",
      67             :                                     "boundary_layer_width>=0",
      68             :                                     "The width of the radial boundary layer (if assigned).");
      69        1272 :   params.addParam<unsigned int>(
      70             :       "n_boundary_layers",
      71         848 :       1,
      72             :       "The number of radial boundary layers. Only active if boundary_layer_width is specified");
      73        1272 :   params.addParamNamesToGroup("boundary_layer_width n_boundary_layers", "Radial boundary layer");
      74             : 
      75         848 :   return params;
      76         424 : }
      77             : 
      78         394 : CylinderComponent::CylinderComponent(const InputParameters & params)
      79             :   : ActionComponent(params),
      80             :     ComponentPhysicsInterface(params),
      81             :     ComponentMaterialPropertyInterface(params),
      82             :     ComponentInitialConditionInterface(params),
      83             :     ComponentBoundaryConditionInterface(params),
      84             :     ComponentMeshTransformHelper(params),
      85         388 :     _radius(getParam<Real>("radius")),
      86         776 :     _height(getParam<Real>("length")),
      87        1170 :     _offset_position_to_center(getParam<bool>("position_is_bottom_center"))
      88             : {
      89         776 :   _dimension = getParam<MooseEnum>("dimension");
      90             :   // The other component interfaces add their required task
      91         776 :   addRequiredTask("add_mesh_generator");
      92         388 : }
      93             : 
      94             : void
      95         388 : CylinderComponent::addMeshGenerators()
      96             : {
      97             :   // Create the base mesh for the component using a mesh generator
      98         388 :   if (_dimension == 0)
      99           0 :     paramError("dimension", "0D cylinder not implemented");
     100         388 :   else if (_dimension == 1 || _dimension == 2)
     101             :   {
     102         564 :     InputParameters params = _factory.getValidParams("GeneratedMeshGenerator");
     103         564 :     params.set<MooseEnum>("dim") = _dimension;
     104        1128 :     params.set<Real>("xmax") = {getParam<Real>("length")};
     105        1128 :     params.set<unsigned int>("nx") = {getParam<unsigned int>("n_axial")};
     106         564 :     params.set<std::string>("boundary_name_prefix") = name();
     107         282 :     if (_dimension == 2)
     108             :     {
     109         870 :       params.set<Real>("ymax") = {getParam<Real>("radius")};
     110         174 :       params.set<Real>("ymin") = 0;
     111         522 :       if (!isParamValid("n_radial"))
     112           0 :         paramError("n_radial", "Should be provided for a 2D cylinder");
     113         870 :       params.set<unsigned int>("ny") = getParam<std::vector<unsigned int>>("n_radial")[0];
     114             :     }
     115         324 :     else if (isParamSetByUser("n_radial"))
     116           0 :       paramError("n_radial", "Should not be provided for a 1D cylinder");
     117         846 :     if (isParamValid("block"))
     118             :     {
     119         630 :       const auto block_name = getParam<SubdomainName>("block");
     120         210 :       params.set<SubdomainName>("subdomain_name") = block_name;
     121         210 :       _blocks.push_back(block_name);
     122         210 :     }
     123         564 :     _app.getMeshGeneratorSystem().addMeshGenerator(
     124         564 :         "GeneratedMeshGenerator", name() + "_base", params);
     125         282 :     _mg_names.push_back(name() + "_base");
     126         282 :   }
     127         106 :   else if (_dimension == 3)
     128             :   {
     129         318 :     if (!isParamValid("n_axial"))
     130           0 :       paramError("n_axial", "Should be provided for a 3D cylinder");
     131         318 :     if (!isParamValid("n_sectors"))
     132           0 :       paramError("n_sectors", "Should be provided in 3D");
     133             : 
     134             :     // create circular face
     135         318 :     InputParameters circle_params = _factory.getValidParams("ConcentricCircleMeshGenerator");
     136         212 :     circle_params.set<bool>("preserve_volumes") = true;
     137         106 :     circle_params.set<bool>("has_outer_square") = false;
     138         212 :     auto ring_disc_vec = getParam<std::vector<unsigned int>>("n_radial");
     139             :     // TODO: multi-ring support
     140         106 :     ring_disc_vec = {std::accumulate(ring_disc_vec.begin(), ring_disc_vec.end(), (unsigned int)0)};
     141         318 :     if (isParamValid("boundary_layer_width"))
     142             :     {
     143          80 :       Real inner_radius = getParam<Real>("radius") - getParam<Real>("boundary_layer_width");
     144          80 :       circle_params.set<std::vector<Real>>("radii") = {inner_radius, getParam<Real>("radius")};
     145          60 :       ring_disc_vec.push_back(getParam<unsigned int>("n_boundary_layers"));
     146             :     }
     147             :     else
     148         430 :       circle_params.set<std::vector<Real>>("radii") = {getParam<Real>("radius")};
     149         106 :     circle_params.set<std::vector<unsigned int>>("rings") = ring_disc_vec;
     150             : 
     151         424 :     circle_params.set<unsigned int>("num_sectors") = getParam<unsigned int>("n_sectors");
     152         318 :     if (isParamValid("block"))
     153             :     {
     154           0 :       const auto block_name = getParam<SubdomainName>("block");
     155           0 :       circle_params.set<SubdomainName>("subdomain_name") = block_name;
     156           0 :       _blocks.push_back(block_name);
     157           0 :     }
     158         212 :     _app.getMeshGeneratorSystem().addMeshGenerator(
     159         212 :         "ConcentricCircleMeshGenerator", name() + "_circle_base", circle_params);
     160         106 :     _mg_names.push_back(name() + "_circle_base");
     161             : 
     162             :     // rotate to have extrusion axis be along x-axis
     163             :     // NOTE: this is re-rotated by the ComponentMeshTransformHelper
     164         212 :     InputParameters rotate_params = _factory.getValidParams("TransformGenerator");
     165         318 :     rotate_params.set<MeshGeneratorName>("input") = _mg_names.back();
     166         318 :     rotate_params.set<MooseEnum>("transform") = "ROTATE_EXT";
     167         106 :     RealVectorValue angles(-90, -90, 90);
     168         106 :     rotate_params.set<RealVectorValue>("vector_value") = angles;
     169         212 :     _app.getMeshGeneratorSystem().addMeshGenerator(
     170         212 :         "TransformGenerator", name() + "_3D_init_rotate", rotate_params);
     171         106 :     _mg_names.push_back(name() + "_3D_init_rotate");
     172             : 
     173             :     // extrude the surface
     174         212 :     InputParameters ext_params = _factory.getValidParams("AdvancedExtruderGenerator");
     175         424 :     ext_params.set<std::vector<unsigned int>>("num_layers") = {getParam<unsigned int>("n_axial")};
     176         212 :     ext_params.set<MeshGeneratorName>("input") = _mg_names.back();
     177         212 :     ext_params.set<std::vector<Real>>("heights") = {_height};
     178         318 :     ext_params.set<BoundaryName>("bottom_boundary") = name() + "_bottom_boundary";
     179         318 :     ext_params.set<BoundaryName>("top_boundary") = name() + "_top_boundary";
     180             : 
     181         106 :     const Point default_direction(1, 0, 0);
     182         106 :     ext_params.set<Point>("direction") = default_direction;
     183         212 :     _app.getMeshGeneratorSystem().addMeshGenerator(
     184         212 :         "AdvancedExtruderGenerator", name() + "_base", ext_params);
     185         106 :     _mg_names.push_back(name() + "_base");
     186         106 :   }
     187         388 :   _top_mg_name = _mg_names.back();
     188             : 
     189         388 :   ComponentMeshTransformHelper::addMeshGenerators();
     190         388 : }
     191             : 
     192             : void
     193           0 : CylinderComponent::setupComponent()
     194             : {
     195           0 :   if (_dimension == 2)
     196             :   {
     197           0 :     _awh.getMesh()->setCoordSystem(_blocks, MultiMooseEnum("COORD_RZ"));
     198           0 :     if (_direction)
     199           0 :       _awh.getMesh()->setGeneralAxisymmetricCoordAxes(
     200             :           {getParam<SubdomainName>("block")},
     201           0 :           {std::make_pair(translation(), _direction ? *_direction : RealVectorValue(0, 1, 0))});
     202           0 :     if (_rotation)
     203           0 :       paramError("rotation", "Rotation + 2D RZ cylinder not implemented");
     204             :   }
     205           0 : }
     206             : 
     207             : void
     208         126 : CylinderComponent::checkIntegrity()
     209             : {
     210         126 :   ComponentInitialConditionInterface::checkIntegrity();
     211         123 :   ComponentBoundaryConditionInterface::checkIntegrity();
     212         120 : }
     213             : 
     214             : Point
     215           0 : CylinderComponent::translation() const
     216             : {
     217             :   // The 1D or 2D RZ cylinders are naturally centered
     218           0 :   if (!_offset_position_to_center || _dimension <= 2)
     219           0 :     return ComponentMeshTransformHelper::translation();
     220             : 
     221           0 :   auto input_translation = ComponentMeshTransformHelper::translation();
     222             :   // The translation will be applied after the rotation, we need to translate by the rotated radius
     223             :   // There are two options for specifying rotations / translations
     224           0 :   if (_rotation)
     225           0 :     paramError("position_is_bottom_center",
     226             :                "Rotation + offset cylinder to center not implemented. Use 'direction' instead");
     227             : 
     228             :   const auto rotation_matrix =
     229           0 :       _direction
     230           0 :           ? RotationMatrix::rodriguesRotationMatrix<false>(RealVectorValue(1, 0, 0), *_direction)
     231           0 :           : RealTensorValue(1, 0, 0, 0, 1, 0, 0, 0, 1);
     232           0 :   input_translation -= rotation_matrix * Point(_radius, 0, 0);
     233             : 
     234           0 :   return input_translation;
     235           0 : }

Generated by: LCOV version 1.14