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 "FillBetweenSidesetsGenerator.h"
11 : #include "FillBetweenPointVectorsTools.h"
12 :
13 : #include "MooseMeshUtils.h"
14 : #include "CastUniquePointer.h"
15 : #include "libmesh/node.h"
16 : #include "libmesh/mesh_serializer.h"
17 :
18 : registerMooseObject("MooseApp", FillBetweenSidesetsGenerator);
19 :
20 : InputParameters
21 3212 : FillBetweenSidesetsGenerator::validParams()
22 : {
23 3212 : InputParameters params = MeshGenerator::validParams();
24 12848 : params.addRequiredParam<MeshGeneratorName>("input_mesh_1",
25 : "The input mesh that contains boundary_1");
26 12848 : params.addRequiredParam<MeshGeneratorName>("input_mesh_2",
27 : "The input mesh that contains boundary_2");
28 12848 : params.addRequiredParam<std::vector<BoundaryName>>(
29 : "boundary_1", "the first boundary that needs to be connected.");
30 12848 : params.addRequiredParam<std::vector<BoundaryName>>(
31 : "boundary_2", "the second boundary that needs to be connected.");
32 9636 : params.addParam<Point>(
33 6424 : "mesh_1_shift", Point(0.0, 0.0, 0.0), "Translation vector to be applied to input_mesh_1");
34 9636 : params.addParam<Point>(
35 6424 : "mesh_2_shift", Point(0.0, 0.0, 0.0), "Translation vector to be applied to input_mesh_2");
36 19272 : params.addRequiredRangeCheckedParam<unsigned int>(
37 : "num_layers", "num_layers>0", "Number of layers of elements created between the boundaries.");
38 12848 : params.addParam<subdomain_id_type>("block_id", 1, "ID to be assigned to the transition layer.");
39 9636 : params.addParam<boundary_id_type>(
40 : "input_boundary_1_id",
41 6424 : 10000,
42 : "Boundary ID to be assigned to the boundary defined by positions_vector_1.");
43 9636 : params.addParam<boundary_id_type>(
44 : "input_boundary_2_id",
45 6424 : 10000,
46 : "Boundary ID to be assigned to the boundary defined by positions_vector_2.");
47 9636 : params.addParam<boundary_id_type>("begin_side_boundary_id",
48 6424 : 10000,
49 : "Boundary ID to be assigned to the boundary connecting "
50 : "starting points of the positions_vectors.");
51 9636 : params.addParam<boundary_id_type>("end_side_boundary_id",
52 6424 : 10000,
53 : "Boundary ID to be assigned to the boundary connecting ending "
54 : "points of the positions_vectors.");
55 9636 : params.addParam<bool>(
56 : "use_quad_elements",
57 6424 : false,
58 : "Whether QUAD4 instead of TRI3 elements are used to construct the transition layer.");
59 16060 : params.addRangeCheckedParam<Real>(
60 : "bias_parameter",
61 6424 : 1.0,
62 : "bias_parameter>=0",
63 : "Parameter used to set up biasing of the layers: bias_parameter > 0.0 is used as the biasing "
64 : "factor; bias_parameter = 0.0 activates automatic biasing based on local node density on "
65 : "both input boundaries.");
66 16060 : params.addRangeCheckedParam<Real>(
67 : "gaussian_sigma",
68 6424 : 3.0,
69 : "gaussian_sigma>0.0",
70 : "Gaussian parameter used to smoothen local node density for automatic biasing; this "
71 : "parameter is not used if another biasing option is selected.");
72 9636 : params.addParam<bool>(
73 : "keep_inputs",
74 6424 : true,
75 : "Whether to output the input meshes stitched with the transition layer connector.");
76 3212 : params.addClassDescription("This FillBetweenSidesetsGenerator object is designed to generate a "
77 : "transition layer to connect two boundaries of two input meshes.");
78 3212 : return params;
79 0 : }
80 :
81 77 : FillBetweenSidesetsGenerator::FillBetweenSidesetsGenerator(const InputParameters & parameters)
82 : : MeshGenerator(parameters),
83 77 : _input_name_1(getParam<MeshGeneratorName>("input_mesh_1")),
84 154 : _input_name_2(getParam<MeshGeneratorName>("input_mesh_2")),
85 154 : _boundary_1(getParam<std::vector<BoundaryName>>("boundary_1")),
86 154 : _boundary_2(getParam<std::vector<BoundaryName>>("boundary_2")),
87 154 : _mesh_1_shift(getParam<Point>("mesh_1_shift")),
88 231 : _mesh_2_shift(getParam<Point>("mesh_2_shift")),
89 154 : _num_layers(getParam<unsigned int>("num_layers")),
90 154 : _block_id(getParam<subdomain_id_type>("block_id")),
91 154 : _input_boundary_1_id(getParam<boundary_id_type>("input_boundary_1_id")),
92 154 : _input_boundary_2_id(getParam<boundary_id_type>("input_boundary_2_id")),
93 154 : _begin_side_boundary_id(getParam<boundary_id_type>("begin_side_boundary_id")),
94 154 : _end_side_boundary_id(getParam<boundary_id_type>("end_side_boundary_id")),
95 154 : _use_quad_elements(getParam<bool>("use_quad_elements")),
96 154 : _bias_parameter(getParam<Real>("bias_parameter")),
97 154 : _sigma(getParam<Real>("gaussian_sigma")),
98 154 : _keep_inputs(getParam<bool>("keep_inputs")),
99 77 : _input_1(getMeshByName(_input_name_1)),
100 154 : _input_2(getMeshByName(_input_name_2))
101 : {
102 77 : if (_input_name_1.compare(_input_name_2) == 0)
103 6 : paramError("input_mesh_2", "This parameter must be different from input_mesh_1.");
104 74 : }
105 :
106 : std::unique_ptr<MeshBase>
107 71 : FillBetweenSidesetsGenerator::generate()
108 : {
109 : // We're querying subdomain id caches from our input meshes
110 71 : if (!_input_1->preparation().has_cached_elem_data)
111 71 : _input_1->cache_elem_data();
112 71 : if (!_input_2->preparation().has_cached_elem_data)
113 71 : _input_2->cache_elem_data();
114 :
115 71 : auto input_mesh_1 = std::move(_input_1);
116 71 : auto input_mesh_2 = std::move(_input_2);
117 :
118 : // Only serialized meshes are supported right now
119 71 : libMesh::MeshSerializer serial_1(*input_mesh_1);
120 71 : libMesh::MeshSerializer serial_2(*input_mesh_2);
121 :
122 142 : if (*(input_mesh_1->elem_dimensions().begin()) != 2 ||
123 142 : *(input_mesh_1->elem_dimensions().rbegin()) != 2)
124 0 : paramError("input_mesh_1", "Only 2D meshes are supported.");
125 142 : if (*(input_mesh_2->elem_dimensions().begin()) != 2 ||
126 142 : *(input_mesh_2->elem_dimensions().rbegin()) != 2)
127 0 : paramError("input_mesh_2", "Only 2D meshes are supported.");
128 :
129 71 : MeshTools::Modification::translate(
130 71 : *input_mesh_1, _mesh_1_shift(0), _mesh_1_shift(1), _mesh_1_shift(2));
131 71 : MeshTools::Modification::translate(
132 71 : *input_mesh_2, _mesh_2_shift(0), _mesh_2_shift(1), _mesh_2_shift(2));
133 :
134 : const auto input_mesh_1_external_bids =
135 71 : MooseMeshUtils::getBoundaryIDs(*input_mesh_1, _boundary_1, false);
136 : const auto input_mesh_2_external_bids =
137 71 : MooseMeshUtils::getBoundaryIDs(*input_mesh_2, _boundary_2, false);
138 :
139 115 : for (unsigned int i = 1; i < input_mesh_1_external_bids.size(); i++)
140 : {
141 44 : MooseMeshUtils::changeBoundaryId(
142 44 : *input_mesh_1, input_mesh_1_external_bids[i], input_mesh_1_external_bids.front(), true);
143 : }
144 109 : for (unsigned int i = 1; i < input_mesh_2_external_bids.size(); i++)
145 : {
146 38 : MooseMeshUtils::changeBoundaryId(
147 38 : *input_mesh_2, input_mesh_2_external_bids[i], input_mesh_2_external_bids.front(), true);
148 : }
149 :
150 71 : if (!FillBetweenPointVectorsTools::isExternalBoundary(*input_mesh_1,
151 71 : input_mesh_1_external_bids.front()))
152 0 : paramError("boundary_1", "The boundary provided is not an external boundary.");
153 71 : if (!FillBetweenPointVectorsTools::isExternalBoundary(*input_mesh_2,
154 71 : input_mesh_2_external_bids.front()))
155 0 : paramError("boundary_2", "The boundary provided is not an external boundary.");
156 :
157 : Real max_input_mesh_1_node_radius;
158 : Real max_input_mesh_2_node_radius;
159 71 : std::vector<dof_id_type> boundary_1_ordered_nodes;
160 71 : std::vector<dof_id_type> boundary_2_ordered_nodes;
161 :
162 : try
163 : {
164 142 : FillBetweenPointVectorsTools::isBoundaryOpenSingleSegment(
165 71 : *input_mesh_1,
166 : max_input_mesh_1_node_radius,
167 : boundary_1_ordered_nodes,
168 71 : MooseMeshUtils::meshCentroidCalculator(*input_mesh_1),
169 71 : input_mesh_1_external_bids.front());
170 : }
171 6 : catch (MooseException & e)
172 : {
173 12 : paramError("boundary_1", e.what());
174 0 : }
175 : try
176 : {
177 130 : FillBetweenPointVectorsTools::isBoundaryOpenSingleSegment(
178 65 : *input_mesh_2,
179 : max_input_mesh_2_node_radius,
180 : boundary_2_ordered_nodes,
181 65 : MooseMeshUtils::meshCentroidCalculator(*input_mesh_2),
182 65 : input_mesh_2_external_bids.front());
183 : }
184 0 : catch (MooseException & e)
185 : {
186 0 : paramError("boundary_2", e.what());
187 0 : }
188 :
189 65 : std::vector<Point> positions_vector_1;
190 65 : std::vector<Point> positions_vector_2;
191 :
192 564 : for (auto & boundary_1_node_id : boundary_1_ordered_nodes)
193 499 : positions_vector_1.push_back(*input_mesh_1->node_ptr(boundary_1_node_id));
194 :
195 692 : for (auto & boundary_2_node_id : boundary_2_ordered_nodes)
196 627 : positions_vector_2.push_back(*input_mesh_2->node_ptr(boundary_2_node_id));
197 :
198 0 : const boundary_id_type input_boundary_1_id = _keep_inputs ? (std::max({_input_boundary_1_id,
199 30 : _input_boundary_2_id,
200 30 : _begin_side_boundary_id,
201 30 : _end_side_boundary_id}) +
202 : 1)
203 95 : : _input_boundary_1_id;
204 35 : const boundary_id_type input_boundary_2_id =
205 65 : _keep_inputs ? (input_boundary_1_id + 1) : _input_boundary_2_id;
206 65 : auto mesh = buildReplicatedMesh(2);
207 65 : FillBetweenPointVectorsTools::fillBetweenPointVectorsGenerator(*mesh,
208 : positions_vector_1,
209 : positions_vector_2,
210 65 : _num_layers,
211 65 : _block_id,
212 : input_boundary_1_id,
213 : input_boundary_2_id,
214 65 : _begin_side_boundary_id,
215 65 : _end_side_boundary_id,
216 65 : _type,
217 65 : _name,
218 65 : _use_quad_elements,
219 65 : _bias_parameter,
220 65 : _sigma);
221 :
222 65 : if (_keep_inputs)
223 : {
224 30 : mesh->prepare_for_use();
225 60 : mesh->stitch_meshes(*input_mesh_1,
226 : input_boundary_1_id,
227 30 : input_mesh_1_external_bids.front(),
228 : TOLERANCE,
229 : true,
230 : false,
231 : true,
232 : true);
233 60 : mesh->stitch_meshes(*input_mesh_2,
234 : input_boundary_2_id,
235 30 : input_mesh_2_external_bids.front(),
236 : TOLERANCE,
237 : true,
238 : false,
239 : true,
240 : true);
241 : }
242 130 : return dynamic_pointer_cast<MeshBase>(mesh);
243 65 : }
|