https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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/dof_map.h"
15#include "libmesh/remote_elem.h"
16#include "libmesh/parallel_ghost_sync.h"
17#include "libmesh/numeric_vector.h"
18#include "libmesh/parameters.h"
19#include <iterator>
20#include <unordered_set>
21
24{
26
27 // ESMs only operate on the undisplaced mesh to gather subdomain and sideset information. This
28 // information is used to modify both the undisplaced and the displaced meshes. It is the
29 // developer's responsibility to make sure the element IDs and sideset info are consistent across
30 // both meshes.
31 params.set<bool>("use_displaced_mesh") = false;
32 params.suppressParameter<bool>("use_displaced_mesh");
33
34 params.addParam<std::vector<BoundaryName>>(
35 "moving_boundaries",
36 {},
37 "Moving boundaries between subdomains. These boundaries (both sidesets and nodesets) will be "
38 "updated for elements that change subdomain. The subdomains that each moving "
39 "boundary lies between shall be specified using the parameter "
40 "'moving_boundary_subdomain_pairs'. If one boundary and multiple subdomain pairs are "
41 "specified, then it is assumed that the pairs all apply to the boundary. A boundary will be "
42 "created on the mesh if it does not already exist.");
43 params.addParam<std::vector<std::vector<SubdomainName>>>(
44 "moving_boundary_subdomain_pairs",
45 {},
46 "The subdomain pairs associated with each moving boundary. For each pair of subdomains, only "
47 "the element side from the first subdomain will be added to the moving boundary, i.e., the "
48 "side normal is pointing from the first subdomain to the second subdomain. The pairs shall "
49 "be delimited by ';'. If a pair only has one subdomain, the moving boundary is associated "
50 "with the subdomain's external boundary, i.e., when the elements have no neighboring "
51 "elements.");
52
53 params.addParam<std::vector<SubdomainName>>(
54 "reinitialize_subdomains",
55 {"ANY_BLOCK_ID"},
56 "By default, any element which changes subdomain is reinitialized. If a list of subdomains "
57 "(IDs or names) is provided, then only elements whose new subdomain is in the list will be "
58 "reinitialized. If an empty list is set, then no elements will be reinitialized.");
59
60 params.addParam<bool>(
61 "old_subdomain_reinitialized",
62 true,
63 "This parameter must be set with a non-empty list in 'reinitialize_subdomains'. When set to "
64 "the default true, the element's old subdomain is not considered when determining if an "
65 "element should be reinitialized. If set to false, only elements whose old subdomain was not "
66 "in 'reinitialize_subdomains' are reinitialized. ");
67
68 params.addParam<std::vector<VariableName>>(
69 "reinitialize_variables", {}, "Which variables to reinitialize when subdomain changes.");
70 MooseEnum reinit_strategy("IC POLYNOMIAL_NEIGHBOR POLYNOMIAL_WHOLE POLYNOMIAL_NEARBY NONE", "IC");
71 params.addParam<std::vector<MooseEnum>>(
72 "reinitialization_strategy",
73 {reinit_strategy},
74 "The strategy used to reinitialize the solution when elements change subdomain. If multiple "
75 "strategies are provided, each strategy will be applied to the corresponding variable. If "
76 "only one strategy is provided, it will be applied to all variables.");
77 params.addParam<std::vector<UserObjectName>>(
78 "polynomial_fitters",
79 {},
80 "List of NodalPatchRecovery UserObjects used for polynomial fitting during variable "
81 "reinitialization. Required only if 'reinitialization_strategy' includes "
82 "POLYNOMIAL_NEIGHBOR, POLYNOMIAL_WHOLE, or POLYNOMIAL_NEARBY.");
83 params.addParam<int>(
84 "nearby_kd_tree_leaf_max_size",
85 10,
86 "Maximum number of elements in a leaf node of the K-D tree used to search for nearby "
87 "elements. Only needed if 'reinitialization_strategy' is set to POLYNOMIAL_NEARBY.");
88 params.addParam<double>(
89 "nearby_distance_threshold",
90 -1.0,
91 "Threshold for considering elements as 'nearby' in the K-D tree search. Only elements within "
92 "this distance will be considered for polynomial fitting.");
93 params.addParam<std::vector<bool>>(
94 "restore_overridden_dofs",
95 {},
96 "A list of boolean flags, one for each variable in 'reinitialize_variables', specifying "
97 "whether overridden DOF values should be restored after reinitialization for each variable. "
98 "This is useful when the solved values on these DOFs should be preserved. If the list is "
99 "empty, overridden DOF values will NOT be restored for any variable by default.");
100
101 params.addParam<bool>("skip_restore_subdomain_changes",
102 false,
103 "Skip restoring the subdomain changes if the timestep is not advanced.");
104
105 params.registerBase("MeshModifier");
106
107 return params;
108}
109
111 : ElementUserObject(parameters),
112 _displaced_problem(_fe_problem.getDisplacedProblem().get()),
113 _displaced_mesh(_displaced_problem ? &_displaced_problem->mesh() : nullptr),
114 _nl_sys(_fe_problem.getNonlinearSystemBase(systemNumber())),
115 _aux_sys(_fe_problem.getAuxiliarySystem()),
116 _t_step_old(declareRestartableData<int>("t_step_old", 0)),
117 _restep(false),
118 _skip_restore_subdomain_changes(getParam<bool>("skip_restore_subdomain_changes")),
119 _old_subdomain_reinitialized(getParam<bool>("old_subdomain_reinitialized")),
120 _pr_names(getParam<std::vector<UserObjectName>>("polynomial_fitters")),
121 _reinit_vars(getParam<std::vector<VariableName>>("reinitialize_variables")),
122 _leaf_max_size(getParam<int>("nearby_kd_tree_leaf_max_size")),
123 _nearby_distance_threshold(getParam<double>("nearby_distance_threshold"))
124{
125}
126
127void
129{
130 const std::vector<SubdomainName> subdomain_names_to_reinitialize =
131 getParam<std::vector<SubdomainName>>("reinitialize_subdomains");
132
133 if (std::find(subdomain_names_to_reinitialize.begin(),
134 subdomain_names_to_reinitialize.end(),
135 "ANY_BLOCK_ID") != subdomain_names_to_reinitialize.end())
137 else
138 _subdomain_ids_to_reinitialize = _mesh.getSubdomainIDs(subdomain_names_to_reinitialize);
139
140 std::set<SubdomainID> set_subdomain_ids_to_reinitialize(_subdomain_ids_to_reinitialize.begin(),
142
143 if (_old_subdomain_reinitialized == false &&
144 (std::find(_subdomain_ids_to_reinitialize.begin(),
147 set_subdomain_ids_to_reinitialize == _mesh.meshSubdomains()))
148 paramError("old_subdomain_reinitialized",
149 "'old_subdomain_reinitialized' can only be set to false if "
150 "reinitialize_subdomains does "
151 "not cover the whole model, otherwise no elements will be reinitialized as it is "
152 "impossible for an element's old subdomain to not be in the list.");
154 paramError("old_subdomain_reinitialized",
155 "'old_subdomain_reinitialized' can only be set to false if "
156 "reinitialize_subdomains is set to a non-empty list of subdomains, otherwise no "
157 "elements will be reinitialized, as it is impossible for an element's new subdomain "
158 "to be in the list.");
159
160 auto bnd_names = getParam<std::vector<BoundaryName>>("moving_boundaries");
161 auto bnd_ids = _mesh.getBoundaryIDs(bnd_names, true);
162 const auto bnd_subdomains =
163 getParam<std::vector<std::vector<SubdomainName>>>("moving_boundary_subdomain_pairs");
164
165 if (bnd_names.size() == 1 && bnd_subdomains.size() > 1)
166 {
167 bnd_names.insert(bnd_names.end(), bnd_subdomains.size() - 1, bnd_names[0]);
168 bnd_ids.insert(bnd_ids.end(), bnd_subdomains.size() - 1, bnd_ids[0]);
169 }
170 else if (bnd_names.size() != bnd_subdomains.size())
171 paramError("moving_boundary_subdomain_pairs",
172 "Each moving boundary must correspond to a pair of subdomains. ",
173 bnd_names.size(),
174 " boundaries are specified by the parameter 'moving_boundaries', while ",
175 bnd_subdomains.size(),
176 " subdomain pairs are provided. Alternatively, if one boundary and multiple "
177 "subdomain pairs are provided, then the subdomain pairs all apply to one boundary.");
178
179 for (auto i : index_range(bnd_names))
180 {
181 _moving_boundary_names[bnd_ids[i]] = bnd_names[i];
182
183 if (bnd_subdomains[i].size() == 2)
184 _moving_boundaries[{_mesh.getSubdomainID(bnd_subdomains[i][0]),
185 _mesh.getSubdomainID(bnd_subdomains[i][1])}] = bnd_ids[i];
186 else if (bnd_subdomains[i].size() == 1)
188 bnd_ids[i];
189 else
190 paramError("moving_boundary_subdomain_pairs",
191 "Each subdomain pair must contain 1 or 2 subdomain names, but ",
192 bnd_subdomains[i].size(),
193 " are given.");
194 }
195
196 // Check if the variables to reinitialize exist in the system
197 for (const auto & var_name : _reinit_vars)
198 if (!_nl_sys.hasVariable(var_name) && !_aux_sys.hasVariable(var_name))
199 paramError("reinitialize_variables", "Variable ", var_name, " does not exist.");
200
201 // Determine the reinitialization strategy for each variable.
202 // (1) If they are of the same size, we perform a 1-to-1 mapping.
203 // (2) If only one strategy or restore flag is provided, it applies to all variables.
204 const auto reinit_strategy_in = getParam<std::vector<MooseEnum>>("reinitialization_strategy");
205 const auto restore_overridden_dofs_in = getParam<std::vector<bool>>("restore_overridden_dofs");
206
207 if (std::any_of(reinit_strategy_in.begin(),
208 reinit_strategy_in.end(),
209 [](const MooseEnum & val) { return val == "POLYNOMIAL_NEARBY"; }) &&
210 !isParamSetByUser("nearby_distance_threshold"))
211 mooseError("The 'nearby_distance_threshold' parameter must be set when using the "
212 "POLYNOMIAL_NEARBY reinitialization strategy.");
213
214 if (std::all_of(reinit_strategy_in.begin(),
215 reinit_strategy_in.end(),
216 [](const MooseEnum & val) { return val != "POLYNOMIAL_NEARBY"; }) &&
217 (isParamSetByUser("nearby_distance_threshold") ||
218 isParamSetByUser("nearby_kd_tree_leaf_max_size")))
219 mooseWarning("The 'nearby_distance_threshold' and 'nearby_kd_tree_leaf_max_size' parameters "
220 "will be ignored because no 'reinitialization_strategy' is set to "
221 "POLYNOMIAL_NEARBY.");
222
223 if (reinit_strategy_in.size() == 1)
224 _reinit_strategy.resize(_reinit_vars.size(), reinit_strategy_in[0].getEnum<ReinitStrategy>());
225 else if (reinit_strategy_in.size() == _reinit_vars.size())
226 for (const auto & e : reinit_strategy_in)
227 _reinit_strategy.push_back(e.getEnum<ReinitStrategy>());
228 else
230 "reinitialization_strategy",
231 "The 'reinitialization_strategy' parameter must have either a single value or a number "
232 "of values equal to the number of 'reinitialize_variables'. "
233 "Got ",
234 reinit_strategy_in.size(),
235 " strategies for ",
236 _reinit_vars.size(),
237 " variables.");
238
239 if (restore_overridden_dofs_in.size() == 1)
240 {
241 if (restore_overridden_dofs_in[0])
243 _reinit_vars; // Restore overridden DOFs for all reinitialized variables
244 }
245 else if (restore_overridden_dofs_in.size() == _reinit_vars.size())
246 {
247 for (auto i : index_range(_reinit_vars))
248 if (restore_overridden_dofs_in[i])
250 }
251 else
252 {
253 if (!restore_overridden_dofs_in.empty())
255 "restore_overridden_dofs",
256 "The 'restore_overridden_dofs' parameter must have either a single value or a number "
257 "of values equal to the number of 'reinitialize_variables'. "
258 "Got ",
259 restore_overridden_dofs_in.size(),
260 " restore_overridden_dofs for ",
261 _reinit_vars.size(),
262 " variables.");
263 }
264
265 // For all the other variables, we set the reinitialization strategy to IC
266 for (const auto & var_name : _fe_problem.getVariableNames())
267 if (std::find(_reinit_vars.begin(), _reinit_vars.end(), var_name) == _reinit_vars.end())
268 {
269 _reinit_vars.push_back(var_name);
271 }
272
273 // Map variable names to the index of the nodal patch recovery user object
274 _pr.resize(_pr_names.size());
275 std::size_t pr_count = 0;
276 for (auto i : index_range(_reinit_vars))
280 {
281 _var_name_to_pr_idx[_reinit_vars[i]] = pr_count;
282 if (pr_count >= _pr_names.size())
283 paramError("polynomial_fitters",
284 "The number of polynomial fitters (",
285 _pr_names.size(),
286 ") is less than the number of variables to reinitialize with polynomial "
287 "extrapolation.");
288 _pr[pr_count] =
290 mooseAssert(_pr[pr_count]->variableName() == _reinit_vars[i],
291 "The patch recovery UserObject's variable name must match the variable being "
292 "reinitialized in ElementSubdomainModifierBase.");
293 _depend_uo.insert(_pr_names[pr_count]);
294 pr_count++;
295 }
296 if (_pr_names.size() != pr_count)
297 paramError("polynomial_fitters",
298 "Mismatch between number of reinitialization strategies using polynomial "
299 "extrapolation and polynomial fitters (expected: ",
300 pr_count,
301 ", given: ",
302 _pr_names.size(),
303 ").");
304}
305
306void
308{
310 {
311 mooseInfoRepeated(name(), ": Restoring element subdomain changes.");
312
313 // Reverse the subdomain changes
314 auto moved_elem_reversed = _moved_elems;
315 for (auto & [elem_id, subdomain] : moved_elem_reversed)
316 std::swap(subdomain.first, subdomain.second);
317
318 _restep = true;
319 modify(moved_elem_reversed);
320 _restep = false;
321 }
322
324}
325
326void
328 const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
329{
330 if (!_restep)
331 // Cache the moved elements for potential restore
332 _moved_elems = moved_elems;
333
334 // If nothing need to change, just return.
335 // This will skip all mesh changes, and so no adaptivity mesh files will be written.
336 auto n_moved_elem = moved_elems.size();
337 gatherSum(n_moved_elem);
338 if (n_moved_elem == 0)
339 return;
340
341 // Create moving boundaries on the undisplaced and displaced meshes
342 //
343 // Note: We do this _everytime_ because previous execution might have removed the sidesets and
344 // nodesets. Most of the moving boundary algorithms below assume that the moving sidesets and
345 // nodesets already exist on the mesh.
347 if (_displaced_mesh)
349
350 // This has to be done *before* subdomain changes are applied
352
353 // Apply cached subdomain changes
354 applySubdomainChanges(moved_elems, _mesh);
355 if (_displaced_mesh)
357
358 // Update moving boundaries
359 gatherMovingBoundaryChanges(moved_elems);
361 if (_displaced_mesh)
363
364 // Some variable reinitialization strategies require patch elements to be gathered
365 // This has to be done *before* reinitializing the equation systems because we need to find
366 // currently evaluable elements
367 if (!_restep)
368 {
369 _evaluable_elems.clear();
370 _patch_elem_ids.clear();
371 for (auto i : index_range(_reinit_vars))
373 }
374
375 // Reinit equation systems
377 /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
378
379 // Initialize solution and stateful material properties
380 if (!_restep)
381 {
382 applyIC();
385 }
386}
387
388void
390{
391 auto & bnd_info = mesh.getMesh().get_boundary_info();
392 for (const auto & [bnd_id, bnd_name] : _moving_boundary_names)
393 {
394 bnd_info.sideset_name(bnd_id) = bnd_name;
395 bnd_info.nodeset_name(bnd_id) = bnd_name;
396 }
397}
398
399void
401 const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems,
402 MooseMesh & mesh)
403{
404 for (const auto & [elem_id, subdomain] : moved_elems)
405 {
406 // Change the element's subdomain ID
407 auto elem = mesh.elemPtr(elem_id);
408 const auto & [from, to] = subdomain;
409 mooseAssert(elem->subdomain_id() == from, "Inconsistent element subdomain ID.");
410 elem->subdomain_id() = to;
411
412 // Change the ancestors' (if any) subdomain ID
413 setAncestorsSubdomainIDs(elem, to);
414 }
415
416 // Synchronize ghost element subdomain changes
417 libMesh::SyncSubdomainIds sync(mesh.getMesh());
418 Parallel::sync_dofobject_data_by_id(
419 mesh.getMesh().comm(), mesh.getMesh().elements_begin(), mesh.getMesh().elements_end(), sync);
420}
421
422void
424{
425 auto curr_elem = elem;
426
427 for (unsigned int i = curr_elem->level(); i > 0; --i)
428 {
429 // Change the parent's subdomain
430 curr_elem = curr_elem->parent();
431 curr_elem->subdomain_id() = subdomain_id;
432 }
433}
434
435void
437 const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
438{
439 // Clear moving boundary changes from last execution
440 _add_element_sides.clear();
441 _add_neighbor_sides.clear();
442 _remove_element_sides.clear();
444
445 const auto & sidesets = _mesh.getMesh().get_boundary_info().get_sideset_map();
446
447 for (const auto & [elem_id, subdomain_assignment] : moved_elems)
448 {
449 auto elem = _mesh.elemPtr(elem_id);
450
451 // The existing moving boundaries on the element side should be removed
452 for (auto itr = sidesets.lower_bound(elem); itr != sidesets.upper_bound(elem); itr++)
453 if (_moving_boundary_names.count(itr->second.second))
454 _remove_element_sides[elem->id()].emplace(itr->second.first, itr->second.second);
455
456 for (auto side : elem->side_index_range())
457 {
458 auto neigh = elem->neighbor_ptr(side);
459
460 // Don't mess with remote element neighbor
461 if (neigh && neigh == libMesh::remote_elem)
462 continue;
463 // If neighbor doesn't exist
464 else if (!neigh)
465 gatherMovingBoundaryChangesHelper(elem, side, nullptr, 0);
466 // If neighbor exists
467 else
468 {
469 auto neigh_side = neigh->which_neighbor_am_i(elem);
470
471 if (neigh->active())
472 gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
473 else
474 {
475 // Find the active neighbors of the element
476 std::vector<const Elem *> active_neighs;
477 // Neighbor has active children, they are neighbors of the element along that side
478 mooseAssert(!neigh->subactive(),
479 "The case where the active neighbor is an ancestor of this neighbor is not "
480 "handled at this time.");
481 neigh->active_family_tree_by_neighbor(active_neighs, elem);
482
483 for (auto active_neigh : active_neighs)
484 gatherMovingBoundaryChangesHelper(elem, side, active_neigh, neigh_side);
485 }
486 }
487 }
488 }
489}
490
491void
493 unsigned short side,
494 const Elem * neigh,
495 unsigned short neigh_side)
496{
497 const auto & sidesets = _mesh.getMesh().get_boundary_info().get_sideset_map();
498
499 // Detect element side change
500 SubdomainPair subdomain_pair = {elem->subdomain_id(),
501 neigh ? neigh->subdomain_id() : Moose::INVALID_BLOCK_ID};
502 if (_moving_boundaries.count(subdomain_pair))
503 _add_element_sides[elem->id()].emplace(side, _moving_boundaries.at(subdomain_pair));
504
505 if (neigh)
506 {
507 // The existing moving boundaries on the neighbor side should be removed
508 for (auto itr = sidesets.lower_bound(neigh); itr != sidesets.upper_bound(neigh); itr++)
509 if (itr->second.first == neigh_side && _moving_boundary_names.count(itr->second.second))
510 _remove_neighbor_sides[neigh->id()].emplace(itr->second.first, itr->second.second);
511
512 // Detect neighbor side change (by reversing the subdomain pair)
513 subdomain_pair = {subdomain_pair.second, subdomain_pair.first};
514 if (_moving_boundaries.count(subdomain_pair))
515 _add_neighbor_sides[neigh->id()].emplace(neigh_side, _moving_boundaries.at(subdomain_pair));
516 }
517}
518
519void
521{
522 auto & bnd_info = mesh.getMesh().get_boundary_info();
523
524 // Remove all boundary nodes from the previous moving boundaries
525 auto nodesets = bnd_info.get_nodeset_map();
526 for (const auto & [node_id, bnd] : nodesets)
527 if (_moving_boundary_names.count(bnd))
528 bnd_info.remove_node(node_id, bnd);
529
530 // Keep track of ghost element changes
531 std::unordered_map<processor_id_type,
532 std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>>>
533 add_ghost_sides, remove_ghost_sides;
534
535 // Remove element sides from moving boundaries
536 for (const auto & [elem_id, sides] : _remove_element_sides)
537 for (const auto & [side, bnd] : sides)
538 bnd_info.remove_side(mesh.elemPtr(elem_id), side, bnd);
539
540 // Remove neighbor sides from moving boundaries
541 for (const auto & [elem_id, sides] : _remove_neighbor_sides)
542 {
543 auto elem = mesh.elemPtr(elem_id);
544 for (const auto & [side, bnd] : sides)
545 {
546 bnd_info.remove_side(elem, side, bnd);
547 // Keep track of changes to ghosted elements
548 if (elem->processor_id() != processor_id())
549 remove_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
550 }
551 }
552
553 Parallel::push_parallel_vector_data(
554 bnd_info.comm(),
555 remove_ghost_sides,
556 [&mesh,
557 &bnd_info](processor_id_type,
558 const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
559 {
560 for (const auto & [elem_id, side, bnd] : received)
561 bnd_info.remove_side(mesh.elemPtr(elem_id), side, bnd);
562 });
563
564 // Add element sides to moving boundaries
565 for (const auto & [elem_id, sides] : _add_element_sides)
566 for (const auto & [side, bnd] : sides)
567 bnd_info.add_side(mesh.elemPtr(elem_id), side, bnd);
568
569 // Add neighbor sides to moving boundaries
570 for (const auto & [elem_id, sides] : _add_neighbor_sides)
571 {
572 auto elem = mesh.elemPtr(elem_id);
573 for (const auto & [side, bnd] : sides)
574 {
575 bnd_info.add_side(elem, side, bnd);
576 // Keep track of changes to ghosted elements
577 if (elem->processor_id() != processor_id())
578 add_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
579 }
580 }
581
582 Parallel::push_parallel_vector_data(
583 bnd_info.comm(),
584 add_ghost_sides,
585 [&mesh,
586 &bnd_info](processor_id_type,
587 const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
588 {
589 for (const auto & [elem_id, side, bnd] : received)
590 bnd_info.add_side(mesh.elemPtr(elem_id), side, bnd);
591 });
592
593 bnd_info.parallel_sync_side_ids();
594 bnd_info.parallel_sync_node_ids();
595 mesh.update();
596}
597
598void
600 ReinitStrategy reinit_strategy)
601{
602 switch (reinit_strategy)
603 {
606 // No additional preparation needed for IC and NONE strategies
607 break;
611 {
612 if (_var_name_to_pr_idx.find(var_name) == _var_name_to_pr_idx.end())
613 return;
614 const int pr_idx = _var_name_to_pr_idx[var_name];
615 // The patch elements might be different for each variable
616 gatherPatchElements(var_name, reinit_strategy);
617
618 // Notify the patch recovery user object about the patch elements
619 _pr[pr_idx]->sync(_patch_elem_ids[var_name]);
620
621 break;
622 }
623 default:
624 mooseError("Unknown reinitialization strategy");
625 break;
626 }
627}
628
629void
641
642void
644{
645 auto & bnd_info = mesh.getMesh().get_boundary_info();
646 auto sidesets = bnd_info.get_sideset_map();
647 for (const auto & i : sidesets)
648 {
649 auto elem = i.first;
650 auto side = i.second.first;
651 auto bnd = i.second.second;
652 if (_moving_boundary_names.count(bnd) && !elem->active())
653 {
654 bnd_info.remove_side(elem, side, bnd);
655
656 std::vector<const Elem *> elem_family;
657 elem->active_family_tree_by_side(elem_family, side);
658 for (auto felem : elem_family)
659 bnd_info.add_side(felem, side, bnd);
660 }
661 }
662
663 bnd_info.parallel_sync_side_ids();
664 bnd_info.parallel_sync_node_ids();
665}
666
667void
669 const std::unordered_map<dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
670{
671 // Clear cached element reinitialization data
672 _reinitialized_elems.clear();
673 _reinitialized_nodes.clear();
674
675 // One more algorithm:
676 // (1) Loop over moved elements
677 // (2) If neighbor element processor ID is not the same as current processor ID (ghost element),
678 // push the moved element ID to the neighbor processor
679
680 std::unordered_map<processor_id_type, std::unordered_set<dof_id_type>> push_data_set;
681 std::unordered_map<processor_id_type, std::vector<dof_id_type>> push_data;
682
683 for (const auto & [elem_id, subdomain] : moved_elems)
684 {
685 mooseAssert(_mesh.elemPtr(elem_id)->active(), "Moved elements should be active");
686 // Default: any element that changes subdomain is reinitialized
687 if (std::find(_subdomain_ids_to_reinitialize.begin(),
690 _reinitialized_elems.insert(elem_id);
691 else // Reinitialize if new subdomain is in list of subdomains to be reinitialized
692 {
693 const auto & [from, to] = subdomain;
695 _reinitialized_elems.insert(elem_id);
696 // Only reinitialize if original subdomain is not in list of subdomains
699 _reinitialized_elems.insert(elem_id);
700 else // New subdomain is not in list of subdomains
701 continue;
702 }
703 const auto & elem = _mesh.elemPtr(elem_id);
704
705 // (1) Loop over nodes of moved elements
706 // (2) node to element map is used to find neighbor elements
707 // (3) If neighbor element processor ID is not the same as current processor ID (means that the
708 // current element is ghosted element to the neighbor processor), push the moved element (or
709 // reinitialized, or newly-activated) ID to the neighbor processor
710 for (const auto & node : elem->node_ref_range())
711 for (const auto & neigh_id : _mesh.nodeToElemMap().at(node.id()))
712 if (neigh_id != elem_id) // Don't check the element itself
713 {
714 const auto neigh_elem = _mesh.elemPtr(neigh_id);
715 if (neigh_elem->processor_id() != processor_id())
716 push_data_set[neigh_elem->processor_id()].insert(elem_id);
717 }
718
719 for (unsigned int i = 0; i < elem->n_nodes(); ++i)
720 if (nodeIsNewlyReinitialized(elem->node_id(i)))
721 _reinitialized_nodes.insert(elem->node_id(i));
722 }
723
724 for (auto & [pid, s] : push_data_set)
725 push_data[pid] = {s.begin(), s.end()};
726
728
729 auto push_receiver =
730 [this](const processor_id_type, const std::vector<dof_id_type> & received_data)
731 {
732 for (const auto & id : received_data)
734 };
735
736 Parallel::push_parallel_vector_data(_mesh.comm(), push_data, push_receiver);
737}
738
739bool
741{
742 // Default: any element that changes subdomain is reinitialized
743 if (std::find(_subdomain_ids_to_reinitialize.begin(),
746 return true;
747
748 // Is subdomain in list of subdomains to be reinitialized
749 return std::find(_subdomain_ids_to_reinitialize.begin(),
752}
753
754bool
756{
757 // If any of the node neighbor elements has reinitialized, then the node is NOT newly
758 // reinitialized.
759 for (auto neighbor_elem_id : _mesh.nodeToElemMap().at(node_id))
760 if (subdomainIsReinitialized(_mesh.elemPtr(neighbor_elem_id)->subdomain_id()))
761 return false;
762 return true;
763}
764
765void
767{
768 // Before reinitializing variables, some DOFs may be overwritten.
769 // By default, these overwritten DOF values are NOT restored.
770 // If the user sets `restore_overridden_dofs` to true, we first save the current
771 // values of these DOFs, then restore them after reinitialization.
772 for (const auto & var_name : _vars_to_restore_overridden_dofs)
773 storeOverriddenDofValues(var_name);
774
775 // ReinitStrategy::IC
776 std::set<VariableName> ic_vars;
777 for (auto i : index_range(_reinit_vars))
779 ic_vars.insert(_reinit_vars[i]);
780 if (!ic_vars.empty())
783
784 // ReinitStrategy::POLYNOMIAL_NEIGHBOR, POLYNOMIAL_WHOLE, POLYNOMIAL_NEARBY
785 for (const auto & [var, patch] : _patch_elem_ids)
787
788 // See the comment above, now we restore the values of the dofs that were overridden
789 for (const auto & var_name : _vars_to_restore_overridden_dofs)
791
792 mooseAssert(_fe_problem.numSolverSystems() <= 1,
793 "This code was written for a single nonlinear system");
794 // Set old and older solutions on the reinitialized dofs to the reinitialized values
795 // note: from current -> old -> older
801
802 // Note: Need method to handle solve failures at timesteps where subdomain changes. The old
803 // solutions are now set to the reinitialized values. Does this impact restoring solutions
804}
805
806void
808{
809 const auto & sys = _fe_problem.getSystem(var_name);
810 const auto & current_solution = *sys.current_local_solution;
811 const auto & dof_map = sys.get_dof_map();
812 const auto & var = _fe_problem.getStandardVariable(0, var_name);
813 const auto var_num = var.number();
814
815 // Get the DOFs on the reinitialized elements
816 // Here we should loop over both ghosted and local reinitialized elements.
817 // The ghosted elements here can take care of DoFs that is belong to the reinitialized
818 // elements but are not on the current processor.
819 std::set<dof_id_type> reinitialized_dofs;
820 for (const auto & elem_id : _semi_local_reinitialized_elems)
821 {
822 const auto & elem = _mesh.elemPtr(elem_id);
823 std::vector<dof_id_type> elem_dofs;
824 dof_map.dof_indices(elem, elem_dofs, var_num);
825 reinitialized_dofs.insert(elem_dofs.begin(), elem_dofs.end());
826 }
827
828 // Get existing DOFs on the active elements excluding reinitialized elements
829 std::set<dof_id_type> existing_dofs;
830 for (const auto * elem : *_mesh.getActiveLocalElementRange())
831 {
832 if (_reinitialized_elems.count(elem->id()))
833 continue; // Skip reinitialized elements
834 std::vector<dof_id_type> elem_dofs;
835 dof_map.dof_indices(elem, elem_dofs, var_num);
836 existing_dofs.insert(elem_dofs.begin(), elem_dofs.end());
837 }
838
839 // Get the DOFs on the nodes that are overridden on reinitialized elements
840 std::vector<dof_id_type> overridden_dofs;
841 std::set_intersection(reinitialized_dofs.begin(),
842 reinitialized_dofs.end(),
843 existing_dofs.begin(),
844 existing_dofs.end(),
845 std::back_inserter(overridden_dofs));
846
847 // Values before overriding (to be restored later)
848 std::vector<Number> values;
849 for (auto dof : overridden_dofs)
850 values.push_back(current_solution(dof));
851
852 _overridden_values_on_reinit_elems[var_name] = {overridden_dofs, values};
853}
854
855void
857{
858 const auto sn = _fe_problem.systemNumForVariable(var_name);
859 auto & sys = _fe_problem.getSystemBase(sn);
860 auto & sol = sys.solution();
861 const auto & dof_map = sys.dofMap();
862 const auto & [dof_ids, values] = _overridden_values_on_reinit_elems[var_name];
863
864 std::unordered_map<processor_id_type, std::vector<std::pair<dof_id_type, Number>>> push_data;
865
866 for (const int i : index_range(dof_ids))
867 {
868 if (dof_map.dof_owner(dof_ids[i]) == processor_id())
869 sol.set(dof_ids[i], values[i]);
870 else
871 push_data[dof_map.dof_owner(dof_ids[i])].emplace_back(dof_ids[i], values[i]);
872 }
873
874 auto push_receiver = [&](const processor_id_type,
875 const std::vector<std::pair<dof_id_type, Number>> & received_data)
876 {
877 for (const auto & [id, value] : received_data)
878 sol.set(id, value);
879 };
880
881 Parallel::push_parallel_vector_data(_mesh.comm(), push_data, push_receiver);
882
883 sol.close();
884 sol.localize(*sys.system().current_local_solution, sys.dofMap().get_send_list());
885}
886
887void
892
893ConstElemRange &
895{
897 return *_reinitialized_elem_range.get();
898
899 // Create a vector of the newly reinitialized elements
900 std::vector<Elem *> elems;
901 for (auto elem_id : _reinitialized_elems)
902 elems.push_back(_mesh.elemPtr(elem_id));
903
904 // Make some fake element iterators defining this vector of elements
905 Elem * const * elem_itr_begin = const_cast<Elem * const *>(elems.data());
906 Elem * const * elem_itr_end = elem_itr_begin + elems.size();
907
908 const auto elems_begin = MeshBase::const_element_iterator(
909 elem_itr_begin, elem_itr_end, Predicates::NotNull<Elem * const *>());
910 const auto elems_end = MeshBase::const_element_iterator(
911 elem_itr_end, elem_itr_end, Predicates::NotNull<Elem * const *>());
912
913 _reinitialized_elem_range = std::make_unique<ConstElemRange>(elems_begin, elems_end);
914
915 return reinitializedElemRange();
916}
917
920{
922 return *_reinitialized_bnd_node_range.get();
923
924 // Create a vector of the newly reinitialized boundary nodes
925 std::vector<const BndNode *> nodes;
926 auto bnd_nodes = _mesh.getBoundaryNodeRange();
927 for (auto bnd_node : *bnd_nodes)
928 if (bnd_node->_node)
929 if (_reinitialized_nodes.count(bnd_node->_node->id()))
930 nodes.push_back(bnd_node);
931
932 BndNode * const * bnd_node_itr_begin = const_cast<BndNode * const *>(nodes.data());
933 BndNode * const * bnd_node_itr_end = bnd_node_itr_begin + nodes.size();
934
935 const auto bnd_nodes_begin = MooseMesh::const_bnd_node_iterator(
936 bnd_node_itr_begin, bnd_node_itr_end, Predicates::NotNull<const BndNode * const *>());
937 const auto bnd_nodes_end = MooseMesh::const_bnd_node_iterator(
938 bnd_node_itr_end, bnd_node_itr_end, Predicates::NotNull<const BndNode * const *>());
939
941 std::make_unique<ConstBndNodeRange>(bnd_nodes_begin, bnd_nodes_end);
942
944}
945
946ConstNodeRange &
948{
950 return *_reinitialized_node_range.get();
951
952 // Create a vector of the newly reinitialized nodes
953 std::vector<const Node *> nodes;
954
955 for (auto node_id : _reinitialized_nodes)
956 nodes.push_back(_mesh.nodePtr(node_id)); // displaced mesh shares the same node object
957
958 Node * const * node_itr_begin = const_cast<Node * const *>(nodes.data());
959 Node * const * node_itr_end = node_itr_begin + nodes.size();
960
961 const auto nodes_begin = MeshBase::const_node_iterator(
962 node_itr_begin, node_itr_end, Predicates::NotNull<const Node * const *>());
963 const auto nodes_end = MeshBase::const_node_iterator(
964 node_itr_end, node_itr_end, Predicates::NotNull<const Node * const *>());
965
966 _reinitialized_node_range = std::make_unique<ConstNodeRange>(nodes_begin, nodes_end);
967
968 return *_reinitialized_node_range.get();
969}
970
971void
973 ConstElemRange & elem_range,
974 ConstBndNodeRange & bnd_node_range)
975{
976 for (auto bnd : bnd_node_range)
977 {
978 const Node * bnode = bnd->_node;
979 if (!bnode)
980 continue;
981 }
982
983 // Don't do anything if this is a steady simulation
984 if (!sys.hasSolutionState(1))
985 return;
986
987 NumericVector<Number> & current_solution = *sys.system().current_local_solution;
988 NumericVector<Number> & old_solution = sys.solutionOld();
989 NumericVector<Number> * older_solution = sys.hasSolutionState(2) ? &sys.solutionOlder() : nullptr;
990
991 // Get dofs for the reinitialized elements and nodes
992 DofMap & dof_map = sys.dofMap();
993 std::vector<dof_id_type> dofs;
994
995 for (auto & elem : elem_range)
996 {
997 std::vector<dof_id_type> elem_dofs;
998 dof_map.dof_indices(elem, elem_dofs);
999 dofs.insert(dofs.end(), elem_dofs.begin(), elem_dofs.end());
1000 }
1001
1002 for (auto & bnd_node : bnd_node_range)
1003 {
1004 std::vector<dof_id_type> bnd_node_dofs;
1005 dof_map.dof_indices(bnd_node->_node, bnd_node_dofs);
1006 dofs.insert(dofs.end(), bnd_node_dofs.begin(), bnd_node_dofs.end());
1007 }
1008
1009 // Set the old and older solutions to match the reinitialization
1010 for (auto dof : dofs)
1011 {
1012 old_solution.set(dof, current_solution(dof));
1013 if (older_solution)
1014 older_solution->set(dof, current_solution(dof));
1015 }
1016
1017 old_solution.close();
1018 if (older_solution)
1019 older_solution->close();
1020}
1021
1022void
1024 ReinitStrategy reinit_strategy)
1025{
1026 _patch_elem_ids[var_name].clear();
1027
1028 // First collect all elements who own dofs in the current dofmap
1029 auto & sys = _fe_problem.getSystem(var_name);
1030
1031 // Cache evaluable elements for the system if not already done
1032 if (!_evaluable_elems.count(sys.number()))
1033 {
1034 auto & [candidate_elems, candidate_elem_ids] = _evaluable_elems[sys.number()];
1035 const auto & dof_map = sys.get_dof_map();
1036 std::vector<dof_id_type> elem_dofs;
1037 auto vn = sys.variable_number(static_cast<std::string>(var_name));
1038 for (const auto elem : *_mesh.getActiveLocalElementRange())
1039 {
1040 if (std::find(_reinitialized_elems.begin(), _reinitialized_elems.end(), elem->id()) !=
1042 continue; // Skip elements that were reinitialized
1043
1044 dof_map.dof_indices(elem, elem_dofs, vn);
1045 if (!elem_dofs.empty())
1046 {
1047 candidate_elems.insert(elem);
1048 candidate_elem_ids.push_back(elem->id());
1049 }
1050 }
1051 }
1052 auto & [candidate_elems, candidate_elem_ids] = _evaluable_elems[sys.number()];
1053
1054 // Now we gather patch elements based on the reinit strategy
1055 auto & patch_elems = _patch_elem_ids[var_name];
1056
1057 switch (reinit_strategy)
1058 {
1060 {
1061 auto has_neighbor_in_reinit_elems = [&](const Elem * elem) -> bool
1062 {
1063 for (const auto & node : elem->node_ref_range())
1064 for (const auto & neigh_id : _mesh.nodeToElemMap().at(node.id()))
1065 // here we need to use _global_reinitialized_elems gathering from all processors
1066 if (_semi_local_reinitialized_elems.count(neigh_id))
1067 return true;
1068 return false;
1069 };
1070 // Loop over all candidate elements, for each element, if any of its point neighbor belongs
1071 // to the reinitialized elements, we will include that element in the patch element set.
1072 for (const auto * elem : candidate_elems)
1073 if (has_neighbor_in_reinit_elems(elem))
1074 patch_elems.push_back(elem->id());
1075 break;
1076 }
1078 {
1079 // This is simple: all candidate elements are patch elements
1080 patch_elems = candidate_elem_ids;
1081 break;
1082 }
1084 {
1085 std::vector<Point> kd_points;
1086 std::vector<dof_id_type> global_candidate_elem_ids;
1087
1089 {
1090 std::vector<std::pair<Point, dof_id_type>> pts_ids(candidate_elem_ids.size());
1091 for (std::size_t i = 0; i < candidate_elem_ids.size(); ++i)
1092 pts_ids[i] = {_mesh.elemPtr(candidate_elem_ids[i])->vertex_average(),
1093 candidate_elem_ids[i]};
1094 _mesh.comm().allgather(pts_ids);
1095 for (const auto & [pt, id] : pts_ids)
1096 {
1097 kd_points.push_back(pt);
1098 global_candidate_elem_ids.push_back(id);
1099 }
1100 }
1101 else
1102 {
1103 _mesh.comm().allgather(candidate_elem_ids);
1104 global_candidate_elem_ids = candidate_elem_ids;
1105 for (const auto & id : candidate_elem_ids)
1106 kd_points.push_back(_mesh.elemPtr(id)->vertex_average());
1107 }
1108
1109 const auto kd_tree = std::make_unique<KDTree>(kd_points, _leaf_max_size);
1110
1111 std::vector<nanoflann::ResultItem<std::size_t, Real>> query_result;
1112 for (const auto & elem_id : _reinitialized_elems)
1113 {
1114 const Point & centroid = _mesh.elemPtr(elem_id)->vertex_average();
1115 kd_tree->radiusSearch(centroid, _nearby_distance_threshold, query_result);
1116 for (const auto & [qid, dist] : query_result)
1117 patch_elems.push_back(global_candidate_elem_ids[qid]);
1118 }
1119 break;
1120 }
1122 // do nothing
1123 break;
1124 default:
1125 mooseError("Unknown reinitialization strategy");
1126 break;
1127 }
1128
1129 // every processor should have the same patch elements to do the polynomial extrapolation,
1130 // so we gather them across all processors
1131 _mesh.comm().allgather(patch_elems);
1132
1133 // Remove duplicates from the patch elements (espcially important for POLYNOMIAL_NEARBY)
1134 std::sort(patch_elems.begin(), patch_elems.end());
1135 patch_elems.erase(std::unique(patch_elems.begin(), patch_elems.end()), patch_elems.end());
1136}
1137
1138void
1140{
1141 const auto & coef =
1142 _pr[_var_name_to_pr_idx[var_name]]->getCachedCoefficients(_patch_elem_ids[var_name]);
1143
1144 const unsigned dim = _mesh.dimension();
1145
1146 libMesh::Parameters function_parameters;
1147
1148 const auto & multi_index = _pr[_var_name_to_pr_idx[var_name]]->multiIndex();
1149
1150 function_parameters.set<std::vector<std::vector<unsigned int>>>("multi_index") = multi_index;
1151
1152 std::vector<Real> coef_vec(coef.size());
1153 for (auto i = 0; i < coef.size(); ++i)
1154 coef_vec[i] = coef(i);
1155
1156 function_parameters.set<std::vector<Real>>("multi_index_coefficients") = coef_vec;
1157 function_parameters.set<unsigned int>("dimension_for_projection") = dim;
1158
1159 // Define projection function
1160 auto poly_func = [](const Point & p,
1162 const std::string &,
1163 const std::string &) -> libMesh::Number
1164 {
1165 const auto & multi_index =
1166 parameters.get<std::vector<std::vector<unsigned int>>>("multi_index");
1167 const auto & coeffs = parameters.get<std::vector<Real>>("multi_index_coefficients");
1168
1169 Real val = 0.0;
1170
1171 for (unsigned int r = 0; r < multi_index.size(); r++)
1172 {
1173 Real monomial = 1.0;
1174 for (unsigned int d = 0; d < multi_index[r].size(); d++)
1175 {
1176 const auto power = multi_index[r][d];
1177 if (power == 0)
1178 continue;
1179
1180 monomial *= std::pow(p(d), power);
1181 }
1182 val += coeffs[r] * monomial;
1183 }
1184
1185 return val;
1186 };
1187
1188 // Define gradient
1189 auto poly_func_grad = [](const Point & p,
1191 const std::string &,
1192 const std::string &) -> libMesh::Gradient
1193 {
1194 const unsigned int dim = parameters.get<unsigned int>("dimension_for_projection");
1195
1196 const auto & multi_index =
1197 parameters.get<std::vector<std::vector<unsigned int>>>("multi_index");
1198 const auto & coeffs = parameters.get<std::vector<Real>>("multi_index_coefficients");
1199
1200 libMesh::Gradient grad; // Zero-initialized
1201
1202 for (unsigned int r = 0; r < multi_index.size(); ++r)
1203 {
1204 const auto & powers = multi_index[r];
1205 const Real coef = coeffs[r];
1206
1207 for (unsigned int d = 0; d < dim; ++d) // Loop over dimension
1208 {
1209 const auto power_d = powers[d];
1210 if (power_d == 0)
1211 continue;
1212
1213 // Compute partial derivative in direction d
1214 Real partial = coef * power_d;
1215
1216 for (unsigned int i = 0; i < powers.size(); ++i)
1217 {
1218 if (i == d)
1219 {
1220 if (powers[i] > 1)
1221 partial *= std::pow(p(i), powers[i] - 1); // reduce power by 1
1222 }
1223 else
1224 {
1225 if (powers[i] > 0)
1226 partial *= std::pow(p(i), powers[i]); // full power
1227 }
1228 }
1229
1230 grad(d) += partial;
1231 }
1232 }
1233
1234 return grad;
1235 };
1236
1237 std::vector<VariableName> var_names = {var_name};
1239 reinitializedElemRange(), poly_func, poly_func_grad, function_parameters, var_names);
1240}
ReinitStrategy
Strategies for (re)initializing the solution:
void mooseInfoRepeated(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
Definition MooseError.h:409
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
std::array< Real, 2 > values
Definition MortarUtils.C:52
char ** sides
unsigned int dim
void ErrorVector unsigned int
std::map< VariableName, std::vector< dof_id_type > > _patch_elem_ids
A map from variable names to their corresponding patch element IDs.
void applySubdomainChanges(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID > > &moved_elems, MooseMesh &mesh)
std::map< VariableName, std::pair< std::vector< dof_id_type >, std::vector< Number > > > _overridden_values_on_reinit_elems
A map from variable name to a pair of: (1) a vector of DOF IDs associated with non-reinitialized node...
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _add_neighbor_sides
Neighbor sides to be added.
std::unordered_map< BoundaryID, BoundaryName > _moving_boundary_names
Boundary names associated with each moving boundary ID.
void restoreOverriddenDofValues(const VariableName &var_name)
Restore values to non-reinitialized DoFs on reinitialized elements.
std::unordered_set< dof_id_type > _semi_local_reinitialized_elems
Semi-local reinitialized elements: ghosted and local reinitialized elements.
std::vector< VariableName > _vars_to_restore_overridden_dofs
List of variable names for which overridden DOF values should be restored.
void timestepSetup() override
Gets called at the beginning of the timestep before this object is asked to do its job.
void createMovingBoundaries(MooseMesh &mesh)
Create moving boundaries.
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _add_element_sides
Element sides to be added.
void findReinitializedElemsAndNodes(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID > > &moved_elems)
void meshChanged() override
Called on this object when the mesh changes.
NonlinearSystemBase & _nl_sys
Nonlinear system.
std::map< VariableName, unsigned int > _var_name_to_pr_idx
map from variable name to the index of the nodal patch recovery user object in _pr
virtual void modify(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID > > &moved_elems)
Modify the element subdomains.
std::unique_ptr< ConstBndNodeRange > _reinitialized_bnd_node_range
Range of reinitialized boundary nodes.
const std::vector< UserObjectName > _pr_names
Names of the NodalPatchRecoveryVariable user objects.
void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job.
void gatherMovingBoundaryChanges(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID > > &moved_elems)
void applyIC()
Reinitialize variables on range of elements and nodes to be reinitialized.
bool nodeIsNewlyReinitialized(dof_id_type node_id) const
Determine if a node is newly reinitialized.
void storeOverriddenDofValues(const VariableName &var_name)
Store values from non-reinitialized DoFs on reinitialized elements Stores the value before re-initial...
std::unordered_map< SubdomainPair, BoundaryID > _moving_boundaries
std::unique_ptr< ConstElemRange > _reinitialized_elem_range
Range of reinitialized elements.
MooseMesh * _displaced_mesh
Displaced mesh.
double _nearby_distance_threshold
Radius threshold for the k-d tree neighbor search.
bool _skip_restore_subdomain_changes
Skipping restoring the subdomain changes if the timestep is not advanced.
std::vector< SubdomainID > _subdomain_ids_to_reinitialize
Reinitialize moved elements whose new subdomain is in this list.
int & _t_step_old
Previous time step number.
std::vector< VariableName > _reinit_vars
List of variable names to be initialized for IC.
void extrapolatePolynomial(const VariableName &var_name)
Extrapolate polynomial for the given variable onto the reinitialized elements.
AuxiliarySystem & _aux_sys
Auxiliary system.
bool _restep
Whether this is a re-step.
std::vector< ReinitStrategy > _reinit_strategy
The strategies used to apply IC on newly activated elements, for each variable.
std::unordered_set< dof_id_type > _reinitialized_nodes
Reinitialized nodes.
const bool _old_subdomain_reinitialized
Whether to reinitialize moved elements whose old subdomain was in _reinitialize_subdomains.
std::map< unsigned int, std::pair< std::unordered_set< const Elem * >, std::vector< dof_id_type > > > _evaluable_elems
local evaluable elements before reinitializing the equation systems Key of the map is the system numb...
ConstBndNodeRange & reinitializedBndNodeRange()
Range of reinitialized boundary nodes.
std::unique_ptr< ConstNodeRange > _reinitialized_node_range
Range of reinitialized nodes.
bool subdomainIsReinitialized(SubdomainID id) const
Determine if a subdomain is to be reinitialized.
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _remove_element_sides
Element sides to be removed.
ConstElemRange & reinitializedElemRange()
Range of reinitialized elements.
void initElementStatefulProps()
Reinitialize stateful material properties on range of elements and nodes to be reinitialized.
std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID > > _moved_elems
Cached moved elements for potential restore.
std::unordered_set< dof_id_type > _reinitialized_elems
Reinitialized elements.
void setOldAndOlderSolutions(SystemBase &sys, ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range)
Set old and older solutions to reinitialized elements and nodes.
void setAncestorsSubdomainIDs(Elem *elem, const SubdomainID subdomain_id)
Change the subdomain ID of all ancestor elements.
std::vector< NodalPatchRecoveryVariable * > _pr
Apply initial conditions using polynomial extrapolation.
std::pair< SubdomainID, SubdomainID > SubdomainPair
Moving boundaries associated with each subdomain pair.
ElementSubdomainModifierBase(const InputParameters &parameters)
void gatherPatchElements(const VariableName &var_name, ReinitStrategy reinit_strategy)
Gather patch elements for reinitialized elements based on the reinitialization strategy.
std::unordered_map< dof_id_type, std::unordered_map< unsigned short, BoundaryID > > _remove_neighbor_sides
Neighbor sides to be removed.
ConstNodeRange & reinitializedNodeRange()
Range of reinitialized nodes.
void updateAMRMovingBoundary(MooseMesh &mesh)
Update boundaries for adaptive mesh from the parent to children elements.
int _leaf_max_size
KD-tree related members.
void gatherMovingBoundaryChangesHelper(const Elem *elem, unsigned short side, const Elem *neigh, unsigned short neigh_side)
void prepareVariableForReinitialization(const VariableName &var_name, ReinitStrategy reinit_strategy)
static InputParameters validParams()
T & getUserObject(const std::string &name, unsigned int tid=0) const
Get the user object by its name.
virtual MooseVariable & getStandardVariable(const THREAD_ID tid, const std::string &var_name) override
Returns the variable reference for requested MooseVariable which may be in any system.
void projectInitialConditionOnCustomRange(libMesh::ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range, const std::optional< std::set< VariableName > > &target_vars=std::nullopt)
Project initial conditions for custom elem_range and bnd_node_range This is needed when elements/boun...
AuxiliarySystem & getAuxiliarySystem()
virtual std::size_t numSolverSystems() const override
unsigned int systemNumForVariable(const VariableName &variable_name) 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...
const MaterialWarehouse & getMaterialWarehouse() const
void projectFunctionOnCustomRange(ConstElemRange &elem_range, Number(*func)(const Point &, const libMesh::Parameters &, const std::string &, const std::string &), Gradient(*func_grad)(const Point &, const libMesh::Parameters &, const std::string &, const std::string &), const libMesh::Parameters &params, const std::vector< VariableName > &target_vars)
Project a function onto a range of elements for a given variable.
virtual std::vector< VariableName > getVariableNames()
Returns a list of all the variables in the problem (both from the NL and Aux systems.
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
virtual const SystemBase & getSystemBase(const unsigned int sys_num) const
Get constant reference to a system in this problem.
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
virtual libMesh::System & getSystem(const std::string &var_name) override
Returns the equation system containing the variable provided.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void suppressParameter(const std::string &name)
This method suppresses an inherited parameter so that it isn't required or valid in the derived class...
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.
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System.
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.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
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:457
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition MooseBase.h:205
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition MooseMesh.C:2986
virtual Elem * elemPtr(const dof_id_type i)
Definition MooseMesh.C:3214
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition MooseMesh.C:3549
virtual bool isDistributedMesh() const
Returns the final Mesh distribution type.
Definition MooseMesh.h:1143
SubdomainID getSubdomainID(const SubdomainName &subdomain_name) const
Get the associated subdomain ID for the subdomain name.
Definition MooseMesh.C:1720
const std::unordered_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:1236
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:1726
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.
Definition MooseMesh.C:3027
virtual const Node * nodePtr(const dof_id_type i) const
Definition MooseMesh.C:855
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition MooseMesh.C:1285
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
Definition MooseMesh.C:3272
const libMesh::ConstElemRange * getActiveLocalElementRange()
Return pointers to range objects for various types of ranges (local nodes, boundary elems,...
Definition MooseMesh.C:1242
bool hasActiveObjects(THREAD_ID tid=0) const
unsigned int number() const
Get variable number coming from libMesh.
Patch recovery from a coupled variable.
Base class for a system (of equations)
Definition SystemBase.h:87
unsigned int number() const
Gets the number of this system.
NumericVector< Number > & solutionOld()
Definition SystemBase.h:204
virtual bool hasVariable(const std::string &var_name) const
Query a system for a variable.
Definition SystemBase.C:850
NumericVector< Number > & solutionOlder()
Definition SystemBase.h:205
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
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,...
NumericVector< Number > & solution()
Definition SystemBase.h:203
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
int & _t_step
The number of the time step.
void gatherSum(T &value)
Gather the parallel sum of the variable passed in.
std::set< std::string > _depend_uo
Depend UserObjects that to be used both for determining user object sorting and by AuxKernel for find...
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
SystemBase & _sys
Reference to the system object for this user object.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
unsigned int variable_number(std::string_view var) const
virtual void set(const numeric_index_type i, const T value)=0
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
T & set(const std::string &)
std::unique_ptr< NumericVector< Number > > current_local_solution
const DofMap & get_dof_map() const
MeshBase & mesh
const SubdomainID ANY_BLOCK_ID
Definition MooseTypes.C:19
const SubdomainID INVALID_BLOCK_ID
Definition MooseTypes.C:20
Real Number
const RemoteElem * remote_elem
MooseUnits pow(const MooseUnits &, int)
Definition Units.C:537
The definition of the const_bnd_node_iterator struct.
Definition MooseMesh.h:2191