https://mooseframework.inl.gov
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.");
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 
49 void
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 
74 void
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 
105 void
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
123  if (displaced_problem)
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 
151  _node_to_remove_from_bnd.clear();
152 }
153 
154 void
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());
165  _node_to_remove_from_bnd.clear();
166  for (auto id : v)
167  _node_to_remove_from_bnd.insert(id);
168 }
169 
170 void
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 
179 void
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 
242 void
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 
262 void
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 
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 
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 
384 bool
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) ==
399  _newly_activated_elem.end())
400  return false;
401  }
402  }
403  return true;
404 }
405 
406 void
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 =
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 }
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
std::set< dof_id_type > _node_to_remove_from_bnd
Somes nodes are to be removed from the boundary when adding/removing sides.
std::unique_ptr< ConstBndNodeRange > _activated_bnd_node_range
void getNodesToRemoveFromBnd(std::set< dof_id_type > &remove_set, std::set< dof_id_type > &add_set)
std::shared_ptr< DisplacedProblem > displaced_problem
const unsigned int invalid_uint
std::unique_ptr< ConstElemRange > _activated_elem_range
Ranges for use with threading.
void push_boundary_node_info(MooseMesh &mesh, std::unordered_map< processor_id_type, std::vector< dof_id_type >> &nodes_to_push)
virtual Elem * elemPtr(const dof_id_type i)
Definition: MooseMesh.C:3108
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
static InputParameters validParams()
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const std::vector< BoundaryName > _expand_boundary_name
expanded boundary name
The definition of the const_bnd_node_iterator struct.
Definition: MooseMesh.h:2011
NumericVector< Number > & solutionOlder()
Definition: SystemBase.h:197
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...
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 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 registerBase(const std::string &value)
This method must be called from every base "Moose System" to create linkage with the Action System...
virtual bool isElementActivated()=0
void execute() override
Execute method.
uint8_t processor_id_type
std::vector< BoundaryID > _boundary_ids
expanded boundary IDs
virtual libMesh::DofMap & dofMap()
Gets writeable reference to the dof map.
Definition: SystemBase.C:1165
ActivateElementsUserObjectBase(const InputParameters &parameters)
const dof_id_type n_nodes
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:3443
const subdomain_id_type _active_subdomain_id
activate subdomain ID
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition: MooseMesh.h:88
virtual void restoreSolutions()
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
SystemBase & _sys
Reference to the system object for this user object.
Definition: UserObject.h:215
void insertNodeIdsOnSide(const Elem *ele, const unsigned short int side, std::set< dof_id_type > &node_ids)
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1159
AuxiliarySystem & getAuxiliarySystem()
virtual void close()=0
void setBoundaryName(BoundaryID boundary_id, BoundaryName name)
This method sets the boundary name of the boundary based on the id parameter.
Definition: MooseMesh.C:1775
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
const Elem *const & _current_elem
The current element pointer (available during execute())
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
Definition: UserObject.h:211
ConstElemRange * getNewlyActivatedElementRange()
Get ranges for use with threading.
std::unique_ptr< ConstNodeRange > _activated_node_range
const subdomain_id_type _inactive_subdomain_id
inactivate subdomain ID (the subdomain that you want to keep the same)
std::unique_ptr< NumericVector< Number > > current_local_solution
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...
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 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 initSolutions(ConstElemRange &elem_range, ConstBndNodeRange &bnd_node_range)
Initialize solutions for the nodes.
virtual void set(const numeric_index_type i, const Number value)=0
virtual libMesh::System & system() override
Get the reference to the libMesh system.
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. ...
NumericVector< Number > & solutionOld()
Definition: SystemBase.h:196
processor_id_type processor_id() const
bool isNewlyActivated(const Node *node)
Returns true if all the connected elements are in the _newly_activated_elem.
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
Definition: MooseMesh.C:1286
uint8_t dof_id_type
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
If not already created, creates a map from every node to all elements to which they are connected...
Definition: MooseMesh.C:1175