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