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 "SimpleHexagonGenerator.h"
11 :
12 : // C++ includes
13 : #include <cmath>
14 :
15 : registerMooseObject("ReactorApp", SimpleHexagonGenerator);
16 :
17 : InputParameters
18 514 : SimpleHexagonGenerator::validParams()
19 : {
20 514 : InputParameters params = PolygonMeshGeneratorBase::validParams();
21 1028 : MooseEnum element_type("TRI QUAD HYBRID", "TRI");
22 1028 : params.addParam<MooseEnum>("element_type",
23 : element_type,
24 : "Whether the simple hexagon mesh is made of TRI or QUAD elements.");
25 1028 : params.addRequiredRangeCheckedParam<Real>(
26 : "hexagon_size", "hexagon_size>0.0", "Size of the hexagon to be generated.");
27 1028 : MooseEnum hexagon_size_style("apothem radius", "apothem");
28 1028 : params.addParam<MooseEnum>(
29 : "hexagon_size_style",
30 : hexagon_size_style,
31 514 : "Style in which the hexagon size is given (default: apothem i.e. half-pitch). Option: " +
32 514 : hexagon_size_style.getRawNames());
33 1028 : params.addRangeCheckedParam<unsigned int>(
34 : "radial_intervals",
35 : "radial_intervals>1",
36 : "Number of pin radial meshing rings (only applicable when 'element_type' is 'HYBRID').");
37 1028 : params.addRangeCheckedParam<std::vector<subdomain_id_type>>(
38 : "block_id",
39 : "block_id>=0",
40 : "Optional customized block id; two ids are needed for HYBRID 'element_type'.");
41 1028 : params.addParam<std::vector<SubdomainName>>(
42 : "block_name",
43 : "Optional customized block name; two names are needed for HYBRID 'element_type'.");
44 1028 : params.addRangeCheckedParam<boundary_id_type>("external_boundary_id",
45 : "external_boundary_id>=0",
46 : "Optional customized external boundary id.");
47 1028 : params.addParam<BoundaryName>("external_boundary_name",
48 : "Optional customized external boundary name.");
49 1028 : params.addParamNamesToGroup("block_id block_name external_boundary_id external_boundary_name",
50 : "Customized Subdomain/Boundary");
51 514 : params.addClassDescription(
52 : "This SimpleHexagonGenerator object is designed to generate a simple hexagonal mesh that "
53 : "only contains six simple azimuthal triangular elements, two quadrilateral elements, or six "
54 : "central azimuthal triangular elements plus a several layers of quadrilateral elements.");
55 :
56 514 : return params;
57 514 : }
58 :
59 246 : SimpleHexagonGenerator::SimpleHexagonGenerator(const InputParameters & parameters)
60 : : PolygonMeshGeneratorBase(parameters),
61 246 : _element_type(getParam<MooseEnum>("element_type").template getEnum<ElemType>()),
62 492 : _hexagon_size(getParam<Real>("hexagon_size")),
63 246 : _hexagon_size_style(
64 246 : getParam<MooseEnum>("hexagon_size_style").template getEnum<PolygonSizeStyle>()),
65 246 : _radial_intervals(isParamValid("radial_intervals")
66 523 : ? getParam<unsigned int>("radial_intervals")
67 215 : : (_element_type == ElemType::HYBRID ? 2 : 1)),
68 984 : _block_id(isParamValid("block_id") ? getParam<std::vector<subdomain_id_type>>("block_id")
69 : : std::vector<subdomain_id_type>()),
70 948 : _block_name(isParamValid("block_name") ? getParam<std::vector<SubdomainName>>("block_name")
71 : : std::vector<SubdomainName>()),
72 492 : _boundary_id_valid(isParamValid("external_boundary_id")),
73 691 : _external_boundary_id(isParamValid("external_boundary_id")
74 644 : ? getParam<boundary_id_type>("external_boundary_id")
75 : : 0),
76 691 : _external_boundary_name(isParamValid("external_boundary_name")
77 246 : ? getParam<BoundaryName>("external_boundary_name")
78 246 : : BoundaryName())
79 : {
80 246 : if (_radial_intervals > 1 && _element_type != ElemType::HYBRID)
81 2 : paramError(
82 : "radial_intervals",
83 : "A non-unity 'radial_intervals' value is only supported when 'element_type' is 'HYBRID'.");
84 244 : _pitch = 2.0 * (_hexagon_size_style == PolygonSizeStyle::apothem
85 244 : ? _hexagon_size
86 0 : : _hexagon_size * std::cos(M_PI / (Real)HEXAGON_NUM_SIDES));
87 244 : if ((_block_id.size() > 1) && _element_type != ElemType::HYBRID)
88 2 : paramError(
89 : "block_id",
90 : "if provided, the size of this parameter must be one if 'element_type' is TRI or QUAD.");
91 242 : if ((_block_id.size() != 0 && _block_id.size() != 2) && _element_type == ElemType::HYBRID)
92 2 : paramError("block_id",
93 : "if provided, the size of this parameter must be two if 'element_type' is HYBRID.");
94 240 : if (_block_name.size() != 0 && _block_name.size() != _block_id.size())
95 2 : paramError("block_name", "if provided, this parameter must have the same size as 'block_id'.");
96 238 : declareMeshProperty<unsigned int>("background_intervals_meta", _radial_intervals);
97 238 : declareMeshProperty<dof_id_type>("node_id_background_meta",
98 238 : _radial_intervals * HEXAGON_NUM_SIDES);
99 238 : declareMeshProperty<Real>("max_radius_meta", 0.0);
100 476 : declareMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", {1, 1, 1, 1, 1, 1});
101 238 : declareMeshProperty<Real>("pitch_meta", _pitch);
102 238 : }
103 :
104 : std::unique_ptr<MeshBase>
105 238 : SimpleHexagonGenerator::generate()
106 : {
107 238 : const Real radius = _pitch / std::sqrt(3.0);
108 238 : auto mesh = buildReplicatedMesh(2);
109 : BoundaryInfo & boundary_info = mesh->get_boundary_info();
110 : // In the ElemType::TRI mode, total nodes number is 6 * _radial_intervals + 1, while
111 : // _radial_intervals must be trivial (1);
112 : // In the ElemType::QUAD model, total nodes number is 6 * _radial_intervals, while
113 : // _radial_intervals must be trivial (1);
114 : // In the ElemType::HYBRID mode, total nodes number is 6 * _radial_intervals + 1.
115 238 : std::vector<Node *> nodes(HEXAGON_NUM_SIDES * _radial_intervals +
116 238 : (_element_type != ElemType::QUAD));
117 238 : if (_element_type != ElemType::QUAD)
118 : {
119 : // The trivial center node with node_id = 6 (HEXAGON_NUM_SIDES) * _radial_intervals
120 : Point center_p = Point(0.0, 0.0, 0.0);
121 157 : nodes[HEXAGON_NUM_SIDES * _radial_intervals] =
122 157 : mesh->add_point(center_p, HEXAGON_NUM_SIDES * _radial_intervals);
123 : }
124 : // loop to create nodes by radial layers
125 514 : for (unsigned int j = 0; j < _radial_intervals; j++)
126 : // loop to create the six nodes in each layer
127 1932 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
128 : {
129 : Point side_p = Point(radius * (Real)(_radial_intervals - j) / (Real)_radial_intervals *
130 1656 : sin(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
131 1656 : radius * (Real)(_radial_intervals - j) / (Real)_radial_intervals *
132 1656 : cos(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
133 1656 : 0.0);
134 1656 : nodes[j * HEXAGON_NUM_SIDES + i] = mesh->add_point(side_p, j * HEXAGON_NUM_SIDES + i);
135 : }
136 :
137 238 : if (_element_type != ElemType::QUAD)
138 : {
139 : // loop to create outer layer QUAD elements
140 : // Note that the direction is from outer to inner
141 195 : for (unsigned int j = 0; j < _radial_intervals - 1; j++)
142 : {
143 : // loop to create the six QUAD elements for each layer
144 266 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
145 : {
146 456 : Elem * elem = mesh->add_elem(new Quad4);
147 228 : elem->set_node(0, nodes[HEXAGON_NUM_SIDES * j + i]);
148 228 : elem->set_node(1, nodes[HEXAGON_NUM_SIDES * j + (i + 1) % HEXAGON_NUM_SIDES]);
149 228 : elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (j + 1) + (i + 1) % HEXAGON_NUM_SIDES]);
150 228 : elem->set_node(3, nodes[HEXAGON_NUM_SIDES * (j + 1) + i]);
151 : // Assign the default external boundary id if applicable so that the mesh can be used as
152 : // input of `PatterneHexMeshGenerator`.
153 228 : if (j == 0)
154 228 : boundary_info.add_side(elem, 0, OUTER_SIDESET_ID);
155 : // Default subdomain id
156 228 : elem->subdomain_id() = 2;
157 : }
158 : }
159 : // loop to create the six TRI elements
160 1099 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
161 : {
162 1884 : Elem * elem = mesh->add_elem(new Tri3);
163 942 : elem->set_node(0, nodes[HEXAGON_NUM_SIDES * _radial_intervals]);
164 942 : elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (_radial_intervals - 1) + i]);
165 942 : elem->set_node(
166 942 : 1, nodes[HEXAGON_NUM_SIDES * (_radial_intervals - 1) + (i + 1) % HEXAGON_NUM_SIDES]);
167 : // Assign the default external boundary id if applicable so that the mesh can be used as input
168 : // of `PatterneHexMeshGenerator`.
169 942 : if (_element_type != ElemType::HYBRID)
170 714 : boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
171 : // Default subdomain id
172 942 : elem->subdomain_id() = 1;
173 : }
174 : }
175 : else
176 : // loop to create the two elements
177 243 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES / 3; i++)
178 : {
179 324 : Elem * elem = mesh->add_elem(new Quad4);
180 162 : elem->set_node(0, nodes[i * 3]);
181 162 : elem->set_node(1, nodes[(i * 3 + 3) % HEXAGON_NUM_SIDES]);
182 162 : elem->set_node(2, nodes[i * 3 + 2]);
183 162 : elem->set_node(3, nodes[i * 3 + 1]);
184 : // Assign the default external boundary id so that the mesh can be used as input of
185 : // `PatterneHexMeshGenerator`.
186 162 : boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
187 162 : boundary_info.add_side(elem, 2, OUTER_SIDESET_ID);
188 162 : boundary_info.add_side(elem, 3, OUTER_SIDESET_ID);
189 : // Default subdomain id
190 162 : elem->subdomain_id() = 1;
191 : }
192 :
193 : // Assign customized (optional) subdomain id/name and external boundary id/name.
194 238 : if (!_block_id.empty())
195 3140 : for (const auto & elem : mesh->active_element_ptr_range())
196 : {
197 1332 : if (elem->subdomain_id() == 1)
198 1104 : elem->subdomain_id() = _block_id.front();
199 : else
200 228 : elem->subdomain_id() = _block_id.back();
201 238 : }
202 238 : if (!_block_name.empty())
203 442 : for (unsigned int i = 0; i < _block_name.size(); i++)
204 240 : mesh->subdomain_name(_block_id[i]) = _block_name[i];
205 :
206 238 : if (_boundary_id_valid)
207 191 : MooseMesh::changeBoundaryId(*mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
208 238 : if (!_external_boundary_name.empty())
209 : {
210 191 : mesh->get_boundary_info().sideset_name(
211 191 : _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
212 191 : _external_boundary_name;
213 191 : mesh->get_boundary_info().nodeset_name(
214 191 : _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
215 : _external_boundary_name;
216 : }
217 :
218 238 : mesh->prepare_for_use();
219 476 : return dynamic_pointer_cast<MeshBase>(mesh);
220 238 : }
|