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 68128 : SetupMeshAction::validParams()
28 : {
29 68128 : InputParameters params = MooseObjectAction::validParams();
30 136256 : 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 272512 : params.addParam<std::string>(
39 : "type",
40 : "FileMesh",
41 : "A string representing the Moose Object that will be built by this Action");
42 :
43 204384 : params.addParam<bool>("second_order",
44 136256 : 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 272512 : params.addParam<std::vector<SubdomainID>>("block_id", "IDs of the block id/name pairs");
50 272512 : params.addParam<std::vector<SubdomainName>>(
51 : "block_name", "Names of the block id/name pairs (must correspond with \"block_id\"");
52 :
53 272512 : params.addParam<std::vector<BoundaryID>>("boundary_id", {}, "IDs of the boundary id/name pairs");
54 272512 : params.addParam<std::vector<BoundaryName>>(
55 : "boundary_name",
56 : {},
57 : "Names of the boundary id/name pairs (must correspond with \"boundary_id\"");
58 :
59 204384 : params.addParam<bool>("construct_side_list_from_node_list",
60 136256 : 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 272512 : 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 204384 : params.addParam<bool>(
72 : "use_displaced_mesh",
73 136256 : 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 272512 : params.addParam<std::vector<BoundaryName>>(
78 : "ghosted_boundaries", {}, "Boundaries to be ghosted if using Nemesis");
79 272512 : 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 204384 : params.addParam<unsigned int>(
86 136256 : "uniform_refine", 0, "Specify the level of uniform refinement applied to the initial mesh");
87 :
88 272512 : params.addParam<bool>("skip_deletion_repartition_after_refine",
89 136256 : 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 204384 : params.addParam<bool>("skip_partitioning",
99 136256 : false,
100 : "If true the mesh won't be partitioned. This may cause large load "
101 : "imbalances.");
102 :
103 204384 : params.addParam<bool>(
104 : "use_split",
105 136256 : false,
106 : "Use split distributed mesh files; is overriden by the --use-split command line option");
107 272512 : 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 272512 : params.addParamNamesToGroup("displacements ghosted_boundaries ghosted_boundaries_inflation",
114 : "Advanced");
115 272512 : params.addParamNamesToGroup("second_order construct_side_list_from_node_list skip_partitioning",
116 : "Advanced");
117 272512 : params.addParamNamesToGroup("block_id block_name boundary_id boundary_name", "Add Names");
118 204384 : params.addParamNamesToGroup("use_split split_file", "Split Mesh");
119 :
120 68128 : return params;
121 0 : }
122 :
123 67890 : SetupMeshAction::SetupMeshAction(const InputParameters & params)
124 : : MooseObjectAction(params),
125 203594 : _use_split(getParam<bool>("use_split") || _app.getParam<bool>("use_split")),
126 271903 : _split_file(_app.isParamSetByUser("split_file") ? _app.getParam<std::string>("split_file")
127 338421 : : getParam<std::string>("split_file"))
128 : {
129 67890 : }
130 :
131 : void
132 68051 : SetupMeshAction::setupMesh(MooseMesh * mesh)
133 : {
134 204153 : if (isParamValid("ghosted_boundaries"))
135 204153 : for (const auto & bnd_name : getParam<std::vector<BoundaryName>>("ghosted_boundaries"))
136 0 : mesh->addGhostedBoundary(mesh->getBoundaryID(bnd_name));
137 :
138 204153 : 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 68051 : mesh->ghostGhostedBoundaries();
146 :
147 204153 : if (getParam<bool>("second_order"))
148 1312 : mesh->getMesh().all_second_order(true);
149 :
150 : #ifdef LIBMESH_ENABLE_AMR
151 136102 : unsigned int level = getParam<unsigned int>("uniform_refine");
152 :
153 : // Did they specify extra refinement levels on the command-line?
154 204153 : if (_app.isParamSetByUser("refinements"))
155 90 : level += _app.getParam<unsigned int>("refinements");
156 :
157 136102 : mesh->setUniformRefineLevel(level, getParam<bool>("skip_deletion_repartition_after_refine"));
158 : #endif // LIBMESH_ENABLE_AMR
159 :
160 : // Add entity names to the mesh
161 204241 : if (_pars.isParamValid("block_id") && _pars.isParamValid("block_name"))
162 : {
163 88 : std::vector<SubdomainID> ids = getParam<std::vector<SubdomainID>>("block_id");
164 88 : std::vector<SubdomainName> names = getParam<std::vector<SubdomainName>>("block_name");
165 44 : std::set<SubdomainName> seen_it;
166 :
167 44 : if (ids.size() != names.size())
168 4 : mooseError("You must supply the same number of block ids and names parameters");
169 :
170 133 : for (unsigned int i = 0; i < ids.size(); ++i)
171 : {
172 97 : if (seen_it.find(names[i]) != seen_it.end())
173 4 : mooseError("The following dynamic block name is not unique: " + names[i]);
174 93 : seen_it.insert(names[i]);
175 93 : mesh->setSubdomainName(ids[i], names[i]);
176 : }
177 36 : }
178 340215 : if (_pars.isParamValid("boundary_id") && _pars.isParamValid("boundary_name"))
179 : {
180 136086 : std::vector<BoundaryID> ids = getParam<std::vector<BoundaryID>>("boundary_id");
181 136086 : std::vector<BoundaryName> names = getParam<std::vector<BoundaryName>>("boundary_name");
182 68043 : std::set<SubdomainName> seen_it;
183 :
184 68043 : if (ids.size() != names.size())
185 4 : mooseError("You must supply the same number of boundary ids and names parameters");
186 :
187 68069 : for (unsigned int i = 0; i < ids.size(); ++i)
188 : {
189 34 : if (seen_it.find(names[i]) != seen_it.end())
190 4 : mooseError("The following dynamic boundary name is not unique: " + names[i]);
191 30 : mesh->setBoundaryName(ids[i], names[i]);
192 30 : seen_it.insert(names[i]);
193 : }
194 68035 : }
195 :
196 204105 : if (getParam<bool>("construct_side_list_from_node_list"))
197 213 : mesh->getMesh().get_boundary_info().build_side_list_from_node_list();
198 :
199 : // Here we can override the partitioning for special cases
200 204105 : if (getParam<bool>("skip_partitioning"))
201 96 : mesh->getMesh().skip_partitioning(getParam<bool>("skip_partitioning"));
202 68035 : }
203 :
204 : std::string
205 294 : 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 294 : auto split_file = _split_file;
210 294 : 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 294 : if (split_file != "" && split_file_ext != "cpr" && split_file_ext != "cpa.gz")
215 162 : split_file = MooseUtils::stripExtension(split_file) + ".cpa.gz";
216 :
217 294 : if (_type != "FileMesh")
218 : {
219 294 : 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 294 : auto new_pars = FileMesh::validParams();
224 :
225 : // Keep existing parameters where possible
226 294 : new_pars.applyParameters(_moose_object_pars);
227 :
228 882 : new_pars.set<MeshFileName>("file") = split_file;
229 588 : new_pars.set<MooseApp *>(MooseBase::app_param) =
230 294 : moose_object_params.get<MooseApp *>(MooseBase::app_param);
231 294 : moose_object_params = new_pars;
232 294 : }
233 : else
234 : {
235 0 : if (!split_file.empty())
236 0 : moose_object_params.set<MeshFileName>("file") = split_file;
237 : else
238 0 : moose_object_params.set<MeshFileName>("file") =
239 0 : MooseUtils::stripExtension(moose_object_params.get<MeshFileName>("file")) + ".cpa.gz";
240 : }
241 :
242 588 : moose_object_params.set<bool>("_is_split") = true;
243 :
244 588 : return "FileMesh";
245 294 : }
246 :
247 : void
248 200912 : SetupMeshAction::act()
249 : {
250 : // Create the mesh object and tell it to build itself
251 200912 : if (_current_task == "setup_mesh")
252 : {
253 338050 : TIME_SECTION("SetupMeshAction::act::setup_mesh", 1, "Setting Up Mesh", true);
254 :
255 67610 : if (_app.useMasterMesh())
256 849 : _mesh = _app.masterMesh()->safeClone();
257 : else
258 : {
259 133522 : const auto & generator_actions = _awh.getActionListByName("add_mesh_generator");
260 :
261 : // If we trigger any actions that can build MeshGenerators, whether through input file
262 : // syntax or through custom actions, change the default type to construct. We can't yet
263 : // check whether there are any actual MeshGenerator objects because those are added after
264 : // setup_mesh
265 66761 : if (!generator_actions.empty())
266 : {
267 : // Check for whether type has been set or whether for the default type (FileMesh) a file has
268 : // been provided
269 130640 : if (!_pars.isParamSetByUser("type") && !_moose_object_pars.isParamValid("file"))
270 : {
271 26074 : _type = "MeshGeneratorMesh";
272 26074 : auto original_params = _moose_object_pars;
273 52148 : _moose_object_pars = _factory.getValidParams("MeshGeneratorMesh");
274 :
275 : // Since we changing the type on the fly, we'll have to manually extract parameters again
276 : // from the input file object.
277 26074 : _app.builder().extractParams(_registered_identifier, _moose_object_pars);
278 26074 : }
279 90 : else if (!_moose_object_pars.get<bool>("_mesh_generator_mesh"))
280 : {
281 : // There are cases where a custom action may register the "add_mesh_generator" task, but
282 : // may not actually add any mesh generators depending on user input. We don't want to risk
283 : // giving false warnings in this case. However, if we triggered the "add_mesh_generator"
284 : // task through explicit input file syntax, then it is definitely safe to warn
285 4 : for (auto generator_action_ptr : generator_actions)
286 4 : if (dynamic_cast<AddMeshGeneratorAction *>(generator_action_ptr))
287 : {
288 4 : mooseError("Mesh Generators present but the [Mesh] block is set to construct a \"",
289 4 : _type,
290 : "\" mesh, which does not use Mesh Generators in constructing the mesh. ");
291 : }
292 : }
293 : }
294 :
295 : // switch non-file meshes to be a file-mesh if using a pre-split mesh configuration.
296 66757 : if (_use_split)
297 294 : _type = modifyParamsForUseSplit(_moose_object_pars);
298 :
299 200223 : _mesh = _factory.create<MooseMesh>(_type, "mesh", _moose_object_pars);
300 : }
301 67558 : }
302 :
303 133302 : else if (_current_task == "set_mesh_base")
304 : {
305 333255 : TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Setting Mesh", true);
306 :
307 66651 : if (!_app.useMasterMesh() && !_mesh->hasMeshBase())
308 : {
309 : // We want to set the MeshBase object to that coming from mesh generators when the following
310 : // conditions are met:
311 : // 1. We have mesh generators
312 : // 2. We are not using the pre-split mesh
313 : // 3. We are not: recovering/restarting and we are the master application
314 91010 : if (!_app.getMeshGeneratorNames().empty() && !_use_split &&
315 25208 : !((_app.isRecovering() || _app.isRestarting()) && _app.isUltimateMaster()))
316 : {
317 24290 : auto & mesh_generator_system = _app.getMeshGeneratorSystem();
318 : auto mesh_base =
319 24290 : mesh_generator_system.getSavedMesh(mesh_generator_system.mainMeshGeneratorName());
320 24290 : if (_mesh->allowRemoteElementRemoval() != mesh_base->allow_remote_element_removal())
321 0 : mooseError("The MooseMesh and libmesh::MeshBase object coming from mesh generators are "
322 : "out of sync with respect to whether remote elements can be deleted");
323 : mooseAssert(mesh_base, "Null mesh");
324 24290 : _mesh->setMeshBase(std::move(mesh_base));
325 24290 : }
326 : else
327 : {
328 41512 : const auto & mg_names = _app.getMeshGeneratorNames();
329 41512 : std::vector<bool> use_dm;
330 43451 : for (const auto & mg_name : mg_names)
331 5817 : if (hasMeshProperty<bool>("use_distributed_mesh", mg_name))
332 201 : use_dm.push_back(getMeshProperty<bool>("use_distributed_mesh", mg_name));
333 :
334 41512 : if (!use_dm.empty())
335 : {
336 67 : if (std::adjacent_find(use_dm.begin(), use_dm.end(), std::not_equal_to<bool>()) !=
337 134 : use_dm.end())
338 0 : mooseError("You cannot use mesh generators that set different values of the mesh "
339 : "property 'use_distributed_mesh' within the same simulation.");
340 :
341 67 : const auto ptype = use_dm.front() ? MooseMesh::ParallelType::DISTRIBUTED
342 67 : : MooseMesh::ParallelType::REPLICATED;
343 67 : _mesh->setParallelType(ptype);
344 : }
345 :
346 41512 : _mesh->setMeshBase(_mesh->buildMeshBaseObject());
347 41512 : }
348 : }
349 66651 : }
350 :
351 66651 : else if (_current_task == "init_mesh")
352 : {
353 333255 : TIME_SECTION("SetupMeshAction::act::set_mesh_base", 1, "Initializing Mesh", true);
354 :
355 66651 : if (_app.useMasterMesh())
356 : {
357 849 : if (_app.masterDisplacedMesh())
358 0 : _displaced_mesh = _app.masterDisplacedMesh()->safeClone();
359 : }
360 : else
361 : {
362 65802 : _mesh->init();
363 :
364 201970 : if (isParamValid("displacements") && getParam<bool>("use_displaced_mesh"))
365 : {
366 2257 : _displaced_mesh = _mesh->safeClone();
367 2257 : _displaced_mesh->isDisplaced(true);
368 4514 : _displaced_mesh->getMesh().allow_remote_element_removal(
369 2257 : _mesh->getMesh().allow_remote_element_removal());
370 :
371 : std::vector<std::string> displacements =
372 4514 : getParam<std::vector<std::string>>("displacements");
373 2257 : if (displacements.size() < _displaced_mesh->dimension())
374 0 : mooseError("Number of displacements must be greater than or equal to the dimension of "
375 : "the mesh!");
376 2257 : }
377 :
378 65794 : setupMesh(_mesh.get());
379 :
380 65778 : if (_displaced_mesh)
381 2257 : setupMesh(_displaced_mesh.get());
382 : }
383 66627 : }
384 200836 : }
|