https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ActivateElementsUserObjectBase.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
13#include "libmesh/quadrature.h"
14#include "libmesh/parallel_algebra.h"
15#include "libmesh/parallel.h"
16#include "libmesh/point.h"
17#include "libmesh/dof_map.h"
18
19#include "libmesh/parallel_ghost_sync.h"
20#include "libmesh/mesh_communication.h"
21
24{
26 params.addClassDescription("Determine activated elements.");
27 params.addRequiredParam<subdomain_id_type>("active_subdomain_id", "The active subdomain ID.");
28 params.addParam<subdomain_id_type>(
29 "inactive_subdomain_id",
31 "The inactivate subdomain ID, i.e., the subdomain that you want to keep the same.");
32 params.addRequiredParam<std::vector<BoundaryName>>("expand_boundary_name",
33 "The expanded boundary name.");
34 params.registerBase("MeshModifier");
35 return params;
36}
37
39 : ElementUserObject(parameters),
40 _active_subdomain_id(declareRestartableData<subdomain_id_type>(
41 "active_subdomain_id", getParam<subdomain_id_type>("active_subdomain_id"))),
42 _inactive_subdomain_id(declareRestartableData<subdomain_id_type>(
43 "inactive_subdomain_id", getParam<subdomain_id_type>("inactive_subdomain_id"))),
44 _expand_boundary_name(getParam<std::vector<BoundaryName>>("expand_boundary_name"))
45{
47}
48
49void
51{
52 mooseAssert(!_expand_boundary_name.empty(), "Expanded boundary name is empty");
53 // add the new boundary and get its boundary id
55 mooseAssert(!_boundary_ids.empty(), "Boundary ID is empty.");
57 _mesh.getMesh().get_boundary_info().sideset_name(_boundary_ids[0]) = _expand_boundary_name[0];
58 _mesh.getMesh().get_boundary_info().nodeset_name(_boundary_ids[0]) = _expand_boundary_name[0];
59
62 {
63 _disp_boundary_ids = displaced_problem->mesh().getBoundaryIDs(_expand_boundary_name, true);
64 mooseAssert(!_disp_boundary_ids.empty(), "Boundary ID in the displaced mesh is empty");
65
66 displaced_problem->mesh().setBoundaryName(_disp_boundary_ids[0], _expand_boundary_name[0]);
67 displaced_problem->mesh().getMesh().get_boundary_info().sideset_name(_disp_boundary_ids[0]) =
69 displaced_problem->mesh().getMesh().get_boundary_info().nodeset_name(_disp_boundary_ids[0]) =
71 }
72}
73
74void
76{
77 if (isElementActivated() && _current_elem->subdomain_id() != _active_subdomain_id &&
78 _current_elem->subdomain_id() != _inactive_subdomain_id)
79 {
80 /*
81 _current_elem subdomain id is not assignable
82 create a copy of this element from MooseMesh
83 */
84 dof_id_type ele_id = _current_elem->id();
85 Elem * ele = _mesh.elemPtr(ele_id);
86
87 // Add element to the activate subdomain
88 ele->subdomain_id() = _active_subdomain_id;
89
90 // Reassign element in the reference mesh while using a displaced mesh
93 {
94 Elem * disp_ele = displaced_problem->mesh().elemPtr(ele_id);
95 disp_ele->subdomain_id() = _active_subdomain_id;
96 }
97
98 // Save the newly activated element id and node for updating boundary info later
99 _newly_activated_elem.insert(ele_id);
100 for (unsigned int i = 0; i < ele->n_nodes(); ++i)
101 _newly_activated_node.insert(ele->node_id(i));
102 }
103}
104
105void
107{
108 /*
109 Synchronize ghost element subdomain ID
110 Note: this needs to be done before updating boundary info because
111 updating boundary requires the updated element subdomain ids
112 */
114 Parallel::sync_dofobject_data_by_id(_mesh.getMesh().comm(),
115 _mesh.getMesh().elements_begin(),
116 _mesh.getMesh().elements_end(),
117 sync);
118 // Update boundary info
120
121 // Similarly for the displaced mesh
124 {
125 libMesh::SyncSubdomainIds sync_mesh(displaced_problem->mesh().getMesh());
126 Parallel::sync_dofobject_data_by_id(displaced_problem->mesh().getMesh().comm(),
127 displaced_problem->mesh().getMesh().elements_begin(),
128 displaced_problem->mesh().getMesh().elements_end(),
129 sync_mesh);
131 }
132
133 // Reinit equation systems
135 /*intermediate_change=*/false, /*contract_mesh=*/false, /*clean_refinement_flags=*/false);
136
137 // Get storage ranges for the newly activated elements and boundary nodes
138 ConstElemRange & elem_range = *this->getNewlyActivatedElementRange();
139 ConstBndNodeRange & bnd_node_range = *this->getNewlyActivatedBndNodeRange();
140
141 // Apply initial condition for the newly activated elements
142 initSolutions(elem_range, bnd_node_range);
143
144 // Initialize stateful material properties for the newly activated elements
145 _fe_problem.initElementStatefulProps(elem_range, false);
146
147 // Clear the list
148 _newly_activated_elem.clear();
149 _newly_activated_node.clear();
150
152}
153
154void
156 std::set<dof_id_type> & add_set)
157{
158 // get the difference between the remove_set and the add_set,
159 // save the difference in _node_to_remove_from_bnd
160 int sz = remove_set.size() + add_set.size();
161 std::vector<dof_id_type> v(sz);
162 std::vector<dof_id_type>::iterator it = std::set_difference(
163 remove_set.begin(), remove_set.end(), add_set.begin(), add_set.end(), v.begin());
164 v.resize(it - v.begin());
166 for (auto id : v)
167 _node_to_remove_from_bnd.insert(id);
168}
169
170void
172 const unsigned short int side,
173 std::set<dof_id_type> & node_ids)
174{
175 for (unsigned int i = 0; i < ele->side_ptr(side)->n_nodes(); ++i)
176 node_ids.insert(ele->side_ptr(side)->node_id(i));
177}
178
179void
181{
182 // save the removed ghost sides and associated nodes to sync across processors
183 std::unordered_map<processor_id_type, std::vector<std::pair<dof_id_type, unsigned int>>>
184 ghost_sides_to_remove;
185 std::unordered_map<processor_id_type, std::vector<dof_id_type>> ghost_nodes_to_remove;
186
187 // save nodes are added and removed
188 std::set<dof_id_type> add_nodes, remove_nodes;
189
190 for (auto ele_id : _newly_activated_elem)
191 {
192 Elem * ele = mesh.elemPtr(ele_id);
193 for (auto s : ele->side_index_range())
194 {
195 Elem * neighbor_ele = ele->neighbor_ptr(s);
196 if (neighbor_ele == nullptr)
197 {
198 // add this side to boundary
199 mesh.getMesh().get_boundary_info().add_side(ele, s, _boundary_ids[0]);
200 insertNodeIdsOnSide(ele, s, add_nodes);
201 }
202 else
203 {
204 if (neighbor_ele->subdomain_id() != _active_subdomain_id &&
205 neighbor_ele->subdomain_id() != _inactive_subdomain_id)
206 {
207 // add this side to boundary
208 mesh.getMesh().get_boundary_info().add_side(ele, s, _boundary_ids[0]);
209 insertNodeIdsOnSide(ele, s, add_nodes);
210 }
211 else
212 {
213 // remove this side from the boundary
214 mesh.getMesh().get_boundary_info().remove_side(ele, s);
215 insertNodeIdsOnSide(ele, s, remove_nodes);
216
217 // remove the neighbor side from the boundary
218 unsigned int neighbor_s = neighbor_ele->which_neighbor_am_i(ele);
219 mesh.getMesh().get_boundary_info().remove_side(neighbor_ele, neighbor_s);
220 insertNodeIdsOnSide(neighbor_ele, neighbor_s, remove_nodes);
221
222 if (neighbor_ele->processor_id() != this->processor_id())
223 ghost_sides_to_remove[neighbor_ele->processor_id()].emplace_back(neighbor_ele->id(),
224 neighbor_s);
225 }
226 }
227 }
228 }
229 // make sure to remove nodes that are not in the add list
230 getNodesToRemoveFromBnd(remove_nodes, add_nodes);
231 for (auto node_id : _node_to_remove_from_bnd)
232 mesh.getMesh().get_boundary_info().remove_node(mesh.nodePtr(node_id), _boundary_ids[0]);
233
234 // synchronize boundary information across processors
235 push_boundary_side_info(mesh, ghost_sides_to_remove);
236 push_boundary_node_info(mesh, ghost_nodes_to_remove);
237 mesh.getMesh().get_boundary_info().parallel_sync_side_ids();
238 mesh.getMesh().get_boundary_info().parallel_sync_node_ids();
239 mesh.update();
240}
241
242void
244 MooseMesh & mesh,
245 std::unordered_map<processor_id_type, std::vector<std::pair<dof_id_type, unsigned int>>> &
246 elems_to_push)
247{
248 auto elem_action_functor =
249 [&mesh, this](processor_id_type,
250 const std::vector<std::pair<dof_id_type, unsigned int>> & received_elem)
251 {
252 // remove the side
253 for (const auto & pr : received_elem)
254 mesh.getMesh().get_boundary_info().remove_side(
255 mesh.getMesh().elem_ptr(pr.first), pr.second, this->getExpandedBoundaryID());
256 };
257
258 Parallel::push_parallel_vector_data(
259 mesh.getMesh().get_boundary_info().comm(), elems_to_push, elem_action_functor);
260}
261
262void
264 MooseMesh & mesh,
265 std::unordered_map<processor_id_type, std::vector<dof_id_type>> & nodes_to_push)
266{
267 auto node_action_functor =
268 [&mesh, this](processor_id_type, const std::vector<dof_id_type> & received_nodes)
269 {
270 for (const auto & pr : received_nodes)
271 {
272 // remove the node
273 mesh.getMesh().get_boundary_info().remove_node(mesh.getMesh().node_ptr(pr),
274 this->getExpandedBoundaryID());
275 }
276 };
277
278 Parallel::push_parallel_vector_data(
279 mesh.getMesh().get_boundary_info().comm(), nodes_to_push, node_action_functor);
280}
281
282ConstElemRange *
284{
285 // deletes the object first
286 _activated_elem_range.reset();
287
288 // create a vector of the newly activated elements
289 std::vector<Elem *> elems;
290 for (auto elem_id : _newly_activated_elem)
291 elems.push_back(_mesh.elemPtr(elem_id));
292
293 // Make some fake element iterators defining this vector of
294 // elements
295 Elem * const * elempp = const_cast<Elem * const *>(elems.data());
296 Elem * const * elemend = elempp + elems.size();
297
298 const auto elems_begin =
299 MeshBase::const_element_iterator(elempp, elemend, Predicates::NotNull<Elem * const *>());
300
301 const auto elems_end =
302 MeshBase::const_element_iterator(elemend, elemend, Predicates::NotNull<Elem * const *>());
304 _activated_elem_range = std::make_unique<ConstElemRange>(elems_begin, elems_end);
305
306 return _activated_elem_range.get();
307}
308
311{
312 // deletes the object first
314
315 // create a vector of the newly activated nodes
316 std::vector<const BndNode *> nodes;
317 std::set<const BndNode *> set_nodes;
319 for (auto & bnode : bnd_nodes)
320 {
321 dof_id_type bnode_id = bnode->_node->id();
322 auto it = _newly_activated_node.find(bnode_id);
323 if (it != _newly_activated_node.end())
324 set_nodes.insert(bnode);
325 }
326
327 nodes.assign(set_nodes.begin(), set_nodes.end());
328
329 // Make some fake element iterators defining this vector of
330 // nodes
331 BndNode * const * nodepp = const_cast<BndNode * const *>(nodes.data());
332 BndNode * const * nodeend = nodepp + nodes.size();
333
334 const auto nodes_begin =
336
337 const auto nodes_end = MooseMesh::const_bnd_node_iterator(
338 nodeend, nodeend, Predicates::NotNull<BndNode * const *>());
339
341 _activated_bnd_node_range = std::make_unique<ConstBndNodeRange>(nodes_begin, nodes_end);
342
343 return _activated_bnd_node_range.get();
344}
345
346ConstNodeRange *
348{
349 // deletes the object first
350 _activated_node_range.reset();
351
352 // create a vector of the newly activated nodes
353 std::vector<const Node *> nodes;
354 for (auto elem_id : _newly_activated_elem)
355 {
356 const Node * const * elem_nodes = _mesh.elemPtr(elem_id)->get_nodes();
357 unsigned int n_nodes = _mesh.elemPtr(elem_id)->n_nodes();
358 for (unsigned int n = 0; n < n_nodes; ++n)
359 {
360 // check if all the elements connected to this node are newly activated
361 const Node * nd = elem_nodes[n];
362 if (isNewlyActivated(nd))
363 nodes.push_back(nd);
364 }
365 }
366
367 // Make some fake node iterators defining this vector of
368 // nodes
369 Node * const * nodepp = const_cast<Node * const *>(nodes.data());
370 Node * const * nodeend = nodepp + nodes.size();
371
372 const auto nodes_begin =
373 MeshBase::const_node_iterator(nodepp, nodeend, Predicates::NotNull<Node * const *>());
374
375 const auto nodes_end =
376 MeshBase::const_node_iterator(nodeend, nodeend, Predicates::NotNull<Node * const *>());
377
379 _activated_node_range = std::make_unique<ConstNodeRange>(nodes_begin, nodes_end);
380
381 return _activated_node_range.get();
382}
383
384bool
386{
387 const auto & node_to_elem_map = _mesh.nodeToElemMap();
388 auto node_to_elem_pair = node_to_elem_map.find(nd->id());
389 if (node_to_elem_pair != node_to_elem_map.end())
390 {
391 const std::vector<dof_id_type> & connected_ele_ids = node_to_elem_pair->second;
392 for (auto connected_ele_id : connected_ele_ids)
393 {
394 // check the connected elements
395 if (_mesh.elemPtr(connected_ele_id)->subdomain_id() == _inactive_subdomain_id)
396 return false;
397 if (_mesh.elemPtr(connected_ele_id)->subdomain_id() == _active_subdomain_id &&
398 std::find(_newly_activated_elem.begin(), _newly_activated_elem.end(), connected_ele_id) ==
400 return false;
401 }
402 }
403 return true;
404}
405
406void
408 ConstBndNodeRange & bnd_node_range)
409{
410 // project initial condition to the current solution
411 _fe_problem.projectInitialConditionOnCustomRange(elem_range, bnd_node_range);
412
414 NumericVector<Number> & current_solution = *nl.system().current_local_solution;
415 NumericVector<Number> & old_solution = nl.solutionOld();
416 NumericVector<Number> & older_solution = nl.solutionOlder();
417
418 NumericVector<Number> & current_aux_solution =
420 NumericVector<Number> & old_aux_solution = _fe_problem.getAuxiliarySystem().solutionOld();
421 NumericVector<Number> & older_aux_solution = _fe_problem.getAuxiliarySystem().solutionOlder();
422
423 DofMap & dof_map = nl.dofMap();
424 DofMap & dof_map_aux = _fe_problem.getAuxiliarySystem().dofMap();
425
426 std::set<dof_id_type> dofs, dofs_aux;
427 // get dofs for the newly added elements
428 for (auto & elem : elem_range)
429 {
430 std::vector<dof_id_type> di, di_aux;
431 dof_map.dof_indices(elem, di);
432 dof_map_aux.dof_indices(elem, di_aux);
433 for (unsigned int i = 0; i < di.size(); ++i)
434 dofs.insert(di[i]);
435 for (unsigned int i = 0; i < di_aux.size(); ++i)
436 dofs_aux.insert(di_aux[i]);
437
438 di.clear();
439 di_aux.clear();
440 }
441
442 // update solutions
443 for (auto dof : dofs)
444 {
445 old_solution.set(dof, current_solution(dof));
446 older_solution.set(dof, current_solution(dof));
447 }
448 // update aux solutions
449 for (auto dof_aux : dofs_aux)
450 {
451 old_aux_solution.set(dof_aux, current_aux_solution(dof_aux));
452 older_aux_solution.set(dof_aux, current_aux_solution(dof_aux));
453 }
454
455 dofs.clear();
456 dofs_aux.clear();
457
458 current_solution.close();
459 old_solution.close();
460 older_solution.close();
461
462 current_aux_solution.close();
463 old_aux_solution.close();
464 older_aux_solution.close();
465
467}
std::shared_ptr< DisplacedProblem > displaced_problem
std::unique_ptr< ConstBndNodeRange > _activated_bnd_node_range
void getNodesToRemoveFromBnd(std::set< dof_id_type > &remove_set, std::set< dof_id_type > &add_set)
void insertNodeIdsOnSide(const Elem *ele, const unsigned short int side, std::set< dof_id_type > &node_ids)
void initSolutions(ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range)
Initialize solutions for the nodes.
std::set< dof_id_type > _node_to_remove_from_bnd
Somes nodes are to be removed from the boundary when adding/removing sides.
void push_boundary_side_info(MooseMesh &mesh, std::unordered_map< processor_id_type, std::vector< std::pair< dof_id_type, unsigned int > > > &elems_to_push)
void push_boundary_node_info(MooseMesh &mesh, std::unordered_map< processor_id_type, std::vector< dof_id_type > > &nodes_to_push)
ConstElemRange * getNewlyActivatedElementRange()
Get ranges for use with threading.
std::unique_ptr< ConstNodeRange > _activated_node_range
virtual bool isElementActivated()=0
bool isNewlyActivated(const Node *node)
Returns true if all the connected elements are in the _newly_activated_elem.
const subdomain_id_type _active_subdomain_id
activate subdomain ID
std::vector< BoundaryID > _boundary_ids
expanded boundary IDs
const subdomain_id_type _inactive_subdomain_id
inactivate subdomain ID (the subdomain that you want to keep the same)
const std::vector< BoundaryName > _expand_boundary_name
expanded boundary name
std::unique_ptr< ConstElemRange > _activated_elem_range
Ranges for use with threading.
ActivateElementsUserObjectBase(const InputParameters &parameters)
virtual libMesh::System & system() override
Get the reference to the libMesh system.
static InputParameters validParams()
const Elem *const & _current_elem
The current element pointer (available during execute())
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()
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...
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
virtual void restoreSolutions()
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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 addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
void registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
void setBoundaryName(BoundaryID boundary_id, BoundaryName name)
This method sets the boundary name of the boundary based on the id parameter.
Definition MooseMesh.C:1768
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
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< 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
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition MooseMesh.C:1285
virtual libMesh::System & system() override
Get the reference to the libMesh system.
unsigned int number() const
Gets the number of this system.
NumericVector< Number > & solutionOld()
Definition SystemBase.h:204
NumericVector< Number > & solutionOlder()
Definition SystemBase.h:205
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
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
StoredRange< iterator_type, object_type > & reset(const iterator_type &first, const iterator_type &last)
std::unique_ptr< NumericVector< Number > > current_local_solution
MeshBase & mesh
const unsigned int invalid_uint
The definition of the const_bnd_node_iterator struct.
Definition MooseMesh.h:2191
const dof_id_type n_nodes