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