https://mooseframework.inl.gov
ElementSubdomainModifierBase.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 
11 #include "DisplacedProblem.h"
12 #include "MaterialWarehouse.h"
13 
14 #include "libmesh/parallel_algebra.h"
15 #include "libmesh/parallel.h"
16 #include "libmesh/dof_map.h"
17 #include "libmesh/remote_elem.h"
18 #include "libmesh/parallel_ghost_sync.h"
19 #include "libmesh/petsc_vector.h"
20 
23 {
25 
26  // ESMs only operate on the undisplaced mesh to gather subdomain and sideset information. This
27  // information is used to modify both the undisplaced and the displaced meshes. It is the
28  // developer's responsibility to make sure the element IDs and sideset info are consistent across
29  // both meshes.
30  params.set<bool>("use_displaced_mesh") = false;
31  params.suppressParameter<bool>("use_displaced_mesh");
32 
33  params.addDeprecatedParam<BoundaryName>(
34  "moving_boundary_name",
35  "Name of the moving boundary",
36  "This has been replaced by 'moving_boundaries' and 'moving_boundary_subdomain_pairs'.");
37  params.addDeprecatedParam<BoundaryName>(
38  "complement_moving_boundary_name",
39  "Name of the moving boundary on the complement subdomain(s)",
40  "This has been replaced by 'moving_boundaries' and 'moving_boundary_subdomain_pairs'.");
41  params.addDeprecatedParam<bool>(
42  "apply_initial_conditions",
43  true,
44  "Whether to apply initial conditions on the moved nodes and elements",
45  "This has been replaced by 'reinitialize_subdomains'");
46 
47  params.addParam<std::vector<BoundaryName>>(
48  "moving_boundaries",
49  {},
50  "Moving boundaries between subdomains. These boundaries (both sidesets and nodesets) will be "
51  "updated for elements that change subdomain. The subdomains that each moving "
52  "boundary lies between shall be specified using the parameter "
53  "'moving_boundary_subdomain_pairs'. If one boundary and multiple subdomain pairs are "
54  "specified, then it is assumed that the pairs all apply to the boundary. A boundary will be "
55  "created on the mesh if it does not already exist.");
56  params.addParam<std::vector<std::vector<SubdomainName>>>(
57  "moving_boundary_subdomain_pairs",
58  {},
59  "The subdomain pairs associated with each moving boundary. For each pair of subdomains, only "
60  "the element side from the first subdomain will be added to the moving boundary, i.e., the "
61  "side normal is pointing from the first subdomain to the second subdomain. The pairs shall "
62  "be delimited by ';'. If a pair only has one subdomain, the moving boundary is associated "
63  "with the subdomain's external boundary, i.e., when the elements have no neighboring "
64  "elements.");
65 
66  params.addParam<std::vector<SubdomainName>>(
67  "reinitialize_subdomains",
68  {"ANY_BLOCK_ID"},
69  "By default, any element which changes subdomain is reinitialized. If a list of subdomains "
70  "(IDs or names) is provided, then only elements whose new subdomain is in the list will be "
71  "reinitialized. If an empty list is set, then no elements will be reinitialized.");
72  params.addParam<bool>(
73  "old_subdomain_reinitialized",
74  true,
75  "This parameter must be set with a non-empty list in 'reinitialize_subdomains'. When set to "
76  "the default true, the element's old subdomain is not considered when determining if an "
77  "element should be reinitialized. If set to false, only elements whose old subdomain was not "
78  "in 'reinitialize_subdomains' are reinitialized. ");
79 
80  params.registerBase("MeshModifier");
81 
82  return params;
83 }
84 
86  : ElementUserObject(parameters),
87  _displaced_problem(_fe_problem.getDisplacedProblem().get()),
88  _displaced_mesh(_displaced_problem ? &_displaced_problem->mesh() : nullptr),
89  _old_subdomain_reinitialized(getParam<bool>("old_subdomain_reinitialized"))
90 {
91  if (isParamSetByUser("moving_boundary_name") ||
92  isParamSetByUser("complement_moving_boundary_name"))
93  mooseError(
94  "'moving_boundary_name' and 'complement_moving_boundary_name' have been replaced by "
95  "'moving_boundaries' and 'moving_boundary_subdomain_pairs'. See the documentation in "
96  "https://mooseframework.inl.gov/blackbear/source/userobjects/"
97  "ElementSubdomainModifier.html for more information. "
98  "Additionally, SidesetAroundSubdomainUpdater can now be used to update boundaries "
99  "that are defined around a subdomain, or between two subdomains.");
100 }
101 
102 void
104 {
105  // When 'apply_initial_conditions' is fully deprecated, change this to 'const' vector
106  std::vector<SubdomainName> subdomain_names_to_reinitialize =
107  getParam<std::vector<SubdomainName>>("reinitialize_subdomains");
108 
109  // When 'apply_initial_conditions' is fully deprecated, remove this block
110  if (isParamSetByUser("apply_initial_conditions") && getParam<bool>("apply_initial_conditions"))
111  subdomain_names_to_reinitialize = {"ANY_BLOCK_ID"};
112  else if (isParamSetByUser("apply_initial_conditions"))
113  subdomain_names_to_reinitialize = {};
114 
115  if (std::find(subdomain_names_to_reinitialize.begin(),
116  subdomain_names_to_reinitialize.end(),
117  "ANY_BLOCK_ID") != subdomain_names_to_reinitialize.end())
119  else
120  _subdomain_ids_to_reinitialize = _mesh.getSubdomainIDs(subdomain_names_to_reinitialize);
121 
122  std::set<SubdomainID> set_subdomain_ids_to_reinitialize(_subdomain_ids_to_reinitialize.begin(),
124 
125  if (_old_subdomain_reinitialized == false &&
126  (std::find(_subdomain_ids_to_reinitialize.begin(),
129  set_subdomain_ids_to_reinitialize == _mesh.meshSubdomains()))
130  paramError("old_subdomain_reinitialized",
131  "'old_subdomain_reinitialized' can only be set to false if "
132  "reinitialize_subdomains does "
133  "not cover the whole model, otherwise no elements will be reinitialized as it is "
134  "impossible for an element's old subdomain to not be in the list.");
136  paramError("old_subdomain_reinitialized",
137  "'old_subdomain_reinitialized' can only be set to false if "
138  "reinitialize_subdomains is set to a non-empty list of subdomains, otherwise no "
139  "elements will be reinitialized, as it is impossible for an element's new subdomain "
140  "to be in the list.");
141 
142  auto bnd_names = getParam<std::vector<BoundaryName>>("moving_boundaries");
143  auto bnd_ids = _mesh.getBoundaryIDs(bnd_names, true);
144  const auto bnd_subdomains =
145  getParam<std::vector<std::vector<SubdomainName>>>("moving_boundary_subdomain_pairs");
146 
147  if (bnd_names.size() == 1 && bnd_subdomains.size() > 1)
148  {
149  bnd_names.insert(bnd_names.end(), bnd_subdomains.size() - 1, bnd_names[0]);
150  bnd_ids.insert(bnd_ids.end(), bnd_subdomains.size() - 1, bnd_ids[0]);
151  }
152  else if (bnd_names.size() != bnd_subdomains.size())
153  paramError("moving_boundary_subdomain_pairs",
154  "Each moving boundary must correspond to a pair of subdomains. ",
155  bnd_names.size(),
156  " boundaries are specified by the parameter 'moving_boundaries', while ",
157  bnd_subdomains.size(),
158  " subdomain pairs are provided. Alternatively, if one boundary and multiple "
159  "subdomain pairs are provided, then the subdomain pairs all apply to one boundary.");
160 
161  for (auto i : index_range(bnd_names))
162  {
163  _moving_boundary_names[bnd_ids[i]] = bnd_names[i];
164 
165  if (bnd_subdomains[i].size() == 2)
166  _moving_boundaries[{_mesh.getSubdomainID(bnd_subdomains[i][0]),
167  _mesh.getSubdomainID(bnd_subdomains[i][1])}] = bnd_ids[i];
168  else if (bnd_subdomains[i].size() == 1)
170  bnd_ids[i];
171  else
172  paramError("moving_boundary_subdomain_pairs",
173  "Each subdomain pair must contain 1 or 2 subdomain names, but ",
174  bnd_subdomains[i].size(),
175  " are given.");
176  }
177 }
178 
179 void
181  const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
182 {
183 
184  // If nothing need to change, just return.
185  // This will skip all mesh changes, and so no adaptivity mesh files will be written.
186  auto n_moved_elem = moved_elems.size();
187  gatherSum(n_moved_elem);
188  if (n_moved_elem == 0)
189  return;
190 
191  // Create moving boundaries on the undisplaced and displaced meshes
192  //
193  // Note: We do this _everytime_ because previous execution might have removed the sidesets and
194  // nodesets. Most of the moving boundary algorithms below assume that the moving sidesets and
195  // nodesets already exist on the mesh.
197  if (_displaced_mesh)
199 
200  // This has to be done _before_ subdomain changes are applied
201  findReinitializedElemsAndNodes(moved_elems);
202 
203  // Apply cached subdomain changes
204  applySubdomainChanges(moved_elems, _mesh);
205  if (_displaced_mesh)
206  applySubdomainChanges(moved_elems, *_displaced_mesh);
207 
208  // Update moving boundaries
209  gatherMovingBoundaryChanges(moved_elems);
211  if (_displaced_mesh)
213 
214  // Reinit equation systems
216  /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
217 
218  // Initialize solution and stateful material properties
219  applyIC(/*displaced=*/false);
221  initElementStatefulProps(/*displaced=*/false);
222 
223  if (_displaced_mesh)
224  {
225  applyIC(/*displaced=*/true);
227  initElementStatefulProps(/*displaced=*/true);
228  }
229 }
230 
231 void
233 {
234  auto & bnd_info = mesh.getMesh().get_boundary_info();
235  for (const auto & [bnd_id, bnd_name] : _moving_boundary_names)
236  {
237  bnd_info.sideset_name(bnd_id) = bnd_name;
238  bnd_info.nodeset_name(bnd_id) = bnd_name;
239  }
240 }
241 
242 void
244  const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems,
245  MooseMesh & mesh)
246 {
247  for (const auto & [elem_id, subdomain] : moved_elems)
248  {
249  // Change the element's subdomain ID
250  auto elem = mesh.elemPtr(elem_id);
251  const auto & [from, to] = subdomain;
252  mooseAssert(elem->subdomain_id() == from, "Inconsistent element subdomain ID.");
253  elem->subdomain_id() = to;
254 
255  // Change the ancestors' (if any) subdomain ID
256  setAncestorsSubdomainIDs(elem, to);
257  }
258 
259  // Synchronize ghost element subdomain changes
260  libMesh::SyncSubdomainIds sync(mesh.getMesh());
261  Parallel::sync_dofobject_data_by_id(
262  mesh.getMesh().comm(), mesh.getMesh().elements_begin(), mesh.getMesh().elements_end(), sync);
263 }
264 
265 void
267 {
268  auto curr_elem = elem;
269 
270  for (unsigned int i = curr_elem->level(); i > 0; --i)
271  {
272  // Change the parent's subdomain
273  curr_elem = curr_elem->parent();
274  curr_elem->subdomain_id() = subdomain_id;
275  }
276 }
277 
278 void
280  const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
281 {
282  // Clear moving boundary changes from last execution
283  _add_element_sides.clear();
284  _add_neighbor_sides.clear();
285  _remove_element_sides.clear();
286  _remove_neighbor_sides.clear();
287 
288  const auto & sidesets = _mesh.getMesh().get_boundary_info().get_sideset_map();
289 
290  for (const auto & [elem_id, subdomain_assignment] : moved_elems)
291  {
292  auto elem = _mesh.elemPtr(elem_id);
293 
294  // The existing moving boundaries on the element side should be removed
295  for (auto itr = sidesets.lower_bound(elem); itr != sidesets.upper_bound(elem); itr++)
296  if (_moving_boundary_names.count(itr->second.second))
297  _remove_element_sides[elem->id()].emplace(itr->second.first, itr->second.second);
298 
299  for (auto side : elem->side_index_range())
300  {
301  auto neigh = elem->neighbor_ptr(side);
302 
303  // Don't mess with remote element neighbor
304  if (neigh && neigh == libMesh::remote_elem)
305  continue;
306  // If neighbor doesn't exist
307  else if (!neigh)
308  gatherMovingBoundaryChangesHelper(elem, side, nullptr, 0);
309  // If neighbor exists
310  else
311  {
312  auto neigh_side = neigh->which_neighbor_am_i(elem);
313 
314  if (neigh->active())
315  gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
316  else
317  {
318  // Find the active neighbors of the element
319  std::vector<const Elem *> active_neighs;
320  // Neighbor has active children, they are neighbors of the element along that side
321  mooseAssert(!neigh->subactive(),
322  "The case where the active neighbor is an ancestor of this neighbor is not "
323  "handled at this time.");
324  neigh->active_family_tree_by_neighbor(active_neighs, elem);
325 
326  for (auto active_neigh : active_neighs)
327  gatherMovingBoundaryChangesHelper(elem, side, active_neigh, neigh_side);
328  }
329  }
330  }
331  }
332 }
333 
334 void
336  unsigned short side,
337  const Elem * neigh,
338  unsigned short neigh_side)
339 {
340  const auto & sidesets = _mesh.getMesh().get_boundary_info().get_sideset_map();
341 
342  // Detect element side change
343  SubdomainPair subdomain_pair = {elem->subdomain_id(),
344  neigh ? neigh->subdomain_id() : Moose::INVALID_BLOCK_ID};
345  if (_moving_boundaries.count(subdomain_pair))
346  _add_element_sides[elem->id()].emplace(side, _moving_boundaries.at(subdomain_pair));
347 
348  if (neigh)
349  {
350  // The existing moving boundaries on the neighbor side should be removed
351  for (auto itr = sidesets.lower_bound(neigh); itr != sidesets.upper_bound(neigh); itr++)
352  if (itr->second.first == neigh_side && _moving_boundary_names.count(itr->second.second))
353  _remove_neighbor_sides[neigh->id()].emplace(itr->second.first, itr->second.second);
354 
355  // Detect neighbor side change (by reversing the subdomain pair)
356  subdomain_pair = {subdomain_pair.second, subdomain_pair.first};
357  if (_moving_boundaries.count(subdomain_pair))
358  _add_neighbor_sides[neigh->id()].emplace(neigh_side, _moving_boundaries.at(subdomain_pair));
359  }
360 }
361 
362 void
364 {
365  auto & bnd_info = mesh.getMesh().get_boundary_info();
366 
367  // Remove all boundary nodes from the previous moving boundaries
368  auto nodesets = bnd_info.get_nodeset_map();
369  for (const auto & [node_id, bnd] : nodesets)
370  if (_moving_boundary_names.count(bnd))
371  bnd_info.remove_node(node_id, bnd);
372 
373  // Keep track of ghost element changes
374  std::unordered_map<processor_id_type,
375  std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>>>
376  add_ghost_sides, remove_ghost_sides;
377 
378  // Remove element sides from moving boundaries
379  for (const auto & [elem_id, sides] : _remove_element_sides)
380  for (const auto & [side, bnd] : sides)
381  bnd_info.remove_side(mesh.elemPtr(elem_id), side, bnd);
382 
383  // Remove neighbor sides from moving boundaries
384  for (const auto & [elem_id, sides] : _remove_neighbor_sides)
385  {
386  auto elem = mesh.elemPtr(elem_id);
387  for (const auto & [side, bnd] : sides)
388  {
389  bnd_info.remove_side(elem, side, bnd);
390  // Keep track of changes to ghosted elements
391  if (elem->processor_id() != processor_id())
392  remove_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
393  }
394  }
395 
396  // Add element sides to moving boundaries
397  for (const auto & [elem_id, sides] : _add_element_sides)
398  for (const auto & [side, bnd] : sides)
399  bnd_info.add_side(mesh.elemPtr(elem_id), side, bnd);
400 
401  // Add neighbor sides to moving boundaries
402  for (const auto & [elem_id, sides] : _add_neighbor_sides)
403  {
404  auto elem = mesh.elemPtr(elem_id);
405  for (const auto & [side, bnd] : sides)
406  {
407  bnd_info.add_side(elem, side, bnd);
408  // Keep track of changes to ghosted elements
409  if (elem->processor_id() != processor_id())
410  add_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
411  }
412  }
413 
414  Parallel::push_parallel_vector_data(
415  bnd_info.comm(),
416  add_ghost_sides,
417  [&mesh,
418  &bnd_info](processor_id_type,
419  const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
420  {
421  for (const auto & [elem_id, side, bnd] : received)
422  bnd_info.add_side(mesh.elemPtr(elem_id), side, bnd);
423  });
424 
425  Parallel::push_parallel_vector_data(
426  bnd_info.comm(),
427  remove_ghost_sides,
428  [&mesh,
429  &bnd_info](processor_id_type,
430  const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
431  {
432  for (const auto & [elem_id, side, bnd] : received)
433  bnd_info.remove_side(mesh.elemPtr(elem_id), side, bnd);
434  });
435 
436  bnd_info.parallel_sync_side_ids();
437  bnd_info.parallel_sync_node_ids();
438  mesh.update();
439 }
440 
441 void
443 {
444  // Clear cached ranges
449 
451  if (_displaced_mesh)
453 }
454 
455 void
457 {
458  auto & bnd_info = mesh.getMesh().get_boundary_info();
459  auto sidesets = bnd_info.get_sideset_map();
460  for (const auto & i : sidesets)
461  {
462  auto elem = i.first;
463  auto side = i.second.first;
464  auto bnd = i.second.second;
465  if (_moving_boundary_names.count(bnd) && !elem->active())
466  {
467  bnd_info.remove_side(elem, side, bnd);
468 
469  std::vector<const Elem *> elem_family;
470  elem->active_family_tree_by_side(elem_family, side);
471  for (auto felem : elem_family)
472  bnd_info.add_side(felem, side, bnd);
473  }
474  }
475 
476  bnd_info.parallel_sync_side_ids();
477  bnd_info.parallel_sync_node_ids();
478 }
479 
480 void
482  const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
483 {
484  // Clear cached element reinitialization data
485  _reinitialized_elems.clear();
486  _reinitialized_nodes.clear();
487 
488  for (const auto & [elem_id, subdomain] : moved_elems)
489  {
490  mooseAssert(_mesh.elemPtr(elem_id)->active(), "Moved elements should be active");
491  // Default: any element that changes subdomain is reinitialized
492  if (std::find(_subdomain_ids_to_reinitialize.begin(),
495  _reinitialized_elems.insert(elem_id);
496  else // Reinitialize if new subdomain is in list of subdomains to be reinitialized
497  {
498  const auto & [from, to] = subdomain;
500  _reinitialized_elems.insert(elem_id);
501  // Only reinitialize if original subdomain is not in list of subdomains
504  _reinitialized_elems.insert(elem_id);
505  else // New subdomain is not in list of subdomains
506  continue;
507  }
508 
509  const auto elem = _mesh.elemPtr(elem_id);
510  for (unsigned int i = 0; i < elem->n_nodes(); ++i)
511  if (nodeIsNewlyReinitialized(elem->node_id(i)))
512  _reinitialized_nodes.insert(elem->node_id(i));
513  }
514 }
515 
516 bool
518 {
519  // Default: any element that changes subdomain is reinitialized
520  if (std::find(_subdomain_ids_to_reinitialize.begin(),
523  return true;
524 
525  // Is subdomain in list of subdomains to be reinitialized
526  return std::find(_subdomain_ids_to_reinitialize.begin(),
528  id) != _subdomain_ids_to_reinitialize.end();
529 }
530 
531 bool
533 {
534  // If any of the node neighbors are already reinitialized, then the node is NOT newly
535  // reinitialized.
536  for (auto neighbor_elem_id : _mesh.nodeToElemMap().at(node_id))
537  if (subdomainIsReinitialized(_mesh.elemPtr(neighbor_elem_id)->subdomain_id()))
538  return false;
539  return true;
540 }
541 
542 void
544 {
546  reinitializedBndNodeRange(displaced));
547 
548  mooseAssert(_fe_problem.numSolverSystems() < 2,
549  "This code was written for a single nonlinear system");
550  // Set old and older solutions on the reinitialized dofs to the reinitialized values
552  reinitializedElemRange(displaced),
553  reinitializedBndNodeRange(displaced));
555  reinitializedElemRange(displaced),
556  reinitializedBndNodeRange(displaced));
557 
558  // Note: Need method to handle solve failures at timesteps where subdomain changes. The old
559  // solutions are now set to the reinitialized values. Does this impact restoring solutions
560 }
561 
562 void
564 {
565  _fe_problem.initElementStatefulProps(reinitializedElemRange(displaced), /*threaded=*/true);
566 }
567 
570 {
571  if (!displaced && _reinitialized_elem_range)
572  return *_reinitialized_elem_range.get();
573 
574  if (displaced && _reinitialized_displaced_elem_range)
576 
577  // Create a vector of the newly reinitialized elements
578  std::vector<Elem *> elems;
579  for (auto elem_id : _reinitialized_elems)
580  elems.push_back(displaced ? _displaced_mesh->elemPtr(elem_id) : _mesh.elemPtr(elem_id));
581 
582  // Make some fake element iterators defining this vector of elements
583  Elem * const * elem_itr_begin = const_cast<Elem * const *>(elems.data());
584  Elem * const * elem_itr_end = elem_itr_begin + elems.size();
585 
586  const auto elems_begin = MeshBase::const_element_iterator(
587  elem_itr_begin, elem_itr_end, Predicates::NotNull<Elem * const *>());
588  const auto elems_end = MeshBase::const_element_iterator(
589  elem_itr_end, elem_itr_end, Predicates::NotNull<Elem * const *>());
590 
591  if (!displaced)
592  _reinitialized_elem_range = std::make_unique<ConstElemRange>(elems_begin, elems_end);
593  else
594  _reinitialized_displaced_elem_range = std::make_unique<ConstElemRange>(elems_begin, elems_end);
595 
596  return reinitializedElemRange(displaced);
597 }
598 
601 {
602  if (!displaced && _reinitialized_bnd_node_range)
603  return *_reinitialized_bnd_node_range.get();
604 
607 
608  // Create a vector of the newly reinitialized boundary nodes
609  std::vector<const BndNode *> nodes;
610  auto bnd_nodes =
612  for (auto bnd_node : *bnd_nodes)
613  if (bnd_node->_node)
614  if (_reinitialized_nodes.count(bnd_node->_node->id()))
615  nodes.push_back(bnd_node);
616 
617  // Make some fake node iterators defining this vector of nodes
618  BndNode * const * bnd_node_itr_begin = const_cast<BndNode * const *>(nodes.data());
619  BndNode * const * bnd_node_itr_end = bnd_node_itr_begin + nodes.size();
620 
621  const auto bnd_nodes_begin = MooseMesh::const_bnd_node_iterator(
622  bnd_node_itr_begin, bnd_node_itr_end, Predicates::NotNull<const BndNode * const *>());
623  const auto bnd_nodes_end = MooseMesh::const_bnd_node_iterator(
624  bnd_node_itr_end, bnd_node_itr_end, Predicates::NotNull<const BndNode * const *>());
625 
626  if (!displaced)
628  std::make_unique<ConstBndNodeRange>(bnd_nodes_begin, bnd_nodes_end);
629  else
631  std::make_unique<ConstBndNodeRange>(bnd_nodes_begin, bnd_nodes_end);
632 
633  return reinitializedBndNodeRange(displaced);
634 }
635 
636 void
638  ConstElemRange & elem_range,
639  ConstBndNodeRange & bnd_node_range)
640 {
641  // Don't do anything if this is a steady simulation
642  if (!sys.hasSolutionState(1))
643  return;
644 
645  NumericVector<Number> & current_solution = *sys.system().current_local_solution;
646  NumericVector<Number> & old_solution = sys.solutionOld();
647  NumericVector<Number> * older_solution = sys.hasSolutionState(2) ? &sys.solutionOlder() : nullptr;
648 
649  // Get dofs for the reinitialized elements and nodes
650  DofMap & dof_map = sys.dofMap();
651  std::vector<dof_id_type> dofs;
652 
653  for (auto & elem : elem_range)
654  {
655  std::vector<dof_id_type> elem_dofs;
656  dof_map.dof_indices(elem, elem_dofs);
657  dofs.insert(dofs.end(), elem_dofs.begin(), elem_dofs.end());
658  }
659 
660  for (auto & bnd_node : bnd_node_range)
661  {
662  std::vector<dof_id_type> bnd_node_dofs;
663  dof_map.dof_indices(bnd_node->_node, bnd_node_dofs);
664  dofs.insert(dofs.end(), bnd_node_dofs.begin(), bnd_node_dofs.end());
665  }
666 
667  // Set the old and older solutions to match the reinitialization
668  for (auto dof : dofs)
669  {
670  old_solution.set(dof, current_solution(dof));
671  if (older_solution)
672  older_solution->set(dof, current_solution(dof));
673  }
674 
675  old_solution.close();
676  if (older_solution)
677  older_solution->close();
678 }
std::unique_ptr< ConstBndNodeRange > _reinitialized_displaced_bnd_node_range
Range of reinitialized boundary nodes on the displaced mesh.
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:3108
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
static InputParameters validParams()
std::unordered_set< dof_id_type > _reinitialized_elems
Reinitialized elements.
std::pair< SubdomainID, SubdomainID > SubdomainPair
Moving boundaries associated with each subdomain pair.
std::unordered_map< BoundaryID, BoundaryName > _moving_boundary_names
Boundary names associated with each moving boundary ID.
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1155
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
MeshBase & mesh
void gatherMovingBoundaryChanges(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID >> &moved_elems)
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
The definition of the const_bnd_node_iterator struct.
Definition: MooseMesh.h:2011
NumericVector< Number > & solutionOlder()
Definition: SystemBase.h:197
const MaterialWarehouse & getMaterialWarehouse() const
void initElementStatefulProps(const libMesh::ConstElemRange &elem_range, const bool threaded)
Initialize stateful properties for elements in a specific elem_range This is needed when elements/bou...
Base class for a system (of equations)
Definition: SystemBase.h:84
void gatherMovingBoundaryChangesHelper(const Elem *elem, unsigned short side, const Elem *neigh, unsigned short neigh_side)
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
virtual void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job...
void projectInitialConditionOnCustomRange(libMesh::ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range)
Project initial conditions for custom elem_range and bnd_node_range This is needed when elements/boun...
StoredRange< MeshBase::const_element_iterator, const Elem *> ConstElemRange
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn&#39;t required or valid in the derived class...
void updateAMRMovingBoundary(MooseMesh &mesh)
Update boundaries for adaptive mesh from the parent to children elements.
void applyIC(bool displaced)
Reinitialize variables on range of elements and nodes to be reinitialized.
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:20
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
virtual void modify(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID >> &moved_elems)
Modify the element subdomains.
uint8_t processor_id_type
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
Definition: SystemBase.C:1165
void createMovingBoundaries(MooseMesh &mesh)
Create moving boundaries.
void gatherSum(T &value)
Gather the parallel sum of the variable passed in.
Definition: UserObject.h:126
ConstElemRange & reinitializedElemRange(bool displaced=false)
Range of reinitialized elements.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3443
char ** sides
virtual void meshChanged() override
Called on this object when the mesh changes.
void setAncestorsSubdomainIDs(Elem *elem, const SubdomainID subdomain_id)
Change the subdomain ID of all ancestor elements.
void applySubdomainChanges(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID >> &moved_elems, MooseMesh &mesh)
std::unordered_set< dof_id_type > _reinitialized_nodes
Reinitialized nodes.
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
std::unique_ptr< ConstElemRange > _reinitialized_displaced_elem_range
Range of reinitialized elements on the displaced mesh.
bool subdomainIsReinitialized(SubdomainID id) const
Determine if a subdomain is to be reinitialized.
std::vector< SubdomainID > _subdomain_ids_to_reinitialize
Reinitialize moved elements whose new subdomain is in this list.
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
SystemBase & _sys
Reference to the system object for this user object.
Definition: UserObject.h:215
virtual bool hasSolutionState(const unsigned int state, Moose::SolutionIterationType iteration_type=Moose::SolutionIterationType::Time) const
Whether or not the system has the solution state (0 = current, 1 = old, 2 = older, etc).
Definition: SystemBase.h:1081
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 ...
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1159
AuxiliarySystem & getAuxiliarySystem()
virtual void close()=0
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _add_element_sides
Element sides to be added.
void initElementStatefulProps(bool displaced)
Reinitialize stateful material properties on range of elements and nodes to be reinitialized.
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.
const SubdomainID ANY_BLOCK_ID
Definition: MooseTypes.C:19
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _remove_element_sides
Element sides to be removed.
bool hasActiveObjects(THREAD_ID tid=0) const
void applyMovingBoundaryChanges(MooseMesh &mesh)
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
Definition: UserObject.h:211
bool nodeIsNewlyReinitialized(dof_id_type node_id) const
Determine if a node is newly reinitialized.
std::unique_ptr< ConstBndNodeRange > _reinitialized_bnd_node_range
Range of reinitialized boundary nodes.
MooseMesh * _displaced_mesh
Displaced mesh.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
std::unique_ptr< NumericVector< Number > > current_local_solution
ConstBndNodeRange & reinitializedBndNodeRange(bool displaced=false)
Range of reinitialized boundary nodes.
std::unique_ptr< ConstElemRange > _reinitialized_elem_range
Range of reinitialized elements.
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...
virtual void set(const numeric_index_type i, const Number value)=0
void setOldAndOlderSolutions(SystemBase &sys, ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range)
Set old and older solutions to reinitialized elements and nodes.
std::vector< BoundaryID > getBoundaryIDs(const Elem *const elem, const unsigned short int side) const
Returns a vector of boundary IDs for the requested element on the requested side. ...
void findReinitializedElemsAndNodes(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID >> &moved_elems)
NumericVector< Number > & solutionOld()
Definition: SystemBase.h:196
processor_id_type processor_id() const
virtual std::size_t numSolverSystems() const override
std::unordered_map< SubdomainPair, BoundaryID > _moving_boundaries
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition: MooseMesh.C:1286
auto index_range(const T &sizable)
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _remove_neighbor_sides
Neighbor sides to be removed.
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _add_neighbor_sides
Neighbor sides to be added.
ElementSubdomainModifierBase(const InputParameters &parameters)
const bool _old_subdomain_reinitialized
Whether to reinitialize moved elements whose old subdomain was in _reinitialize_subdomains.
uint8_t dof_id_type
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
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
const RemoteElem * remote_elem