LCOV - code coverage report
Current view: top level - src/materials - ControlDrumMaterial.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #32971 (54bef8) with base c6cf66 Lines: 83 93 89.2 %
Date: 2026-05-29 20:39:24 Functions: 3 3 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 "ControlDrumMaterial.h"
      11             : 
      12             : registerMooseObject("ReactorApp", ControlDrumMaterial);
      13             : 
      14             : InputParameters
      15         273 : ControlDrumMaterial::validParams()
      16             : {
      17         273 :   InputParameters params = Material::validParams();
      18             : 
      19         546 :   params.addRequiredParam<std::vector<Point>>("rotation_centers", "The centers of the rotation");
      20             : 
      21         546 :   params.addRequiredParam<std::vector<MooseFunctorName>>("rotation_angle_functors",
      22             :                                                          "The rotation angle as functor values");
      23         546 :   params.addParam<std::vector<Real>>(
      24             :       "rotation_angle_offsets", "Offsets of rotation angles corresponding to rotation centers");
      25             : 
      26         546 :   MooseEnum dir("x y z -x -y -z", "z");
      27         546 :   params.addParam<MooseEnum>("rotation_axis", dir, "The rotation axis");
      28             : 
      29         546 :   params.addRequiredParam<std::vector<Real>>(
      30             :       "segment_angles",
      31             :       "The covering angles in degree of all segments that sum to 360.\n"
      32             :       "Order by starting segment in a counter-clock-wise direction with respect to the rotation "
      33             :       "axis.\n"
      34             :       "All rotation centers share the same segment angles.");
      35             : 
      36         546 :   params.addRequiredParam<std::vector<std::vector<MaterialPropertyName>>>(
      37             :       "segment_material_properties",
      38             :       "Material properties for all the rotation segments corresponding to drum material "
      39             :       "properties");
      40         546 :   params.addRequiredParam<std::vector<MaterialPropertyName>>(
      41             :       "drum_material_properties", "Material property names for the drums");
      42             : 
      43         273 :   params.addClassDescription("Evaluate a material property based on the material properties of all "
      44             :                              "segments of a rotating drum.");
      45         273 :   return params;
      46         273 : }
      47             : 
      48         210 : ControlDrumMaterial::ControlDrumMaterial(const InputParameters & parameters)
      49             :   : Material(parameters),
      50         210 :     _rotation_centers(parameters.get<std::vector<Point>>("rotation_centers")),
      51         210 :     _rotation_axis(parameters.get<MooseEnum>("rotation_axis")),
      52         210 :     _plus(_rotation_axis == "x" || _rotation_axis == "y" || _rotation_axis == "z"),
      53         210 :     _rotation_offsets(isParamValid("rotation_angle_offsets")
      54         210 :                           ? parameters.get<std::vector<Real>>("rotation_angle_offsets")
      55         210 :                           : std::vector<Real>(_rotation_centers.size(), 0.0)),
      56         210 :     _segment_angles(parameters.get<std::vector<Real>>("segment_angles")),
      57         420 :     _n_segments(_segment_angles.size())
      58             : {
      59         210 :   if (_rotation_axis == "x" || _rotation_axis == "-x")
      60          60 :     _dir = 0;
      61         150 :   else if (_rotation_axis == "y" || _rotation_axis == "-y")
      62          60 :     _dir = 1;
      63             :   else
      64          90 :     _dir = 2;
      65             : 
      66         210 :   if ((_dir == 0 || _dir == 1) && _mesh.spatialDimension() < 3)
      67           0 :     parameters.paramError(
      68             :         "rotation_axis", _rotation_axis, " requires mesh spatial dimention to be three.");
      69             : 
      70         210 :   const auto funcs = parameters.get<std::vector<MooseFunctorName>>("rotation_angle_functors");
      71         630 :   for (const auto & func_name : funcs)
      72             :   {
      73         420 :     _rotation_functors.push_back(&getFunctor<Real>(func_name));
      74             :     // fixme: we should check whether the functor is constant in space, but
      75             :     // that requires resolving MOOSE Issue #32787.
      76             :   }
      77             : 
      78         210 :   if (_rotation_centers.size() != _rotation_functors.size())
      79             :   {
      80           0 :     if (_rotation_functors.size() == 1)
      81             :     {
      82             :       // all rotation centers share the same function
      83           0 :       _rotation_functors.resize(_rotation_centers.size(), _rotation_functors[0]);
      84             :     }
      85             :     else
      86           0 :       parameters.paramError("rotation_angle_function",
      87             :                             "Number of rotation angle functions must agree with "
      88             :                             "the size of 'rotation_centers' or be equal to one in case of all "
      89             :                             "rotation centers sharing "
      90             :                             "the same function");
      91             :   }
      92         210 :   if (_rotation_offsets.size() != _rotation_centers.size())
      93           0 :     parameters.paramError("rotation_angle_offsets",
      94             :                           "Size must be equal to the size of 'rotation_centers' ");
      95             : 
      96         210 :   if (_n_segments < 2)
      97           0 :     parameters.paramError("segment_angles", "At least 2 segments are required.");
      98             : 
      99             :   Real angle = 0;
     100        1050 :   for (const auto & v : _segment_angles)
     101         840 :     angle += v;
     102         210 :   if (angle != 360)
     103           0 :     parameters.paramError("segment_angles", "Must sum to 360 degree.");
     104             : 
     105         630 :   for (const auto & c : _rotation_centers)
     106         420 :     if (c(_dir) != 0)
     107           0 :       parameters.paramError("rotation_centers",
     108             :                             "Must have zero coordinate in the rotation direction");
     109             : 
     110         630 :   const auto drum_props = getParam<std::vector<MaterialPropertyName>>("drum_material_properties");
     111         450 :   for (const auto & prop_name : drum_props)
     112         240 :     _drum_properties.push_back(&declareProperty<Real>(prop_name));
     113             : 
     114             :   const auto all_prop_names =
     115         630 :       getParam<std::vector<std::vector<MaterialPropertyName>>>("segment_material_properties");
     116         210 :   if (all_prop_names.size() != drum_props.size())
     117           0 :     paramError(
     118             :         "segment_material_properties",
     119             :         "Leading size of the 2D array must be equal to the size of 'drum_material_properties'");
     120         450 :   for (const auto & prop_names : all_prop_names)
     121             :   {
     122         240 :     if (prop_names.size() != _n_segments)
     123           0 :       paramError("segment_material_properties",
     124             :                  "Number of segment materal properties of one drum material property must be equal "
     125             :                  "to the number of segments (",
     126             :                  _n_segments,
     127             :                  ")");
     128             :     std::vector<const MaterialProperty<Real> *> props;
     129        1200 :     for (const auto & prop_name : prop_names)
     130         960 :       props.push_back(&getMaterialPropertyByName<Real>(prop_name));
     131         240 :     _segment_properties.push_back(props);
     132         240 :   }
     133         210 : }
     134             : 
     135             : void
     136       11088 : ControlDrumMaterial::computeQpProperties()
     137             : {
     138             :   // get the id of the rotation center the current element is rotating around
     139             :   unsigned int rotation_id = 0;
     140             :   Real min_dist = std::numeric_limits<Real>::max();
     141       11088 :   auto p = _current_elem->vertex_average();
     142       11088 :   p(_dir) = 0;
     143       33264 :   for (const auto i : index_range(_rotation_centers))
     144             :   {
     145       22176 :     auto c = _rotation_centers[i];
     146       22176 :     Real dist = (p - c).norm();
     147       22176 :     if (dist < min_dist)
     148             :     {
     149       15840 :       rotation_id = i;
     150             :       min_dist = dist;
     151             :     }
     152             :   }
     153             : 
     154             :   // functor does not depend on state and element, but we pass them to meet the interface
     155       11088 :   const auto state = determineState();
     156       11088 :   const auto elem_arg = makeElemArg(_current_elem);
     157             :   Real rotation_angle =
     158       11088 :       (*_rotation_functors[rotation_id])(elem_arg, state) + _rotation_offsets[rotation_id];
     159             : 
     160             :   // get the angle of the current quadrature point
     161       11088 :   Point v = _q_point[_qp] - _rotation_centers[rotation_id];
     162       11088 :   v(_dir) = 0;
     163       11088 :   const Real vnorm = v.norm();
     164       11088 :   if (vnorm != 0.0)
     165             :     v /= vnorm;
     166             : 
     167             :   // (-180, 180]
     168       11088 :   Real ang = std::acos(v((_dir + 1) % 3)) * (180 / M_PI);
     169       11088 :   if (v((_dir + 2) % 3) < 0)
     170        5544 :     ang = -ang;
     171             : 
     172             :   // make sure returned angle is within [rotation_angle, rotation_angle+360)
     173       17226 :   while (ang < rotation_angle)
     174        6138 :     ang += 360;
     175       11088 :   while (ang - 360 >= rotation_angle)
     176             :     ang -= 360;
     177             : 
     178             :   // rotation wrt current rotation_angle [0, 360)
     179       11088 :   if (_plus)
     180        6048 :     ang -= rotation_angle;
     181             :   else
     182             :   {
     183             :     // flip the angle
     184        5040 :     if (ang == rotation_angle)
     185             :       ang = 0;
     186             :     else
     187        5040 :       ang = rotation_angle + 360 - ang;
     188             :   }
     189             : 
     190             :   // find the segment where the qp is located
     191             :   unsigned int seg_id = 0;
     192       11088 :   Real upper_angle = _segment_angles[0];
     193       29106 :   while (ang > upper_angle)
     194             :   {
     195       18018 :     ++seg_id;
     196             :     mooseAssert(seg_id < _n_segments, "Internal error: segement id");
     197       18018 :     upper_angle += _segment_angles[seg_id];
     198             :   }
     199             : 
     200             :   // assign material properties
     201             :   // Note: we do not attempt adjust the value considering the weight with the location
     202             :   //       of the segment interface.
     203       23184 :   for (const auto i : index_range(_drum_properties))
     204       12096 :     (*_drum_properties[i])[_qp] = (*_segment_properties[i][seg_id])[_qp];
     205       11088 : }

Generated by: LCOV version 1.14