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" 30 params.
set<
bool>(
"use_displaced_mesh") =
false;
34 "moving_boundary_name",
35 "Name of the moving boundary",
36 "This has been replaced by 'moving_boundaries' and 'moving_boundary_subdomain_pairs'.");
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'.");
42 "apply_initial_conditions",
44 "Whether to apply initial conditions on the moved nodes and elements",
45 "This has been replaced by 'reinitialize_subdomains'");
47 params.
addParam<std::vector<BoundaryName>>(
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",
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 " 66 params.
addParam<std::vector<SubdomainName>>(
67 "reinitialize_subdomains",
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.");
73 "old_subdomain_reinitialized",
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. ");
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"))
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.");
106 std::vector<SubdomainName> subdomain_names_to_reinitialize =
107 getParam<std::vector<SubdomainName>>(
"reinitialize_subdomains");
110 if (
isParamSetByUser(
"apply_initial_conditions") && getParam<bool>(
"apply_initial_conditions"))
111 subdomain_names_to_reinitialize = {
"ANY_BLOCK_ID"};
113 subdomain_names_to_reinitialize = {};
115 if (std::find(subdomain_names_to_reinitialize.begin(),
116 subdomain_names_to_reinitialize.end(),
117 "ANY_BLOCK_ID") != subdomain_names_to_reinitialize.end())
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.");
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.");
142 auto bnd_names = getParam<std::vector<BoundaryName>>(
"moving_boundaries");
144 const auto bnd_subdomains =
145 getParam<std::vector<std::vector<SubdomainName>>>(
"moving_boundary_subdomain_pairs");
147 if (bnd_names.size() == 1 && bnd_subdomains.size() > 1)
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]);
152 else if (bnd_names.size() != bnd_subdomains.size())
154 "Each moving boundary must correspond to a pair of subdomains. ",
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.");
165 if (bnd_subdomains[i].size() == 2)
168 else if (bnd_subdomains[i].size() == 1)
173 "Each subdomain pair must contain 1 or 2 subdomain names, but ",
174 bnd_subdomains[i].size(),
181 const std::unordered_map<
dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
186 auto n_moved_elem = moved_elems.size();
188 if (n_moved_elem == 0)
216 false,
false,
false);
234 auto & bnd_info =
mesh.getMesh().get_boundary_info();
237 bnd_info.sideset_name(bnd_id) = bnd_name;
238 bnd_info.nodeset_name(bnd_id) = bnd_name;
244 const std::unordered_map<
dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems,
247 for (
const auto & [elem_id, subdomain] : moved_elems)
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;
261 Parallel::sync_dofobject_data_by_id(
262 mesh.getMesh().comm(),
mesh.getMesh().elements_begin(),
mesh.getMesh().elements_end(), sync);
268 auto curr_elem = elem;
270 for (
unsigned int i = curr_elem->level(); i > 0; --i)
273 curr_elem = curr_elem->parent();
274 curr_elem->subdomain_id() = subdomain_id;
280 const std::unordered_map<
dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
288 const auto & sidesets =
_mesh.
getMesh().get_boundary_info().get_sideset_map();
290 for (
const auto & [elem_id, subdomain_assignment] : moved_elems)
295 for (
auto itr = sidesets.lower_bound(elem); itr != sidesets.upper_bound(elem); itr++)
299 for (
auto side : elem->side_index_range())
301 auto neigh = elem->neighbor_ptr(side);
312 auto neigh_side = neigh->which_neighbor_am_i(elem);
319 std::vector<const Elem *> active_neighs;
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);
326 for (
auto active_neigh : active_neighs)
338 unsigned short neigh_side)
340 const auto & sidesets =
_mesh.
getMesh().get_boundary_info().get_sideset_map();
351 for (
auto itr = sidesets.lower_bound(neigh); itr != sidesets.upper_bound(neigh); itr++)
356 subdomain_pair = {subdomain_pair.second, subdomain_pair.first};
365 auto & bnd_info =
mesh.getMesh().get_boundary_info();
368 auto nodesets = bnd_info.get_nodeset_map();
369 for (
const auto & [node_id, bnd] : nodesets)
371 bnd_info.remove_node(node_id, bnd);
375 std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>>>
376 add_ghost_sides, remove_ghost_sides;
380 for (
const auto & [side, bnd] :
sides)
381 bnd_info.remove_side(
mesh.elemPtr(elem_id), side, bnd);
386 auto elem =
mesh.elemPtr(elem_id);
387 for (
const auto & [side, bnd] :
sides)
389 bnd_info.remove_side(elem, side, bnd);
392 remove_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
398 for (
const auto & [side, bnd] :
sides)
399 bnd_info.add_side(
mesh.elemPtr(elem_id), side, bnd);
404 auto elem =
mesh.elemPtr(elem_id);
405 for (
const auto & [side, bnd] :
sides)
407 bnd_info.add_side(elem, side, bnd);
410 add_ghost_sides[elem->processor_id()].push_back({elem_id, side, bnd});
414 Parallel::push_parallel_vector_data(
419 const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
421 for (
const auto & [elem_id, side, bnd] : received)
422 bnd_info.add_side(
mesh.elemPtr(elem_id), side, bnd);
425 Parallel::push_parallel_vector_data(
430 const std::vector<std::tuple<dof_id_type, unsigned short, BoundaryID>> & received)
432 for (
const auto & [elem_id, side, bnd] : received)
433 bnd_info.remove_side(
mesh.elemPtr(elem_id), side, bnd);
436 bnd_info.parallel_sync_side_ids();
437 bnd_info.parallel_sync_node_ids();
458 auto & bnd_info =
mesh.getMesh().get_boundary_info();
459 auto sidesets = bnd_info.get_sideset_map();
460 for (
const auto & i : sidesets)
463 auto side = i.second.first;
464 auto bnd = i.second.second;
467 bnd_info.remove_side(elem, side, bnd);
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);
476 bnd_info.parallel_sync_side_ids();
477 bnd_info.parallel_sync_node_ids();
482 const std::unordered_map<
dof_id_type, std::pair<SubdomainID, SubdomainID>> & moved_elems)
488 for (
const auto & [elem_id, subdomain] : moved_elems)
490 mooseAssert(
_mesh.
elemPtr(elem_id)->active(),
"Moved elements should be active");
498 const auto & [from, to] = subdomain;
510 for (
unsigned int i = 0; i < elem->n_nodes(); ++i)
549 "This code was written for a single nonlinear system");
578 std::vector<Elem *> elems;
583 Elem *
const * elem_itr_begin =
const_cast<Elem *
const *
>(elems.data());
584 Elem *
const * elem_itr_end = elem_itr_begin + elems.size();
586 const auto elems_begin = MeshBase::const_element_iterator(
588 const auto elems_end = MeshBase::const_element_iterator(
609 std::vector<const BndNode *> nodes;
612 for (
auto bnd_node : *bnd_nodes)
615 nodes.push_back(bnd_node);
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();
628 std::make_unique<ConstBndNodeRange>(bnd_nodes_begin, bnd_nodes_end);
631 std::make_unique<ConstBndNodeRange>(bnd_nodes_begin, bnd_nodes_end);
650 DofMap & dof_map = sys.
dofMap();
651 std::vector<dof_id_type> dofs;
653 for (
auto & elem : elem_range)
655 std::vector<dof_id_type> elem_dofs;
657 dofs.insert(dofs.end(), elem_dofs.begin(), elem_dofs.end());
660 for (
auto & bnd_node : bnd_node_range)
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());
668 for (
auto dof : dofs)
670 old_solution.
set(dof, current_solution(dof));
672 older_solution->
set(dof, current_solution(dof));
675 old_solution.
close();
677 older_solution->
close();
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.
virtual Elem * elemPtr(const dof_id_type i)
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...
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
void gatherMovingBoundaryChanges(const std::unordered_map< dof_id_type, std::pair< SubdomainID, SubdomainID >> &moved_elems)
The definition of the const_bnd_node_iterator struct.
NumericVector< Number > & solutionOlder()
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)
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.
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 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
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.
void createMovingBoundaries(MooseMesh &mesh)
Create moving boundaries.
static InputParameters validParams()
void gatherSum(T &value)
Gather the parallel sum of the variable passed in.
ConstElemRange & reinitializedElemRange(bool displaced=false)
Range of reinitialized elements.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
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...
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.
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).
void paramError(const std::string ¶m, 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.
AuxiliarySystem & getAuxiliarySystem()
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
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.
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.
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()
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()
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 ¶meters)
const bool _old_subdomain_reinitialized
Whether to reinitialize moved elements whose old subdomain was in _reinitialize_subdomains.
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...
const std::set< SubdomainID > & meshSubdomains() const
Returns a read-only reference to the set of subdomains currently present in the Mesh.
SubdomainID getSubdomainID(const SubdomainName &subdomain_name) const
Get the associated subdomain ID for the subdomain name.
const RemoteElem * remote_elem