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 : }