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