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