https://mooseframework.inl.gov
ElementDeletionGeneratorBase.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 "libmesh/remote_elem.h"
12 
13 #include "MooseMeshUtils.h"
14 #include "CastUniquePointer.h"
15 
18 {
20 
21  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
22  params.addParam<bool>("delete_exteriors",
23  true,
24  "Whether to delete lower-d elements whose interior parents are deleted");
25  params.addParam<BoundaryName>("new_boundary",
26  "optional boundary name to assign to the cut surface");
27 
28  return params;
29 }
30 
32  : MeshGenerator(parameters),
33  _input(getMesh("input")),
34  _assign_boundary(isParamValid("new_boundary")),
35  _delete_exteriors(getParam<bool>("delete_exteriors")),
36  _boundary_name(_assign_boundary ? getParam<BoundaryName>("new_boundary") : "")
37 {
38 }
39 
40 std::unique_ptr<MeshBase>
42 {
43  std::unique_ptr<MeshBase> mesh = std::move(_input);
44 
45  // Make sure that the mesh is prepared. We'll just do a full
46  // prepare_for_use() here, since we expect to be able to use
47  // neighbor pointers, multiple caches, *and* on distributed meshes a
48  // load-balanced partitioning.
49  if (!mesh->is_prepared())
50  mesh->prepare_for_use();
51 
52  // Elements that the deleter will remove
53  std::set<Elem *> deleteable_elems;
54 
55  // First let's figure out which elements need to be deleted
56  for (auto & elem : mesh->element_ptr_range())
57  {
58  if (shouldDelete(elem))
59  deleteable_elems.insert(elem);
60  }
61 
62  // check for dangling interior parents
63  for (auto & elem : mesh->element_ptr_range())
64  if (elem->dim() < mesh->mesh_dimension() && deleteable_elems.count(elem->interior_parent()) > 0)
65  {
67  deleteable_elems.insert(elem);
68  else
69  elem->set_interior_parent(nullptr);
70  }
71 
76 #ifdef DEBUG
77  dof_id_type pmax_elem_id = mesh->max_elem_id();
78  mesh->comm().max(pmax_elem_id);
79 
80  for (dof_id_type i = 0; i != pmax_elem_id; ++i)
81  {
82  Elem * elem = mesh->query_elem_ptr(i);
83  bool is_deleteable = elem && deleteable_elems.count(elem);
84 
85  libmesh_assert(mesh->comm().semiverify(elem ? &is_deleteable : libmesh_nullptr));
86  }
87 #endif
88 
89  // Get the BoundaryID from the mesh
90  boundary_id_type boundary_id = 0;
91  if (_assign_boundary)
92  boundary_id = MooseMeshUtils::getBoundaryIDs(*mesh, {_boundary_name}, true)[0];
93 
94  // Get a reference to our BoundaryInfo object for later use
95  BoundaryInfo & boundary_info = mesh->get_boundary_info();
96 
104  for (auto & elem : deleteable_elems)
105  {
106  // On distributed meshes, we'll need neighbor links to be useable
107  // shortly, so we can't just leave dangling pointers.
108  //
109  // FIXME - this could be made AMR-aware and refactored into
110  // libMesh - roystgnr
111  unsigned int n_sides = elem->n_sides();
112  for (unsigned int n = 0; n != n_sides; ++n)
113  {
114  Elem * neighbor = elem->neighbor_ptr(n);
115  if (!neighbor || neighbor == remote_elem)
116  continue;
117 
118  const unsigned int return_side = neighbor->which_neighbor_am_i(elem);
119 
120  if (neighbor->neighbor_ptr(return_side) == elem)
121  {
122  neighbor->set_neighbor(return_side, nullptr);
123 
124  // assign cut surface boundary
125  if (_assign_boundary)
126  boundary_info.add_side(neighbor, return_side, boundary_id);
127  }
128  }
129 
130  mesh->delete_elem(elem);
131  }
132 
139  if (!mesh->is_serial())
140  {
141  const processor_id_type my_n_proc = mesh->n_processors();
142  const processor_id_type my_proc_id = mesh->processor_id();
143  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
144  std::vector<vec_type> queries(my_n_proc);
145 
146  // Loop over the elements looking for those with remote neighbors
147  // or interior parents.
148  // The ghost_elements iterators in libMesh need to be updated
149  // before we can use them safely here, so we'll test for
150  // ghost-vs-local manually.
151  for (const auto & elem : mesh->element_ptr_range())
152  {
153  const processor_id_type pid = elem->processor_id();
154  if (pid == my_proc_id)
155  continue;
156 
157  const unsigned int n_sides = elem->n_sides();
158  for (unsigned int n = 0; n != n_sides; ++n)
159  if (elem->neighbor_ptr(n) == remote_elem)
160  queries[pid].push_back(std::make_pair(elem->id(), n));
161 
162  // Use an OOB side index to encode "interior_parent". We will use this OOB index later
163  if (elem->interior_parent() == remote_elem)
164  queries[pid].push_back(std::make_pair(elem->id(), n_sides));
165  }
166 
167  const auto queries_tag = mesh->comm().get_unique_tag(),
168  replies_tag = mesh->comm().get_unique_tag();
169 
170  std::vector<Parallel::Request> query_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
171 
172  // Make all requests
173  for (processor_id_type p = 0; p != my_n_proc; ++p)
174  {
175  if (p == my_proc_id)
176  continue;
177 
178  Parallel::Request & request = query_requests[p - (p > my_proc_id)];
179 
180  mesh->comm().send(p, queries[p], request, queries_tag);
181  }
182 
183  // Reply to all requests
184  std::vector<vec_type> responses(my_n_proc - 1);
185 
186  for (processor_id_type p = 1; p != my_n_proc; ++p)
187  {
188  vec_type query;
189 
190  Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
191  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
192 
193  mesh->comm().receive(source_pid, query, queries_tag);
194 
195  Parallel::Request & request = reply_requests[p - 1];
196 
197  for (const auto & q : query)
198  {
199  const Elem * elem = mesh->elem_ptr(q.first);
200  const unsigned int side = q.second;
201  const Elem * target =
202  (side >= elem->n_sides()) ? elem->interior_parent() : elem->neighbor_ptr(side);
203 
204  if (target == nullptr) // linked element was deleted!
205  responses[p - 1].push_back(std::make_pair(elem->id(), side));
206  }
207 
208  mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
209  }
210 
211  // Process all incoming replies
212  for (processor_id_type p = 1; p != my_n_proc; ++p)
213  {
214  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
215  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
216 
217  vec_type response;
218 
219  this->comm().receive(source_pid, response, replies_tag);
220 
221  for (const auto & r : response)
222  {
223  Elem * elem = mesh->elem_ptr(r.first);
224  const unsigned int side = r.second;
225 
226  if (side < elem->n_sides())
227  {
228  mooseAssert(elem->neighbor_ptr(side) == remote_elem, "element neighbor != remote_elem");
229 
230  elem->set_neighbor(side, nullptr);
231 
232  // assign cut surface boundary
233  if (_assign_boundary)
234  boundary_info.add_side(elem, side, boundary_id);
235  }
236  else
237  {
238  mooseAssert(side == elem->n_sides(), "internal communication error");
239  mooseAssert(elem->interior_parent() == remote_elem, "interior parent != remote_elem");
240 
241  elem->set_interior_parent(nullptr);
242  }
243  }
244  }
245 
246  Parallel::wait(query_requests);
247  Parallel::wait(reply_requests);
248  }
249 
250  if (_assign_boundary)
251  {
252  boundary_info.sideset_name(boundary_id) = _boundary_name;
253  boundary_info.nodeset_name(boundary_id) = _boundary_name;
254  }
255 
262  mesh->contract();
263  mesh->prepare_for_use();
264 
265  return dynamic_pointer_cast<MeshBase>(mesh);
266 }
MPI_Request request
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
const bool _delete_exteriors
Delete elements whose interior parents are slated for deletion?
const bool _assign_boundary
Assign a boundary name to the cut surface?
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...
MPI_Status status
uint8_t processor_id_type
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
int8_t boundary_id_type
ElementDeletionGeneratorBase(const InputParameters &parameters)
libmesh_assert(ctx)
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
static InputParameters validParams()
Definition: MeshGenerator.C:23
std::unique_ptr< MeshBase > & _input
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
query_obj query
virtual bool shouldDelete(const Elem *elem)=0
Method that returns a Boolean indicating whether an element should be removed from the mesh...
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...
const BoundaryName _boundary_name
Name of the boundary name to assign to the cut surface.
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:33
uint8_t dof_id_type
const RemoteElem * remote_elem