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 410 : SimpleHexagonGenerator::validParams()
19 : {
20 410 : InputParameters params = PolygonMeshGeneratorBase::validParams();
21 820 : MooseEnum element_type("TRI QUAD HYBRID", "TRI");
22 820 : params.addParam<MooseEnum>("element_type",
23 : element_type,
24 : "Whether the simple hexagon mesh is made of TRI or QUAD elements.");
25 820 : params.addRequiredRangeCheckedParam<Real>(
26 : "hexagon_size", "hexagon_size>0.0", "Size of the hexagon to be generated.");
27 820 : MooseEnum hexagon_size_style("apothem radius", "apothem");
28 820 : params.addParam<MooseEnum>(
29 : "hexagon_size_style",
30 : hexagon_size_style,
31 410 : "Style in which the hexagon size is given (default: apothem i.e. half-pitch). Option: " +
32 410 : hexagon_size_style.getRawNames());
33 820 : 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 820 : 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 820 : params.addParam<std::vector<SubdomainName>>(
42 : "block_name",
43 : "Optional customized block name; two names are needed for HYBRID 'element_type'.");
44 820 : params.addRangeCheckedParam<boundary_id_type>("external_boundary_id",
45 : "external_boundary_id>=0",
46 : "Optional customized external boundary id.");
47 820 : params.addParam<BoundaryName>("external_boundary_name",
48 : "Optional customized external boundary name.");
49 820 : params.addParamNamesToGroup("block_id block_name external_boundary_id external_boundary_name",
50 : "Customized Subdomain/Boundary");
51 410 : 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 410 : return params;
57 410 : }
58 :
59 194 : SimpleHexagonGenerator::SimpleHexagonGenerator(const InputParameters & parameters)
60 : : PolygonMeshGeneratorBase(parameters),
61 194 : _element_type(getParam<MooseEnum>("element_type").template getEnum<ElemType>()),
62 388 : _hexagon_size(getParam<Real>("hexagon_size")),
63 194 : _hexagon_size_style(
64 194 : getParam<MooseEnum>("hexagon_size_style").template getEnum<PolygonSizeStyle>()),
65 194 : _radial_intervals(isParamValid("radial_intervals")
66 413 : ? getParam<unsigned int>("radial_intervals")
67 169 : : (_element_type == ElemType::HYBRID ? 2 : 1)),
68 776 : _block_id(isParamValid("block_id") ? getParam<std::vector<subdomain_id_type>>("block_id")
69 : : std::vector<subdomain_id_type>()),
70 748 : _block_name(isParamValid("block_name") ? getParam<std::vector<SubdomainName>>("block_name")
71 : : std::vector<SubdomainName>()),
72 388 : _boundary_id_valid(isParamValid("external_boundary_id")),
73 545 : _external_boundary_id(isParamValid("external_boundary_id")
74 508 : ? getParam<boundary_id_type>("external_boundary_id")
75 : : 0),
76 545 : _external_boundary_name(isParamValid("external_boundary_name")
77 194 : ? getParam<BoundaryName>("external_boundary_name")
78 194 : : BoundaryName())
79 : {
80 194 : 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 192 : _pitch = 2.0 * (_hexagon_size_style == PolygonSizeStyle::apothem
85 192 : ? _hexagon_size
86 0 : : _hexagon_size * std::cos(M_PI / (Real)HEXAGON_NUM_SIDES));
87 192 : 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 190 : 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 188 : 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 186 : declareMeshProperty<unsigned int>("background_intervals_meta", _radial_intervals);
97 186 : declareMeshProperty<dof_id_type>("node_id_background_meta",
98 186 : _radial_intervals * HEXAGON_NUM_SIDES);
99 186 : declareMeshProperty<Real>("max_radius_meta", 0.0);
100 372 : declareMeshProperty<std::vector<unsigned int>>("num_sectors_per_side_meta", {1, 1, 1, 1, 1, 1});
101 186 : declareMeshProperty<Real>("pitch_meta", _pitch);
102 186 : }
103 :
104 : std::unique_ptr<MeshBase>
105 186 : SimpleHexagonGenerator::generate()
106 : {
107 186 : const Real radius = _pitch / std::sqrt(3.0);
108 186 : 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 186 : std::vector<Node *> nodes(HEXAGON_NUM_SIDES * _radial_intervals +
116 186 : (_element_type != ElemType::QUAD));
117 186 : 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 123 : nodes[HEXAGON_NUM_SIDES * _radial_intervals] =
122 123 : mesh->add_point(center_p, HEXAGON_NUM_SIDES * _radial_intervals);
123 : }
124 : // loop to create nodes by radial layers
125 402 : for (unsigned int j = 0; j < _radial_intervals; j++)
126 : // loop to create the six nodes in each layer
127 1512 : 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 1296 : sin(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
131 1296 : radius * (Real)(_radial_intervals - j) / (Real)_radial_intervals *
132 1296 : cos(M_PI / ((Real)HEXAGON_NUM_SIDES / 2.0) * (Real)i),
133 1296 : 0.0);
134 1296 : nodes[j * HEXAGON_NUM_SIDES + i] = mesh->add_point(side_p, j * HEXAGON_NUM_SIDES + i);
135 : }
136 :
137 186 : 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 153 : for (unsigned int j = 0; j < _radial_intervals - 1; j++)
142 : {
143 : // loop to create the six QUAD elements for each layer
144 210 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
145 : {
146 360 : Elem * elem = mesh->add_elem(new Quad4);
147 180 : elem->set_node(0, nodes[HEXAGON_NUM_SIDES * j + i]);
148 180 : elem->set_node(1, nodes[HEXAGON_NUM_SIDES * j + (i + 1) % HEXAGON_NUM_SIDES]);
149 180 : elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (j + 1) + (i + 1) % HEXAGON_NUM_SIDES]);
150 180 : 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 180 : if (j == 0)
154 180 : boundary_info.add_side(elem, 0, OUTER_SIDESET_ID);
155 : // Default subdomain id
156 180 : elem->subdomain_id() = 2;
157 : }
158 : }
159 : // loop to create the six TRI elements
160 861 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES; i++)
161 : {
162 1476 : Elem * elem = mesh->add_elem(new Tri3);
163 738 : elem->set_node(0, nodes[HEXAGON_NUM_SIDES * _radial_intervals]);
164 738 : elem->set_node(2, nodes[HEXAGON_NUM_SIDES * (_radial_intervals - 1) + i]);
165 738 : elem->set_node(
166 738 : 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 738 : if (_element_type != ElemType::HYBRID)
170 558 : boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
171 : // Default subdomain id
172 738 : elem->subdomain_id() = 1;
173 : }
174 : }
175 : else
176 : // loop to create the two elements
177 189 : for (unsigned int i = 0; i < HEXAGON_NUM_SIDES / 3; i++)
178 : {
179 252 : Elem * elem = mesh->add_elem(new Quad4);
180 126 : elem->set_node(0, nodes[i * 3]);
181 126 : elem->set_node(1, nodes[(i * 3 + 3) % HEXAGON_NUM_SIDES]);
182 126 : elem->set_node(2, nodes[i * 3 + 2]);
183 126 : 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 126 : boundary_info.add_side(elem, 1, OUTER_SIDESET_ID);
187 126 : boundary_info.add_side(elem, 2, OUTER_SIDESET_ID);
188 126 : boundary_info.add_side(elem, 3, OUTER_SIDESET_ID);
189 : // Default subdomain id
190 126 : elem->subdomain_id() = 1;
191 : }
192 :
193 : // Assign customized (optional) subdomain id/name and external boundary id/name.
194 186 : if (!_block_id.empty())
195 2460 : for (const auto & elem : mesh->active_element_ptr_range())
196 : {
197 1044 : if (elem->subdomain_id() == 1)
198 864 : elem->subdomain_id() = _block_id.front();
199 : else
200 180 : elem->subdomain_id() = _block_id.back();
201 186 : }
202 186 : if (!_block_name.empty())
203 346 : for (unsigned int i = 0; i < _block_name.size(); i++)
204 188 : mesh->subdomain_name(_block_id[i]) = _block_name[i];
205 :
206 186 : if (_boundary_id_valid)
207 149 : MooseMesh::changeBoundaryId(*mesh, OUTER_SIDESET_ID, _external_boundary_id, false);
208 186 : if (!_external_boundary_name.empty())
209 : {
210 149 : mesh->get_boundary_info().sideset_name(
211 149 : _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
212 149 : _external_boundary_name;
213 149 : mesh->get_boundary_info().nodeset_name(
214 149 : _external_boundary_id > 0 ? _external_boundary_id : (boundary_id_type)OUTER_SIDESET_ID) =
215 : _external_boundary_name;
216 : }
217 :
218 186 : mesh->prepare_for_use();
219 372 : return dynamic_pointer_cast<MeshBase>(mesh);
220 186 : }
|