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 "SetupMeshAction.h"
11 : #include "MooseApp.h"
12 : #include "MooseMesh.h"
13 : #include "FileMesh.h"
14 : #include "FEProblem.h"
15 : #include "ActionWarehouse.h"
16 : #include "Factory.h"
17 : #include "AddMeshGeneratorAction.h"
18 :
19 : #include <functional>
20 : #include <algorithm>
21 :
22 : registerMooseAction("MooseApp", SetupMeshAction, "setup_mesh");
23 : registerMooseAction("MooseApp", SetupMeshAction, "set_mesh_base");
24 : registerMooseAction("MooseApp", SetupMeshAction, "init_mesh");
25 :
26 : InputParameters
27 62412 : SetupMeshAction::validParams()
28 : {
29 62412 : InputParameters params = MooseObjectAction::validParams();
30 62412 : params.addClassDescription("Add or create Mesh object to the simulation.");
31 :
32 : // Here we are setting the default type of the mesh to construct to "FileMesh". This is to support
33 : // the very long-running legacy syntax where only a file parameter is required to determine the
34 : // type of the "Mesh" block. We are re-adding it though so that we can detect whether or not the
35 : // user has explicitly set the type in an input file. We do this because we want to support
36 : // automatically building a "MeshGeneratorMesh" type when MeshGenerators are added to the
37 : // simulation.
38 62412 : params.addParam<std::string>(
39 : "type",
40 : "FileMesh",
41 : "A string representing the Moose Object that will be built by this Action");
42 :
43 187236 : params.addParam<bool>("second_order",
44 124824 : false,
45 : "Converts a first order mesh to a second order "
46 : "mesh. Note: This is NOT needed if you are reading "
47 : "an actual first order mesh.");
48 :
49 62412 : params.addParam<std::vector<SubdomainID>>("block_id", "IDs of the block id/name pairs");
50 62412 : params.addParam<std::vector<SubdomainName>>(
51 : "block_name", "Names of the block id/name pairs (must correspond with \"block_id\"");
52 :
53 62412 : params.addParam<std::vector<BoundaryID>>("boundary_id", {}, "IDs of the boundary id/name pairs");
54 62412 : params.addParam<std::vector<BoundaryName>>(
55 : "boundary_name",
56 : {},
57 : "Names of the boundary id/name pairs (must correspond with \"boundary_id\"");
58 :
59 187236 : params.addParam<bool>("construct_side_list_from_node_list",
60 124824 : false,
61 : "If true, construct side lists from the nodesets in the mesh (i.e. if "
62 : "every node on a give side is in a nodeset then add that side to a "
63 : "sideset");
64 :
65 62412 : params.addParam<std::vector<std::string>>(
66 : "displacements",
67 : "The variables corresponding to the x y z displacements of the mesh. If "
68 : "this is provided then the displacements will be taken into account during "
69 : "the computation. Creation of the displaced mesh can be suppressed even if "
70 : "this is set by setting 'use_displaced_mesh = false'.");
71 187236 : params.addParam<bool>(
72 : "use_displaced_mesh",
73 124824 : true,
74 : "Create the displaced mesh if the 'displacements' "
75 : "parameter is set. If this is 'false', a displaced mesh will not be created, "
76 : "regardless of whether 'displacements' is set.");
77 62412 : params.addParam<std::vector<BoundaryName>>(
78 : "ghosted_boundaries", {}, "Boundaries to be ghosted if using Nemesis");
79 62412 : params.addParam<std::vector<Real>>("ghosted_boundaries_inflation",
80 : "If you are using ghosted boundaries you will want to set "
81 : "this value to a vector of amounts to inflate the bounding "
82 : "boxes by. ie if you are running a 3D problem you might set "
83 : "it to '0.2 0.1 0.4'");
84 :
85 187236 : params.addParam<unsigned int>(
86 124824 : "uniform_refine", 0, "Specify the level of uniform refinement applied to the initial mesh");
87 :
88 187236 : params.addParam<bool>("skip_deletion_repartition_after_refine",
89 124824 : false,
90 : "If the flag is true, uniform refinements will run more efficiently, "
91 : "but at the same time, there might be extra ghosting elements. "
92 : "The number of layers of additional ghosting elements depends "
93 : "on the number of uniform refinement levels. This flag "
94 : "should be used only when you have a 'fine enough' coarse mesh and want "
95 : "to refine the mesh by a few levels. Otherwise, it might introduce an "
96 : "unbalanced workload and too large ghosting domain. ");
97 :
98 187236 : params.addParam<bool>("skip_partitioning",
99 124824 : false,
100 : "If true the mesh won't be partitioned. This may cause large load "
101 : "imbalances.");
102 :
103 187236 : params.addParam<bool>(
104 : "use_split",
105 124824 : false,
106 : "Use split distributed mesh files; is overriden by the --use-split command line option");
107 62412 : params.addParam<std::string>("split_file",
108 : "",
109 : "Optional name of split mesh file(s) to write/read; is overridden "
110 : "by the --split-file command line option");
111 :
112 : // groups
113 62412 : params.addParamNamesToGroup("displacements ghosted_boundaries ghosted_boundaries_inflation",
114 : "Advanced");
115 62412 : params.addParamNamesToGroup("second_order construct_side_list_from_node_list skip_partitioning",
116 : "Advanced");
117 62412 : params.addParamNamesToGroup("block_id block_name boundary_id boundary_name", "Add Names");
118 62412 : params.addParamNamesToGroup("use_split split_file", "Split Mesh");
119 :
120 62412 : return params;
121 0 : }
122 :
123 62174 : SetupMeshAction::SetupMeshAction(const InputParameters & params)
124 : : MooseObjectAction(params),
125 62174 : _use_split(getParam<bool>("use_split") || _app.getParam<bool>("use_split")),
126 186211 : _split_file(_app.isParamSetByUser("split_file") ? _app.getParam<std::string>("split_file")
127 186211 : : getParam<std::string>("split_file"))
128 : {
129 62174 : }
130 :
131 : void
132 62264 : SetupMeshAction::setupMesh(MooseMesh * mesh)
133 : {
134 62264 : if (isParamValid("ghosted_boundaries"))
135 62264 : for (const auto & bnd_name : getParam<std::vector<BoundaryName>>("ghosted_boundaries"))
136 0 : mesh->addGhostedBoundary(mesh->getBoundaryID(bnd_name));
137 :
138 62264 : if (isParamValid("ghosted_boundaries_inflation"))
139 : {
140 : std::vector<Real> ghosted_boundaries_inflation =
141 0 : getParam<std::vector<Real>>("ghosted_boundaries_inflation");
142 0 : mesh->setGhostedBoundaryInflation(ghosted_boundaries_inflation);
143 0 : }
144 :
145 62264 : mesh->ghostGhostedBoundaries();
146 :
147 62264 : if (getParam<bool>("second_order"))
148 1151 : mesh->getMesh().all_second_order(true);
149 :
150 : #ifdef LIBMESH_ENABLE_AMR
151 62264 : unsigned int level = getParam<unsigned int>("uniform_refine");
152 :
153 : // Did they specify extra refinement levels on the command-line?
154 62264 : if (_app.isParamSetByUser("refinements"))
155 27 : level += _app.getParam<unsigned int>("refinements");
156 :
157 62264 : mesh->setUniformRefineLevel(level, getParam<bool>("skip_deletion_repartition_after_refine"));
158 : #endif // LIBMESH_ENABLE_AMR
159 :
160 : // Add entity names to the mesh
161 62264 : if (_pars.isParamValid("block_id") && _pars.isParamValid("block_name"))
162 : {
163 43 : std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("block_id");
164 43 : std::vector<SubdomainName> names = getParam<std::vector<SubdomainName>>("block_name");
165 43 : std::set<SubdomainName> seen_it;
166 :
167 43 : if (ids.size() != names.size())
168 4 : mooseError("You must supply the same number of block ids and names parameters");
169 :
170 129 : for (unsigned int i = 0; i < ids.size(); ++i)
171 : {
172 94 : if (seen_it.find(names[i]) != seen_it.end())
173 4 : mooseError("The following dynamic block name is not unique: " + names[i]);
174 90 : seen_it.insert(names[i]);
175 90 : mesh->setSubdomainName(ids[i], names[i]);
176 : }
177 35 : }
178 62256 : if (_pars.isParamValid("boundary_id") && _pars.isParamValid("boundary_name"))
179 : {
180 62256 : std::vector<BoundaryID> ids = getParam<std::vector<BoundaryID>>("boundary_id");
181 62256 : std::vector<BoundaryName> names = getParam<std::vector<BoundaryName>>("boundary_name");
182 62256 : std::set<SubdomainName> seen_it;
183 :
184 62256 : if (ids.size() != names.size())
185 4 : mooseError("You must supply the same number of boundary ids and names parameters");
186 :
187 62280 : for (unsigned int i = 0; i < ids.size(); ++i)
188 : {
189 32 : if (seen_it.find(names[i]) != seen_it.end())
190 4 : mooseError("The following dynamic boundary name is not unique: " + names[i]);
191 28 : mesh->setBoundaryName(ids[i], names[i]);
192 28 : seen_it.insert(names[i]);
193 : }
194 62248 : }
195 :
196 62248 : if (getParam<bool>("construct_side_list_from_node_list"))
197 198 : mesh->getMesh().get_boundary_info().build_side_list_from_node_list();
198 :
199 : // Here we can override the partitioning for special cases
200 62248 : if (getParam<bool>("skip_partitioning"))
201 28 : mesh->getMesh().skip_partitioning(getParam<bool>("skip_partitioning"));
202 62248 : }
203 :
204 : std::string
205 266 : SetupMeshAction::modifyParamsForUseSplit(InputParameters & moose_object_params) const
206 : {
207 : // Get the split_file extension, if there is one, and use that to decide
208 : // between .cpr and .cpa.gz
209 266 : auto split_file = _split_file;
210 266 : std::string split_file_ext = MooseUtils::getExtension(split_file);
211 :
212 : // If split_file already has the .cpr or .cpa.gz extension, we go with
213 : // that, otherwise we strip off the extension and append ".cpa.gz".
214 266 : if (split_file != "" && split_file_ext != "cpr" && split_file_ext != "cpa.gz")
215 149 : split_file = MooseUtils::stripExtension(split_file) + ".cpa.gz";
216 :
217 266 : if (_type != "FileMesh")
218 : {
219 266 : if (split_file.empty())
220 0 : mooseError("Cannot use split mesh for a non-file mesh without specifying --split-file on "
221 : "command line or the Mesh/split_file parameter");
222 :
223 266 : auto new_pars = FileMesh::validParams();
224 :
225 : // Keep existing parameters where possible
226 266 : new_pars.applyParameters(_moose_object_pars);
227 :
228 266 : new_pars.set<MeshFileName>("file") = split_file;
229 266 : new_pars.set<MooseApp *>("_moose_app") = moose_object_params.get<MooseApp *>("_moose_app");
230 266 : moose_object_params = new_pars;
231 266 : }
232 : else
233 : {
234 0 : if (!split_file.empty())
235 0 : moose_object_params.set<MeshFileName>("file") = split_file;
236 : else
237 0 : moose_object_params.set<MeshFileName>("file") =
238 0 : MooseUtils::stripExtension(moose_object_params.get<MeshFileName>("file")) + ".cpa.gz";
239 : }
240 :
241 266 : moose_object_params.set<bool>("_is_split") = true;
242 :
243 532 : return "FileMesh";
244 266 : }
245 :
246 : void
247 183864 : SetupMeshAction::act()
248 : {
249 : // Create the mesh object and tell it to build itself
250 183864 : if (_current_task == "setup_mesh")
251 : {
252 61898 : TIME_SECTION("SetupMeshAction::act::setup_mesh", 1, "Setting Up Mesh", true);
253 :
254 61898 : if (_app.useMasterMesh())
255 784 : _mesh = _app.masterMesh()->safeClone();
256 : else
257 : {
258 61114 : const auto & generator_actions = _awh.getActionListByName("add_mesh_generator");
259 :
260 : // If we trigger any actions that can build MeshGenerators, whether through input file
261 : // syntax or through custom actions, change the default type to construct. We can't yet
262 : // check whether there are any actual MeshGenerator objects because those are added after
263 : // setup_mesh
264 61114 : if (!generator_actions.empty())
265 : {
266 : // Check for whether type has been set or whether for the default type (FileMesh) a file has
267 : // been provided
268 23550 : if (!_pars.isParamSetByUser("type") && !_moose_object_pars.isParamValid("file"))
269 : {
270 23466 : _type = "MeshGeneratorMesh";
271 23466 : auto original_params = _moose_object_pars;
272 23466 : _moose_object_pars = _factory.getValidParams("MeshGeneratorMesh");
273 :
274 : // Since we changing the type on the fly, we'll have to manually extract parameters again
275 : // from the input file object.
276 23466 : _app.builder().extractParams(_registered_identifier, _moose_object_pars);
277 23466 : }
278 84 : else if (!_moose_object_pars.get<bool>("_mesh_generator_mesh"))
279 : {
280 : // There are cases where a custom action may register the "add_mesh_generator" task, but
281 : // may not actually add any mesh generators depending on user input. We don't want to risk
282 : // giving false warnings in this case. However, if we triggered the "add_mesh_generator"
283 : // task through explicit input file syntax, then it is definitely safe to warn
284 4 : for (auto generator_action_ptr : generator_actions)
285 4 : if (dynamic_cast<AddMeshGeneratorAction *>(generator_action_ptr))
286 : {
287 4 : mooseError("Mesh Generators present but the [Mesh] block is set to construct a \"",
288 4 : _type,
289 : "\" mesh, which does not use Mesh Generators in constructing the mesh. ");
290 : }
291 : }
292 : }
293 :
294 : // switch non-file meshes to be a file-mesh if using a pre-split mesh configuration.
295 61110 : if (_use_split)
296 266 : _type = modifyParamsForUseSplit(_moose_object_pars);
297 :
298 61110 : _mesh = _factory.create<MooseMesh>(_type, "mesh", _moose_object_pars);
299 : }
300 61846 : }
301 :
302 121966 : else if (_current_task == "set_mesh_base")
303 : {
304 60983 : TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Setting Mesh", true);
305 :
306 60983 : if (!_app.useMasterMesh() && !_mesh->hasMeshBase())
307 : {
308 : // We want to set the MeshBase object to that coming from mesh generators when the following
309 : // conditions are met:
310 : // 1. We have mesh generators
311 : // 2. We are not using the pre-split mesh
312 : // 3. We are not: recovering/restarting and we are the master application
313 82842 : if (!_app.getMeshGeneratorNames().empty() && !_use_split &&
314 22643 : !((_app.isRecovering() || _app.isRestarting()) && _app.isUltimateMaster()))
315 : {
316 21760 : auto & mesh_generator_system = _app.getMeshGeneratorSystem();
317 : auto mesh_base =
318 21760 : mesh_generator_system.getSavedMesh(mesh_generator_system.mainMeshGeneratorName());
319 21760 : if (_mesh->allowRemoteElementRemoval() != mesh_base->allow_remote_element_removal())
320 0 : mooseError("The MooseMesh and libmesh::MeshBase object coming from mesh generators are "
321 : "out of sync with respect to whether remote elements can be deleted");
322 : mooseAssert(mesh_base, "Null mesh");
323 21760 : _mesh->setMeshBase(std::move(mesh_base));
324 21760 : }
325 : else
326 : {
327 38439 : const auto & mg_names = _app.getMeshGeneratorNames();
328 38439 : std::vector<bool> use_dm;
329 40281 : for (const auto & mg_name : mg_names)
330 1842 : if (hasMeshProperty<bool>("use_distributed_mesh", mg_name))
331 67 : use_dm.push_back(getMeshProperty<bool>("use_distributed_mesh", mg_name));
332 :
333 38439 : if (!use_dm.empty())
334 : {
335 67 : if (std::adjacent_find(use_dm.begin(), use_dm.end(), std::not_equal_to<bool>()) !=
336 134 : use_dm.end())
337 0 : mooseError("You cannot use mesh generators that set different values of the mesh "
338 : "property 'use_distributed_mesh' within the same simulation.");
339 :
340 67 : const auto ptype = use_dm.front() ? MooseMesh::ParallelType::DISTRIBUTED
341 67 : : MooseMesh::ParallelType::REPLICATED;
342 67 : _mesh->setParallelType(ptype);
343 : }
344 :
345 38439 : _mesh->setMeshBase(_mesh->buildMeshBaseObject());
346 38439 : }
347 : }
348 60983 : }
349 :
350 60983 : else if (_current_task == "init_mesh")
351 : {
352 60983 : TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Initializing Mesh", true);
353 :
354 60983 : if (_app.useMasterMesh())
355 : {
356 784 : if (_app.masterDisplacedMesh())
357 0 : _displaced_mesh = _app.masterDisplacedMesh()->safeClone();
358 : }
359 : else
360 : {
361 60199 : _mesh->init();
362 :
363 60191 : if (isParamValid("displacements") && getParam<bool>("use_displaced_mesh"))
364 : {
365 2073 : _displaced_mesh = _mesh->safeClone();
366 2073 : _displaced_mesh->isDisplaced(true);
367 4146 : _displaced_mesh->getMesh().allow_remote_element_removal(
368 2073 : _mesh->getMesh().allow_remote_element_removal());
369 :
370 : std::vector<std::string> displacements =
371 2073 : getParam<std::vector<std::string>>("displacements");
372 2073 : if (displacements.size() < _displaced_mesh->dimension())
373 0 : mooseError("Number of displacements must be greater than or equal to the dimension of "
374 : "the mesh!");
375 2073 : }
376 :
377 60191 : setupMesh(_mesh.get());
378 :
379 60175 : if (_displaced_mesh)
380 2073 : setupMesh(_displaced_mesh.get());
381 : }
382 60959 : }
383 183788 : }
|