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