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)
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:435
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:3113
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:198
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:1737
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:1155
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:3448
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:1090
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1149
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.
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.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
MooseMesh * _displaced_mesh
Displaced mesh.
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:197
processor_id_type processor_id() const
virtual std::size_t numSolverSystems() const override
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition: MooseBase.h:201
std::unordered_map< SubdomainPair, BoundaryID > _moving_boundaries
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition: MooseMesh.C:1289
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:1178
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
Definition: MooseMesh.C:3171
SubdomainID getSubdomainID(const SubdomainName &subdomain_name) const
Get the associated subdomain ID for the subdomain name.
Definition: MooseMesh.C:1731
const RemoteElem * remote_elem