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