www.mooseframework.org
ElementDeleterBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
10 #include "ElementDeleterBase.h"
11 #include "MooseMesh.h"
12 
13 #include "libmesh/remote_elem.h"
14 
15 template <>
18 {
20  params.addParam<BoundaryName>("new_boundary",
21  "optional boundary name to assign to the cut surface");
22  return params;
23 }
24 
26  : MeshModifier(parameters),
27  _assign_boundary(isParamValid("new_boundary")),
28  _boundary_name(_assign_boundary ? getParam<BoundaryName>("new_boundary") : "")
29 {
30 }
31 
32 void
34 {
35  libmesh_assert(this->comm().verify(this->name()));
36 
37  // Check that we have access to the mesh
38  if (!_mesh_ptr)
39  mooseError("_mesh_ptr must be initialized before calling ElementDeleterBase::modify()");
40 
41  MeshBase & mesh = _mesh_ptr->getMesh();
42 
43  // Elements that the deleter will remove
44  std::set<Elem *> deleteable_elems;
45 
46  // First let's figure out which elements need to be deleted
47  for (auto & elem : mesh.element_ptr_range())
48  {
49  if (shouldDelete(elem))
50  deleteable_elems.insert(elem);
51  }
52 
57 #ifdef DEBUG
58  dof_id_type pmax_elem_id = mesh.max_elem_id();
59  mesh.comm().max(pmax_elem_id);
60 
61  for (dof_id_type i = 0; i != pmax_elem_id; ++i)
62  {
63  Elem * elem = mesh.query_elem_ptr(i);
64  bool is_deleteable = elem && deleteable_elems.count(elem);
65 
66  libmesh_assert(mesh.comm().semiverify(elem ? &is_deleteable : libmesh_nullptr));
67  }
68 #endif
69 
70  // Get the BoundaryID from the mesh
71  BoundaryID boundary_id = 0;
72  if (_assign_boundary)
73  boundary_id = _mesh_ptr->getBoundaryIDs({_boundary_name}, true)[0];
74 
75  // Get a reference to our BoundaryInfo object for later use
76  BoundaryInfo & boundary_info = mesh.get_boundary_info();
77 
85  for (auto & elem : deleteable_elems)
86  {
87  // On distributed meshes, we'll need neighbor links to be useable
88  // shortly, so we can't just leave dangling pointers.
89  //
90  // FIXME - this could be made AMR-aware and refactored into
91  // libMesh - roystgnr
92  unsigned int n_sides = elem->n_sides();
93  for (unsigned int n = 0; n != n_sides; ++n)
94  {
95  Elem * neighbor = elem->neighbor_ptr(n);
96  if (!neighbor || neighbor == remote_elem)
97  continue;
98 
99  const unsigned int return_side = neighbor->which_neighbor_am_i(elem);
100 
101  if (neighbor->neighbor_ptr(return_side) == elem)
102  {
103  neighbor->set_neighbor(return_side, nullptr);
104 
105  // assign cut surface boundary
106  if (_assign_boundary)
107  boundary_info.add_side(neighbor, return_side, boundary_id);
108  }
109  }
110 
111  mesh.delete_elem(elem);
112  }
113 
120  if (!mesh.is_serial())
121  {
122  const processor_id_type my_n_proc = mesh.n_processors();
123  const processor_id_type my_proc_id = mesh.processor_id();
124  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
125  std::vector<vec_type> queries(my_n_proc);
126 
127  // Loop over the elements looking for those with remote neighbors.
128  // The ghost_elements iterators in libMesh need to be updated
129  // before we can use them safely here, so we'll test for
130  // ghost-vs-local manually.
131  for (const auto & elem : mesh.element_ptr_range())
132  {
133  const processor_id_type pid = elem->processor_id();
134  if (pid == my_proc_id)
135  continue;
136 
137  const unsigned int n_sides = elem->n_sides();
138  for (unsigned int n = 0; n != n_sides; ++n)
139  if (elem->neighbor_ptr(n) == remote_elem)
140  queries[pid].push_back(std::make_pair(elem->id(), n));
141  }
142 
143  Parallel::MessageTag queries_tag = mesh.comm().get_unique_tag(42),
144  replies_tag = mesh.comm().get_unique_tag(6 * 9);
145 
146  std::vector<Parallel::Request> query_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
147 
148  // Make all requests
149  for (processor_id_type p = 0; p != my_n_proc; ++p)
150  {
151  if (p == my_proc_id)
152  continue;
153 
154  Parallel::Request & request = query_requests[p - (p > my_proc_id)];
155 
156  mesh.comm().send(p, queries[p], request, queries_tag);
157  }
158 
159  // Reply to all requests
160  std::vector<vec_type> responses(my_n_proc - 1);
161 
162  for (processor_id_type p = 1; p != my_n_proc; ++p)
163  {
164  vec_type query;
165 
166  Parallel::Status status(mesh.comm().probe(Parallel::any_source, queries_tag));
167  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
168 
169  mesh.comm().receive(source_pid, query, queries_tag);
170 
171  Parallel::Request & request = reply_requests[p - 1];
172 
173  for (const auto & q : query)
174  {
175  const Elem * elem = mesh.elem_ptr(q.first);
176  const unsigned int side = q.second;
177  const Elem * neighbor = elem->neighbor_ptr(side);
178 
179  if (neighbor == nullptr) // neighboring element was deleted!
180  responses[p - 1].push_back(std::make_pair(elem->id(), side));
181  }
182 
183  mesh.comm().send(source_pid, responses[p - 1], request, replies_tag);
184  }
185 
186  // Process all incoming replies
187  for (processor_id_type p = 1; p != my_n_proc; ++p)
188  {
189  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
190  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
191 
192  vec_type response;
193 
194  this->comm().receive(source_pid, response, replies_tag);
195 
196  for (const auto & r : response)
197  {
198  Elem * elem = mesh.elem_ptr(r.first);
199  const unsigned int side = r.second;
200 
201  mooseAssert(elem->neighbor_ptr(side) == remote_elem, "element neighbor != remote_elem");
202 
203  elem->set_neighbor(side, nullptr);
204 
205  // assign cut surface boundary
206  if (_assign_boundary)
207  boundary_info.add_side(elem, side, boundary_id);
208  }
209  }
210 
211  Parallel::wait(query_requests);
212  Parallel::wait(reply_requests);
213  }
214 
215  if (_assign_boundary)
216  {
217  boundary_info.sideset_name(boundary_id) = _boundary_name;
218  boundary_info.nodeset_name(boundary_id) = _boundary_name;
219  }
220 
227  mesh.contract();
229 }
const bool _assign_boundary
Assign a boundary name to the cut surface?
InputParameters validParams< ElementDeleterBase >()
void needsPrepareForUse()
If this method is called, we will call libMesh&#39;s prepare_for_use method when we call Moose&#39;s prepare ...
Definition: MooseMesh.C:2310
MeshModifiers are objects that can modify or add to an existing mesh.
Definition: MeshModifier.h:25
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
void mooseError(Args &&... args) const
Definition: MooseObject.h:147
MooseMesh * _mesh_ptr
Pointer to the mesh.
Definition: MeshModifier.h:68
virtual void modify() override
Pure virtual modify function MUST be overridden by children classes.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
Definition: MooseMesh.C:2567
boundary_id_type BoundaryID
PetscInt n
MPI_Comm comm
const std::string & name() const
Get the name of the object.
Definition: MooseObject.h:59
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:2153
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
ElementDeleterBase(const InputParameters &parameters)
virtual bool shouldDelete(const Elem *elem)=0
Method that returns a Boolean indicating whether an element should be removed from the mesh...
InputParameters validParams< MeshModifier >()
Definition: MeshModifier.C:15
const BoundaryName _boundary_name
Name of the boundary name to assign to the cut surface.