https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseMesh.C
Go to the documentation of this file.
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 "MooseError.h"
11#include "MooseMesh.h"
12#include "Factory.h"
14#include "MooseUtils.h"
15#include "MooseApp.h"
16#include "RelationshipManager.h"
17#include "PointListAdaptor.h"
18#include "Executioner.h"
19#include "NonlinearSystemBase.h"
20#include "LinearSystem.h"
21#include "AuxiliarySystem.h"
22#include "Assembly.h"
23#include "SubProblem.h"
24#include "MooseVariableBase.h"
25#include "MooseMeshUtils.h"
27#include "FEProblemBase.h"
28
29#include <utility>
30
31// libMesh
32#include "libmesh/bounding_box.h"
33#include "libmesh/boundary_info.h"
34#include "libmesh/mesh_tools.h"
35#include "libmesh/parallel.h"
36#include "libmesh/mesh_communication.h"
37#include "libmesh/periodic_boundary_base.h"
38#include "libmesh/fe_base.h"
39#include "libmesh/fe_interface.h"
40#include "libmesh/mesh_communication.h"
41#include "libmesh/mesh_tools.h"
42#include "libmesh/parallel.h"
43#include "libmesh/parallel_elem.h"
44#include "libmesh/parallel_node.h"
45#include "libmesh/parallel_ghost_sync.h"
46#include "libmesh/utility.h"
47#include "libmesh/remote_elem.h"
48#include "libmesh/linear_partitioner.h"
49#include "libmesh/centroid_partitioner.h"
50#include "libmesh/parmetis_partitioner.h"
51#include "libmesh/hilbert_sfc_partitioner.h"
52#include "libmesh/morton_sfc_partitioner.h"
53#include "libmesh/edge_edge2.h"
54#include "libmesh/checkpoint_io.h"
55#include "libmesh/mesh_refinement.h"
56#include "libmesh/quadrature.h"
57#include "libmesh/boundary_info.h"
58#include "libmesh/periodic_boundaries.h"
59#include "libmesh/quadrature_gauss.h"
60#include "libmesh/point_locator_base.h"
61#include "libmesh/default_coupling.h"
62#include "libmesh/ghost_point_neighbors.h"
63#include "libmesh/fe_type.h"
64#include "libmesh/enum_to_string.h"
65#include "libmesh/elem_side_builder.h"
66
67// Make newer nanoflann API compatible with older nanoflann versions
68#if NANOFLANN_VERSION < 0x150
69namespace nanoflann
70{
71typedef SearchParams SearchParameters;
72
73template <typename T, typename U>
74using ResultItem = std::pair<T, U>;
75}
76#endif
77
78const std::array<bool, 3> MooseMesh::periodic_dim_default{false, false, false};
79
82{
84
85 MooseEnum parallel_type("DEFAULT REPLICATED DISTRIBUTED", "DEFAULT");
86 params.addParam<MooseEnum>("parallel_type",
87 parallel_type,
88 "DEFAULT: Use libMesh::ReplicatedMesh unless --distributed-mesh is "
89 "specified on the command line "
90 "REPLICATED: Always use libMesh::ReplicatedMesh "
91 "DISTRIBUTED: Always use libMesh::DistributedMesh");
92
93 params.addParam<bool>(
94 "allow_renumbering",
95 true,
96 "If allow_renumbering=false, node and element numbers are kept fixed until deletion");
97
98 params.addParam<MooseEnum>(
99 "partitioner",
100 partitioning(),
101 "Specifies a mesh partitioner to use when splitting the mesh for a parallel computation.");
102 MooseEnum direction("x y z radial");
103 params.addParam<MooseEnum>("centroid_partitioner_direction",
104 direction,
105 "Specifies the sort direction if using the centroid partitioner. "
106 "Available options: x, y, z, radial");
107
108 MooseEnum patch_update_strategy("never always auto iteration", "never");
109 params.addParam<MooseEnum>(
110 "patch_update_strategy",
111 patch_update_strategy,
112 "How often to update the geometric search 'patch'. The default is to "
113 "never update it (which is the most efficient but could be a problem "
114 "with lots of relative motion). 'always' will update the patch for all "
115 "secondary nodes at the beginning of every timestep which might be time "
116 "consuming. 'auto' will attempt to determine at the start of which "
117 "timesteps the patch for all secondary nodes needs to be updated automatically."
118 "'iteration' updates the patch at every nonlinear iteration for a "
119 "subset of secondary nodes for which penetration is not detected. If there "
120 "can be substantial relative motion between the primary and secondary surfaces "
121 "during the nonlinear iterations within a timestep, it is advisable to use "
122 "'iteration' option to ensure accurate contact detection.");
123
124 // Note: This parameter is named to match 'construct_side_list_from_node_list' in SetupMeshAction
125 params.addParam<bool>(
126 "construct_node_list_from_side_list",
127 true,
128 "Whether or not to generate nodesets from the sidesets (currently often required).");
129 params.addParam<bool>(
130 "displace_node_list_by_side_list",
131 true,
132 "Whether to renumber existing nodesets with ids matching sidesets that "
133 "lack names matching sidesets, when constructing nodesets from sidesets via the default "
134 "'construct_node_list_from_side_list' option, rather than to merge them with the sideset.");
135 params.addParam<unsigned int>(
136 "patch_size", 40, "The number of nodes to consider in the NearestNode neighborhood.");
137 params.addParam<unsigned int>("ghosting_patch_size",
138 "The number of nearest neighbors considered "
139 "for ghosting purposes when 'iteration' "
140 "patch update strategy is used. Default is "
141 "5 * patch_size.");
142 params.addParam<unsigned int>("max_leaf_size",
143 10,
144 "The maximum number of points in each leaf of the KDTree used in "
145 "the nearest neighbor search. As the leaf size becomes larger,"
146 "KDTree construction becomes faster but the nearest neighbor search"
147 "becomes slower.");
148
149 params.addParam<bool>("build_all_side_lowerd_mesh",
150 false,
151 "True to build the lower-dimensional mesh for all sides.");
152
153 params.addParam<bool>("skip_refine_when_use_split",
154 true,
155 "True to skip uniform refinements when using a pre-split mesh.");
156
157 params.addParam<std::vector<SubdomainID>>(
158 "add_subdomain_ids",
159 "The listed subdomain ids will be assumed valid for the mesh. This permits setting up "
160 "subdomain restrictions for subdomains initially containing no elements, which can occur, "
161 "for example, in additive manufacturing simulations which dynamically add and remove "
162 "elements. Names for this subdomains may be provided using add_subdomain_names. In this case "
163 "this list and add_subdomain_names must contain the same number of items.");
164 params.addParam<std::vector<SubdomainName>>(
165 "add_subdomain_names",
166 "The listed subdomain names will be assumed valid for the mesh. This permits setting up "
167 "subdomain restrictions for subdomains initially containing no elements, which can occur, "
168 "for example, in additive manufacturing simulations which dynamically add and remove "
169 "elements. IDs for this subdomains may be provided using add_subdomain_ids. Otherwise IDs "
170 "are automatically assigned. In case add_subdomain_ids is set too, both lists must contain "
171 "the same number of items.");
172
173 params.addParam<std::vector<BoundaryID>>(
174 "add_sideset_ids",
175 "The listed sideset ids will be assumed valid for the mesh. This permits setting up boundary "
176 "restrictions for sidesets initially containing no sides. Names for this sidesets may be "
177 "provided using add_sideset_names. In this case this list and add_sideset_names must contain "
178 "the same number of items.");
179 params.addParam<std::vector<BoundaryName>>(
180 "add_sideset_names",
181 "The listed sideset names will be assumed valid for the mesh. This permits setting up "
182 "boundary restrictions for sidesets initially containing no sides. Ids for this sidesets may "
183 "be provided using add_sideset_ids. In this case this list and add_sideset_ids must contain "
184 "the same number of items.");
185
186 params.addParam<std::vector<BoundaryID>>(
187 "add_nodeset_ids",
188 "The listed nodeset ids will be assumed valid for the mesh. This permits setting up boundary "
189 "restrictions for node initially containing no sides. Names for this nodesets may be "
190 "provided using add_nodeset_names. In this case this list and add_nodeset_names must contain "
191 "the same number of items.");
192 params.addParam<std::vector<BoundaryName>>(
193 "add_nodeset_names",
194 "The listed nodeset names will be assumed valid for the mesh. This permits setting up "
195 "boundary restrictions for nodesets initially containing no sides. Ids for this nodesets may "
196 "be provided using add_nodesets_ids. In this case this list and add_nodesets_ids must "
197 "contain the same number of items.");
198
200
201 // This indicates that the derived mesh type accepts a MeshGenerator, and should be set to true in
202 // derived types that do so.
203 params.addPrivateParam<bool>("_mesh_generator_mesh", false);
204
205 // Whether or not the mesh is pre split
206 params.addPrivateParam<bool>("_is_split", false);
207
208 params.registerBase("MooseMesh");
209
210 // groups
211 params.addParamNamesToGroup("patch_update_strategy patch_size max_leaf_size", "Geometric search");
212 params.addParamNamesToGroup("add_subdomain_ids add_subdomain_names add_sideset_ids "
213 "add_sideset_names add_nodeset_ids add_nodeset_names",
214 "Pre-declaration of future mesh sub-entities");
215 params.addParamNamesToGroup("construct_node_list_from_side_list build_all_side_lowerd_mesh "
216 "displace_node_list_by_side_list",
217 "Automatic definition of mesh element sides entities");
218 params.addParamNamesToGroup("partitioner centroid_partitioner_direction", "Partitioning");
219
220 return params;
221}
222
224 : MooseObject(parameters),
225 Restartable(this, "Mesh"),
226 PerfGraphInterface(this),
227 _parallel_type(getParam<MooseEnum>("parallel_type").getEnum<MooseMesh::ParallelType>()),
228 _use_distributed_mesh(false),
229 _distribution_overridden(false),
230 _parallel_type_overridden(false),
231 _mesh(nullptr),
232 _partitioner_name(getParam<MooseEnum>("partitioner")),
233 _partitioner_overridden(false),
234 _custom_partitioner_requested(false),
235 _uniform_refine_level(0),
236 _skip_refine_when_use_split(getParam<bool>("skip_refine_when_use_split")),
237 _skip_deletion_repartition_after_refine(false),
238 _is_nemesis(false),
239 _patch_size(getParam<unsigned int>("patch_size")),
240 _ghosting_patch_size(isParamValid("ghosting_patch_size")
241 ? getParam<unsigned int>("ghosting_patch_size")
242 : 5 * _patch_size),
243 _max_leaf_size(getParam<unsigned int>("max_leaf_size")),
244 _patch_update_strategy(
245 getParam<MooseEnum>("patch_update_strategy").getEnum<Moose::PatchUpdateType>()),
246 _regular_orthogonal_mesh(false),
247 _is_split(getParam<bool>("_is_split")),
248 _allow_recovery(true),
249 _construct_node_list_from_side_list(getParam<bool>("construct_node_list_from_side_list")),
250 _displace_node_list_by_side_list(getParam<bool>("displace_node_list_by_side_list")),
251 _need_delete(false),
252 _allow_remote_element_removal(true),
253 _need_ghost_ghosted_boundaries(true),
254 _is_displaced(false),
255 _coord_sys(
256 declareRestartableData<std::map<SubdomainID, Moose::CoordinateSystemType>>("coord_sys")),
257 _rz_coord_axis(getParam<MooseEnum>("rz_coord_axis")),
258 _coord_system_set(false),
259 _doing_p_refinement(false)
260{
261 if (isParamValid("ghosting_patch_size") && (_patch_update_strategy != Moose::Iteration))
262 mooseError("Ghosting patch size parameter has to be set in the mesh block "
263 "only when 'iteration' patch update strategy is used.");
264
265 if (isParamValid("coord_block"))
266 {
267 if (isParamValid("block"))
268 paramWarning("block",
269 "You set both 'Mesh/block' and 'Mesh/coord_block'. The value of "
270 "'Mesh/coord_block' will be used.");
271
272 _provided_coord_blocks = getParam<std::vector<SubdomainName>>("coord_block");
273 }
274 else if (isParamValid("block"))
275 _provided_coord_blocks = getParam<std::vector<SubdomainName>>("block");
276
277 if (getParam<bool>("build_all_side_lowerd_mesh"))
278 // Do not initially allow removal of remote elements
280
282
283#ifdef MOOSE_KOKKOS_ENABLED
285 _kokkos_mesh = std::make_unique<Moose::Kokkos::Mesh>(*this);
286#endif
287}
288
290 : MooseObject(other_mesh._pars),
291 Restartable(this, "Mesh"),
292 PerfGraphInterface(this, "CopiedMesh"),
293 _built_from_other_mesh(true),
294 _parallel_type(other_mesh._parallel_type),
295 _use_distributed_mesh(other_mesh._use_distributed_mesh),
296 _distribution_overridden(other_mesh._distribution_overridden),
297 _parallel_type_overridden(other_mesh._parallel_type_overridden),
298 _mesh(other_mesh.getMesh().clone()),
299 _partitioner_name(other_mesh._partitioner_name),
300 _partitioner_overridden(other_mesh._partitioner_overridden),
301 _custom_partitioner_requested(other_mesh._custom_partitioner_requested),
302 _uniform_refine_level(other_mesh.uniformRefineLevel()),
303 _skip_refine_when_use_split(other_mesh._skip_refine_when_use_split),
304 _skip_deletion_repartition_after_refine(other_mesh._skip_deletion_repartition_after_refine),
305 _is_nemesis(other_mesh._is_nemesis),
306 _mesh_subdomains(other_mesh._mesh_subdomains),
307 _mesh_boundary_ids(other_mesh._mesh_boundary_ids),
308 _mesh_sideset_ids(other_mesh._mesh_sideset_ids),
309 _mesh_nodeset_ids(other_mesh._mesh_nodeset_ids),
310 _patch_size(other_mesh._patch_size),
311 _ghosting_patch_size(other_mesh._ghosting_patch_size),
312 _max_leaf_size(other_mesh._max_leaf_size),
313 _patch_update_strategy(other_mesh._patch_update_strategy),
314 _regular_orthogonal_mesh(false),
315 _is_split(other_mesh._is_split),
316 _allow_recovery(other_mesh._allow_recovery),
317 _construct_node_list_from_side_list(other_mesh._construct_node_list_from_side_list),
318 _displace_node_list_by_side_list(other_mesh._displace_node_list_by_side_list),
319 _need_delete(other_mesh._need_delete),
320 _allow_remote_element_removal(other_mesh._allow_remote_element_removal),
321 _need_ghost_ghosted_boundaries(other_mesh._need_ghost_ghosted_boundaries),
322 _coord_sys(other_mesh._coord_sys),
323 _rz_coord_axis(other_mesh._rz_coord_axis),
324 _subdomain_id_to_rz_coord_axis(other_mesh._subdomain_id_to_rz_coord_axis),
325 _coord_system_set(other_mesh._coord_system_set),
326 _provided_coord_blocks(other_mesh._provided_coord_blocks),
327 _doing_p_refinement(other_mesh._doing_p_refinement)
328{
329 mooseAssert(other_mesh._moose_mesh_prepared,
330 "The mesh being cloned from must already be fully prepared; we rely on that to "
331 "rebuild our own prepare()-derived caches below");
332
333 _bounds.resize(other_mesh._bounds.size());
334 for (std::size_t i = 0; i < _bounds.size(); ++i)
335 {
336 _bounds[i].resize(other_mesh._bounds[i].size());
337 for (std::size_t j = 0; j < _bounds[i].size(); ++j)
338 _bounds[i][j] = other_mesh._bounds[i][j];
339 }
340
342
343#ifdef MOOSE_KOKKOS_ENABLED
345 _kokkos_mesh = std::make_unique<Moose::Kokkos::Mesh>(*this);
346#endif
347
348 // update() rebuilds caches (boundary node/element lists, lower-D/higher-D element maps, element
349 // ID info, etc.) directly from our own (just-cloned) _mesh. Those caches hold pointers into the
350 // MeshBase they were built from, so other_mesh's copies of them cannot simply be copied above;
351 // they must be rebuilt against our own clone instead.
352 update();
354}
355
362
363void
365{
366 // free memory
367 for (auto & bnode : _bnd_nodes)
368 delete bnode;
369
370 for (auto & it : _node_set_nodes)
371 it.second.clear();
372
373 _node_set_nodes.clear();
374
375 for (auto & it : _bnd_node_ids)
376 it.second.clear();
377
378 _bnd_node_ids.clear();
379 _bnd_node_range.reset();
380}
381
382void
384{
385 // free memory
386 for (auto & belem : _bnd_elems)
387 delete belem;
388
389 for (auto & it : _bnd_elem_ids)
390 it.second.clear();
391
392 _bnd_elem_ids.clear();
393 _bnd_elem_range.reset();
394}
395
396void
398{
399 TIME_SECTION("prepare", 2, "Preparing Mesh", true);
400
401 parallel_object_only();
402
403 mooseAssert(_mesh, "The MeshBase has not been constructed");
404
405 if (!dynamic_cast<DistributedMesh *>(&getMesh()) || _is_nemesis)
406 // For whatever reason we do not want to allow renumbering here nor ever in the future?
407 getMesh().allow_renumbering(false);
408
409 if (!_mesh->is_prepared())
410 {
411 _mesh->complete_preparation();
412 _moose_mesh_prepared = false;
413 }
414
416 return;
417
418 // Collect (local) subdomain IDs
419 _mesh_subdomains.clear();
420 for (const auto & elem : getMesh().element_ptr_range())
421 _mesh_subdomains.insert(elem->subdomain_id());
422
423 // add explicitly requested subdomains
424 if (isParamValid("add_subdomain_ids") && !isParamValid("add_subdomain_names"))
425 {
426 // only subdomain ids are explicitly given
427 const auto & add_subdomain_id = getParam<std::vector<SubdomainID>>("add_subdomain_ids");
428 _mesh_subdomains.insert(add_subdomain_id.begin(), add_subdomain_id.end());
429 }
430 else if (isParamValid("add_subdomain_ids") && isParamValid("add_subdomain_names"))
431 {
432 const auto add_subdomain =
433 getParam<SubdomainID, SubdomainName>("add_subdomain_ids", "add_subdomain_names");
434 for (const auto & [sub_id, sub_name] : add_subdomain)
435 {
436 // add subdomain id
437 _mesh_subdomains.insert(sub_id);
438 // set name of the subdomain just added
439 setSubdomainName(sub_id, sub_name, true);
440 }
441 }
442 else if (isParamValid("add_subdomain_names"))
443 {
444 // the user has defined add_subdomain_names, but not add_subdomain_ids
445 const auto & add_subdomain_names = getParam<std::vector<SubdomainName>>("add_subdomain_names");
446
447 // to define subdomain ids, we need the largest subdomain id defined yet.
448 subdomain_id_type offset = 0;
449 if (!_mesh_subdomains.empty())
450 offset = *_mesh_subdomains.rbegin();
451
452 // add all subdomains (and auto-assign ids)
453 for (const SubdomainName & sub_name : add_subdomain_names)
454 {
455 // to avoid two subdomains with the same ID (notably on recover)
456 if (getSubdomainID(sub_name) != libMesh::Elem::invalid_subdomain_id)
457 continue;
458 const auto sub_id = ++offset;
459 // add subdomain id
460 _mesh_subdomains.insert(sub_id);
461 // set name of the subdomain just added
462 setSubdomainName(sub_id, sub_name, true);
463 }
464 }
465
466 // Make sure nodesets have been generated
468
469 // Collect (local) boundary IDs
470 const std::set<BoundaryID> & local_bids = getMesh().get_boundary_info().get_boundary_ids();
471 _mesh_boundary_ids.insert(local_bids.begin(), local_bids.end());
472
473 const std::set<BoundaryID> & local_node_bids =
474 getMesh().get_boundary_info().get_node_boundary_ids();
475 _mesh_nodeset_ids.insert(local_node_bids.begin(), local_node_bids.end());
476
477 const std::set<BoundaryID> & local_side_bids =
478 getMesh().get_boundary_info().get_side_boundary_ids();
479 _mesh_sideset_ids.insert(local_side_bids.begin(), local_side_bids.end());
480
481 // Add explicitly requested sidesets/nodesets
482 // This is done *after* the side boundaries (e.g. "right", ...) have been generated.
483 auto add_sets = [this](const bool sidesets, auto & set_ids)
484 {
485 const std::string type = sidesets ? "sideset" : "nodeset";
486 const std::string id_param = "add_" + type + "_ids";
487 const std::string name_param = "add_" + type + "_names";
488
489 if (isParamValid(id_param))
490 {
491 const auto & add_ids = getParam<std::vector<BoundaryID>>(id_param);
492 _mesh_boundary_ids.insert(add_ids.begin(), add_ids.end());
493 set_ids.insert(add_ids.begin(), add_ids.end());
495 {
496 const auto & add_names = getParam<std::vector<BoundaryName>>(name_param);
497 mooseAssert(add_names.size() == add_ids.size(),
498 "Id and name sets must be the same size when adding.");
499 for (const auto i : index_range(add_ids))
500 setBoundaryName(add_ids[i], add_names[i]);
501 }
502 }
503 else if (isParamValid(name_param))
504 {
505 // the user has defined names, but not ids
506 const auto & add_names = getParam<std::vector<BoundaryName>>(name_param);
507
508 auto & mesh_ids = sidesets ? _mesh_sideset_ids : _mesh_nodeset_ids;
509
510 // to define ids, we need the largest id defined yet.
511 boundary_id_type offset = 0;
512 if (!mesh_ids.empty())
513 offset = *mesh_ids.rbegin();
514 if (!_mesh_boundary_ids.empty())
515 offset = std::max(offset, *_mesh_boundary_ids.rbegin());
516
517 // add all sidesets/nodesets (and auto-assign ids)
518 for (const auto & name : add_names)
519 {
520 // to avoid two sets with the same ID (notably on recover)
522 continue;
523 const auto id = ++offset;
524 // add sideset id
525 _mesh_boundary_ids.insert(id);
526 set_ids.insert(id);
527 // set name of the sideset just added
529 }
530 }
531 };
532
533 add_sets(true, _mesh_sideset_ids);
534 add_sets(false, _mesh_nodeset_ids);
535
536 // Communicate subdomain and boundary IDs if this is a parallel mesh
537 if (!getMesh().is_serial())
538 {
543 }
544
546 {
548 setCoordSystem(_provided_coord_blocks, getParam<MultiMooseEnum>("coord_type"));
549 else if (_pars.isParamSetByUser("coord_type"))
551 "Trying to set coordinate system type information based on the user input file, but "
552 "the coordinate system type information has already been set programmatically! "
553 "Either remove your coordinate system type information from the input file, or contact "
554 "your application developer");
555 }
556
557 // Set general axisymmetric axes if provided
558 if (isParamValid("rz_coord_blocks") && isParamValid("rz_coord_origins") &&
559 isParamValid("rz_coord_directions"))
560 {
561 const auto rz_coord_blocks = getParam<std::vector<SubdomainName>>("rz_coord_blocks");
562 const auto rz_coord_origins = getParam<std::vector<Point>>("rz_coord_origins");
563 const auto rz_coord_directions = getParam<std::vector<RealVectorValue>>("rz_coord_directions");
564 if (rz_coord_origins.size() == rz_coord_blocks.size() &&
565 rz_coord_directions.size() == rz_coord_blocks.size())
566 {
567 std::vector<std::pair<Point, RealVectorValue>> rz_coord_axes;
568 for (unsigned int i = 0; i < rz_coord_origins.size(); ++i)
569 rz_coord_axes.push_back(std::make_pair(rz_coord_origins[i], rz_coord_directions[i]));
570
571 setGeneralAxisymmetricCoordAxes(rz_coord_blocks, rz_coord_axes);
572
573 if (isParamSetByUser("rz_coord_axis"))
574 mooseError("The parameter 'rz_coord_axis' may not be provided if 'rz_coord_blocks', "
575 "'rz_coord_origins', and 'rz_coord_directions' are provided.");
576 }
577 else
578 mooseError("The parameters 'rz_coord_blocks', 'rz_coord_origins', and "
579 "'rz_coord_directions' must all have the same size.");
580 }
581 else if (isParamValid("rz_coord_blocks") || isParamValid("rz_coord_origins") ||
582 isParamValid("rz_coord_directions"))
583 mooseError("If any of the parameters 'rz_coord_blocks', 'rz_coord_origins', and "
584 "'rz_coord_directions' are provided, then all must be provided.");
585
587
588 update();
589
590 // Check if there is subdomain name duplication for the same subdomain ID
592
594}
595
596void
597MooseMesh::prepare(const MeshBase * libmesh_dbg_var(mesh_to_clone))
598{
599 mooseDeprecated("MooseMesh::prepare(const MeshBase *) is deprecated, please use the "
600 "no-argument MooseMesh::prepare() instead");
601 mooseAssert(!mesh_to_clone, "Cloning a mesh_to_clone is no longer supported by prepare()");
602 prepare();
603}
604
605bool
607{
608 // *Rebuild* the node to element map. I emphasize rebuild because if it has not been built
609 // previously we won't do anything
611 {
612 mooseAssert(_node_to_elem_map.empty(), "If it hasn't been built, it better well be empty");
613 return false;
614 }
615
616 _node_to_elem_map.clear();
619 return true;
620}
621
622void
624{
625 TIME_SECTION("update", 3, "Updating Mesh", true);
626
627 // Rebuild the boundary conditions
629
632 cacheInfo();
634
635 // this will make moose mesh aware of p-refinement added by mesh generators including
636 // a file mesh generator loading a restart checkpoint file
637 _max_p_level = 0;
638 _max_h_level = 0;
639 for (const auto & elem : getMesh().active_local_element_ptr_range())
640 {
641 if (elem->p_level() > _max_p_level)
642 _max_p_level = elem->p_level();
643 if (elem->level() > _max_h_level)
644 _max_h_level = elem->level();
645 }
648
649 // the flag might have been set by calling doingPRefinement(true)
651
653
654#ifdef MOOSE_KOKKOS_ENABLED
657 _kokkos_mesh->update();
658#endif
659
661
663}
664
665void
667{
668 auto & mesh = getMesh();
669
670 if (!mesh.is_serial())
672 "Hybrid finite element method must use replicated mesh.\nCurrently lower-dimensional mesh "
673 "does not support mesh re-partitioning and a debug assertion being hit related with "
674 "neighbors of lower-dimensional element, with distributed mesh.");
675
676 // Lower-D element build requires neighboring element information
677 if (!mesh.is_prepared())
678 mesh.find_neighbors();
679
680 // maximum number of sides of all elements
681 unsigned int max_n_sides = 0;
682
683 // remove existing lower-d element first
684 std::set<Elem *> deleteable_elems;
685 for (auto & elem : mesh.element_ptr_range())
686 if (_lower_d_interior_blocks.count(elem->subdomain_id()) ||
687 _lower_d_boundary_blocks.count(elem->subdomain_id()))
688 deleteable_elems.insert(elem);
689 else if (elem->n_sides() > max_n_sides)
690 max_n_sides = elem->n_sides();
691
692 for (auto & elem : deleteable_elems)
693 mesh.delete_elem(elem);
694 for (const auto & id : _lower_d_interior_blocks)
695 _mesh_subdomains.erase(id);
696 for (const auto & id : _lower_d_boundary_blocks)
697 _mesh_subdomains.erase(id);
700
701 mesh.comm().max(max_n_sides);
702
703 deleteable_elems.clear();
704
705 // get all side types
706 std::set<int> interior_side_types;
707 std::set<int> boundary_side_types;
708 for (const auto & elem : mesh.active_element_ptr_range())
709 for (const auto side : elem->side_index_range())
710 {
711 Elem * neig = elem->neighbor_ptr(side);
712 std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side));
713 if (neig)
714 interior_side_types.insert(side_elem->type());
715 else
716 boundary_side_types.insert(side_elem->type());
717 }
718 mesh.comm().set_union(interior_side_types);
719 mesh.comm().set_union(boundary_side_types);
720
721 // assign block ids for different side types
722 std::map<ElemType, SubdomainID> interior_block_ids;
723 std::map<ElemType, SubdomainID> boundary_block_ids;
724 // we assume this id is not used by the mesh
725 auto id = libMesh::Elem::invalid_subdomain_id - 2;
726 for (const auto & tpid : interior_side_types)
727 {
728 const auto type = ElemType(tpid);
729 mesh.set_subdomain_name(
730 id, "INTERNAL_SIDE_LOWERD_SUBDOMAIN_" + Utility::enum_to_string(type), true);
731 interior_block_ids[type] = id;
732 _lower_d_interior_blocks.insert(id);
733 if (_mesh_subdomains.count(id) > 0)
734 mooseError("Trying to add a mesh block with id ", id, " that has existed in the mesh");
735 _mesh_subdomains.insert(id);
736 --id;
737 }
738 for (const auto & tpid : boundary_side_types)
739 {
740 const auto type = ElemType(tpid);
741 mesh.set_subdomain_name(
742 id, "BOUNDARY_SIDE_LOWERD_SUBDOMAIN_" + Utility::enum_to_string(type), true);
743 boundary_block_ids[type] = id;
744 _lower_d_boundary_blocks.insert(id);
745 if (_mesh_subdomains.count(id) > 0)
746 mooseError("Trying to add a mesh block with id ", id, " that has existed in the mesh");
747 _mesh_subdomains.insert(id);
748 --id;
749 }
750
751 dof_id_type max_elem_id = mesh.max_elem_id();
752 unique_id_type max_unique_id = mesh.parallel_max_unique_id();
753
754 std::vector<Elem *> side_elems;
756 for (const auto & elem : mesh.active_element_ptr_range())
757 {
758 // skip existing lower-d elements
759 if (elem->interior_parent())
760 continue;
761
762 for (const auto side : elem->side_index_range())
763 {
764 Elem * neig = elem->neighbor_ptr(side);
765
766 bool build_side = false;
767 if (!neig)
768 build_side = true;
769 else
770 {
771 mooseAssert(!neig->is_remote(), "We error if the mesh is not serial");
772 if (!neig->active())
773 build_side = true;
774 else if (neig->level() == elem->level() && elem->id() < neig->id())
775 build_side = true;
776 }
777
778 if (build_side)
779 {
780 std::unique_ptr<Elem> side_elem(elem->build_side_ptr(side));
781
782 // The side will be added with the same processor id as the parent.
783 side_elem->processor_id() = elem->processor_id();
784
785 // Add subdomain ID
786 if (neig)
787 side_elem->subdomain_id() = interior_block_ids.at(side_elem->type());
788 else
789 side_elem->subdomain_id() = boundary_block_ids.at(side_elem->type());
790
791 // set ids consistently across processors (these ids will be temporary)
792 side_elem->set_id(max_elem_id + elem->id() * max_n_sides + side);
793 side_elem->set_unique_id(max_unique_id + elem->id() * max_n_sides + side);
794
795 // Also assign the side's interior parent, so it is always
796 // easy to figure out the Elem we came from.
797 // Note: the interior parent could be a ghost element.
798 side_elem->set_interior_parent(elem);
799
800 side_elems.push_back(side_elem.release());
801
802 // add link between higher d element to lower d element
803 auto pair = std::make_pair(elem, side);
804 auto link = std::make_pair(pair, side_elems.back());
805 auto ilink = std::make_pair(side_elems.back(), side);
808 }
809 }
810 }
811
812 // finally, add the lower-dimensional element to the mesh
813 // Note: lower-d interior element will exist on a processor if its associated interior
814 // parent exists on a processor whether or not being a ghost. Lower-d elements will
815 // get its interior parent's processor id.
816 for (auto & elem : side_elems)
817 mesh.add_elem(elem);
818
819 // we do all the stuff in prepare_for_use such as renumber_nodes_and_elements(),
820 // update_parallel_id_counts(), cache_elem_dims(), etc. except partitioning here.
821 const bool skip_partitioning_old = mesh.skip_partitioning();
822 mesh.skip_partitioning(true);
823 // Finding neighbors is ambiguous for lower-dimensional elements on interior faces
824 mesh.allow_find_neighbors(false);
825 mesh.prepare_for_use();
826 mesh.skip_partitioning(skip_partitioning_old);
827}
828
829const Node &
830MooseMesh::node(const dof_id_type i) const
831{
832 mooseDeprecated("MooseMesh::node() is deprecated, please use MooseMesh::nodeRef() instead");
833 return nodeRef(i);
834}
835
836Node &
837MooseMesh::node(const dof_id_type i)
838{
839 mooseDeprecated("MooseMesh::node() is deprecated, please use MooseMesh::nodeRef() instead");
840 return nodeRef(i);
841}
842
843const Node &
844MooseMesh::nodeRef(const dof_id_type i) const
845{
846 const auto node_ptr = queryNodePtr(i);
847 mooseAssert(node_ptr, "Missing node");
848 return *node_ptr;
849}
850
851Node &
852MooseMesh::nodeRef(const dof_id_type i)
853{
854 return const_cast<Node &>(const_cast<const MooseMesh *>(this)->nodeRef(i));
855}
856
857const Node *
858MooseMesh::nodePtr(const dof_id_type i) const
859{
860 return &nodeRef(i);
861}
862
863Node *
864MooseMesh::nodePtr(const dof_id_type i)
865{
866 return &nodeRef(i);
867}
868
869const Node *
870MooseMesh::queryNodePtr(const dof_id_type i) const
871{
872 if (i > getMesh().max_node_id())
873 {
874 auto it = _quadrature_nodes.find(i);
875 if (it == _quadrature_nodes.end())
876 return nullptr;
877 auto & node_ptr = it->second;
878 mooseAssert(node_ptr, "Uninitialized quadrature node");
879 return node_ptr;
880 }
881
882 return getMesh().query_node_ptr(i);
883}
884
885Node *
886MooseMesh::queryNodePtr(const dof_id_type i)
887{
888 return const_cast<Node *>(const_cast<const MooseMesh *>(this)->queryNodePtr(i));
889}
890
891void
893{
894 TIME_SECTION("meshChanged", 3, "Updating Because Mesh Changed");
895
896 update();
897
898 // Delete all of the cached ranges
899 _active_node_range.reset();
901 _local_node_range.reset();
902 _bnd_node_range.reset();
903 _bnd_elem_range.reset();
904
905 // Rebuild the ranges
911
912 // Call the callback function onMeshChanged
914}
915
916void
920
921void
923{
924 TIME_SECTION("cacheChangedLists", 5, "Caching Changed Lists");
925
926 ConstElemRange elem_range(getMesh().local_elements_begin(), getMesh().local_elements_end(), 1);
927 CacheChangedListsThread cclt(*this);
928 Threads::parallel_reduce(elem_range, cclt);
929
931
932 _refined_elements = std::make_unique<ConstElemPointerRange>(cclt._refined_elements.begin(),
933 cclt._refined_elements.end());
934 _coarsened_elements = std::make_unique<ConstElemPointerRange>(cclt._coarsened_elements.begin(),
935 cclt._coarsened_elements.end());
937}
938
941{
942 return _refined_elements.get();
943}
944
947{
948 return _coarsened_elements.get();
949}
950
951const std::vector<const Elem *> &
953{
954 auto elem_to_child_pair = _coarsened_element_children.find(elem);
955 mooseAssert(elem_to_child_pair != _coarsened_element_children.end(), "Missing element in map");
956 return elem_to_child_pair->second;
957}
958
959void
960MooseMesh::updateActiveSemiLocalNodeRange(std::set<dof_id_type> & ghosted_elems)
961{
962 TIME_SECTION("updateActiveSemiLocalNodeRange", 5, "Updating ActiveSemiLocalNode Range");
963
964 _semilocal_node_list.clear();
965
966 // First add the nodes connected to local elems
967 const ConstElemRange * active_local_elems = getActiveLocalElementRange();
968 for (const auto & elem : *active_local_elems)
969 {
970 for (unsigned int n = 0; n < elem->n_nodes(); ++n)
971 {
972 // Since elem is const here but we require a non-const Node * to
973 // store in the _semilocal_node_list (otherwise things like
974 // UpdateDisplacedMeshThread don't work), we are using a
975 // const_cast. A more long-term fix would be to have
976 // getActiveLocalElementRange return a non-const ElemRange.
977 Node * node = const_cast<Node *>(elem->node_ptr(n));
978
980 }
981 }
982
983 // Now add the nodes connected to ghosted_elems
984 for (const auto & ghost_elem_id : ghosted_elems)
985 {
986 Elem * elem = getMesh().elem_ptr(ghost_elem_id);
987 for (unsigned int n = 0; n < elem->n_nodes(); n++)
988 {
989 Node * node = elem->node_ptr(n);
990
992 }
993 }
994
995 // Now create the actual range
996 _active_semilocal_node_range = std::make_unique<SemiLocalNodeRange>(_semilocal_node_list.begin(),
998}
999
1000bool
1001MooseMesh::isSemiLocal(Node * const node) const
1002{
1003 return _semilocal_node_list.find(node) != _semilocal_node_list.end();
1004}
1005
1011{
1012public:
1014
1015 bool operator()(const BndNode * const & lhs, const BndNode * const & rhs)
1016 {
1017 if (lhs->_bnd_id < rhs->_bnd_id)
1018 return true;
1019
1020 if (lhs->_bnd_id > rhs->_bnd_id)
1021 return false;
1022
1023 if (lhs->_node->id() < rhs->_node->id())
1024 return true;
1025
1026 if (lhs->_node->id() > rhs->_node->id())
1027 return false;
1028
1029 return false;
1030 }
1031};
1032
1033void
1035{
1036 TIME_SECTION("buildNodeList", 5, "Building Node List");
1037
1038 freeBndNodes();
1039
1040 auto bc_tuples = getMesh().get_boundary_info().build_node_list();
1041
1042 int n = bc_tuples.size();
1043 _bnd_nodes.clear();
1044 _bnd_nodes.reserve(n);
1045 for (const auto & t : bc_tuples)
1046 {
1047 auto node_id = std::get<0>(t);
1048 auto bc_id = std::get<1>(t);
1049
1050 _bnd_nodes.push_back(new BndNode(getMesh().node_ptr(node_id), bc_id));
1051 _node_set_nodes[bc_id].push_back(node_id);
1052 _bnd_node_ids[bc_id].insert(node_id);
1053 }
1054
1055 _bnd_nodes.reserve(_bnd_nodes.size() + _extra_bnd_nodes.size());
1056 for (unsigned int i = 0; i < _extra_bnd_nodes.size(); i++)
1057 {
1058 BndNode * bnode = new BndNode(_extra_bnd_nodes[i]._node, _extra_bnd_nodes[i]._bnd_id);
1059 _bnd_nodes.push_back(bnode);
1060 _bnd_node_ids[std::get<1>(bc_tuples[i])].insert(_extra_bnd_nodes[i]._node->id());
1061 }
1062
1063 // This sort is here so that boundary conditions are always applied in the same order
1064 std::sort(_bnd_nodes.begin(), _bnd_nodes.end(), BndNodeCompare());
1065}
1066
1067void
1069{
1070 auto & mesh = getMesh();
1071
1075
1076 for (auto & elem : as_range(mesh.local_elements_begin(), mesh.local_elements_end()))
1077 {
1078 _max_sides_per_elem = std::max(_max_sides_per_elem, elem->n_sides());
1079 _max_nodes_per_elem = std::max(_max_nodes_per_elem, elem->n_nodes());
1080
1081 for (unsigned int side = 0; side < elem->n_sides(); ++side)
1082 _max_nodes_per_side = std::max(_max_nodes_per_side, elem->side_ptr(side)->n_nodes());
1083 }
1084
1085 mesh.comm().max(_max_sides_per_elem);
1086 mesh.comm().max(_max_nodes_per_elem);
1087 mesh.comm().max(_max_nodes_per_side);
1088}
1089
1090void
1092{
1093 unsigned int n = getMesh().n_elem_integers() + 1;
1094
1095 _block_id_mapping.clear();
1096 _max_ids.clear();
1097 _min_ids.clear();
1098 _id_identical_flag.clear();
1099
1100 _block_id_mapping.resize(n);
1101 _max_ids.resize(n, std::numeric_limits<dof_id_type>::min());
1102 _min_ids.resize(n, std::numeric_limits<dof_id_type>::max());
1103 _id_identical_flag.resize(n, std::vector<bool>(n, true));
1104 for (const auto & elem : getMesh().active_local_element_ptr_range())
1105 for (unsigned int i = 0; i < n; ++i)
1106 {
1107 auto id = (i == n - 1 ? elem->subdomain_id() : elem->get_extra_integer(i));
1108 _block_id_mapping[i][elem->subdomain_id()].insert(id);
1109 if (id > _max_ids[i])
1110 _max_ids[i] = id;
1111 if (id < _min_ids[i])
1112 _min_ids[i] = id;
1113 for (unsigned int j = 0; j < n; ++j)
1114 {
1115 auto idj = (j == n - 1 ? elem->subdomain_id() : elem->get_extra_integer(j));
1116 if (i != j && _id_identical_flag[i][j] && id != idj)
1117 _id_identical_flag[i][j] = false;
1118 }
1119 }
1120
1121 for (unsigned int i = 0; i < n; ++i)
1122 {
1123 for (auto & blk : meshSubdomains())
1124 comm().set_union(_block_id_mapping[i][blk]);
1126 }
1127 comm().max(_max_ids);
1128 comm().min(_min_ids);
1129}
1130
1131std::unordered_map<dof_id_type, std::set<dof_id_type>>
1132MooseMesh::getElemIDMapping(const std::string & from_id_name, const std::string & to_id_name) const
1133{
1134 auto & mesh_base = getMesh();
1135
1136 if (!mesh_base.has_elem_integer(from_id_name))
1137 mooseError("Mesh does not have the element integer name '", from_id_name, "'");
1138 if (!mesh_base.has_elem_integer(to_id_name))
1139 mooseError("Mesh does not have the element integer name '", to_id_name, "'");
1140
1141 const auto id1 = mesh_base.get_elem_integer_index(from_id_name);
1142 const auto id2 = mesh_base.get_elem_integer_index(to_id_name);
1143
1144 std::unordered_map<dof_id_type, std::set<dof_id_type>> id_map;
1145 for (const auto id : getAllElemIDs(id1))
1146 id_map[id] = std::set<dof_id_type>();
1147
1148 for (const auto & elem : mesh_base.active_local_element_ptr_range())
1149 id_map[elem->get_extra_integer(id1)].insert(elem->get_extra_integer(id2));
1150
1151 for (auto & [id, ids] : id_map)
1152 {
1153 libmesh_ignore(id); // avoid overzealous gcc 9.4 unused var warning
1154 comm().set_union(ids);
1155 }
1156
1157 return id_map;
1158}
1159
1160std::set<dof_id_type>
1161MooseMesh::getAllElemIDs(unsigned int elem_id_index) const
1162{
1163 std::set<dof_id_type> unique_ids;
1164 for (auto & pair : _block_id_mapping[elem_id_index])
1165 for (auto & id : pair.second)
1166 unique_ids.insert(id);
1167 return unique_ids;
1168}
1169
1170std::set<dof_id_type>
1171MooseMesh::getElemIDsOnBlocks(unsigned int elem_id_index, const std::set<SubdomainID> & blks) const
1172{
1173 std::set<dof_id_type> unique_ids;
1174 for (auto & blk : blks)
1175 {
1176 auto it = _block_id_mapping[elem_id_index].find(blk);
1177 if (it == _block_id_mapping[elem_id_index].end())
1178 mooseError("Block ", blk, " is not available on the mesh");
1179
1180 for (auto & mid : it->second)
1181 unique_ids.insert(mid);
1182 }
1183 return unique_ids;
1184}
1185
1186void
1188{
1189 TIME_SECTION("buildBndElemList", 5, "Building Boundary Elements List");
1190
1191 freeBndElems();
1192
1193 auto bc_tuples = getMesh().get_boundary_info().build_active_side_list();
1194
1195 int n = bc_tuples.size();
1196 _bnd_elems.clear();
1197 _bnd_elems.reserve(n);
1198 for (const auto & t : bc_tuples)
1199 {
1200 auto elem_id = std::get<0>(t);
1201 auto side_id = std::get<1>(t);
1202 auto bc_id = std::get<2>(t);
1203
1204 _bnd_elems.push_back(new BndElement(getMesh().elem_ptr(elem_id), side_id, bc_id));
1205 _bnd_elem_ids[bc_id].insert(elem_id);
1206 }
1207}
1208
1209std::unordered_map<dof_id_type, std::vector<dof_id_type>> &
1211{
1212 if (!_node_to_elem_map_built) // Guard the creation with a double checked lock
1213 {
1214 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1215
1217 {
1218 // This is allowing the timing to be run even with threads
1219 // This is safe because all threads will be waiting on this section when it runs
1220 // NOTE: Do not copy this construction to other places without thinking REALLY hard about it
1221 // The PerfGraph is NOT threadsafe and will cause all kinds of havok if care isn't taken
1222 auto in_threads = Threads::in_threads;
1223 Threads::in_threads = false;
1224 TIME_SECTION("nodeToElemMap", 5, "Building Node To Elem Map");
1225 Threads::in_threads = in_threads;
1226
1227 mooseAssert(_node_to_elem_map.empty(), "Expected empty map before building");
1228 for (const auto & elem : getMesh().active_element_ptr_range())
1229 for (unsigned int n = 0; n < elem->n_nodes(); n++)
1230 _node_to_elem_map[elem->node_id(n)].push_back(elem->id());
1231
1232 _node_to_elem_map_built = true; // MUST be set at the end for double-checked locking to work!
1233 }
1234 }
1235 return _node_to_elem_map;
1236}
1237
1238const std::unordered_map<dof_id_type, std::vector<dof_id_type>> &
1243
1244const ConstElemRange *
1246{
1247 return &getMesh().active_local_element_stored_range();
1248}
1249
1250NodeRange *
1252{
1253 if (!_active_node_range)
1254 {
1255 TIME_SECTION("getActiveNodeRange", 5);
1256
1258 std::make_unique<NodeRange>(getMesh().active_nodes_begin(), getMesh().active_nodes_end());
1259 }
1260
1261 return _active_node_range.get();
1262}
1263
1266{
1267 mooseAssert(_active_semilocal_node_range,
1268 "_active_semilocal_node_range has not been created yet!");
1269
1270 return _active_semilocal_node_range.get();
1271}
1272
1273ConstNodeRange *
1275{
1276 if (!_local_node_range)
1277 {
1278 TIME_SECTION("getLocalNodeRange", 5);
1279
1280 _local_node_range = std::make_unique<ConstNodeRange>(getMesh().local_nodes_begin(),
1281 getMesh().local_nodes_end());
1282 }
1283
1284 return _local_node_range.get();
1285}
1286
1289{
1290 if (!_bnd_node_range)
1291 {
1292 TIME_SECTION("getBoundaryNodeRange", 5);
1293
1294 _bnd_node_range = std::make_unique<ConstBndNodeRange>(bndNodesBegin(), bndNodesEnd());
1295 }
1296
1297 return _bnd_node_range.get();
1298}
1299
1302{
1303 if (!_bnd_elem_range)
1304 {
1305 TIME_SECTION("getBoundaryElementRange", 5);
1306
1307 _bnd_elem_range = std::make_unique<ConstBndElemRange>(bndElemsBegin(), bndElemsEnd());
1308 }
1309
1310 return _bnd_elem_range.get();
1311}
1312
1313const std::unordered_map<boundary_id_type, std::unordered_set<dof_id_type>> &
1315{
1316 mooseDeprecated("MooseMesh::getBoundariesToElems is deprecated, "
1317 "use MooseMesh::getBoundariesToActiveSemiLocalElemIds");
1319}
1320
1321const std::unordered_map<boundary_id_type, std::unordered_set<dof_id_type>> &
1326
1327std::unordered_set<dof_id_type>
1329{
1330 // The boundary to element map is computed on every mesh update
1331 const auto it = _bnd_elem_ids.find(bid);
1332 if (it == _bnd_elem_ids.end())
1333 // Boundary is not local to this domain, return an empty set
1334 return std::unordered_set<dof_id_type>{};
1335 return it->second;
1336}
1337
1338std::unordered_set<dof_id_type>
1340{
1341 // Vector of boundary elems is updated every mesh update
1342 std::unordered_set<dof_id_type> neighbor_elems;
1343 for (const auto & bnd_elem : _bnd_elems)
1344 {
1345 const auto & [elem_ptr, elem_side, elem_bid] = *bnd_elem;
1346 if (elem_bid == bid)
1347 {
1348 const auto * neighbor = elem_ptr->neighbor_ptr(elem_side);
1349 // Dont add fully remote elements, ghosted is fine
1350 if (neighbor && neighbor != libMesh::remote_elem)
1351 {
1352 // handle mesh refinement, only return active elements near the boundary
1353 if (neighbor->active())
1354 neighbor_elems.insert(neighbor->id());
1355 else
1356 {
1357 std::vector<const Elem *> family;
1358 neighbor->active_family_tree_by_neighbor(family, elem_ptr);
1359 for (const auto & child_neighbor : family)
1360 neighbor_elems.insert(child_neighbor->id());
1361 }
1362 }
1363 }
1364 }
1365
1366 return neighbor_elems;
1367}
1368
1369bool
1371 const std::set<SubdomainID> & blk_group) const
1372{
1373 mooseAssert(_bnd_elem_range, "Boundary element range is not initialized");
1374
1375 // Loop over all side elements of the mesh, select those on the boundary
1376 for (const auto & bnd_elem : *_bnd_elem_range)
1377 {
1378 const auto & [elem_ptr, elem_side, elem_bid] = *bnd_elem;
1379 if (elem_bid == bid)
1380 {
1381 // If an element is internal to the group of subdomain, check the neighbor
1382 if (blk_group.find(elem_ptr->subdomain_id()) != blk_group.end())
1383 {
1384 const auto * const neighbor = elem_ptr->neighbor_ptr(elem_side);
1385
1386 // If we did not ghost the neighbor, we cannot decide
1387 if (neighbor == libMesh::remote_elem)
1388 mooseError("Insufficient level of geometrical ghosting to determine "
1389 "if a boundary is internal to the mesh");
1390 // If the neighbor does not exist, then we are on the edge of the mesh
1391 if (!neighbor)
1392 continue;
1393 // If the neighbor is also in the group of subdomain,
1394 // then the boundary cuts the subdomains
1395 if (blk_group.find(neighbor->subdomain_id()) != blk_group.end())
1396 return false;
1397 }
1398 }
1399 }
1400 return true;
1401}
1402
1403void
1405{
1406 TIME_SECTION("cacheInfo", 3);
1407
1408 _sub_to_data.clear();
1410 _block_node_list.clear();
1415
1416 const auto & mesh = getMesh();
1417
1418 // Cache higher and lowerD element information
1419 for (const auto & elem : mesh.element_ptr_range())
1420 {
1421 const Elem * ip_elem = elem->interior_parent();
1422
1423 if (ip_elem)
1424 {
1425 unsigned int ip_side = ip_elem->which_side_am_i(elem);
1426
1427 // For some grid sequencing tests: ip_side == libMesh::invalid_uint
1428 if (ip_side != libMesh::invalid_uint)
1429 {
1430 auto pair = std::make_pair(ip_elem, ip_side);
1432 std::pair<std::pair<const Elem *, unsigned short int>, const Elem *>(pair, elem));
1434 std::pair<const Elem *, unsigned short int>(elem, ip_side));
1435
1436 auto id = elem->subdomain_id();
1437 if (ip_elem->neighbor_ptr(ip_side))
1438 {
1439 if (mesh.subdomain_name(id).find("INTERNAL_SIDE_LOWERD_SUBDOMAIN_") != std::string::npos)
1440 _lower_d_interior_blocks.insert(id);
1441 }
1442 else
1443 {
1444 if (mesh.subdomain_name(id).find("BOUNDARY_SIDE_LOWERD_SUBDOMAIN_") != std::string::npos)
1445 _lower_d_boundary_blocks.insert(id);
1446 }
1447 }
1448 }
1449
1450 for (unsigned int nd = 0; nd < elem->n_nodes(); ++nd)
1451 {
1452 const Node & node = *elem->node_ptr(nd);
1453 _block_node_list[node.id()].insert(elem->subdomain_id());
1454 }
1455 }
1458
1459 // Cache the boundaries next to each subdomain
1460 for (const auto & elem : mesh.active_local_element_ptr_range())
1461 {
1462 SubdomainID subdomain_id = elem->subdomain_id();
1463 auto & sub_data = _sub_to_data[subdomain_id];
1464 const auto elem_boundary_ids = getBoundaryIDs(elem);
1465 for (unsigned int side = 0; side < elem->n_sides(); side++)
1466 {
1467 const auto & boundary_ids = elem_boundary_ids[side];
1468 sub_data.boundary_ids.insert(boundary_ids.begin(), boundary_ids.end());
1469
1470 const Elem * neig = elem->neighbor_ptr(side);
1471 if (neig)
1472 {
1473 _neighbor_subdomain_boundary_ids[neig->subdomain_id()].insert(boundary_ids.begin(),
1474 boundary_ids.end());
1475 SubdomainID neighbor_subdomain_id = neig->subdomain_id();
1476 if (neighbor_subdomain_id != subdomain_id)
1477 sub_data.neighbor_subs.insert(neighbor_subdomain_id);
1478 }
1479 }
1480 }
1481
1482 for (const auto blk_id : _mesh_subdomains)
1483 {
1484 auto & sub_data = _sub_to_data[blk_id];
1485 _communicator.set_union(sub_data.neighbor_subs);
1486 _communicator.set_union(sub_data.boundary_ids);
1488 }
1489}
1490
1491const std::set<SubdomainID> &
1492MooseMesh::getNodeBlockIds(const Node & node) const
1493{
1494 auto it = _block_node_list.find(node.id());
1495
1496 if (it == _block_node_list.end())
1497 mooseError("Unable to find node: ", node.id(), " in any block list.");
1498
1499 return it->second;
1500}
1501
1504{
1505 return face_info_iterator(
1506 _face_info.begin(),
1507 _face_info.end(),
1508 libMesh::Predicates::pid<std::vector<const FaceInfo *>::iterator>(this->processor_id()));
1509}
1510
1513{
1514 return face_info_iterator(
1515 _face_info.end(),
1516 _face_info.end(),
1517 libMesh::Predicates::pid<std::vector<const FaceInfo *>::iterator>(this->processor_id()));
1518}
1519
1522{
1523 return elem_info_iterator(_elem_info.begin(),
1524 _elem_info.end(),
1525 Predicates::NotNull<std::vector<const ElemInfo *>::iterator>());
1526}
1527
1530{
1531 return elem_info_iterator(_elem_info.end(),
1532 _elem_info.end(),
1533 Predicates::NotNull<std::vector<const ElemInfo *>::iterator>());
1534}
1535
1536// default begin() accessor
1543
1544// default end() accessor
1551
1552// default begin() accessor
1559
1560// default end() accessor
1567
1568const Node *
1569MooseMesh::addUniqueNode(const Point & p, Real tol)
1570{
1575 if (getMesh().n_nodes() != _node_map.size())
1576 {
1577 _node_map.clear();
1578 _node_map.reserve(getMesh().n_nodes());
1579 for (const auto & node : getMesh().node_ptr_range())
1580 _node_map.push_back(node);
1581 }
1582
1583 Node * node = nullptr;
1584 for (unsigned int i = 0; i < _node_map.size(); ++i)
1585 {
1586 if (p.relative_fuzzy_equals(*_node_map[i], tol))
1587 {
1588 node = _node_map[i];
1589 break;
1590 }
1591 }
1592 if (node == nullptr)
1593 {
1594 node = getMesh().add_node(new Node(p));
1595 _node_map.push_back(node);
1596 }
1597
1598 mooseAssert(node != nullptr, "Node is NULL");
1599 return node;
1600}
1601
1602Node *
1604 const unsigned short int side,
1605 const unsigned int qp,
1606 BoundaryID bid,
1607 const Point & point)
1608{
1609 Node * qnode;
1610
1611 if (_elem_to_side_to_qp_to_quadrature_nodes[elem->id()][side].find(qp) ==
1613 {
1614 // Create a new node id starting from the max node id and counting down. This will be the least
1615 // likely to collide with an existing node id.
1616 // Note that we are using numeric_limits<unsigned>::max even
1617 // though max_id is stored as a dof_id_type. I tried this with
1618 // numeric_limits<dof_id_type>::max and it broke several tests in
1619 // MOOSE. So, this is some kind of a magic number that we will
1620 // just continue to use...
1621 dof_id_type max_id = std::numeric_limits<unsigned int>::max() - 100;
1622 dof_id_type new_id = max_id - _quadrature_nodes.size();
1623
1624 if (new_id <= getMesh().max_node_id())
1625 mooseError("Quadrature node id collides with existing node id!");
1626
1627 qnode = new Node(point, new_id);
1628
1629 // Keep track of this new node in two different ways for easy lookup
1630 _quadrature_nodes[new_id] = qnode;
1631 _elem_to_side_to_qp_to_quadrature_nodes[elem->id()][side][qp] = qnode;
1632
1633 if (elem->active())
1634 internalNodeToElemMap()[new_id].push_back(elem->id());
1635 }
1636 else
1637 qnode = _elem_to_side_to_qp_to_quadrature_nodes[elem->id()][side][qp];
1638
1639 BndNode * bnode = new BndNode(qnode, bid);
1640 _bnd_nodes.push_back(bnode);
1641 _bnd_node_ids[bid].insert(qnode->id());
1642
1643 _extra_bnd_nodes.push_back(*bnode);
1644
1645 // Do this so the range will be regenerated next time it is accessed
1646 _bnd_node_range.reset();
1647
1648 return qnode;
1649}
1650
1651Node *
1653 const unsigned short int side,
1654 const unsigned int qp)
1655{
1656 mooseAssert(_elem_to_side_to_qp_to_quadrature_nodes.find(elem->id()) !=
1658 "Elem has no quadrature nodes!");
1659 mooseAssert(_elem_to_side_to_qp_to_quadrature_nodes[elem->id()].find(side) !=
1661 "Side has no quadrature nodes!");
1662 mooseAssert(_elem_to_side_to_qp_to_quadrature_nodes[elem->id()][side].find(qp) !=
1664 "qp not found on side!");
1665
1666 return _elem_to_side_to_qp_to_quadrature_nodes[elem->id()][side][qp];
1667}
1668
1669void
1671{
1672 // Delete all the quadrature nodes
1673 for (auto & it : _quadrature_nodes)
1674 delete it.second;
1675
1676 _quadrature_nodes.clear();
1678 _extra_bnd_nodes.clear();
1679
1680 // NOTE: this does not clear them from the nodeToElem map
1681}
1682
1684MooseMesh::getBoundaryID(const BoundaryName & boundary_name) const
1685{
1686 if (boundary_name == "ANY_BOUNDARY_ID")
1687 mooseError("Please use getBoundaryIDs() when passing \"ANY_BOUNDARY_ID\"");
1688
1689 return MooseMeshUtils::getBoundaryID(boundary_name, getMesh());
1690}
1691
1692const Elem *
1693MooseMesh::getLowerDElem(const Elem * elem, unsigned short int side) const
1694{
1695 auto it = _higher_d_elem_side_to_lower_d_elem.find(std::make_pair(elem, side));
1696
1698 return it->second;
1699 else
1700 return nullptr;
1701}
1702
1703unsigned int
1704MooseMesh::getHigherDSide(const Elem * elem) const
1705{
1707
1709 return it->second;
1710 else
1711 return libMesh::invalid_uint;
1712}
1713
1714std::vector<BoundaryID>
1715MooseMesh::getBoundaryIDs(const std::vector<BoundaryName> & boundary_name,
1716 bool generate_unknown) const
1717{
1719 getMesh(), boundary_name, generate_unknown, _mesh_boundary_ids);
1720}
1721
1723MooseMesh::getSubdomainID(const SubdomainName & subdomain_name) const
1724{
1725 return MooseMeshUtils::getSubdomainID(subdomain_name, getMesh());
1726}
1727
1728std::vector<SubdomainID>
1729MooseMesh::getSubdomainIDs(const std::vector<SubdomainName> & subdomain_name) const
1730{
1731 return MooseMeshUtils::getSubdomainIDs(getMesh(), subdomain_name);
1732}
1733
1734std::set<SubdomainID>
1735MooseMesh::getSubdomainIDs(const std::set<SubdomainName> & subdomain_name) const
1736{
1737 return MooseMeshUtils::getSubdomainIDs(getMesh(), subdomain_name);
1738}
1739
1740void
1742 const SubdomainName & name,
1743 const bool synchronous)
1744{
1745 setSubdomainName(getMesh(), subdomain_id, name, synchronous);
1746}
1747
1748void
1750 SubdomainID subdomain_id,
1751 const SubdomainName & name,
1752 const bool synchronous)
1753{
1754 mooseAssert(name != "ANY_BLOCK_ID", "Cannot set subdomain name to 'ANY_BLOCK_ID'");
1755 mesh.set_subdomain_name(subdomain_id, name, synchronous);
1756}
1757
1758const std::string &
1760{
1761 return getMesh().subdomain_name(subdomain_id);
1762}
1763
1764std::vector<SubdomainName>
1765MooseMesh::getSubdomainNames(const std::vector<SubdomainID> & subdomain_ids) const
1766{
1767 std::vector<SubdomainName> names(subdomain_ids.size());
1768
1769 for (unsigned int i = 0; i < subdomain_ids.size(); i++)
1770 names[i] = getSubdomainName(subdomain_ids[i]);
1771
1772 return names;
1773}
1774
1775void
1776MooseMesh::setBoundaryName(BoundaryID boundary_id, BoundaryName name)
1777{
1778 BoundaryInfo & boundary_info = getMesh().get_boundary_info();
1779
1780 // We need to figure out if this boundary is a sideset or nodeset
1781 if (boundary_info.get_side_boundary_ids().count(boundary_id))
1782 boundary_info.sideset_name(boundary_id) = name;
1783 else
1784 boundary_info.nodeset_name(boundary_id) = name;
1785}
1786
1787const std::string &
1789{
1790 const BoundaryInfo & boundary_info = getMesh().get_boundary_info();
1791
1792 // We need to figure out if this boundary is a sideset or nodeset
1793 if (boundary_info.get_side_boundary_ids().count(boundary_id))
1794 return boundary_info.get_sideset_name(boundary_id);
1795 else
1796 return boundary_info.get_nodeset_name(boundary_id);
1797}
1798
1799std::string
1801{
1802 const auto name = getBoundaryName(boundary_id);
1803 return name.size() ? name : std::to_string(boundary_id);
1804}
1805
1806// specialization for PointListAdaptor<MooseMesh::PeriodicNodeInfo>
1807template <>
1808inline const Point &
1810 const MooseMesh::PeriodicNodeInfo & item) const
1811{
1812 return *(item.first);
1813}
1814
1815void
1816MooseMesh::buildPeriodicNodeMap(std::multimap<dof_id_type, dof_id_type> & periodic_node_map,
1817 unsigned int var_number,
1818 libMesh::PeriodicBoundaries * pbs) const
1819{
1820 TIME_SECTION("buildPeriodicNodeMap", 5);
1821
1822 // clear existing map
1823 periodic_node_map.clear();
1824
1825 // get periodic nodes
1826 std::vector<PeriodicNodeInfo> periodic_nodes;
1827 for (const auto & t : getMesh().get_boundary_info().build_node_list())
1828 {
1829 // unfortunately libMesh does not give us a pointer, so we have to look it up ourselves
1830 auto node = _mesh->node_ptr(std::get<0>(t));
1831 mooseAssert(node != nullptr,
1832 "libMesh::BoundaryInfo::build_node_list() returned an ID for a non-existing node");
1833 auto bc_id = std::get<1>(t);
1834 periodic_nodes.emplace_back(node, bc_id);
1835 }
1836
1837 // sort by boundary id
1838 std::sort(periodic_nodes.begin(),
1839 periodic_nodes.end(),
1840 [](const PeriodicNodeInfo & a, const PeriodicNodeInfo & b) -> bool
1841 { return a.second > b.second; });
1842
1843 // build kd-tree
1844 using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1845 nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<PeriodicNodeInfo>, Real, std::size_t>,
1847 LIBMESH_DIM,
1848 std::size_t>;
1849 const unsigned int max_leaf_size = 20; // slightly affects runtime
1850 auto point_list =
1851 PointListAdaptor<PeriodicNodeInfo>(periodic_nodes.begin(), periodic_nodes.end());
1852 auto kd_tree = std::make_unique<KDTreeType>(
1853 LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1854 mooseAssert(kd_tree != nullptr, "KDTree was not properly initialized.");
1855 kd_tree->buildIndex();
1856
1857 // data structures for kd-tree search
1858 nanoflann::SearchParameters search_params;
1859 std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1860
1861 // iterate over periodic nodes (boundary ids are in contiguous blocks)
1862 libMesh::PeriodicBoundaryBase * periodic = nullptr;
1863 BoundaryID current_bc_id = BoundaryInfo::invalid_id;
1864 for (auto & pair : periodic_nodes)
1865 {
1866 // entering a new block of boundary IDs
1867 if (pair.second != current_bc_id)
1868 {
1869 current_bc_id = pair.second;
1870 periodic = pbs->boundary(current_bc_id);
1871 if (periodic && !periodic->is_my_variable(var_number))
1872 periodic = nullptr;
1873 }
1874
1875 // variable is not periodic at this node, skip
1876 if (!periodic)
1877 continue;
1878
1879 // clear result buffer
1880 ret_matches.clear();
1881
1882 // id of the current node
1883 const auto id = pair.first->id();
1884
1885 // position where we expect a periodic partner for the current node and boundary
1886 Point search_point = periodic->get_corresponding_pos(*pair.first);
1887
1888 // search at the expected point
1889 kd_tree->radiusSearch(&(search_point)(0), libMesh::TOLERANCE, ret_matches, search_params);
1890 for (auto & match_pair : ret_matches)
1891 {
1892 const auto & match = periodic_nodes[match_pair.first];
1893 // add matched node if the boundary id is the corresponding id in the periodic pair
1894 if (match.second == periodic->pairedboundary)
1895 periodic_node_map.emplace(id, match.first->id());
1896 }
1897 }
1898}
1899
1900void
1901MooseMesh::buildPeriodicNodeSets(std::map<BoundaryID, std::set<dof_id_type>> & periodic_node_sets,
1902 unsigned int var_number,
1903 libMesh::PeriodicBoundaries * pbs) const
1904{
1905 TIME_SECTION("buildPeriodicNodeSets", 5);
1906
1907 periodic_node_sets.clear();
1908
1909 // Loop over all the boundary nodes adding the periodic nodes to the appropriate set
1910 for (const auto & t : getMesh().get_boundary_info().build_node_list())
1911 {
1912 auto node_id = std::get<0>(t);
1913 auto bc_id = std::get<1>(t);
1914
1915 // Is this current node on a known periodic boundary?
1916 if (periodic_node_sets.find(bc_id) != periodic_node_sets.end())
1917 periodic_node_sets[bc_id].insert(node_id);
1918 else // This still might be a periodic node but we just haven't seen this boundary_id yet
1919 {
1920 const libMesh::PeriodicBoundaryBase * periodic = pbs->boundary(bc_id);
1921 if (periodic && periodic->is_my_variable(var_number))
1922 periodic_node_sets[bc_id].insert(node_id);
1923 }
1924 }
1925}
1926
1927bool
1929{
1930 TIME_SECTION("detectOrthogonalDimRanges", 5);
1931
1933 return true;
1934
1935 std::vector<Real> min(3, std::numeric_limits<Real>::max());
1936 std::vector<Real> max(3, std::numeric_limits<Real>::min());
1937 unsigned int dim = getMesh().mesh_dimension();
1938
1939 // Find the bounding box of our mesh
1940 for (const auto & node : getMesh().node_ptr_range())
1941 // Check all coordinates, we don't know if this mesh might be lying in a higher dim even if the
1942 // mesh dimension is lower.
1943 for (const auto i : make_range(Moose::dim))
1944 {
1945 if ((*node)(i) < min[i])
1946 min[i] = (*node)(i);
1947 if ((*node)(i) > max[i])
1948 max[i] = (*node)(i);
1949 }
1950
1951 this->comm().max(max);
1952 this->comm().min(min);
1953
1954 _extreme_nodes.resize(8); // 2^LIBMESH_DIM
1955 // Now make sure that there are actual nodes at all of the extremes
1956 std::vector<bool> extreme_matches(8, false);
1957 std::vector<unsigned int> comp_map(3);
1958 for (const auto & node : getMesh().node_ptr_range())
1959 {
1960 // See if the current node is located at one of the extremes
1961 unsigned int coord_match = 0;
1962
1963 for (const auto i : make_range(Moose::dim))
1964 {
1965 if (std::abs((*node)(i)-min[i]) < tol)
1966 {
1967 comp_map[i] = MIN;
1968 ++coord_match;
1969 }
1970 else if (std::abs((*node)(i)-max[i]) < tol)
1971 {
1972 comp_map[i] = MAX;
1973 ++coord_match;
1974 }
1975 }
1976
1977 if (coord_match == LIBMESH_DIM) // Found a coordinate at one of the extremes
1978 {
1979 _extreme_nodes[comp_map[X] * 4 + comp_map[Y] * 2 + comp_map[Z]] = node;
1980 extreme_matches[comp_map[X] * 4 + comp_map[Y] * 2 + comp_map[Z]] = true;
1981 }
1982 }
1983
1984 // See if we matched all of the extremes for the mesh dimension
1985 this->comm().max(extreme_matches);
1986 if (std::count(extreme_matches.begin(), extreme_matches.end(), true) == (1 << dim))
1988
1989 // Set the bounds
1990 _bounds.resize(LIBMESH_DIM);
1991 for (const auto i : make_range(Moose::dim))
1992 {
1993 _bounds[i].resize(2);
1994 _bounds[i][MIN] = min[i];
1995 _bounds[i][MAX] = max[i];
1996 }
1997
1999}
2000
2001void
2003{
2004 TIME_SECTION("detectPairedSidesets", 5);
2005
2006 _paired_boundary = std::vector<std::pair<BoundaryID, BoundaryID>>();
2007
2008 // Loop over level-0 elements (since boundary condition information
2009 // is only directly stored for them) and find sidesets with normals
2010 // that point in the -x, +x, -y, +y, and -z, +z direction. If there
2011 // is a unique sideset id for each direction, then the paired
2012 // sidesets consist of (-x,+x), (-y,+y), (-z,+z). If there are
2013 // multiple sideset ids for a given direction, then we can't pick a
2014 // single pair for that direction. In that case, we'll just return
2015 // as was done in the original algorithm.
2016
2017 // we need to test all element dimensions from dim down to 1
2018 const unsigned int mesh_dim = getMesh().mesh_dimension();
2019
2020 // Helper for iterating through unit dimensions (0=x, 1=y, 2=z)
2021 static constexpr std::array<std::size_t, 3> unit_dims{0, 1, 2};
2022 // Helper for mapping from unit dim -> name
2023 static const std::array<std::string, 3> unit_dim_names{"x", "y", "z"};
2024
2025 // Boundary id sets for elements of different dimensions
2026 // First index: side dimension; 0=1D, 1=2D, 2=3D
2027 // Second index: unit dimension; 0=x, 1=y, 2=z
2028 // Third index: false for minus, true for plus
2029 std::array<std::array<std::array<std::set<BoundaryID>, 2>, 3>, 3> ids{};
2030
2031 // Build quadrature needed to evaluate side normals
2032 std::array<std::unique_ptr<FEBase>, 3> fe_faces{};
2033 std::array<std::unique_ptr<libMesh::QGauss>, 3> qfaces{};
2034 for (const auto side_dim : make_range(mesh_dim))
2035 {
2036 // Face is assumed to be flat, therefore normal is assumed to be
2037 // constant over the face, therefore only compute it at 1 qp.
2038 qfaces[side_dim] = std::unique_ptr<libMesh::QGauss>(new libMesh::QGauss(side_dim, CONSTANT));
2039
2040 // A first-order Lagrange FE for the face.
2041 fe_faces[side_dim] = FEBase::build(side_dim + 1, FEType(FIRST, libMesh::LAGRANGE));
2042 fe_faces[side_dim]->attach_quadrature_rule(qfaces[side_dim].get());
2043 fe_faces[side_dim]->get_normals();
2044 }
2045
2046 // Get boundary IDs for each dimension that are in the unit normal
2047 const auto & boundary_info = getMesh().get_boundary_info();
2048 // Temporary for evaluating boundary_ids
2049 std::vector<boundary_id_type> face_ids;
2050 // The side dimensions we've come across, so that we only report
2051 // warnings for side dimensions that we have
2052 std::set<unsigned int> side_dims;
2053 // Normal dimensions that we found that were nonzero; lets us
2054 // skip warnings for dimensions that we don't have
2055 std::array<bool, 3> nonzero_dims = periodic_dim_default;
2056 for (auto & elem : as_range(getMesh().level_elements_begin(0), getMesh().level_elements_end(0)))
2057 {
2058 // If not on the boundary, nothing to do
2059 if (!elem->on_boundary())
2060 continue;
2061
2062 const auto side_dim = elem->dim() - 1;
2063 side_dims.insert(side_dim);
2064
2065 // Check for unit normals on each boundary side
2066 for (const auto s : elem->side_index_range())
2067 if (!elem->neighbor_ptr(s))
2068 {
2069 // Reinit to get the normal
2070 fe_faces[side_dim]->reinit(elem, s);
2071 const auto & normal = fe_faces[side_dim]->get_normals()[0];
2072
2073 // Get the boundary ID(s) for this side. If there is more
2074 // than 1 boundary id, then we already can't determine a
2075 // unique pairing of sides in this direction, but we'll just
2076 // keep going to keep the logic simple.
2077 boundary_info.boundary_ids(elem, s, face_ids);
2078
2079 bool found = false;
2080 for (const auto unit_dim : unit_dims)
2081 {
2082 if (libMesh::absolute_fuzzy_equals(normal(unit_dim), 0.0))
2083 continue;
2084 nonzero_dims[unit_dim] = true;
2085 if (!found)
2086 for (const auto plus : {false, true})
2087 {
2088 if (libMesh::absolute_fuzzy_equals(normal(unit_dim), plus ? 1.0 : -1.0))
2089 {
2090 ids[side_dim][unit_dim][plus].insert(face_ids.begin(), face_ids.end());
2091 found = true;
2092 break;
2093 }
2094 }
2095 }
2096 }
2097 }
2098
2099 // For a distributed mesh, boundaries may be distributed as well. We therefore collect information
2100 // from everyone. If the mesh is already serial, then there is no need to do an allgather. Note
2101 // that this is just going to gather information about what the periodic bc ids are. We are not
2102 // gathering any remote elements or anything like that. It's just that the GhostPointNeighbors
2103 // ghosting functor currently relies on the fact that every process agrees on whether we have
2104 // periodic boundaries; every process that thinks there are periodic boundaries will call
2105 // MeshBase::sub_point_locator which makes a parallel_object_only() assertion (right or wrong). So
2106 // we all need to go there (or not go there)
2107 if (_use_distributed_mesh && !_mesh->is_serial())
2108 {
2109 // Communicate id data by packing as [side dim, unit dim, plus (as a char), boundary id]
2110 std::vector<std::tuple<unsigned int, unsigned int, unsigned char, boundary_id_type>> id_data;
2111 for (const auto side_dim : side_dims)
2112 for (const auto unit_dim : unit_dims)
2113 for (const auto plus : {false, true})
2114 for (const auto bd : ids[side_dim][unit_dim][plus])
2115 id_data.emplace_back(side_dim, unit_dim, plus, bd);
2116 _communicator.allgather(id_data, false);
2117 for (const auto & [side_dim, unit_dim, plus_char, bd] : id_data)
2118 ids[side_dim][unit_dim][bool(plus_char)].insert(bd);
2119
2120 // Gather true-ness of nonzero_dims
2121 for (auto & entry : nonzero_dims)
2122 _communicator.max(entry);
2123
2124 // Gather found side dimensions
2125 _communicator.set_union(side_dims);
2126 } // end if (_use_distributed_mesh && !_need_ghost_ghosted_boundaries)
2127
2128 // Find pairings that have exactly one boundary on each side
2129 std::ostringstream oss_found, oss_missing;
2130 for (const auto side_dim : side_dims)
2131 {
2132 for (const auto unit_dim : unit_dims)
2133 if (nonzero_dims[unit_dim])
2134 {
2135 const auto & unit_name = unit_dim_names[unit_dim];
2136 const auto & minus = ids[side_dim][unit_dim][false];
2137 const auto & plus = ids[side_dim][unit_dim][true];
2138
2139 if (minus.size() == 1 && plus.size() == 1)
2140 {
2141 const auto get_boundary_name = [this](const auto id)
2142 {
2143 const auto & name = getBoundaryName(id);
2144 return name.size() ? name : std::to_string(id);
2145 };
2146
2147 oss_found << "\n " << side_dim + 1 << "D " << unit_name
2148 << "-direction: " << get_boundary_name(*minus.begin()) << " <-> "
2149 << get_boundary_name(*plus.begin());
2150 _paired_boundary->emplace_back(std::make_pair(*minus.begin(), *plus.begin()));
2151 }
2152 else
2153 oss_missing << "\n " << side_dim + 1 << "D -" << unit_name << "/+" << unit_name
2154 << ": Found " << minus.size() << " -" << unit_name << " boundaries and "
2155 << plus.size() << " +" << unit_name << " boundaries";
2156 }
2157 }
2158
2159 std::ostringstream oss;
2160 const auto found = oss_found.str();
2161 const auto missing = oss_missing.str();
2162 if (found.size())
2163 oss << "The following paired boundaries were automatically detected for periodicity:\n"
2164 << found << "\n";
2165 if (missing.size())
2166 {
2167 if (found.size())
2168 oss << "\n";
2169 oss << "Paired boundaries were not automatically detected for the following:\n"
2170 << missing
2171 << "\n\nAutomatic detection requires that exactly one boundary is found in each unit "
2172 "direction.\n";
2173 }
2174
2175 mooseInfoRepeated(oss.str());
2176}
2177
2178Real
2179MooseMesh::dimensionWidth(unsigned int component) const
2180{
2181 return getMaxInDimension(component) - getMinInDimension(component);
2182}
2183
2184Real
2185MooseMesh::getMinInDimension(unsigned int component) const
2186{
2187 mooseAssert(_mesh, "The MeshBase has not been constructed");
2188 mooseAssert(component < _bounds.size(), "Requested dimension out of bounds");
2189
2190 return _bounds[component][MIN];
2191}
2192
2193Real
2194MooseMesh::getMaxInDimension(unsigned int component) const
2195{
2196 mooseAssert(_mesh, "The MeshBase has not been constructed");
2197 mooseAssert(component < _bounds.size(), "Requested dimension out of bounds");
2198
2199 return _bounds[component][MAX];
2200}
2201
2202void
2203MooseMesh::addPeriodicVariable(const unsigned int sys_num,
2204 const unsigned int var_num,
2205 const BoundaryID primary,
2206 const BoundaryID secondary)
2207{
2209 return;
2210
2211 const auto key = std::make_pair(sys_num, var_num);
2212 auto & entry = _periodic_dim.try_emplace(key, periodic_dim_default).first->second;
2213
2214 _half_range = Point(dimensionWidth(0) / 2.0, dimensionWidth(1) / 2.0, dimensionWidth(2) / 2.0);
2215
2216 bool component_found = false;
2217 for (const auto component : make_range(dimension()))
2218 {
2219 const std::pair<BoundaryID, BoundaryID> * boundary_ids = getPairedBoundaryMapping(component);
2220
2221 if (boundary_ids && ((boundary_ids->first == primary && boundary_ids->second == secondary) ||
2222 (boundary_ids->first == secondary && boundary_ids->second == primary)))
2223 {
2224 entry[component] = true;
2225 component_found = true;
2226 }
2227 }
2228
2229 if (!component_found)
2230 mooseWarning("Could not find a match between boundary '",
2231 getBoundaryName(primary),
2232 "' and '",
2233 getBoundaryName(secondary),
2234 "' to set periodic boundary conditions for variable (index:",
2235 var_num,
2236 ") in either the X, Y or Z direction. The periodic dimension of the mesh for this "
2237 "variable will not be stored.");
2238}
2239
2240const std::array<bool, 3> &
2241MooseMesh::queryPeriodicDimensions(const unsigned int sys_num, const unsigned int var_num) const
2242{
2243 const auto key = std::make_pair(sys_num, var_num);
2244 if (const auto it = _periodic_dim.find(key); it != _periodic_dim.end())
2245 return it->second;
2246 return periodic_dim_default;
2247}
2248
2249const std::array<bool, 3> &
2251{
2252 return queryPeriodicDimensions(var.sys().number(), var.number());
2253}
2254
2255bool
2256MooseMesh::isTranslatedPeriodic(const unsigned int sys_num,
2257 const unsigned int var_num,
2258 const unsigned int component) const
2259{
2260 mooseAssert(component < dimension(), "Requested dimension out of bounds");
2261 return queryPeriodicDimensions(sys_num, var_num)[component];
2262}
2263
2264bool
2265MooseMesh::isTranslatedPeriodic(const MooseVariableBase & var, const unsigned int component) const
2266{
2267 return isTranslatedPeriodic(var.sys().number(), var.number(), component);
2268}
2269
2270bool
2271MooseMesh::isTranslatedPeriodic(const unsigned int var_num, const unsigned int component) const
2272{
2273 mooseDoOnce(mooseDeprecated(
2274 "MooseMesh::isTranslatedPeriodic(const unsigned int, const unsigned int) is deprecated. Use "
2275 "the method that additionally takes the system number or the MooseVariableBase instead."));
2276 return isTranslatedPeriodic(0, var_num, component);
2277}
2278
2279RealVectorValue
2280MooseMesh::minPeriodicVector(const unsigned int sys_num,
2281 const unsigned int var_num,
2282 Point p,
2283 Point q) const
2284{
2285 const auto & periodic_dims = queryPeriodicDimensions(sys_num, var_num);
2286
2287 for (const auto i : make_range(dimension()))
2288 {
2289 // check to see if we're closer in real or periodic space in x, y, and z
2290 if (periodic_dims[i])
2291 {
2292 // Need to test order before differencing
2293 if (p(i) > q(i))
2294 {
2295 if (p(i) - q(i) > _half_range(i))
2296 p(i) -= _half_range(i) * 2;
2297 }
2298 else
2299 {
2300 if (q(i) - p(i) > _half_range(i))
2301 p(i) += _half_range(i) * 2;
2302 }
2303 }
2304 }
2305
2306 return q - p;
2307}
2308
2309RealVectorValue
2310MooseMesh::minPeriodicVector(const MooseVariableBase & var, const Point & p, const Point & q) const
2311{
2312 return minPeriodicVector(var.sys().number(), var.number(), p, q);
2313}
2314
2315RealVectorValue
2316MooseMesh::minPeriodicVector(const unsigned int var_num, const Point & p, const Point & q) const
2317{
2318 mooseDoOnce(mooseDeprecated("MooseMesh::minPeriodicVector(const unsigned int, const Point &, "
2319 "const Point &) is deprecated. Use the method that additionally "
2320 "takes the system number or the MooseVariableBase instead."));
2321 return minPeriodicVector(0, var_num, p, q);
2322}
2323
2324Real
2325MooseMesh::minPeriodicDistance(const unsigned int sys_num,
2326 const unsigned int var_num,
2327 const Point & p,
2328 const Point & q) const
2329{
2330 return minPeriodicVector(sys_num, var_num, p, q).norm();
2331}
2332
2333Real
2335 const Point & p,
2336 const Point & q) const
2337{
2338 return minPeriodicDistance(var.sys().number(), var.number(), p, q);
2339}
2340
2341Real
2342MooseMesh::minPeriodicDistance(const unsigned int var_num, const Point & p, const Point & q) const
2343{
2344 mooseDoOnce(mooseDeprecated("MooseMesh::minPeriodicDistance(const unsigned int, const Point &, "
2345 "const Point &) is deprecated. Use the method that additionally "
2346 "takes the system number or the MooseVariableBase instead."));
2347 return minPeriodicDistance(0, var_num, p, q);
2348}
2349
2350const std::pair<BoundaryID, BoundaryID> *
2351MooseMesh::getPairedBoundaryMapping(unsigned int component) const
2352{
2354 mooseError("Trying to retrieve automatic paired mapping for a mesh that is not regular and "
2355 "orthogonal");
2356
2357 mooseAssert(component < dimension(), "Requested dimension out of bounds");
2358
2360 mooseError("MooseMesh::getPairedBoundaryMapping(): Paired boundaries not built; must call "
2361 "detectPairedSidesets() first");
2362
2363 if (component < _paired_boundary->size())
2364 return &(*_paired_boundary)[component];
2365 else
2366 return nullptr;
2367}
2368
2369void
2371{
2372 std::map<ElemType, Elem *> canonical_elems;
2373
2374 // First, loop over all elements and find a canonical element for each type
2375 // Doing it this way guarantees that this is going to work in parallel
2376 for (const auto & elem : getMesh().element_ptr_range()) // TODO: Thread this
2377 {
2378 ElemType type = elem->type();
2379
2380 if (canonical_elems.find(type) ==
2381 canonical_elems.end()) // If we haven't seen this type of elem before save it
2382 canonical_elems[type] = elem;
2383 else
2384 {
2385 Elem * stored = canonical_elems[type];
2386 if (elem->id() < stored->id()) // Arbitrarily keep the one with a lower id
2387 canonical_elems[type] = elem;
2388 }
2389 }
2390 // Now build the maps using these templates
2391 // Note: This MUST be done NOT threaded!
2392 for (const auto & can_it : canonical_elems)
2393 {
2394 Elem * elem = can_it.second;
2395
2396 // Need to do this just once to get the right qrules put in place
2397 assembly->setCurrentSubdomainID(elem->subdomain_id());
2398 assembly->reinit(elem);
2399 assembly->reinit(elem, 0);
2400 auto && qrule = assembly->writeableQRule();
2401 auto && qrule_face = assembly->writeableQRuleFace();
2402
2403 // Volume to volume projection for refinement
2404 buildRefinementMap(*elem, *qrule, *qrule_face, -1, -1, -1);
2405
2406 // Volume to volume projection for coarsening
2407 buildCoarseningMap(*elem, *qrule, *qrule_face, -1);
2408
2409 // Map the sides of children
2410 for (unsigned int side = 0; side < elem->n_sides(); side++)
2411 {
2412 // Side to side for sides that match parent's sides
2413 buildRefinementMap(*elem, *qrule, *qrule_face, side, -1, side);
2414 buildCoarseningMap(*elem, *qrule, *qrule_face, side);
2415 }
2416
2417 // Child side to parent volume mapping for "internal" child sides
2418 for (unsigned int child = 0; child < elem->n_children(); ++child)
2419 for (unsigned int side = 0; side < elem->n_sides();
2420 ++side) // Assume children have the same number of sides!
2421 if (!elem->is_child_on_side(child, side)) // Otherwise we already computed that map
2422 buildRefinementMap(*elem, *qrule, *qrule_face, -1, child, side);
2423 }
2424}
2425
2426void
2428{
2433
2434 std::map<ElemType, std::pair<Elem *, unsigned int>> elems_and_max_p_level;
2435
2436 for (const auto & elem : getMesh().active_element_ptr_range())
2437 {
2438 const auto type = elem->type();
2439 auto & [picked_elem, max_p_level] = elems_and_max_p_level[type];
2440 if (!picked_elem)
2441 picked_elem = elem;
2442 max_p_level = std::max(max_p_level, elem->p_level());
2443 }
2444
2445 // The only requirement on the FEType is that it can be arbitrarily p-refined
2446 const FEType p_refinable_fe_type(CONSTANT, libMesh::MONOMIAL);
2447 std::vector<Point> volume_ref_points_coarse, volume_ref_points_fine, face_ref_points_coarse,
2448 face_ref_points_fine;
2449 std::vector<unsigned int> p_levels;
2450
2451 for (auto & [elem_type, elem_p_level_pair] : elems_and_max_p_level)
2452 {
2453 auto & [moose_elem, max_p_level] = elem_p_level_pair;
2454 const auto dim = moose_elem->dim();
2455 // Need to do this just once to get the right qrules put in place
2456 assembly->setCurrentSubdomainID(moose_elem->subdomain_id());
2457 assembly->reinit(moose_elem);
2458 assembly->reinit(moose_elem, 0);
2459 auto & qrule = assembly->writeableQRule();
2460 auto & qrule_face = assembly->writeableQRuleFace();
2461
2463 ReplicatedMesh mesh(self_comm);
2464 mesh.set_mesh_dimension(dim);
2465 for (const auto & nd : moose_elem->node_ref_range())
2466 mesh.add_point(nd);
2467
2468 Elem * const elem = mesh.add_elem(Elem::build(elem_type).release());
2469 for (const auto i : elem->node_index_range())
2470 elem->set_node(i, mesh.node_ptr(i));
2471
2472 std::unique_ptr<FEBase> fe_face(FEBase::build(dim, p_refinable_fe_type));
2473 fe_face->get_phi();
2474 const auto & face_phys_points = fe_face->get_xyz();
2475 fe_face->attach_quadrature_rule(qrule_face);
2476
2477 qrule->init(*elem);
2478 volume_ref_points_coarse = qrule->get_points();
2479 fe_face->reinit(elem, (unsigned int)0);
2480 libMesh::FEMap::inverse_map(dim, elem, face_phys_points, face_ref_points_coarse);
2481
2482 p_levels.resize(max_p_level + 1);
2483 std::iota(p_levels.begin(), p_levels.end(), 0);
2484 libMesh::MeshRefinement mesh_refinement(mesh);
2485
2486 for (const auto p_level : p_levels)
2487 {
2488 mesh_refinement.uniformly_p_refine(1);
2489 qrule->init(*elem);
2490 volume_ref_points_fine = qrule->get_points();
2491 fe_face->reinit(elem, (unsigned int)0);
2492 libMesh::FEMap::inverse_map(dim, elem, face_phys_points, face_ref_points_fine);
2493
2494 const auto map_key = std::make_pair(elem_type, p_level);
2495 auto & volume_refine_map = _elem_type_to_p_refinement_map[map_key];
2496 auto & face_refine_map = _elem_type_to_p_refinement_side_map[map_key];
2497 auto & volume_coarsen_map = _elem_type_to_p_coarsening_map[map_key];
2498 auto & face_coarsen_map = _elem_type_to_p_coarsening_side_map[map_key];
2499
2500 auto fill_maps = [this](const auto & coarse_ref_points,
2501 const auto & fine_ref_points,
2502 auto & coarsen_map,
2503 auto & refine_map)
2504 {
2505 mapPoints(fine_ref_points, coarse_ref_points, refine_map);
2506 mapPoints(coarse_ref_points, fine_ref_points, coarsen_map);
2507 };
2508
2509 fill_maps(
2510 volume_ref_points_coarse, volume_ref_points_fine, volume_coarsen_map, volume_refine_map);
2511 fill_maps(face_ref_points_coarse, face_ref_points_fine, face_coarsen_map, face_refine_map);
2512
2513 // With this level's maps filled our fine points now become our coarse points
2514 volume_ref_points_fine.swap(volume_ref_points_coarse);
2515 face_ref_points_fine.swap(face_ref_points_coarse);
2516 }
2517 }
2518}
2519
2520void
2522{
2523 TIME_SECTION("buildRefinementAndCoarseningMaps", 5, "Building Refinement And Coarsening Maps");
2524 if (doingPRefinement())
2526 else
2528}
2529
2530void
2532 QBase & qrule,
2533 QBase & qrule_face,
2534 int parent_side,
2535 int child,
2536 int child_side)
2537{
2538 TIME_SECTION("buildRefinementMap", 5, "Building Refinement Map");
2539
2540 if (child == -1) // Doing volume mapping or parent side mapping
2541 {
2542 mooseAssert(parent_side == child_side,
2543 "Parent side must match child_side if not passing a specific child!");
2544
2545 std::pair<int, ElemType> the_pair(parent_side, elem.type());
2546
2548 mooseError("Already built a qp refinement map!");
2549
2550 std::vector<std::pair<unsigned int, QpMap>> coarsen_map;
2551 std::vector<std::vector<QpMap>> & refinement_map = _elem_type_to_refinement_map[the_pair];
2553 &elem, qrule, qrule_face, refinement_map, coarsen_map, parent_side, child, child_side);
2554 }
2555 else // Need to map a child side to parent volume qps
2556 {
2557 std::pair<int, int> child_pair(child, child_side);
2558
2561 _elem_type_to_child_side_refinement_map[elem.type()].find(child_pair) !=
2563 mooseError("Already built a qp refinement map!");
2564
2565 std::vector<std::pair<unsigned int, QpMap>> coarsen_map;
2566 std::vector<std::vector<QpMap>> & refinement_map =
2569 &elem, qrule, qrule_face, refinement_map, coarsen_map, parent_side, child, child_side);
2570 }
2571}
2572
2573const std::vector<std::vector<QpMap>> &
2574MooseMesh::getRefinementMap(const Elem & elem, int parent_side, int child, int child_side)
2575{
2576 if (child == -1) // Doing volume mapping or parent side mapping
2577 {
2578 mooseAssert(parent_side == child_side,
2579 "Parent side must match child_side if not passing a specific child!");
2580
2581 std::pair<int, ElemType> the_pair(parent_side, elem.type());
2582
2584 mooseError("Could not find a suitable qp refinement map!");
2585
2586 return _elem_type_to_refinement_map[the_pair];
2587 }
2588 else // Need to map a child side to parent volume qps
2589 {
2590 std::pair<int, int> child_pair(child, child_side);
2591
2594 _elem_type_to_child_side_refinement_map[elem.type()].find(child_pair) ==
2596 mooseError("Could not find a suitable qp refinement map!");
2597
2598 return _elem_type_to_child_side_refinement_map[elem.type()][child_pair];
2599 }
2600
2607}
2608
2609void
2610MooseMesh::buildCoarseningMap(const Elem & elem, QBase & qrule, QBase & qrule_face, int input_side)
2611{
2612 TIME_SECTION("buildCoarseningMap", 5, "Building Coarsening Map");
2613
2614 std::pair<int, ElemType> the_pair(input_side, elem.type());
2615
2617 mooseError("Already built a qp coarsening map!");
2618
2619 std::vector<std::vector<QpMap>> refinement_map;
2620 std::vector<std::pair<unsigned int, QpMap>> & coarsen_map =
2622
2623 // The -1 here is for a specific child. We don't do that for coarsening maps
2624 // Also note that we're always mapping the same side to the same side (which is guaranteed by
2625 // libMesh).
2627 &elem, qrule, qrule_face, refinement_map, coarsen_map, input_side, -1, input_side);
2628
2635}
2636
2637const std::vector<std::pair<unsigned int, QpMap>> &
2638MooseMesh::getCoarseningMap(const Elem & elem, int input_side)
2639{
2640 std::pair<int, ElemType> the_pair(input_side, elem.type());
2641
2643 mooseError("Could not find a suitable qp refinement map!");
2644
2645 return _elem_type_to_coarsening_map[the_pair];
2646}
2647
2648void
2649MooseMesh::mapPoints(const std::vector<Point> & from,
2650 const std::vector<Point> & to,
2651 std::vector<QpMap> & qp_map)
2652{
2653 unsigned int n_from = from.size();
2654 unsigned int n_to = to.size();
2655
2656 qp_map.resize(n_from);
2657
2658 for (unsigned int i = 0; i < n_from; ++i)
2659 {
2660 const Point & from_point = from[i];
2661
2662 QpMap & current_map = qp_map[i];
2663
2664 for (unsigned int j = 0; j < n_to; ++j)
2665 {
2666 const Point & to_point = to[j];
2667 Real distance = (from_point - to_point).norm();
2668
2669 if (distance < current_map._distance)
2670 {
2671 current_map._distance = distance;
2672 current_map._from = i;
2673 current_map._to = j;
2674 }
2675 }
2676 }
2677}
2678
2679void
2680MooseMesh::findAdaptivityQpMaps(const Elem * template_elem,
2681 QBase & qrule,
2682 QBase & qrule_face,
2683 std::vector<std::vector<QpMap>> & refinement_map,
2684 std::vector<std::pair<unsigned int, QpMap>> & coarsen_map,
2685 int parent_side,
2686 int child,
2687 int child_side)
2688{
2689 TIME_SECTION("findAdaptivityQpMaps", 5);
2690
2691 ReplicatedMesh mesh(_communicator);
2692 mesh.skip_partitioning(true);
2693
2694 unsigned int dim = template_elem->dim();
2695 mesh.set_mesh_dimension(dim);
2696
2697 for (unsigned int i = 0; i < template_elem->n_nodes(); ++i)
2698 mesh.add_point(template_elem->point(i));
2699
2700 Elem * elem = mesh.add_elem(Elem::build(template_elem->type()).release());
2701
2702 for (unsigned int i = 0; i < template_elem->n_nodes(); ++i)
2703 elem->set_node(i, mesh.node_ptr(i));
2704
2705 std::unique_ptr<FEBase> fe(FEBase::build(dim, FEType()));
2706 fe->get_phi();
2707 const std::vector<Point> & q_points_volume = fe->get_xyz();
2708
2709 std::unique_ptr<FEBase> fe_face(FEBase::build(dim, FEType()));
2710 fe_face->get_phi();
2711 const std::vector<Point> & q_points_face = fe_face->get_xyz();
2712
2713 fe->attach_quadrature_rule(&qrule);
2714 fe_face->attach_quadrature_rule(&qrule_face);
2715
2716 // The current q_points (locations in *physical* space)
2717 const std::vector<Point> * q_points;
2718
2719 if (parent_side != -1)
2720 {
2721 fe_face->reinit(elem, parent_side);
2722 q_points = &q_points_face;
2723 }
2724 else
2725 {
2726 fe->reinit(elem);
2727 q_points = &q_points_volume;
2728 }
2729
2730 std::vector<Point> parent_ref_points;
2731
2732 libMesh::FEMap::inverse_map(elem->dim(), elem, *q_points, parent_ref_points);
2733 libMesh::MeshRefinement mesh_refinement(mesh);
2734 mesh_refinement.uniformly_refine(1);
2735
2736 // A map from the child element index to the locations of all the child's quadrature points in
2737 // *reference* space. Note that we use a map here instead of a vector because the caller can
2738 // pass an explicit child index. We are not guaranteed to have a sequence from [0, n_children)
2739 std::map<unsigned int, std::vector<Point>> child_to_ref_points;
2740
2741 unsigned int n_children = elem->n_children();
2742
2743 refinement_map.resize(n_children);
2744
2745 std::vector<unsigned int> children;
2746
2747 if (child != -1) // Passed in a child explicitly
2748 children.push_back(child);
2749 else
2750 {
2751 children.resize(n_children);
2752 for (unsigned int child = 0; child < n_children; ++child)
2753 children[child] = child;
2754 }
2755
2756 for (unsigned int i = 0; i < children.size(); ++i)
2757 {
2758 unsigned int child = children[i];
2759
2760 if ((parent_side != -1 && !elem->is_child_on_side(child, parent_side)))
2761 continue;
2762
2763 const Elem * child_elem = elem->child_ptr(child);
2764
2765 if (child_side != -1)
2766 {
2767 fe_face->reinit(child_elem, child_side);
2768 q_points = &q_points_face;
2769 }
2770 else
2771 {
2772 fe->reinit(child_elem);
2773 q_points = &q_points_volume;
2774 }
2775
2776 std::vector<Point> child_ref_points;
2777
2778 libMesh::FEMap::inverse_map(elem->dim(), elem, *q_points, child_ref_points);
2779 child_to_ref_points[child] = child_ref_points;
2780
2781 std::vector<QpMap> & qp_map = refinement_map[child];
2782
2783 // Find the closest parent_qp to each child_qp
2784 mapPoints(child_ref_points, parent_ref_points, qp_map);
2785 }
2786
2787 coarsen_map.resize(parent_ref_points.size());
2788
2789 // For each parent qp find the closest child qp
2790 for (unsigned int child = 0; child < n_children; child++)
2791 {
2792 if (parent_side != -1 && !elem->is_child_on_side(child, child_side))
2793 continue;
2794
2795 std::vector<Point> & child_ref_points = child_to_ref_points[child];
2796
2797 std::vector<QpMap> qp_map;
2798
2799 // Find all of the closest points from parent_qp to _THIS_ child's qp
2800 mapPoints(parent_ref_points, child_ref_points, qp_map);
2801
2802 // Check those to see if they are closer than what we currently have for each point
2803 for (unsigned int parent_qp = 0; parent_qp < parent_ref_points.size(); ++parent_qp)
2804 {
2805 std::pair<unsigned int, QpMap> & child_and_map = coarsen_map[parent_qp];
2806 unsigned int & closest_child = child_and_map.first;
2807 QpMap & closest_map = child_and_map.second;
2808
2809 QpMap & current_map = qp_map[parent_qp];
2810
2811 if (current_map._distance < closest_map._distance)
2812 {
2813 closest_child = child;
2814 closest_map = current_map;
2815 }
2816 }
2817 }
2818}
2819
2820void
2821MooseMesh::changeBoundaryId(const boundary_id_type old_id,
2822 const boundary_id_type new_id,
2823 bool delete_prev)
2824{
2825 TIME_SECTION("changeBoundaryId", 6);
2826 changeBoundaryId(getMesh(), old_id, new_id, delete_prev);
2827}
2828
2829void
2831 const boundary_id_type old_id,
2832 const boundary_id_type new_id,
2833 bool delete_prev)
2834{
2835 // Get a reference to our BoundaryInfo object, we will use it several times below...
2836 BoundaryInfo & boundary_info = mesh.get_boundary_info();
2837
2838 // Container to catch ids passed back from BoundaryInfo
2839 std::vector<boundary_id_type> old_ids;
2840
2841 // Only level-0 elements store BCs. Loop over them.
2842 for (auto & elem : as_range(mesh.level_elements_begin(0), mesh.level_elements_end(0)))
2843 {
2844 unsigned int n_sides = elem->n_sides();
2845 for (unsigned int s = 0; s != n_sides; ++s)
2846 {
2847 boundary_info.boundary_ids(elem, s, old_ids);
2848 if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
2849 {
2850 std::vector<boundary_id_type> new_ids(old_ids);
2851 std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
2852 if (delete_prev)
2853 {
2854 boundary_info.remove_side(elem, s);
2855 boundary_info.add_side(elem, s, new_ids);
2856 }
2857 else
2858 boundary_info.add_side(elem, s, new_ids);
2859 }
2860 }
2861 }
2862
2863 // Remove any remaining references to the old ID from the
2864 // BoundaryInfo object. This prevents things like empty sidesets
2865 // from showing up when printing information, etc.
2866 if (delete_prev)
2867 boundary_info.remove_id(old_id);
2868
2869 // The cached boundary id sets will need re-preparation
2870 mesh.unset_has_boundary_id_sets();
2871}
2872
2873const RealVectorValue &
2875{
2876 mooseAssert(_boundary_to_normal_map.get() != nullptr, "Boundary To Normal Map not built!");
2877
2878 // Note: Boundaries that are not in the map (existing boundaries) will default
2879 // construct a new RealVectorValue - (x,y,z)=(0, 0, 0)
2880 return (*_boundary_to_normal_map)[id];
2881}
2882
2883MooseMesh &
2885{
2886 mooseError("MooseMesh::clone() is no longer supported, use MooseMesh::safeClone() instead.");
2887}
2888
2889void
2891{
2892 switch (_parallel_type)
2893 {
2895 // The user did not specify 'parallel_type = XYZ' in the input file,
2896 // so we allow the --distributed-mesh command line arg to possibly turn
2897 // on DistributedMesh. If the command line arg is not present, we pick ReplicatedMesh.
2899 _use_distributed_mesh = true;
2900 break;
2904 _use_distributed_mesh = false;
2905 break;
2907 _use_distributed_mesh = true;
2908 break;
2909 }
2910
2911 // If the user specifies 'nemesis = true' in the Mesh block, or they are using --use-split,
2912 // we must use DistributedMesh.
2913 if (_is_nemesis || _is_split)
2914 _use_distributed_mesh = true;
2915}
2916
2917std::unique_ptr<MeshBase>
2919{
2920 std::unique_ptr<MeshBase> mesh;
2922 mesh = buildTypedMesh<DistributedMesh>(dim);
2923 else
2924 mesh = buildTypedMesh<ReplicatedMesh>(dim);
2925
2926 return mesh;
2927}
2928
2929void
2930MooseMesh::setMeshBase(std::unique_ptr<MeshBase> mesh_base)
2931{
2932 _mesh = std::move(mesh_base);
2933 _mesh->allow_remote_element_removal(_allow_remote_element_removal);
2934}
2935
2936void
2938{
2945 if (!_mesh)
2947
2949 mooseError("You cannot use the mesh splitter capability with DistributedMesh!");
2950
2951 TIME_SECTION("init", 2);
2952
2954 {
2955 // Some partitioners are not idempotent. Some recovery data
2956 // files require partitioning to match mesh partitioning. This
2957 // means that, when recovering, we can't safely repartition.
2958 const bool skip_partitioning_later = getMesh().skip_partitioning();
2959 getMesh().skip_partitioning(true);
2960 const bool allow_renumbering_later = getMesh().allow_renumbering();
2961 getMesh().allow_renumbering(false);
2962
2963 // For now, only read the recovery mesh on the Ultimate Master..
2964 // sub-apps need to just build their mesh like normal
2965 {
2966 TIME_SECTION("readRecoveredMesh", 2);
2968 }
2969
2970 getMesh().allow_renumbering(allow_renumbering_later);
2971 getMesh().skip_partitioning(skip_partitioning_later);
2972 }
2973 else // Normally just build the mesh
2974 {
2975 // Don't allow partitioning during building
2976 if (_app.isSplitMesh())
2977 getMesh().skip_partitioning(true);
2978 buildMesh();
2979
2980 if (getParam<bool>("build_all_side_lowerd_mesh"))
2982 }
2983}
2984
2985std::vector<std::filesystem::path>
2986MooseMesh::writeRecoveryFiles(const std::filesystem::path & file_base)
2987{
2988 libMesh::CheckpointIO io(getMesh(), false);
2989 io.write(file_base);
2990 return {};
2991}
2992
2993unsigned int
2995{
2996 return getMesh().mesh_dimension();
2997}
2998
2999unsigned int
3001{
3002 const Real abs_zero = 1e-12;
3003
3004 // See if the mesh is completely containd in the z and y planes to calculate effective spatial
3005 // dim
3006 for (unsigned int dim = LIBMESH_DIM; dim >= 1; --dim)
3007 if (dimensionWidth(dim - 1) >= abs_zero)
3008 return dim;
3009
3010 // If we get here, we have a 1D mesh on the x-axis.
3011 return 1;
3012}
3013
3014unsigned int
3015MooseMesh::getBlocksMaxDimension(const std::vector<SubdomainName> & blocks) const
3016{
3017 const auto & mesh = getMesh();
3018
3019 // Take a shortcut if possible
3020 if (const auto & elem_dims = mesh.elem_dimensions(); mesh.is_prepared() && elem_dims.size() == 1)
3021 return *elem_dims.begin();
3022
3023 unsigned short dim = 0;
3024 const auto subdomain_ids = getSubdomainIDs(blocks);
3025 const std::set<SubdomainID> subdomain_ids_set(subdomain_ids.begin(), subdomain_ids.end());
3026 for (const auto & elem : mesh.active_subdomain_set_elements_ptr_range(subdomain_ids_set))
3027 dim = std::max(dim, elem->dim());
3028
3029 // Get the maximumal globally
3031 return dim;
3032}
3033
3034std::vector<BoundaryID>
3035MooseMesh::getBoundaryIDs(const Elem * const elem, const unsigned short int side) const
3036{
3037 std::vector<BoundaryID> ids;
3038 getMesh().get_boundary_info().boundary_ids(elem, side, ids);
3039 return ids;
3040}
3041
3042std::vector<std::vector<BoundaryID>>
3043MooseMesh::getBoundaryIDs(const Elem * const elem) const
3044{
3045 std::vector<std::vector<BoundaryID>> ids;
3046 getMesh().get_boundary_info().side_boundary_ids(elem, ids);
3047 return ids;
3048}
3049
3050const std::set<BoundaryID> &
3052{
3053 return getMesh().get_boundary_info().get_boundary_ids();
3054}
3055
3056void
3058{
3059 auto & boundary_info = getMesh().get_boundary_info();
3060
3062 {
3063 const std::set<boundary_id_type> & side_bcids = boundary_info.get_side_boundary_ids();
3064
3066 {
3067 // Don't want to use auto here - the rbegin trick relies on a
3068 // sorted set and we want the compiler to scream if libMesh ever
3069 // switches type
3070 const std::set<boundary_id_type> & node_bcids = boundary_info.get_node_boundary_ids();
3071
3072 // If we've got a reasonable largest BC id, we can just use the
3073 // subsequent unused ones
3074 boundary_id_type next_bcid = 0;
3075 if (!node_bcids.empty())
3076 next_bcid = std::max(next_bcid, cast_int<boundary_id_type>(*node_bcids.rbegin() + 1));
3077 if (!side_bcids.empty())
3078 next_bcid = std::max(next_bcid, cast_int<boundary_id_type>(*side_bcids.rbegin() + 1));
3079
3080 // We need all processors to agree on the id to use, even when
3081 // each only sees the bcids on their own portions of a
3082 // distributed mesh.
3083 _communicator.max(next_bcid);
3084
3085 // If we've got an unreasonably high largest BC id, we should
3086 // probably just search for unused ones with moderate values, so we
3087 // don't risk wrapping.
3088 if (next_bcid > 1000 || next_bcid <= 0)
3089 next_bcid = 1000;
3090
3091 // If any side bcid is already a node bcid with a different name,
3092 // that's a different boundary condition that we need to reassign
3093 // rather than overwrite or merge to.
3094 for (auto bcid : side_bcids)
3095 if (node_bcids.count(bcid) &&
3096 (boundary_info.get_sideset_name(bcid) != boundary_info.get_nodeset_name(bcid)))
3097 {
3098 boundary_info.renumber_node_id(bcid, next_bcid);
3099 do
3100 {
3101 ++next_bcid;
3102 } while (node_bcids.count(next_bcid) || side_bcids.count(next_bcid));
3103 }
3104 }
3105
3106 // For any side bcid that has a name, make sure that our new node
3107 // bcid is given the same name. We need to iterate over the
3108 // actual name map (which is global) here, not over side_bcids
3109 // (which only includes local ids on a distributed mesh).
3110 for (auto & [id, name] : boundary_info.get_sideset_name_map())
3111 boundary_info.nodeset_name(id) = name;
3112
3113 boundary_info.build_node_list_from_side_list();
3114 }
3115}
3116
3117std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
3119{
3120 return getMesh().get_boundary_info().build_side_list();
3121}
3122
3123std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>>
3125{
3126 return getMesh().get_boundary_info().build_active_side_list();
3127}
3128
3129unsigned int
3130MooseMesh::sideWithBoundaryID(const Elem * const elem, const BoundaryID boundary_id) const
3131{
3132 return getMesh().get_boundary_info().side_with_boundary_id(elem, boundary_id);
3133}
3134
3135MeshBase::node_iterator
3137{
3138 return getMesh().local_nodes_begin();
3139}
3140
3141MeshBase::node_iterator
3143{
3144 return getMesh().local_nodes_end();
3145}
3146
3147MeshBase::const_node_iterator
3149{
3150 return getMesh().local_nodes_begin();
3151}
3152
3153MeshBase::const_node_iterator
3155{
3156 return getMesh().local_nodes_end();
3157}
3158
3159MeshBase::element_iterator
3161{
3162 return getMesh().active_local_elements_begin();
3163}
3164
3165const MeshBase::element_iterator
3167{
3168 return getMesh().active_local_elements_end();
3169}
3170
3171MeshBase::const_element_iterator
3173{
3174 return getMesh().active_local_elements_begin();
3175}
3176
3177const MeshBase::const_element_iterator
3179{
3180 return getMesh().active_local_elements_end();
3181}
3182
3183dof_id_type
3185{
3186 return getMesh().n_nodes();
3187}
3188
3189dof_id_type
3191{
3192 return getMesh().n_elem();
3193}
3194
3195dof_id_type
3197{
3198 return getMesh().max_node_id();
3199}
3200
3201dof_id_type
3203{
3204 return getMesh().max_elem_id();
3205}
3206
3207Elem *
3208MooseMesh::elem(const dof_id_type i)
3209{
3210 mooseDeprecated("MooseMesh::elem() is deprecated, please use MooseMesh::elemPtr() instead");
3211 return elemPtr(i);
3212}
3213
3214const Elem *
3215MooseMesh::elem(const dof_id_type i) const
3216{
3217 mooseDeprecated("MooseMesh::elem() is deprecated, please use MooseMesh::elemPtr() instead");
3218 return elemPtr(i);
3219}
3220
3221Elem *
3222MooseMesh::elemPtr(const dof_id_type i)
3223{
3224 return getMesh().elem_ptr(i);
3225}
3226
3227const Elem *
3228MooseMesh::elemPtr(const dof_id_type i) const
3229{
3230 return getMesh().elem_ptr(i);
3231}
3232
3233Elem *
3234MooseMesh::queryElemPtr(const dof_id_type i)
3235{
3236 return getMesh().query_elem_ptr(i);
3237}
3238
3239const Elem *
3240MooseMesh::queryElemPtr(const dof_id_type i) const
3241{
3242 return getMesh().query_elem_ptr(i);
3243}
3244
3245bool
3247{
3248 return _mesh->is_prepared() && _moose_mesh_prepared;
3249}
3250
3251void
3253{
3254 if (state)
3255 mooseError("We don't have any right to tell the libmesh mesh that it *is* prepared. Only a "
3256 "call to prepare_for_use should tell us that");
3257
3258 // Some people may call this even before we have a MeshBase object. This isn't dangerous really
3259 // because when the MeshBase object is born, it knows it's in an unprepared state
3260 if (_mesh)
3261 _mesh->unset_is_prepared();
3262
3263 // If the libMesh mesh isn't preparead, then our MooseMesh wrapper is also no longer prepared
3264 _moose_mesh_prepared = false;
3265
3271}
3272
3273void
3275{
3276 prepared(false);
3277}
3278
3279const std::set<SubdomainID> &
3281{
3282 return _mesh_subdomains;
3283}
3284
3285const std::set<BoundaryID> &
3287{
3288 return _mesh_boundary_ids;
3289}
3290
3291const std::set<BoundaryID> &
3293{
3294 return _mesh_sideset_ids;
3295}
3296
3297const std::set<BoundaryID> &
3299{
3300 return _mesh_nodeset_ids;
3301}
3302
3303void
3304MooseMesh::setMeshBoundaryIDs(std::set<BoundaryID> boundary_IDs)
3305{
3306 _mesh_boundary_ids = boundary_IDs;
3307}
3308
3309void
3311 std::unique_ptr<std::map<BoundaryID, RealVectorValue>> boundary_map)
3312{
3313 _boundary_to_normal_map = std::move(boundary_map);
3314}
3315
3316void
3317MooseMesh::setBoundaryToNormalMap(std::map<BoundaryID, RealVectorValue> * boundary_map)
3318{
3319 mooseDeprecated("setBoundaryToNormalMap(std::map<BoundaryID, RealVectorValue> * boundary_map) is "
3320 "deprecated, use the unique_ptr version instead");
3321 _boundary_to_normal_map.reset(boundary_map);
3322}
3323
3324unsigned int
3329
3330void
3331MooseMesh::setUniformRefineLevel(unsigned int level, bool deletion)
3332{
3333 _uniform_refine_level = level;
3335}
3336
3337void
3339{
3340 _ghosted_boundaries.insert(boundary_id);
3341}
3342
3343void
3344MooseMesh::setGhostedBoundaryInflation(const std::vector<Real> & inflation)
3345{
3347}
3348
3349const std::set<unsigned int> &
3354
3355const std::vector<Real> &
3360
3361namespace // Anonymous namespace for helpers
3362{
3363// A class for templated methods that expect output iterator
3364// arguments, which adds objects to the Mesh.
3365// Although extra_ghost_elem_inserter can add any object, we
3366// template it around object type so that type inference and
3367// iterator_traits will work.
3368// This object specifically is used to insert extra ghost elems into the mesh
3369template <typename T>
3370struct extra_ghost_elem_inserter
3371{
3372 using iterator_category = std::output_iterator_tag;
3373 using value_type = T;
3374
3375 extra_ghost_elem_inserter(DistributedMesh & m) : mesh(m) {}
3376
3377 void operator=(const Elem * e) { mesh.add_extra_ghost_elem(const_cast<Elem *>(e)); }
3378
3379 void operator=(Node * n) { mesh.add_node(n); }
3380
3381 void operator=(Point * p) { mesh.add_point(*p); }
3382
3383 extra_ghost_elem_inserter & operator++() { return *this; }
3384
3385 extra_ghost_elem_inserter operator++(int) { return extra_ghost_elem_inserter(*this); }
3386
3387 // We don't return a reference-to-T here because we don't want to
3388 // construct one or have any of its methods called. We just want
3389 // to allow the returned object to be able to do mesh insertions
3390 // with operator=().
3391 extra_ghost_elem_inserter & operator*() { return *this; }
3392
3393private:
3394 DistributedMesh & mesh;
3395};
3396
3407struct CompareElemsByLevel
3408{
3409 bool operator()(const Elem * a, const Elem * b) const
3410 {
3411 libmesh_assert(a);
3412 libmesh_assert(b);
3413 const unsigned int al = a->level(), bl = b->level();
3414 const dof_id_type aid = a->id(), bid = b->id();
3415
3416 return (al == bl) ? aid < bid : al < bl;
3417 }
3418};
3419
3420} // anonymous namespace
3421
3422void
3424{
3425 // No need to do this if using a serial mesh
3426 // We do not need to ghost boundary elements when _need_ghost_ghosted_boundaries
3427 // is not true. _need_ghost_ghosted_boundaries can be set by a mesh generator
3428 // where boundaries are already ghosted accordingly
3430 return;
3431
3432 TIME_SECTION("GhostGhostedBoundaries", 3);
3433
3434 parallel_object_only();
3435
3436 DistributedMesh & mesh = dynamic_cast<DistributedMesh &>(getMesh());
3437
3438 // We clear ghosted elements that were added by previous invocations of this
3439 // method but leave ghosted elements that were added by other code, e.g.
3440 // OversampleOutput, untouched
3441 mesh.clear_extra_ghost_elems(_ghost_elems_from_ghost_boundaries);
3443
3444 std::set<const Elem *, CompareElemsByLevel> boundary_elems_to_ghost;
3445 std::set<Node *> connected_nodes_to_ghost;
3446
3447 std::vector<const Elem *> family_tree;
3448
3449 for (const auto & t : mesh.get_boundary_info().build_side_list())
3450 {
3451 auto elem_id = std::get<0>(t);
3452 auto bc_id = std::get<2>(t);
3453
3454 if (_ghosted_boundaries.find(bc_id) != _ghosted_boundaries.end())
3455 {
3456 Elem * elem = mesh.elem_ptr(elem_id);
3457
3458#ifdef LIBMESH_ENABLE_AMR
3459 elem->family_tree(family_tree);
3460 Elem * parent = elem->parent();
3461 while (parent)
3462 {
3463 family_tree.push_back(parent);
3464 parent = parent->parent();
3465 }
3466#else
3467 family_tree.clear();
3468 family_tree.push_back(elem);
3469#endif
3470 for (const auto & felem : family_tree)
3471 {
3472 boundary_elems_to_ghost.insert(felem);
3473
3474 // The entries of connected_nodes_to_ghost need to be
3475 // non-constant, so that they will work in things like
3476 // UpdateDisplacedMeshThread. The container returned by
3477 // family_tree contains const Elems even when the Elem
3478 // it is called on is non-const, so once that interface
3479 // gets fixed we can remove this const_cast.
3480 for (unsigned int n = 0; n < felem->n_nodes(); ++n)
3481 connected_nodes_to_ghost.insert(const_cast<Node *>(felem->node_ptr(n)));
3482 }
3483 }
3484 }
3485
3486 // We really do want to store this by value instead of by reference
3487 const auto prior_ghost_elems = mesh.extra_ghost_elems();
3488
3489 mesh.comm().allgather_packed_range(&mesh,
3490 connected_nodes_to_ghost.begin(),
3491 connected_nodes_to_ghost.end(),
3492 extra_ghost_elem_inserter<Node>(mesh));
3493
3494 mesh.comm().allgather_packed_range(&mesh,
3495 boundary_elems_to_ghost.begin(),
3496 boundary_elems_to_ghost.end(),
3497 extra_ghost_elem_inserter<Elem>(mesh));
3498
3499 const auto & current_ghost_elems = mesh.extra_ghost_elems();
3500
3501 std::set_difference(current_ghost_elems.begin(),
3502 current_ghost_elems.end(),
3503 prior_ghost_elems.begin(),
3504 prior_ghost_elems.end(),
3507}
3508
3509unsigned int
3511{
3512 return _patch_size;
3513}
3514
3515void
3517{
3518 _patch_update_strategy = patch_update_strategy;
3519}
3520
3526
3527BoundingBox
3528MooseMesh::getInflatedProcessorBoundingBox(Real inflation_multiplier) const
3529{
3530 // Grab a bounding box to speed things up. Note that
3531 // local_bounding_box is *not* equivalent to processor_bounding_box
3532 // with processor_id() except in serial.
3533 BoundingBox bbox = MeshTools::create_local_bounding_box(getMesh());
3534
3535 // Inflate the bbox just a bit to deal with roundoff
3536 // Adding 1% of the diagonal size in each direction on each end
3537 Real inflation_amount = inflation_multiplier * (bbox.max() - bbox.min()).norm();
3538 Point inflation(inflation_amount, inflation_amount, inflation_amount);
3539
3540 bbox.first -= inflation; // min
3541 bbox.second += inflation; // max
3542
3543 return bbox;
3544}
3545
3546MooseMesh::operator libMesh::MeshBase &() { return getMesh(); }
3547
3548MooseMesh::operator const libMesh::MeshBase &() const { return getMesh(); }
3549
3550const MeshBase *
3552{
3553 return _mesh.get();
3554}
3555
3556MeshBase &
3558{
3559 mooseAssert(_mesh, "Mesh hasn't been created");
3560 return *_mesh;
3561}
3562
3563const MeshBase &
3565{
3566 mooseAssert(_mesh, "Mesh hasn't been created");
3567 return *_mesh;
3568}
3569
3570void
3571MooseMesh::printInfo(std::ostream & os, const unsigned int verbosity /* = 0 */) const
3572{
3573 os << '\n';
3574 getMesh().print_info(os, verbosity);
3575 os << std::flush;
3576}
3577
3578const std::vector<dof_id_type> &
3579MooseMesh::getNodeList(boundary_id_type nodeset_id) const
3580{
3581 std::map<boundary_id_type, std::vector<dof_id_type>>::const_iterator it =
3582 _node_set_nodes.find(nodeset_id);
3583
3584 if (it == _node_set_nodes.end())
3585 {
3586 // On a distributed mesh we might not know about a remote nodeset,
3587 // so we'll return an empty vector and hope the nodeset exists
3588 // elsewhere.
3589 if (!getMesh().is_serial())
3590 {
3591 static const std::vector<dof_id_type> empty_vec;
3592 return empty_vec;
3593 }
3594 // On a replicated mesh we should know about every nodeset and if
3595 // we're asked for one that doesn't exist then it must be a bug.
3596 else
3597 {
3598 mooseError("Unable to nodeset ID: ", nodeset_id, '.');
3599 }
3600 }
3601
3602 return it->second;
3603}
3604
3605const std::set<BoundaryID> &
3607{
3608 const auto it = _sub_to_data.find(subdomain_id);
3609
3610 if (it == _sub_to_data.end())
3611 mooseError("Unable to find subdomain ID: ", subdomain_id, '.');
3612
3613 return it->second.boundary_ids;
3614}
3615
3616std::set<BoundaryID>
3618{
3619 const auto & bnd_ids = getSubdomainBoundaryIds(subdomain_id);
3620 std::set<BoundaryID> boundary_ids(bnd_ids.begin(), bnd_ids.end());
3621 std::unordered_map<SubdomainID, std::set<BoundaryID>>::const_iterator it =
3622 _neighbor_subdomain_boundary_ids.find(subdomain_id);
3623
3624 boundary_ids.insert(it->second.begin(), it->second.end());
3625
3626 return boundary_ids;
3627}
3628
3629std::set<SubdomainID>
3631{
3632 std::set<SubdomainID> subdomain_ids;
3633 for (const auto & [sub_id, data] : _sub_to_data)
3634 if (data.boundary_ids.find(bid) != data.boundary_ids.end())
3635 subdomain_ids.insert(sub_id);
3636
3637 return subdomain_ids;
3638}
3639
3640std::set<SubdomainID>
3642{
3643 std::set<SubdomainID> subdomain_ids;
3644 for (const auto & it : _neighbor_subdomain_boundary_ids)
3645 if (it.second.find(bid) != it.second.end())
3646 subdomain_ids.insert(it.first);
3647
3648 return subdomain_ids;
3649}
3650
3651std::set<SubdomainID>
3653{
3654 std::set<SubdomainID> subdomain_ids = getBoundaryConnectedBlocks(bid);
3655 for (const auto & it : _neighbor_subdomain_boundary_ids)
3656 if (it.second.find(bid) != it.second.end())
3657 subdomain_ids.insert(it.first);
3658
3659 return subdomain_ids;
3660}
3661
3662const std::set<SubdomainID> &
3664{
3665 const auto it = _sub_to_data.find(subdomain_id);
3666
3667 if (it == _sub_to_data.end())
3668 mooseError("Unable to find subdomain ID: ", subdomain_id, '.');
3669
3670 return it->second.neighbor_subs;
3671}
3672
3673bool
3674MooseMesh::isBoundaryNode(dof_id_type node_id) const
3675{
3676 bool found_node = false;
3677 for (const auto & it : _bnd_node_ids)
3678 {
3679 if (it.second.find(node_id) != it.second.end())
3680 {
3681 found_node = true;
3682 break;
3683 }
3684 }
3685 return found_node;
3686}
3687
3688bool
3689MooseMesh::isBoundaryNode(dof_id_type node_id, BoundaryID bnd_id) const
3690{
3691 bool found_node = false;
3692 std::map<boundary_id_type, std::set<dof_id_type>>::const_iterator it = _bnd_node_ids.find(bnd_id);
3693 if (it != _bnd_node_ids.end())
3694 if (it->second.find(node_id) != it->second.end())
3695 found_node = true;
3696 return found_node;
3697}
3698
3699bool
3700MooseMesh::isBoundaryElem(dof_id_type elem_id) const
3701{
3702 bool found_elem = false;
3703 for (const auto & it : _bnd_elem_ids)
3704 {
3705 if (it.second.find(elem_id) != it.second.end())
3706 {
3707 found_elem = true;
3708 break;
3709 }
3710 }
3711 return found_elem;
3712}
3713
3714bool
3715MooseMesh::isBoundaryElem(dof_id_type elem_id, BoundaryID bnd_id) const
3716{
3717 bool found_elem = false;
3718 auto it = _bnd_elem_ids.find(bnd_id);
3719 if (it != _bnd_elem_ids.end())
3720 if (it->second.find(elem_id) != it->second.end())
3721 found_elem = true;
3722 return found_elem;
3723}
3724
3725void
3727{
3729 mooseError("Cannot use ",
3730 name,
3731 " with DistributedMesh!\n",
3732 "Consider specifying parallel_type = 'replicated' in your input file\n",
3733 "to prevent it from being run with DistributedMesh.");
3734}
3735
3736void
3738{
3739 if (_use_distributed_mesh && (_partitioner_name != "default" && _partitioner_name != "parmetis"))
3740 {
3741 _partitioner_name = "parmetis";
3743 }
3744
3746}
3747
3748void
3749MooseMesh::setPartitioner(MeshBase & mesh_base,
3750 MooseEnum & partitioner,
3751 bool use_distributed_mesh,
3752 const InputParameters & params,
3753 MooseObject & context_obj)
3754{
3755 // Set the partitioner based on partitioner name
3756 switch (partitioner)
3757 {
3758 case -3: // default
3759 // We'll use the default partitioner, but notify the user of which one is being used...
3760 if (use_distributed_mesh)
3761 partitioner = "parmetis";
3762 else
3763 partitioner = "metis";
3764 break;
3765
3766 // No need to explicitily create the metis or parmetis partitioners,
3767 // They are the default for serial and parallel mesh respectively
3768 case -2: // metis
3769 case -1: // parmetis
3770 break;
3771
3772 case 0: // linear
3773 mesh_base.partitioner().reset(new libMesh::LinearPartitioner);
3774 break;
3775 case 1: // centroid
3776 {
3777 if (!params.isParamValid("centroid_partitioner_direction"))
3778 context_obj.paramError(
3779 "centroid_partitioner_direction",
3780 "If using the centroid partitioner you _must_ specify centroid_partitioner_direction!");
3781
3782 MooseEnum direction = params.get<MooseEnum>("centroid_partitioner_direction");
3783
3784 if (direction == "x")
3785 mesh_base.partitioner().reset(
3787 else if (direction == "y")
3788 mesh_base.partitioner().reset(
3790 else if (direction == "z")
3791 mesh_base.partitioner().reset(
3793 else if (direction == "radial")
3794 mesh_base.partitioner().reset(
3796 break;
3797 }
3798 case 2: // hilbert_sfc
3799 mesh_base.partitioner().reset(new libMesh::HilbertSFCPartitioner);
3800 break;
3801 case 3: // morton_sfc
3802 mesh_base.partitioner().reset(new libMesh::MortonSFCPartitioner);
3803 break;
3804 }
3805}
3806
3807void
3808MooseMesh::setCustomPartitioner(Partitioner * partitioner)
3809{
3810 _custom_partitioner = partitioner->clone();
3812 if (_mesh)
3813 _mesh->partitioner() = _custom_partitioner->clone();
3814 _partitioner_name = "custom";
3815}
3816
3817bool
3822
3823bool
3825{
3826 bool mesh_has_second_order_elements = false;
3827 for (auto it = activeLocalElementsBegin(), end = activeLocalElementsEnd(); it != end; ++it)
3828 if ((*it)->default_order() == SECOND)
3829 {
3830 mesh_has_second_order_elements = true;
3831 break;
3832 }
3833
3834 // We checked our local elements, so take the max over all processors.
3835 comm().max(mesh_has_second_order_elements);
3836 return mesh_has_second_order_elements;
3837}
3838
3839void
3844
3845std::unique_ptr<libMesh::PointLocatorBase>
3847{
3848 return getMesh().sub_point_locator();
3849}
3850
3851void
3853{
3854 mooseAssert(!Threads::in_threads,
3855 "This routine has not been implemented for threads. Please query this routine before "
3856 "a threaded region or contact a MOOSE developer to discuss.");
3858
3859 using Keytype = std::pair<const Elem *, unsigned short int>;
3860
3861 // create a map from elem/side --> boundary ids
3862 std::vector<std::tuple<dof_id_type, unsigned short int, boundary_id_type>> side_list =
3864 std::map<Keytype, std::set<boundary_id_type>> side_map;
3865 for (auto & [elem_id, side, bc_id] : side_list)
3866 {
3867 const Elem * elem = _mesh->elem_ptr(elem_id);
3868 Keytype key(elem, side);
3869 auto & bc_set = side_map[key];
3870 bc_set.insert(bc_id);
3871 }
3872
3873 _face_info.clear();
3874 _all_face_info.clear();
3876
3877 _elem_to_elem_info.clear();
3878 _elem_info.clear();
3879
3880 // by performing the element ID comparison check in the below loop, we are ensuring that we never
3881 // double count face contributions. If a face lies along a process boundary, the only process that
3882 // will contribute to both sides of the face residuals/Jacobians will be the process that owns the
3883 // element with the lower ID.
3884 auto begin = getMesh().active_elements_begin();
3885 auto end = getMesh().active_elements_end();
3886
3887 // We prepare a map connecting the Elem* and the corresponding ElemInfo
3888 // for the active elements.
3890 unsigned int num_sides = 0;
3891 for (const Elem * elem : as_range(begin, end))
3892 {
3893 _elem_to_elem_info.emplace(elem->id(), elem);
3894 num_sides += elem->n_sides();
3895 }
3896
3897 // Used to speed up FaceInfo creation:
3898 // - element side builder that caches per type of element
3899 libMesh::ElemSideBuilder side_builder;
3900
3901 _all_face_info.reserve(num_sides / 2);
3902 dof_id_type face_index = 0;
3903 for (const Elem * elem : as_range(begin, end))
3904 {
3905 for (unsigned int side = 0; side < elem->n_sides(); ++side)
3906 {
3907 // get the neighbor element
3908 const Elem * neighbor = elem->neighbor_ptr(side);
3909
3910 // Check if the FaceInfo shall belong to the element. If yes,
3911 // create and initialize the FaceInfo. We need this to ensure that
3912 // we do not duplicate FaceInfo-s.
3913 if (Moose::FV::elemHasFaceInfo(*elem, neighbor))
3914 {
3915 mooseAssert(!neighbor || (neighbor->level() < elem->level() ? neighbor->active() : true),
3916 "If the neighbor is coarser than the element, we expect that the neighbor must "
3917 "be active.");
3918
3919 // We construct the faceInfo using the elementinfo and side index
3920 mooseAssert(elem->default_order() < 4, "Did not expect such high element orders in FV");
3921 _all_face_info.emplace_back(
3922 &_elem_to_elem_info[elem->id()], side, face_index++, side_builder);
3923
3924 auto & fi = _all_face_info.back();
3925
3926 // get all the sidesets that this face is contained in and cache them
3927 // in the face info.
3928 std::set<boundary_id_type> & boundary_ids = fi.boundaryIDs();
3929 boundary_ids.clear();
3930
3931 // We initialize the weights/other information in faceInfo. If the neighbor does not exist
3932 // or is remote (so when we are on some sort of mesh boundary), we initialize the ghost
3933 // cell and use it to compute the weights corresponding to the faceInfo.
3934 if (!neighbor || neighbor == libMesh::remote_elem)
3935 fi.computeBoundaryCoefficients();
3936 else
3937 fi.computeInternalCoefficients(&_elem_to_elem_info[neighbor->id()]);
3938
3939 auto lit = side_map.find(Keytype(&fi.elem(), fi.elemSideID()));
3940 if (lit != side_map.end())
3941 boundary_ids.insert(lit->second.begin(), lit->second.end());
3942
3943 if (fi.neighborPtr())
3944 {
3945 auto rit = side_map.find(Keytype(fi.neighborPtr(), fi.neighborSideID()));
3946 if (rit != side_map.end())
3947 boundary_ids.insert(rit->second.begin(), rit->second.end());
3948 }
3949 }
3950 }
3951 }
3952
3953 // Build the local face info and elem_side to face info maps. We need to do this after
3954 // _all_face_info is finished being constructed because emplace_back invalidates all iterators and
3955 // references if ever the new size exceeds capacity
3957 // heuristic to avoid resizing too much
3958 _face_info.reserve(_all_face_info.size());
3959 for (auto & fi : _all_face_info)
3960 {
3961 const Elem * const elem = &fi.elem();
3962 const auto side = fi.elemSideID();
3963
3964#ifndef NDEBUG
3965 auto pair_it =
3966#endif
3967 _elem_side_to_face_info.emplace(std::make_pair(elem, side), &fi);
3968 mooseAssert(pair_it.second, "We should be adding unique FaceInfo objects.");
3969
3970 // We will add the faces on processor boundaries to the list of face infos on each
3971 // associated processor.
3972 if (fi.elem().processor_id() == this->processor_id() ||
3973 (fi.neighborPtr() && (fi.neighborPtr()->processor_id() == this->processor_id())))
3974 _face_info.push_back(&fi);
3975 }
3976
3977 _elem_info.reserve(nActiveLocalElem());
3978 for (auto & ei : _elem_to_elem_info)
3979 if (ei.second.elem()->processor_id() == this->processor_id())
3980 _elem_info.push_back(&ei.second);
3981}
3982
3983const FaceInfo *
3984MooseMesh::faceInfo(const Elem * elem, unsigned int side) const
3985{
3986 auto it = _elem_side_to_face_info.find(std::make_pair(elem, side));
3987
3988 if (it == _elem_side_to_face_info.end())
3989 return nullptr;
3990 else
3991 {
3992 mooseAssert(it->second,
3993 "For some reason, the FaceInfo object is NULL! Try calling "
3994 "`buildFiniteVolumeInfo()` before using this accessor!");
3995 return it->second;
3996 }
3997}
3998
3999const ElemInfo &
4000MooseMesh::elemInfo(const dof_id_type id) const
4001{
4002 return libmesh_map_find(_elem_to_elem_info, id);
4003}
4004
4005void
4007{
4009 mooseError("Trying to compute face- and elem-info coords when the information is dirty");
4010
4011 for (auto & fi : _all_face_info)
4012 {
4013 // get elem & neighbor elements, and set subdomain ids
4014 const SubdomainID elem_subdomain_id = fi.elemSubdomainID();
4015 const SubdomainID neighbor_subdomain_id = fi.neighborSubdomainID();
4016
4018 *this, elem_subdomain_id, fi.faceCentroid(), fi.faceCoord(), neighbor_subdomain_id);
4019 }
4020
4021 for (auto & ei : _elem_to_elem_info)
4023 *this, ei.second.subdomain_id(), ei.second.centroid(), ei.second.coordFactor());
4024}
4025
4028{
4030 "default=-3 metis=-2 parmetis=-1 linear=0 centroid hilbert_sfc morton_sfc custom", "default");
4031 return partitioning;
4032}
4033
4036{
4038 "EDGE EDGE2 EDGE3 EDGE4 QUAD QUAD4 QUAD8 QUAD9 TRI3 TRI6 HEX HEX8 HEX20 HEX27 TET4 TET10 "
4039 "PRISM6 PRISM15 PRISM18 PYRAMID5 PYRAMID13 PYRAMID14");
4040 return elemTypes;
4041}
4042
4043void
4044MooseMesh::allowRemoteElementRemoval(const bool allow_remote_element_removal)
4045{
4046 _allow_remote_element_removal = allow_remote_element_removal;
4047 if (_mesh)
4048 _mesh->allow_remote_element_removal(allow_remote_element_removal);
4049
4050 if (!allow_remote_element_removal)
4051 // If we're not allowing remote element removal now, then we will need deletion later after
4052 // late geoemetric ghosting functors have been added (late geometric ghosting functor addition
4053 // happens when algebraic ghosting functors are added)
4054 _need_delete = true;
4055}
4056
4057void
4059{
4061 if (!_mesh)
4062 mooseError("Cannot delete remote elements because we have not yet attached a MeshBase");
4063
4064 _mesh->allow_remote_element_removal(true);
4065
4066 _mesh->delete_remote_elements();
4067}
4068
4069void
4071{
4072 mooseAssert(
4074 "Performing writes to faceInfo variable association maps. This must be done unthreaded!");
4075
4076 const unsigned int num_eqs = _app.feProblem().es().n_systems();
4077
4078 auto face_lambda = [this](const SubdomainID elem_subdomain_id,
4079 const SubdomainID neighbor_subdomain_id,
4080 SystemBase & sys,
4081 std::vector<std::vector<FaceInfo::VarFaceNeighbors>> & face_type_vector)
4082 {
4083 face_type_vector[sys.number()].resize(sys.nVariables(), FaceInfo::VarFaceNeighbors::NEITHER);
4084 const auto & variables = sys.getVariables(0);
4085
4086 for (const auto & var : variables)
4087 {
4088 const unsigned int var_num = var->number();
4089 const unsigned int sys_num = var->sys().number();
4090 std::set<SubdomainID> var_subdomains = var->blockIDs();
4100 bool var_defined_elem = var_subdomains.find(elem_subdomain_id) != var_subdomains.end();
4101 bool var_defined_neighbor =
4102 var_subdomains.find(neighbor_subdomain_id) != var_subdomains.end();
4103 if (var_defined_elem && var_defined_neighbor)
4104 face_type_vector[sys_num][var_num] = FaceInfo::VarFaceNeighbors::BOTH;
4105 else if (!var_defined_elem && !var_defined_neighbor)
4106 face_type_vector[sys_num][var_num] = FaceInfo::VarFaceNeighbors::NEITHER;
4107 else
4108 {
4109 // this is a boundary face for this variable, set elem or neighbor
4110 if (var_defined_elem)
4111 face_type_vector[sys_num][var_num] = FaceInfo::VarFaceNeighbors::ELEM;
4112 else if (var_defined_neighbor)
4113 face_type_vector[sys_num][var_num] = FaceInfo::VarFaceNeighbors::NEIGHBOR;
4114 else
4115 mooseError("Should never get here");
4116 }
4117 }
4118 };
4119
4120 // We loop through the faces and check if they are internal, boundary or external to
4121 // the variables in the problem
4122 for (FaceInfo & face : _all_face_info)
4123 {
4124 const SubdomainID elem_subdomain_id = face.elemSubdomainID();
4125 const SubdomainID neighbor_subdomain_id = face.neighborSubdomainID();
4126
4127 auto & face_type_vector = face.faceType();
4128
4129 face_type_vector.clear();
4130 face_type_vector.resize(num_eqs);
4131
4132 // First, we check the variables in the solver systems (linear/nonlinear)
4133 for (const auto i : make_range(_app.feProblem().numSolverSystems()))
4134 face_lambda(elem_subdomain_id,
4135 neighbor_subdomain_id,
4137 face_type_vector);
4138
4139 // Then we check the variables in the auxiliary system
4140 face_lambda(elem_subdomain_id,
4141 neighbor_subdomain_id,
4143 face_type_vector);
4144 }
4145}
4146
4147void
4149{
4150 mooseAssert(!Threads::in_threads,
4151 "Performing writes to elemInfo dof indices. This must be done unthreaded!");
4152
4153 auto elem_lambda = [](const ElemInfo & elem_info,
4154 SystemBase & sys,
4155 std::vector<std::vector<dof_id_type>> & dof_vector)
4156 {
4157 if (sys.nFVVariables())
4158 {
4159 dof_vector[sys.number()].resize(sys.nVariables(), libMesh::DofObject::invalid_id);
4160 const auto & variables = sys.getVariables(0);
4161
4162 for (const auto & var : variables)
4163 if (var->isFV())
4164 {
4165 const auto & var_subdomains = var->blockIDs();
4166
4167 // We will only cache for FV variables and if they live on the current subdomain
4168 if (var_subdomains.find(elem_info.subdomain_id()) != var_subdomains.end())
4169 {
4170 std::vector<dof_id_type> indices;
4171 var->dofMap().dof_indices(elem_info.elem(), indices, var->number());
4172 mooseAssert(indices.size() == 1, "We expect to have only one dof per element!");
4173 dof_vector[sys.number()][var->number()] = indices[0];
4174 }
4175 }
4176 }
4177 };
4178
4179 const unsigned int num_eqs = _app.feProblem().es().n_systems();
4180
4181 // We loop through the elements in the mesh and cache the dof indices
4182 // for the corresponding variables.
4183 for (auto & ei_pair : _elem_to_elem_info)
4184 {
4185 auto & elem_info = ei_pair.second;
4186 auto & dof_vector = elem_info.dofIndices();
4187
4188 dof_vector.clear();
4189 dof_vector.resize(num_eqs);
4190
4191 // First, we cache the dof indices for the variables in the solver systems (linear, nonlinear)
4192 for (const auto i : make_range(_app.feProblem().numSolverSystems()))
4193 elem_lambda(elem_info, _app.feProblem().getSolverSystem(i), dof_vector);
4194
4195 // Then we cache the dof indices for the auxvariables
4196 elem_lambda(elem_info, _app.feProblem().getAuxiliarySystem(), dof_vector);
4197 }
4198}
4199
4200void
4208
4209void
4210MooseMesh::setCoordSystem(const std::vector<SubdomainName> & blocks,
4211 const MultiMooseEnum & coord_sys)
4212{
4213 TIME_SECTION("setCoordSystem", 5, "Setting Coordinate System");
4215 {
4216 const std::string param_name = isParamValid("coord_block") ? "coord_block" : "block";
4217 mooseWarning("Supplied blocks in the 'setCoordSystem' method do not match the value of the "
4218 "'Mesh/",
4219 param_name,
4220 "' parameter. Did you provide different parameter values for 'Mesh/",
4221 param_name,
4222 "' and 'Problem/block'?. We will honor the parameter value from 'Mesh/",
4223 param_name,
4224 "'");
4225 mooseAssert(_coord_system_set,
4226 "If we are arriving here due to a bad specification in the Problem block, then we "
4227 "should have already set our coordinate system subdomains from the Mesh block");
4228 return;
4229 }
4230 if (_pars.isParamSetByUser("coord_type") && getParam<MultiMooseEnum>("coord_type") != coord_sys)
4231 mooseError("Supplied coordinate systems in the 'setCoordSystem' method do not match the value "
4232 "of the 'Mesh/coord_type' parameter. Did you provide different parameter values for "
4233 "'coord_type' to 'Mesh' and 'Problem'?");
4234
4235 // If blocks contain ANY_BLOCK_ID, it should be the only block specified, and coord_sys should
4236 // have one and only one entry. In that case, the same coordinate system will be set for all
4237 // subdomains.
4238 if (blocks.size() == 1 && blocks[0] == "ANY_BLOCK_ID")
4239 {
4240 if (coord_sys.size() > 1)
4241 mooseError("If you specify ANY_BLOCK_ID as the only block, you must also specify a single "
4242 "coordinate system for it.");
4243 if (!_mesh->is_prepared())
4244 mooseError(
4245 "You cannot set the coordinate system for ANY_BLOCK_ID before the mesh is prepared. "
4246 "Please call this method after the mesh is prepared.");
4247 const auto coord_type = coord_sys.size() == 0
4249 : Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[0]);
4250 for (const auto sid : meshSubdomains())
4251 _coord_sys[sid] = coord_type;
4252 return;
4253 }
4254
4255 // If multiple blocks are specified, but one of them is ANY_BLOCK_ID, let's emit a helpful error
4256 if (std::find(blocks.begin(), blocks.end(), "ANY_BLOCK_ID") != blocks.end())
4257 mooseError("You cannot specify ANY_BLOCK_ID together with other blocks in the "
4258 "setCoordSystem() method. If you want to set the same coordinate system for all "
4259 "blocks, use ANY_BLOCK_ID as the only block.");
4260
4261 auto subdomains = meshSubdomains();
4262 // It's possible that a user has called this API before the mesh is prepared and consequently we
4263 // don't yet have the subdomains in meshSubdomains()
4264 for (const auto & sub_name : blocks)
4265 {
4266 const auto sub_id = getSubdomainID(sub_name);
4267 subdomains.insert(sub_id);
4268 }
4269
4270 if (coord_sys.size() <= 1)
4271 {
4272 // We will specify the same coordinate system for all blocks
4273 const auto coord_type = coord_sys.size() == 0
4275 : Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[0]);
4276 for (const auto sid : subdomains)
4277 _coord_sys[sid] = coord_type;
4278 }
4279 else
4280 {
4281 if (blocks.size() != coord_sys.size())
4282 mooseError("Number of blocks and coordinate systems does not match.");
4283
4284 for (const auto i : index_range(blocks))
4285 {
4287 Moose::CoordinateSystemType coord_type =
4288 Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[i]);
4289 _coord_sys[sid] = coord_type;
4290 }
4291
4292 for (const auto & sid : subdomains)
4293 if (_coord_sys.find(sid) == _coord_sys.end())
4294 mooseError("Subdomain '" + Moose::stringify(sid) +
4295 "' does not have a coordinate system specified.");
4296 }
4297
4298 _coord_system_set = true;
4299
4301}
4302
4305{
4306 auto it = _coord_sys.find(sid);
4307 if (it != _coord_sys.end())
4308 return (*it).second;
4309 else
4310 mooseError("Requested subdomain ", sid, " does not exist.");
4311}
4312
4315{
4316 const auto unique_system = _coord_sys.find(*meshSubdomains().begin())->second;
4317 // Check that it is actually unique
4318 bool result = std::all_of(
4319 std::next(_coord_sys.begin()),
4320 _coord_sys.end(),
4321 [unique_system](
4322 typename std::unordered_map<SubdomainID, Moose::CoordinateSystemType>::const_reference
4323 item) { return (item.second == unique_system); });
4324 if (!result)
4325 mooseError("The unique coordinate system of the mesh was requested by the mesh contains "
4326 "multiple blocks with different coordinate systems");
4327
4329 mooseError("General axisymmetric coordinate axes are being used, and it is currently "
4330 "conservatively assumed that in this case there is no unique coordinate system.");
4331
4332 return unique_system;
4333}
4334
4335const std::map<SubdomainID, Moose::CoordinateSystemType> &
4337{
4338 return _coord_sys;
4339}
4340
4341void
4343{
4344 _rz_coord_axis = rz_coord_axis;
4345
4347}
4348
4349void
4351 const std::vector<SubdomainName> & blocks,
4352 const std::vector<std::pair<Point, RealVectorValue>> & axes)
4353{
4354 // Set the axes for the given blocks
4355 mooseAssert(blocks.size() == axes.size(), "Blocks and axes vectors must be the same length.");
4356 for (const auto i : index_range(blocks))
4357 {
4358 const auto subdomain_id = getSubdomainID(blocks[i]);
4359 const auto it = _coord_sys.find(subdomain_id);
4360 if (it == _coord_sys.end())
4361 mooseError("The block '",
4362 blocks[i],
4363 "' has not set a coordinate system. Make sure to call setCoordSystem() before "
4364 "setGeneralAxisymmetricCoordAxes().");
4365 else
4366 {
4367 if (it->second == Moose::COORD_RZ)
4368 {
4369 const auto direction = axes[i].second;
4370 if (direction.is_zero())
4371 mooseError("Only nonzero vectors may be supplied for RZ directions.");
4372
4373 _subdomain_id_to_rz_coord_axis[subdomain_id] =
4374 std::make_pair(axes[i].first, direction.unit());
4375 }
4376 else
4377 mooseError("The block '",
4378 blocks[i],
4379 "' was provided in setGeneralAxisymmetricCoordAxes(), but the coordinate system "
4380 "for this block is not 'RZ'.");
4381 }
4382 }
4383
4384 // Make sure there are no RZ blocks that still do not have axes
4385 const auto all_subdomain_ids = meshSubdomains();
4386 for (const auto subdomain_id : all_subdomain_ids)
4387 if (getCoordSystem(subdomain_id) == Moose::COORD_RZ &&
4388 !_subdomain_id_to_rz_coord_axis.count(subdomain_id))
4389 mooseError("The block '",
4390 getSubdomainName(subdomain_id),
4391 "' was specified to use the 'RZ' coordinate system but was not given in "
4392 "setGeneralAxisymmetricCoordAxes().");
4393
4395}
4396
4397const std::pair<Point, RealVectorValue> &
4399{
4400 auto it = _subdomain_id_to_rz_coord_axis.find(subdomain_id);
4401 if (it != _subdomain_id_to_rz_coord_axis.end())
4402 return (*it).second;
4403 else
4404 mooseError("Requested subdomain ", subdomain_id, " does not exist.");
4405}
4406
4407bool
4412
4413void
4415{
4416 if (!_coord_transform)
4417 _coord_transform = std::make_unique<MooseAppCoordTransform>(*this);
4418 else
4419 _coord_transform->setCoordinateSystem(*this);
4420}
4421
4422unsigned int
4424{
4426 mooseError("getAxisymmetricRadialCoord() should not be called if "
4427 "setGeneralAxisymmetricCoordAxes() has been called.");
4428
4429 if (_rz_coord_axis == 0)
4430 return 1; // if the rotation axis is x (0), then the radial direction is y (1)
4431 else
4432 return 0; // otherwise the radial direction is assumed to be x, i.e., the rotation axis is y
4433}
4434
4435void
4437{
4438 for (const auto & elem : getMesh().element_ptr_range())
4439 {
4440 SubdomainID sid = elem->subdomain_id();
4441 if (_coord_sys[sid] == Moose::COORD_RZ && elem->dim() == 3)
4442 mooseError("An RZ coordinate system was requested for subdomain " + Moose::stringify(sid) +
4443 " which contains 3D elements.");
4444 if (_coord_sys[sid] == Moose::COORD_RSPHERICAL && elem->dim() > 1)
4445 mooseError("An RSPHERICAL coordinate system was requested for subdomain " +
4446 Moose::stringify(sid) + " which contains 2D or 3D elements.");
4447 }
4448}
4449
4450void
4452{
4453 _coord_sys = other_mesh._coord_sys;
4454 _rz_coord_axis = other_mesh._rz_coord_axis;
4456}
4457
4458const MooseUnits &
4460{
4461 mooseAssert(_coord_transform, "This must be non-null");
4462 return _coord_transform->lengthUnit();
4463}
4464
4465void
4467{
4468 std::map<SubdomainName, SubdomainID> subdomain;
4469 for (const auto & sbd_id : _mesh_subdomains)
4470 {
4471 std::string sub_name = getSubdomainName(sbd_id);
4472 if (!sub_name.empty() && subdomain.count(sub_name) > 0)
4473 mooseError("The subdomain name ",
4474 sub_name,
4475 " is used for both subdomain with ID=",
4476 subdomain[sub_name],
4477 " and ID=",
4478 sbd_id,
4479 ", Please rename one of them!");
4480 else
4481 subdomain[sub_name] = sbd_id;
4482 }
4483}
4484
4485const std::vector<QpMap> &
4487 const Elem & elem,
4488 const std::map<std::pair<ElemType, unsigned int>, std::vector<QpMap>> & map) const
4489{
4490 // We are actually seeking the map stored with the p_level - 1 key, e.g. the refinement map that
4491 // maps from the previous p_level to this element's p_level
4492 return libmesh_map_find(map,
4493 std::make_pair(elem.type(), cast_int<unsigned int>(elem.p_level() - 1)));
4494}
4495
4496const std::vector<QpMap> &
4498 const Elem & elem,
4499 const std::map<std::pair<ElemType, unsigned int>, std::vector<QpMap>> & map) const
4500{
4501 mooseAssert(elem.active() && elem.p_refinement_flag() == Elem::JUST_COARSENED,
4502 "These are the conditions that should be met for requesting a coarsening map");
4503 return libmesh_map_find(map, std::make_pair(elem.type(), elem.p_level()));
4504}
4505
4506const std::vector<QpMap> &
4511
4512const std::vector<QpMap> &
4517
4518const std::vector<QpMap> &
4523
4524const std::vector<QpMap> &
4529
4530bool
4532{
4533 return _mesh->skip_noncritical_partitioning();
4534}
void coordTransformFactor(const SubProblem &s, SubdomainID sub_id, const P &point, C &factor, SubdomainID neighbor_sub_id=libMesh::Elem::invalid_subdomain_id)
Computes a conversion multiplier for use when computing integraals for the current coordinate system ...
Definition Assembly.C:41
boundary_id_type BoundaryID
subdomain_id_type SubdomainID
void mooseInfoRepeated(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition MooseError.h:409
char ** blocks
auto operator*(const T1 &a, const RankFourTensorTempl< T2 > &b) -> typename std::enable_if< libMesh::ScalarTraits< T1 >::value, RankFourTensorTempl< decltype(T1() *T2())> >::type
unsigned int dim
void ErrorVector unsigned int
Keeps track of stuff related to assembling.
Definition Assembly.h:101
libMesh::QBase *const & writeableQRule()
Returns the reference to the current quadrature being used.
Definition Assembly.h:232
libMesh::QBase *const & writeableQRuleFace()
Returns the reference to the current quadrature being used on a current face.
Definition Assembly.h:319
void setCurrentSubdomainID(SubdomainID i)
set the current subdomain ID
Definition Assembly.h:415
void reinit(const Elem *elem)
Reinitialize objects (JxW, q_points, ...) for an elements.
Definition Assembly.C:1819
Helper class for sorting Boundary Nodes so that we always get the same order of application for bound...
Definition MooseMesh.C:1011
bool operator()(const BndNode *const &lhs, const BndNode *const &rhs)
Definition MooseMesh.C:1015
std::vector< const Elem * > _refined_elements
The elements that were just refined.
std::map< const Elem *, std::vector< const Elem * > > _coarsened_element_children
Map of Parent elements to children elements for elements that were just coarsened.
std::vector< const Elem * > _coarsened_elements
The elements that were just coarsened.
Class used for caching additional information for elements such as the volume and centroid.
Definition ElemInfo.h:26
SubdomainID subdomain_id() const
We return the subdomain ID of the corresponding libmesh element.
Definition ElemInfo.h:43
const Elem * elem() const
Definition ElemInfo.h:34
const std::vector< std::vector< dof_id_type > > & dofIndices() const
Definition ElemInfo.h:39
virtual libMesh::EquationSystems & es() override
AuxiliarySystem & getAuxiliarySystem()
virtual std::size_t numSolverSystems() const override
bool hasKokkosObjects() const
SolverSystem & getSolverSystem(unsigned int sys_num)
Get non-constant reference to a solver system.
bool initialized() const
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition FaceInfo.h:38
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addPrivateParam(const std::string &name, const T &value)
These method add a parameter to the InputParameters object which can be retrieved like any other para...
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System.
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another,...
static InputParameters validParams()
Describes the parameters this object can take to setup transformations.
bool isKokkosAvailable() const
Get whether Kokkos is available.
Definition MooseApp.h:1149
bool isSplitMesh() const
Whether or not this is a split mesh operation.
Definition MooseApp.C:1687
Executioner * getExecutioner() const
Retrieve the Executioner for this App.
Definition MooseApp.C:2021
static const std::string & checkpointSuffix()
The file suffix for the checkpoint mesh.
Definition MooseApp.C:3045
bool isUltimateMaster() const
Whether or not this app is the ultimate master app.
Definition MooseApp.h:866
bool getDistributedMeshOnCommandLine() const
Returns true if the user specified –distributed-mesh (or –parallel-mesh, for backwards compatibility)...
Definition MooseApp.h:466
FEProblemBase & feProblem() const
Definition MooseApp.C:1858
std::string getRestartRecoverFileBase() const
The file_base for the recovery file.
Definition MooseApp.h:500
bool isRecovering() const
Whether or not this is a "recover" calculation.
Definition MooseApp.C:1675
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
static const std::string name_param
The name of the parameter that contains the object name.
Definition MooseBase.h:55
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition MooseBase.h:205
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition MooseBase.h:271
const InputParameters & _pars
The object's parameters.
Definition MooseBase.h:384
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition MooseBase.h:406
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
std::set< SubdomainID > getInterfaceConnectedBlocks(const BoundaryID bid) const
Get the list of subdomains contacting the given boundary.
Definition MooseMesh.C:3652
virtual bnd_node_iterator bndNodesBegin()
Return iterators to the beginning/end of the boundary nodes list.
Definition MooseMesh.C:1538
const Moose::PatchUpdateType & getPatchUpdateStrategy() const
Get the current patch update strategy.
Definition MooseMesh.C:3522
std::vector< std::vector< bool > > _id_identical_flag
Flags to indicate whether or not any two extra element integers are the same.
Definition MooseMesh.h:2008
bool _need_delete
Whether we need to delete remote elements after init'ing the EquationSystems.
Definition MooseMesh.h:1987
void setBoundaryName(BoundaryID boundary_id, BoundaryName name)
This method sets the boundary name of the boundary based on the id parameter.
Definition MooseMesh.C:1776
virtual bnd_node_iterator bndNodesEnd()
Definition MooseMesh.C:1546
virtual ~MooseMesh()
Definition MooseMesh.C:356
bool isBoundaryElem(dof_id_type elem_id) const
Returns true if the requested element is in the list of boundary elements, false otherwise.
Definition MooseMesh.C:3700
void setupFiniteVolumeMeshData() const
Sets up the additional data needed for finite volume computations.
Definition MooseMesh.C:4201
const std::set< BoundaryID > & getSubdomainBoundaryIds(const SubdomainID subdomain_id) const
Get the list of boundary ids associated with the given subdomain id.
Definition MooseMesh.C:3606
void buildBndElemList()
Definition MooseMesh.C:1187
void printInfo(std::ostream &os=libMesh::out, const unsigned int verbosity=0) const
Calls print_info() on the underlying Mesh.
Definition MooseMesh.C:3571
const Elem * getLowerDElem(const Elem *, unsigned short int) const
Returns a const pointer to a lower dimensional element that corresponds to a side of a higher dimensi...
Definition MooseMesh.C:1693
virtual std::vector< std::filesystem::path > writeRecoveryFiles(const std::filesystem::path &file_base)
Write the mesh files needed for recovery/checkpointing.
Definition MooseMesh.C:2986
bool _allow_recovery
Whether or not this Mesh is allowed to read a recovery file.
Definition MooseMesh.h:1977
MeshBase::node_iterator localNodesEnd()
Definition MooseMesh.C:3142
unsigned int _max_p_level
Maximum p-refinement level of all elements.
Definition MooseMesh.h:2053
std::map< const Elem *, std::vector< const Elem * > > _coarsened_element_children
Map of Parent elements to child elements for elements that were just coarsened.
Definition MooseMesh.h:1653
std::unordered_set< dof_id_type > getBoundaryActiveSemiLocalElemIds(BoundaryID bid) const
Return all ids of elements which have a side which is part of a sideset.
Definition MooseMesh.C:1328
std::unique_ptr< ConstElemPointerRange > _coarsened_elements
The elements that were just coarsened.
Definition MooseMesh.h:1646
unsigned int getAxisymmetricRadialCoord() const
Returns the desired radial direction for RZ coordinate transformation.
Definition MooseMesh.C:4423
face_info_iterator ownedFaceInfoEnd()
Definition MooseMesh.C:1512
unsigned int sideWithBoundaryID(const Elem *const elem, const BoundaryID boundary_id) const
Calls BoundaryInfo::side_with_boundary_id().
Definition MooseMesh.C:3130
void meshChanged()
Declares that the MooseMesh has changed, invalidates cached data and rebuilds caches.
Definition MooseMesh.C:892
virtual const Node & nodeRef(const dof_id_type i) const
Definition MooseMesh.C:844
const std::vector< QpMap > & getPRefinementMap(const Elem &elem) const
Get the map describing for each volumetric quadrature point (qp) on the refined level which qp on the...
Definition MooseMesh.C:4507
bool _displace_node_list_by_side_list
Whether or not to displace unrelated nodesets by nodesets constructed from sidesets.
Definition MooseMesh.h:1984
void changeBoundaryId(const boundary_id_type old_id, const boundary_id_type new_id, bool delete_prev)
Change all the boundary IDs for a given side from old_id to new_id.
Definition MooseMesh.C:2821
const std::vector< const Elem * > & coarsenedElementChildren(const Elem *elem) const
Get the newly removed children element ids for an element that was just coarsened.
Definition MooseMesh.C:952
void mapPoints(const std::vector< Point > &from, const std::vector< Point > &to, std::vector< QpMap > &qp_map)
Find the closest points that map "from" to "to" and fill up "qp_map".
Definition MooseMesh.C:2649
libMesh::BoundingBox getInflatedProcessorBoundingBox(Real inflation_multiplier=0.01) const
Get a (slightly inflated) processor bounding box.
Definition MooseMesh.C:3528
RealVectorValue minPeriodicVector(const unsigned int sys_num, const unsigned int var_num, Point p, Point q) const
Returns the minimum vector between two points on the mesh taking into account periodicity for the giv...
Definition MooseMesh.C:2280
std::set< Node * > _semilocal_node_list
Used for generating the semilocal node range.
Definition MooseMesh.h:1656
Real minPeriodicDistance(const unsigned int sys_num, const unsigned int var_num, const Point &p, const Point &q) const
Returns the distance between two points on the mesh taking into account periodicity for the given var...
Definition MooseMesh.C:2325
std::unordered_map< dof_id_type, ElemInfo > _elem_to_elem_info
Map connecting elems with their corresponding ElemInfo, we use the element ID as the key.
Definition MooseMesh.h:1766
unsigned int uniformRefineLevel() const
Returns the level of uniform refinement requested (zero if AMR is disabled).
Definition MooseMesh.C:3325
virtual dof_id_type maxElemId() const
Definition MooseMesh.C:3202
const std::vector< std::pair< unsigned int, QpMap > > & getCoarseningMap(const Elem &elem, int input_side)
Get the coarsening map for a given element type.
Definition MooseMesh.C:2638
bool possiblyRebuildNodeToElemMap()
rebuild the node to element map if it's been requsted previously
Definition MooseMesh.C:606
std::vector< const FaceInfo * > _face_info
Holds only those FaceInfo objects that have processor_id equal to this process's id,...
Definition MooseMesh.h:1778
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition MooseMesh.C:2994
static const std::array< bool, 3 > periodic_dim_default
Default value for the automatically detected paired boundaries for each unit dimension,...
Definition MooseMesh.h:78
virtual Elem * elem(const dof_id_type i)
Various accessors (pointers/references) for Elem "i".
Definition MooseMesh.C:3208
std::unique_ptr< ConstElemPointerRange > _refined_elements
The elements that were just refined.
Definition MooseMesh.h:1643
bool _custom_partitioner_requested
Definition MooseMesh.h:1609
bool _need_ghost_ghosted_boundaries
A parallel mesh generator such as DistributedRectilinearMeshGenerator already make everything ready.
Definition MooseMesh.h:1999
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > buildSideList()
Calls BoundaryInfo::build_side_list(), returns a std::vector of (elem-id, side-id,...
Definition MooseMesh.C:3118
Node * getQuadratureNode(const Elem *elem, const unsigned short int side, const unsigned int qp)
Get a specified quadrature node.
Definition MooseMesh.C:1652
void updateCoordTransform()
Update the coordinate transformation object based on our coordinate system data.
Definition MooseMesh.C:4414
elem_info_iterator ownedElemInfoEnd()
Definition MooseMesh.C:1529
virtual MooseMesh & clone() const
Clone method.
Definition MooseMesh.C:2884
std::unordered_map< SubdomainID, std::pair< Point, RealVectorValue > > _subdomain_id_to_rz_coord_axis
Map of subdomain ID to general axisymmetric axis.
Definition MooseMesh.h:2038
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3222
virtual void onMeshChanged()
Declares a callback function that is executed at the conclusion of meshChanged().
Definition MooseMesh.C:917
bool _coord_system_set
Whether the coordinate system has been set.
Definition MooseMesh.h:2045
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3557
MooseEnum _partitioner_name
The partitioner used on this mesh.
Definition MooseMesh.h:1604
bool _parallel_type_overridden
Definition MooseMesh.h:1593
void buildRefinementAndCoarseningMaps(Assembly *assembly)
Create the refinement and coarsening maps necessary for projection of stateful material properties wh...
Definition MooseMesh.C:2521
void detectPairedSidesets()
This routine detects paired sidesets of a regular orthogonal mesh (.i.e.
Definition MooseMesh.C:2002
MooseMesh()=delete
virtual void buildMesh()=0
Must be overridden by child classes.
std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > _elem_type_to_p_coarsening_map
Definition MooseMesh.h:1947
std::set< BoundaryID > _mesh_boundary_ids
A set of boundary IDs currently present in the mesh.
Definition MooseMesh.h:1688
const std::vector< Real > & getGhostedBoundaryInflation() const
Return a writable reference to the _ghosted_boundaries_inflation vector.
Definition MooseMesh.C:3356
virtual void init()
Initialize the Mesh object.
Definition MooseMesh.C:2937
virtual const Node & node(const dof_id_type i) const
Various accessors (pointers/references) for Node "i".
Definition MooseMesh.C:830
std::vector< SubdomainName > getSubdomainNames(const std::vector< SubdomainID > &subdomain_ids) const
Get the associated subdomainNames for the subdomain ids that are passed in.
Definition MooseMesh.C:1765
Real dimensionWidth(unsigned int component) const
Returns the width of the requested dimension.
Definition MooseMesh.C:2179
std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > _elem_type_to_p_coarsening_side_map
Definition MooseMesh.h:1949
void prepare()
Calls prepare_for_use() if the underlying MeshBase object isn't prepared, then communicates various b...
Definition MooseMesh.C:397
void computeMaxPerElemAndSide()
Compute the maximum numbers per element and side.
Definition MooseMesh.C:1068
virtual dof_id_type nActiveLocalElem() const
Definition MooseMesh.h:338
void update()
Calls buildNodeListFromSideList(), buildNodeList(), and buildBndElemList().
Definition MooseMesh.C:623
std::map< boundary_id_type, std::vector< dof_id_type > > _node_set_nodes
list of nodes that belongs to a specified nodeset: indexing [nodeset_id] -> [array of node ids]
Definition MooseMesh.h:1720
void freeBndNodes()
Definition MooseMesh.C:364
std::set< dof_id_type > getElemIDsOnBlocks(unsigned int elem_id_index, const std::set< SubdomainID > &blks) const
Return all the unique element IDs for an extra element integer with its index on a set of subdomains.
Definition MooseMesh.C:1171
std::vector< FaceInfo > _all_face_info
FaceInfo object storing information for face based loops.
Definition MooseMesh.h:1774
const std::string & getBoundaryName(const BoundaryID boundary_id) const
Return the name of the boundary given the id.
Definition MooseMesh.C:1788
std::unique_ptr< libMesh::MeshBase > _mesh
Pointer to underlying libMesh mesh object.
Definition MooseMesh.h:1596
void determineUseDistributedMesh()
Determine whether to use a distributed mesh.
Definition MooseMesh.C:2890
std::vector< Node * > _node_map
Vector of all the Nodes in the mesh for determining when to add a new point.
Definition MooseMesh.h:1738
std::unique_ptr< libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > > _bnd_elem_range
Definition MooseMesh.h:1668
bool hasDetectedPairedSidesets() const
Whether or not detectedPairedSidesets() has been called.
Definition MooseMesh.h:1000
std::map< SubdomainID, Moose::CoordinateSystemType > & _coord_sys
Type of coordinate system per subdomain.
Definition MooseMesh.h:2032
std::map< std::pair< int, libMesh::ElemType >, std::vector< std::vector< QpMap > > > _elem_type_to_refinement_map
Holds mappings for volume to volume and parent side to child side Map key:
Definition MooseMesh.h:1918
std::unique_ptr< libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > > _bnd_node_range
Definition MooseMesh.h:1666
const MeshBase * getMeshPtr() const
Definition MooseMesh.C:3551
ParallelType _parallel_type
Can be set to DISTRIBUTED, REPLICATED, or DEFAULT.
Definition MooseMesh.h:1586
Moose::CoordinateSystemType getUniqueCoordSystem() const
Get the coordinate system from the mesh, it must be the same in all subdomains otherwise this will er...
Definition MooseMesh.C:4314
std::pair< const Node *, BoundaryID > PeriodicNodeInfo
Helper type for building periodic node maps.
Definition MooseMesh.h:1214
void buildNodeListFromSideList()
Calls BoundaryInfo::build_node_list_from_side_list().
Definition MooseMesh.C:3057
void setMeshBoundaryIDs(std::set< BoundaryID > boundary_IDs)
Sets the set of BoundaryIDs Is called by AddAllSideSetsByNormals.
Definition MooseMesh.C:3304
const std::map< SubdomainID, Moose::CoordinateSystemType > & getCoordSystem() const
Get the map from subdomain ID to coordinate system type, e.g.
Definition MooseMesh.C:4336
unsigned int _max_h_level
Maximum h-refinement level of all elements.
Definition MooseMesh.h:2055
virtual unsigned int effectiveSpatialDimension() const
Returns the effective spatial dimension determined by the coordinates actually used by the mesh.
Definition MooseMesh.C:3000
bool prepared() const
Setter/getter for whether the mesh is prepared.
Definition MooseMesh.C:3246
std::vector< std::unordered_map< SubdomainID, std::set< dof_id_type > > > _block_id_mapping
Unique element integer IDs for each subdomain and each extra element integers.
Definition MooseMesh.h:2002
std::map< std::pair< int, libMesh::ElemType >, std::vector< std::pair< unsigned int, QpMap > > > _elem_type_to_coarsening_map
Holds mappings for volume to volume and parent side to child side Map key:
Definition MooseMesh.h:1944
std::unordered_map< std::pair< const Elem *, unsigned short int >, const Elem * > _higher_d_elem_side_to_lower_d_elem
Holds a map from a high-order element side to its corresponding lower-d element.
Definition MooseMesh.h:1973
std::unordered_map< dof_id_type, std::set< dof_id_type > > getElemIDMapping(const std::string &from_id_name, const std::string &to_id_name) const
Definition MooseMesh.C:1132
bool _use_distributed_mesh
False by default.
Definition MooseMesh.h:1591
void addGhostedBoundary(BoundaryID boundary_id)
This will add the boundary ids to be ghosted to this processor.
Definition MooseMesh.C:3338
unsigned int getHigherDSide(const Elem *elem) const
Returns the local side ID of the interior parent aligned with the lower dimensional element.
Definition MooseMesh.C:1704
std::set< SubdomainID > _mesh_subdomains
A set of subdomain IDs currently present in the mesh.
Definition MooseMesh.h:1680
static MooseEnum partitioning()
returns MooseMesh partitioning options so other classes can use it
Definition MooseMesh.C:4027
virtual dof_id_type maxNodeId() const
Calls max_node/elem_id() on the underlying libMesh mesh object.
Definition MooseMesh.C:3196
void setCoordData(const MooseMesh &other_mesh)
Set the coordinate system data to that of other_mesh.
Definition MooseMesh.C:4451
void checkDuplicateSubdomainNames()
Loop through all subdomain IDs and check if there is name duplication used for the subdomains with sa...
Definition MooseMesh.C:4466
std::map< dof_id_type, std::map< unsigned int, std::map< dof_id_type, Node * > > > _elem_to_side_to_qp_to_quadrature_nodes
Definition MooseMesh.h:1713
bool _regular_orthogonal_mesh
Boolean indicating whether this mesh was detected to be regular and orthogonal.
Definition MooseMesh.h:1741
SemiLocalNodeRange * getActiveSemiLocalNodeRange() const
Definition MooseMesh.C:1265
ConstElemPointerRange * refinedElementRange() const
Return a range that is suitable for threaded execution over elements that were just refined.
Definition MooseMesh.C:940
SubdomainID getSubdomainID(const SubdomainName &subdomain_name) const
Get the associated subdomain ID for the subdomain name.
Definition MooseMesh.C:1723
void clearQuadratureNodes()
Clear out any existing quadrature nodes.
Definition MooseMesh.C:1670
void cacheFaceInfoVariableOwnership() const
Cache if variables live on the elements connected by the FaceInfo objects.
Definition MooseMesh.C:4070
virtual Real getMaxInDimension(unsigned int component) const
Definition MooseMesh.C:2194
void buildFiniteVolumeInfo() const
Builds the face and elem info vectors that store meta-data needed for looping over and doing calculat...
Definition MooseMesh.C:3852
static InputParameters validParams()
Typical "Moose-style" constructor and copy constructor.
Definition MooseMesh.C:81
const std::set< BoundaryID > & meshNodesetIds() const
Returns a read-only reference to the set of nodesets currently present in the Mesh.
Definition MooseMesh.C:3298
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected.
Definition MooseMesh.C:1239
face_info_iterator ownedFaceInfoBegin()
Iterators to owned faceInfo objects.
Definition MooseMesh.C:1503
libMesh::ConstNodeRange * getLocalNodeRange()
Definition MooseMesh.C:1274
void setIsCustomPartitionerRequested(bool cpr)
Definition MooseMesh.C:3840
void deleteRemoteElements()
Delete remote elements.
Definition MooseMesh.C:4058
bool allowRemoteElementRemoval() const
Whether we are allow remote element removal.
Definition MooseMesh.h:1234
elem_info_iterator ownedElemInfoBegin()
Iterators to owned faceInfo objects.
Definition MooseMesh.C:1521
std::vector< BndElement * > _bnd_elems
array of boundary elems
Definition MooseMesh.h:1704
void ghostGhostedBoundaries()
Actually do the ghosting of boundaries that need to be ghosted to this processor.
Definition MooseMesh.C:3423
const std::vector< QpMap > & getPCoarseningMap(const Elem &elem) const
Get the map describing for each volumetric quadrature point (qp) on the coarse level which qp on the ...
Definition MooseMesh.C:4519
bool _is_nemesis
True if a Nemesis Mesh was read in.
Definition MooseMesh.h:1637
void updateActiveSemiLocalNodeRange(std::set< dof_id_type > &ghosted_elems)
Clears the "semi-local" node list and rebuilds it.
Definition MooseMesh.C:960
virtual bool skipNoncriticalPartitioning() const
Definition MooseMesh.C:4531
void checkCoordinateSystems()
Performs a sanity check for every element in the mesh.
Definition MooseMesh.C:4436
void buildRefinementMap(const Elem &elem, libMesh::QBase &qrule, libMesh::QBase &qrule_face, int parent_side, int child, int child_side)
Build the refinement map for a given element type.
Definition MooseMesh.C:2531
const std::vector< const FaceInfo * > & faceInfo() const
Accessor for local FaceInfo objects.
Definition MooseMesh.h:2347
void buildElemIDInfo()
Build extra data for faster access to the information of extra element integers.
Definition MooseMesh.C:1091
virtual bnd_elem_iterator bndElemsBegin()
Return iterators to the beginning/end of the boundary elements list.
Definition MooseMesh.C:1554
unsigned int getBlocksMaxDimension(const std::vector< SubdomainName > &blocks) const
Returns the maximum element dimension on the given blocks.
Definition MooseMesh.C:3015
const std::vector< QpMap > & getPCoarseningSideMap(const Elem &elem) const
Get the map describing for each side quadrature point (qp) on the coarse level which qp on the previo...
Definition MooseMesh.C:4525
virtual Elem * queryElemPtr(const dof_id_type i)
Definition MooseMesh.C:3234
const std::set< unsigned int > & getGhostedBoundaries() const
Return a writable reference to the set of ghosted boundary IDs.
Definition MooseMesh.C:3350
void cacheFVElementalDoFs() const
Cache the DoF indices for FV variables on each element.
Definition MooseMesh.C:4148
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
Proxy function to get a (sub)PointLocator from either the underlying libMesh mesh (default),...
Definition MooseMesh.C:3846
bool _partitioner_overridden
Definition MooseMesh.h:1605
const std::set< BoundaryID > & getBoundaryIDs() const
Returns a const reference to a set of all user-specified boundary IDs.
Definition MooseMesh.C:3051
std::vector< std::vector< Real > > _bounds
The bounds in each dimension of the mesh for regular orthogonal meshes.
Definition MooseMesh.h:1744
void freeBndElems()
Definition MooseMesh.C:383
std::set< SubdomainID > _lower_d_boundary_blocks
Mesh blocks for boundary lower-d elements in different types.
Definition MooseMesh.h:1970
const ElemInfo & elemInfo(const dof_id_type id) const
Accessor for the elemInfo object for a given element ID.
Definition MooseMesh.C:4000
void setBoundaryToNormalMap(std::unique_ptr< std::map< BoundaryID, RealVectorValue > > boundary_map)
Sets the mapping between BoundaryID and normal vector Is called by AddAllSideSetsByNormals.
Definition MooseMesh.C:3310
bool isCustomPartitionerRequested() const
Setter and getter for _custom_partitioner_requested.
Definition MooseMesh.C:3818
const std::vector< QpMap > & getPRefinementSideMap(const Elem &elem) const
Get the map describing for each side quadrature point (qp) on the refined level which qp on the previ...
Definition MooseMesh.C:4513
void computeFiniteVolumeCoords() const
Compute the face coordinate value for all FaceInfo and ElemInfo objects.
Definition MooseMesh.C:4006
bool _moose_mesh_prepared
True if prepare has been called on the mesh.
Definition MooseMesh.h:1640
const std::unordered_map< boundary_id_type, std::unordered_set< dof_id_type > > & getBoundariesToActiveSemiLocalElemIds() const
Returns a map of boundaries to ids of elements on the boundary.
Definition MooseMesh.C:1322
bool _doing_p_refinement
Whether we have p-refinement (whether exclusively p- or hp-refinement)
Definition MooseMesh.h:2051
bool _skip_deletion_repartition_after_refine
Whether or not skip remote deletion and repartition after uniform refinements.
Definition MooseMesh.h:1631
void buildNodeList()
Calls BoundaryInfo::build_node_list()/build_side_list() and makes separate copies of Nodes/Elems in t...
Definition MooseMesh.C:1034
virtual dof_id_type nNodes() const
Calls n_nodes/elem() on the underlying libMesh mesh object.
Definition MooseMesh.C:3184
std::vector< Node * > _extreme_nodes
A vector containing the nodes at the corners of a regular orthogonal mesh.
Definition MooseMesh.h:1806
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
Get the associated BoundaryID for the boundary name.
Definition MooseMesh.C:1684
std::unique_ptr< libMesh::Partitioner > _custom_partitioner
The custom partitioner.
Definition MooseMesh.h:1608
std::optional< std::vector< std::pair< BoundaryID, BoundaryID > > > _paired_boundary
A vector holding the paired boundaries for a regular orthogonal mesh.
Definition MooseMesh.h:1747
const std::vector< dof_id_type > & getNodeList(boundary_id_type nodeset_id) const
Return a writable reference to a vector of node IDs that belong to nodeset_id.
Definition MooseMesh.C:3579
std::set< SubdomainID > getBoundaryConnectedSecondaryBlocks(const BoundaryID bid) const
Get the list of subdomains associated with the given boundary of its secondary side.
Definition MooseMesh.C:3641
std::unordered_map< std::pair< const Elem *, unsigned int >, FaceInfo * > _elem_side_to_face_info
Map from elem-side pair to FaceInfo.
Definition MooseMesh.h:1782
const std::vector< QpMap > & getPRefinementMapHelper(const Elem &elem, const std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > &) const
Definition MooseMesh.C:4486
unsigned int _max_nodes_per_elem
The maximum number of nodes per element.
Definition MooseMesh.h:2014
static MooseEnum elemTypes()
returns MooseMesh element type options
Definition MooseMesh.C:4035
std::set< BoundaryID > _mesh_nodeset_ids
Definition MooseMesh.h:1690
void setGeneralAxisymmetricCoordAxes(const std::vector< SubdomainName > &blocks, const std::vector< std::pair< Point, RealVectorValue > > &axes)
Sets the general coordinate axes for axisymmetric blocks.
Definition MooseMesh.C:4350
unsigned int getPatchSize() const
Getter for the patch_size parameter.
Definition MooseMesh.C:3510
void cacheInfo()
Definition MooseMesh.C:1404
void addPeriodicVariable(const unsigned int sys_num, const unsigned int var_num, const BoundaryID primary, const BoundaryID secondary)
For "regular orthogonal" meshes, determine if variable var_num is periodic with respect to the primar...
Definition MooseMesh.C:2203
void cacheChangedLists()
Cache information about what elements were refined and coarsened in the previous step.
Definition MooseMesh.C:922
bool isTranslatedPeriodic(const unsigned int sys_num, const unsigned int var_num, const unsigned int component) const
Returns whether this generated mesh is periodic in the given dimension for the given variable on the ...
Definition MooseMesh.C:2256
const std::pair< Point, RealVectorValue > & getGeneralAxisymmetricCoordAxis(SubdomainID subdomain_id) const
Gets the general axisymmetric coordinate axis for a block.
Definition MooseMesh.C:4398
std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > _elem_type_to_p_refinement_side_map
Definition MooseMesh.h:1923
bool _allow_remote_element_removal
Whether to allow removal of remote elements.
Definition MooseMesh.h:1990
bool _construct_node_list_from_side_list
Whether or not to allow generation of nodesets from sidesets.
Definition MooseMesh.h:1980
std::set< BoundaryID > getSubdomainInterfaceBoundaryIds(const SubdomainID subdomain_id) const
Get the list of boundaries that contact the given subdomain.
Definition MooseMesh.C:3617
const Node * addUniqueNode(const Point &p, Real tol=1e-6)
Add a new node to the mesh.
Definition MooseMesh.C:1569
const std::set< BoundaryID > & meshBoundaryIds() const
Returns a read-only reference to the set of boundary IDs currently present in the Mesh.
Definition MooseMesh.C:3286
std::vector< BndNode * > _bnd_nodes
array of boundary nodes
Definition MooseMesh.h:1697
std::unordered_map< dof_id_type, std::vector< dof_id_type > > _node_to_elem_map
A map of all of the current nodes to the elements that they are connected to.
Definition MooseMesh.h:1671
void buildPeriodicNodeSets(std::map< BoundaryID, std::set< dof_id_type > > &periodic_node_sets, unsigned int var_number, libMesh::PeriodicBoundaries *pbs) const
This routine builds a datastructure of node ids organized by periodic boundary ids.
Definition MooseMesh.C:1901
std::unique_ptr< MooseAppCoordTransform > _coord_transform
A coordinate transformation object that describes how to transform this problem's coordinate system i...
Definition MooseMesh.h:2042
const std::set< SubdomainID > & getNodeBlockIds(const Node &node) const
Return list of blocks to which the given node belongs.
Definition MooseMesh.C:1492
std::map< libMesh::ElemType, std::map< std::pair< int, int >, std::vector< std::vector< QpMap > > > > _elem_type_to_child_side_refinement_map
Holds mappings for "internal" child sides to parent volume. The second key is (child,...
Definition MooseMesh.h:1927
void buildPeriodicNodeMap(std::multimap< dof_id_type, dof_id_type > &periodic_node_map, unsigned int var_number, libMesh::PeriodicBoundaries *pbs) const
This routine builds a multimap of boundary ids to matching boundary ids across all periodic boundarie...
Definition MooseMesh.C:1816
const RealVectorValue & getNormalByBoundaryID(BoundaryID id) const
Returns the normal vector associated with a given BoundaryID.
Definition MooseMesh.C:2874
std::unordered_map< SubdomainID, SubdomainData > _sub_to_data
Holds a map from subdomain ids to associated data.
Definition MooseMesh.h:1962
const MooseUnits & lengthUnit() const
Definition MooseMesh.C:4459
std::unique_ptr< std::map< BoundaryID, RealVectorValue > > _boundary_to_normal_map
The boundary to normal map - valid only when AddAllSideSetsByNormals is active.
Definition MooseMesh.h:1694
std::unique_ptr< libMesh::NodeRange > _active_node_range
Definition MooseMesh.h:1663
std::set< SubdomainID > _lower_d_interior_blocks
Mesh blocks for interior lower-d elements in different types.
Definition MooseMesh.h:1968
void setPatchUpdateStrategy(Moose::PatchUpdateType patch_update_strategy)
Set the patch size update strategy.
Definition MooseMesh.C:3516
std::vector< SubdomainID > getSubdomainIDs(const std::vector< SubdomainName > &subdomain_names) const
Get the associated subdomainIDs for the subdomain names that are passed in.
Definition MooseMesh.C:1729
void setPartitionerHelper(MeshBase *mesh=nullptr)
Definition MooseMesh.C:3737
const std::pair< BoundaryID, BoundaryID > * getPairedBoundaryMapping(unsigned int component) const
This function attempts to return the paired boundary ids for the given component.
Definition MooseMesh.C:2351
const std::set< BoundaryID > & meshSidesetIds() const
Returns a read-only reference to the set of sidesets currently present in the Mesh.
Definition MooseMesh.C:3292
std::map< boundary_id_type, std::set< dof_id_type > > _bnd_node_ids
Map of sets of node IDs in each boundary.
Definition MooseMesh.h:1701
unsigned int _rz_coord_axis
Storage for RZ axis selection.
Definition MooseMesh.h:2035
ConstElemPointerRange * coarsenedElementRange() const
Return a range that is suitable for threaded execution over elements that were just coarsened.
Definition MooseMesh.C:946
std::unordered_map< SubdomainID, std::set< BoundaryID > > _neighbor_subdomain_boundary_ids
Holds a map from neighbor subomdain ids to the boundary ids that are attached to it.
Definition MooseMesh.h:1965
std::unordered_map< boundary_id_type, std::unordered_set< dof_id_type > > _bnd_elem_ids
Map of set of elem IDs connected to each boundary.
Definition MooseMesh.h:1709
unsigned int _uniform_refine_level
The level of uniform refinement requested (set to zero if AMR is disabled)
Definition MooseMesh.h:1625
const std::string & getSubdomainName(SubdomainID subdomain_id) const
Return the name of a block given an id.
Definition MooseMesh.C:1759
void buildCoarseningMap(const Elem &elem, libMesh::QBase &qrule, libMesh::QBase &qrule_face, int input_side)
Build the coarsening map for a given element type.
Definition MooseMesh.C:2610
bool hasSecondOrderElements()
check if the mesh has SECOND order elements
Definition MooseMesh.C:3824
std::unordered_map< const Elem *, unsigned short int > _lower_d_elem_to_higher_d_elem_side
Definition MooseMesh.h:1974
bool _finite_volume_info_dirty
Definition MooseMesh.h:1785
std::unordered_set< dof_id_type > getBoundaryActiveNeighborElemIds(BoundaryID bid) const
Return all ids of neighbors of elements which have a side which is part of a sideset.
Definition MooseMesh.C:1339
virtual const Node * nodePtr(const dof_id_type i) const
Definition MooseMesh.C:858
std::map< dof_id_type, Node * > _quadrature_nodes
Definition MooseMesh.h:1711
const std::unordered_map< boundary_id_type, std::unordered_set< dof_id_type > > & getBoundariesToElems() const
Returns a map of boundaries to ids of elements on the boundary.
Definition MooseMesh.C:1314
const std::vector< QpMap > & getPCoarseningMapHelper(const Elem &elem, const std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > &) const
Definition MooseMesh.C:4497
libMesh::NodeRange * getActiveNodeRange()
Definition MooseMesh.C:1251
std::vector< SubdomainName > _provided_coord_blocks
Set for holding user-provided coordinate system type block names.
Definition MooseMesh.h:2048
unsigned int _patch_size
The number of nodes to consider in the NearestNode neighborhood.
Definition MooseMesh.h:1726
void setCustomPartitioner(libMesh::Partitioner *partitioner)
Setter for custom partitioner.
Definition MooseMesh.C:3808
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition MooseMesh.C:1288
void setMeshBase(std::unique_ptr< MeshBase > mesh_base)
Method to set the mesh_base object.
Definition MooseMesh.C:2930
std::unique_ptr< libMesh::ConstNodeRange > _local_node_range
Definition MooseMesh.h:1664
void setSubdomainName(SubdomainID subdomain_id, const SubdomainName &name, const bool synchronous=false)
This method sets the name for subdomain_id to name.
Definition MooseMesh.C:1741
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
Definition MooseMesh.C:3280
virtual bnd_elem_iterator bndElemsEnd()
Definition MooseMesh.C:1562
MeshBase::node_iterator localNodesBegin()
Calls local_nodes_begin/end() on the underlying libMesh mesh object.
Definition MooseMesh.C:3136
const std::vector< std::vector< QpMap > > & getRefinementMap(const Elem &elem, int parent_side, int child, int child_side)
Get the refinement map for a given element type.
Definition MooseMesh.C:2574
void setCoordSystem(const std::vector< SubdomainName > &blocks, const MultiMooseEnum &coord_sys)
Set the coordinate system for the provided blocks to coord_sys.
Definition MooseMesh.C:4210
Node * addQuadratureNode(const Elem *elem, const unsigned short int side, const unsigned int qp, BoundaryID bid, const Point &point)
Adds a fictitious "QuadratureNode".
Definition MooseMesh.C:1603
void buildLowerDMesh()
Build lower-d mesh for all sides.
Definition MooseMesh.C:666
bool doingPRefinement() const
Query whether the kind of adaptivity we're doing includes p-refinement.
Definition MooseMesh.h:1507
virtual const Node * queryNodePtr(const dof_id_type i) const
Definition MooseMesh.C:870
std::map< std::pair< unsigned int, unsigned int >, std::array< bool, 3 > > _periodic_dim
A map from (system number, vector number) to which dimensions are periodic in a regular orthogonal me...
Definition MooseMesh.h:1798
std::vector< dof_id_type > _max_ids
Maximum integer ID for each extra element integer.
Definition MooseMesh.h:2004
std::unique_ptr< Moose::Kokkos::Mesh > _kokkos_mesh
Pointer to Kokkos mesh object.
Definition MooseMesh.h:1600
void findAdaptivityQpMaps(const Elem *template_elem, libMesh::QBase &qrule, libMesh::QBase &qrule_face, std::vector< std::vector< QpMap > > &refinement_map, std::vector< std::pair< unsigned int, QpMap > > &coarsen_map, int parent_side, int child, int child_side)
Given an elem type, get maps that tell us what qp's are closest to each other between a parent and it...
Definition MooseMesh.C:2680
unsigned int _max_nodes_per_side
The maximum number of nodes per side.
Definition MooseMesh.h:2017
bool _node_to_elem_map_built
Whether _node_to_elem_map has been built.
Definition MooseMesh.h:1674
const MeshBase::element_iterator activeLocalElementsEnd()
Definition MooseMesh.C:3166
std::set< BoundaryID > _mesh_sideset_ids
Definition MooseMesh.h:1689
std::vector< Real > _ghosted_boundaries_inflation
Definition MooseMesh.h:1723
void setGhostedBoundaryInflation(const std::vector< Real > &inflation)
This sets the inflation amount for the bounding box for each partition for use in ghosting boundaries...
Definition MooseMesh.C:3344
std::string getBoundaryString(const BoundaryID boundary_id) const
Return the name of the boundary given the id, if it exists.
Definition MooseMesh.C:1800
std::set< SubdomainID > getBoundaryConnectedBlocks(const BoundaryID bid) const
Get the list of subdomains associated with the given boundary.
Definition MooseMesh.C:3630
const std::array< bool, 3 > & queryPeriodicDimensions(const unsigned int sys_num, const unsigned int var_num) const
Query the translated periodic dimension flags for the given variable on the given system.
Definition MooseMesh.C:2241
const bool _is_split
Whether or not we are using a (pre-)split mesh (automatically DistributedMesh)
Definition MooseMesh.h:1750
std::unique_ptr< SemiLocalNodeRange > _active_semilocal_node_range
Ranges for use with threading, cached so they don't have to get rebuilt all the time (which takes tim...
Definition MooseMesh.h:1662
void setUniformRefineLevel(unsigned int, bool deletion=true)
Set uniform refinement level.
Definition MooseMesh.C:3331
Moose::PatchUpdateType _patch_update_strategy
The patch update strategy.
Definition MooseMesh.h:1735
virtual Real getMinInDimension(unsigned int component) const
Returns the min or max of the requested dimension respectively.
Definition MooseMesh.C:2185
bool isBoundaryFullyExternalToSubdomains(BoundaryID bid, const std::set< SubdomainID > &blk_group) const
Returns whether a boundary (given by its id) is not crossing through a group of blocks,...
Definition MooseMesh.C:1370
void errorIfDistributedMesh(std::string name) const
Generate a unified error message if the underlying libMesh mesh is a DistributedMesh.
Definition MooseMesh.C:3726
void setAxisymmetricCoordAxis(const MooseEnum &rz_coord_axis)
For axisymmetric simulations, set the symmetry coordinate axis.
Definition MooseMesh.C:4342
void needsPrepareForUse()
If this method is called, we will call libMesh's prepare_for_use method when we call Moose's prepare ...
Definition MooseMesh.C:3274
const libMesh::ConstElemRange * getActiveLocalElementRange()
Return pointers to range objects for various types of ranges (local nodes, boundary elems,...
Definition MooseMesh.C:1245
std::map< std::pair< libMesh::ElemType, unsigned int >, std::vector< QpMap > > _elem_type_to_p_refinement_map
Definition MooseMesh.h:1921
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
Method to construct a libMesh::MeshBase object that is normally set and used by the MooseMesh object ...
Definition MooseMesh.C:2918
bool _built_from_other_mesh
Whether or not this mesh was built from another mesh.
Definition MooseMesh.h:1582
virtual dof_id_type nElem() const
Definition MooseMesh.C:3190
const std::set< SubdomainID > & getBlockConnectedBlocks(const SubdomainID subdomain_id) const
Get the list of subdomains neighboring a given subdomain.
Definition MooseMesh.C:3663
std::set< Elem * > _ghost_elems_from_ghost_boundaries
Set of elements ghosted by ghostGhostedBoundaries.
Definition MooseMesh.h:1993
std::vector< const ElemInfo * > _elem_info
Holds only those ElemInfo objects that have processor_id equal to this process's id,...
Definition MooseMesh.h:1770
bool usingGeneralAxisymmetricCoordAxes() const
Returns true if general axisymmetric coordinate axes are being used.
Definition MooseMesh.C:4408
std::set< dof_id_type > getAllElemIDs(unsigned int elem_id_index) const
Return all the unique element IDs for an extra element integer with its index.
Definition MooseMesh.C:1161
std::vector< BndNode > _extra_bnd_nodes
Definition MooseMesh.h:1714
void buildHRefinementAndCoarseningMaps(Assembly *assembly)
Definition MooseMesh.C:2370
std::set< unsigned int > _ghosted_boundaries
Definition MooseMesh.h:1722
std::vector< dof_id_type > _min_ids
Minimum integer ID for each extra element integer.
Definition MooseMesh.h:2006
libMesh::StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > * getBoundaryElementRange()
Definition MooseMesh.C:1301
bool isBoundaryNode(dof_id_type node_id) const
Returns true if the requested node is in the list of boundary nodes, false otherwise.
Definition MooseMesh.C:3674
RealVectorValue _half_range
A convenience vector used to hold values in each dimension representing half of the range.
Definition MooseMesh.h:1803
MeshBase::element_iterator activeLocalElementsBegin()
Calls active_local_nodes_begin/end() on the underlying libMesh mesh object.
Definition MooseMesh.C:3160
std::map< dof_id_type, std::set< SubdomainID > > _block_node_list
list of nodes that belongs to a specified block (domain)
Definition MooseMesh.h:1717
unsigned int _max_sides_per_elem
The maximum number of sides per element.
Definition MooseMesh.h:2011
bool isSemiLocal(Node *const node) const
Returns true if the node is semi-local.
Definition MooseMesh.C:1001
void buildPRefinementAndCoarseningMaps(Assembly *assembly)
Definition MooseMesh.C:2427
static void setPartitioner(MeshBase &mesh_base, MooseEnum &partitioner, bool use_distributed_mesh, const InputParameters &params, MooseObject &context_obj)
Method for setting the partitioner on the passed in mesh_base object.
Definition MooseMesh.C:3749
std::vector< std::tuple< dof_id_type, unsigned short int, boundary_id_type > > buildActiveSideList() const
Calls BoundaryInfo::build_active_side_list.
Definition MooseMesh.C:3124
bool detectOrthogonalDimRanges(Real tol=1e-6)
This routine determines whether the Mesh is a regular orthogonal mesh (i.e.
Definition MooseMesh.C:1928
std::unordered_map< dof_id_type, std::vector< dof_id_type > > & internalNodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected.
Definition MooseMesh.C:1210
Every object that can be built by the factory should be derived from this class.
Definition MooseObject.h:31
static InputParameters validParams()
Definition MooseObject.C:25
MooseApp & _app
The MOOSE application this is associated with.
Definition MooseBase.h:375
Physical unit management class with runtime unit string parsing, unit checking, unit conversion,...
Definition Units.h:33
Base variable class.
SystemBase & sys()
Get the system this variable is part of.
unsigned int number() const
Get variable number coming from libMesh.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type.
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
Interface for objects interacting with the PerfGraph.
const Point & getPoint(const PointObject &item) const
get a Point reference from the PointData object at index idx in the list
Helper object for holding qp mapping info.
Definition MooseMesh.h:76
unsigned int _from
The qp to map from.
Definition MooseMesh.h:81
unsigned int _to
The qp to map to.
Definition MooseMesh.h:84
Real _distance
The distance between them.
Definition MooseMesh.h:87
A class for creating restricted objects.
Definition Restartable.h:29
void mooseWarning(Args &&... args) const
void paramWarning(const std::string &param, Args... args) const
void mooseDeprecated(Args &&... args) const
Base class for a system (of equations)
Definition SystemBase.h:87
unsigned int number() const
Gets the number of this system.
void max(const T &r, T &o, Request &req) const
void min(const T &r, T &o, Request &req) const
void set_union(T &data, const unsigned int root_id) const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
virtual void write(const std::string &name) override
static constexpr dof_id_type invalid_id
dof_id_type id() const
unsigned int n_systems() const
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
void uniformly_refine(unsigned int n=1)
void uniformly_p_refine(unsigned int n=1)
const Parallel::Communicator & _communicator
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
PeriodicBoundaryBase * boundary(boundary_id_type id)
bool is_my_variable(unsigned int var_num) const
virtual Point get_corresponding_pos(const Point &pt) const=0
boundary_id_type pairedboundary
MeshBase & mesh
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
SubdomainID getSubdomainID(const SubdomainName &subdomain_name, const MeshBase &mesh)
Gets the subdomain ID associated with the given SubdomainName.
bool elemHasFaceInfo(const Elem &elem, const Elem *const neighbor)
This function infers based on elements if the faceinfo between them belongs to the element or not.
Definition FVUtils.C:21
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
PatchUpdateType
Type of patch update strategy for modeling node-face constraints or contact.
@ Iteration
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition Moose.h:175
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
CoordinateSystemType
Definition MooseTypes.h:864
@ COORD_RZ
Definition MooseTypes.h:866
@ COORD_RSPHERICAL
Definition MooseTypes.h:867
@ COORD_XYZ
Definition MooseTypes.h:865
const BoundaryID INVALID_BOUNDARY_ID
Definition MooseTypes.C:22
libMesh::BoundingBox create_local_bounding_box(const MeshBase &mesh)
spin_mutex spin_mtx
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
std::string enum_to_string(const T e)
bool absolute_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
libmesh_assert(ctx)
const unsigned int invalid_uint
const RemoteElem * remote_elem
static constexpr Real TOLERANCE
uint8_t dof_id_type
std::pair< T, U > ResultItem
Definition KDTree.h:24
SearchParams SearchParameters
const boundary_id_type side_id
BoundaryID _bnd_id
boundary id for the node
Definition BndNode.h:26
libMesh::Node * _node
pointer to the node
Definition BndNode.h:24
The definition of the bnd_elem_iterator struct.
Definition MooseMesh.h:2215
The definition of the bnd_node_iterator struct.
Definition MooseMesh.h:2172
The definition of the elem_info_iterator struct.
Definition MooseMesh.h:2129
The definition of the face_info_iterator struct.
Definition MooseMesh.h:2085
Real distance(const Point &p)
const dof_id_type n_nodes