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
46  if (!mesh->is_prepared())
47  mesh->prepare_for_use();
48 
49  // Elements that the deleter will remove
50  std::set<Elem *> deleteable_elems;
51 
52  // First let's figure out which elements need to be deleted
53  for (auto & elem : mesh->element_ptr_range())
54  {
55  if (shouldDelete(elem))
56  deleteable_elems.insert(elem);
57  }
58 
59  // check for dangling interior parents
60  for (auto & elem : mesh->element_ptr_range())
61  if (elem->dim() < mesh->mesh_dimension() && deleteable_elems.count(elem->interior_parent()) > 0)
62  {
64  deleteable_elems.insert(elem);
65  else
66  elem->set_interior_parent(nullptr);
67  }
68 
73 #ifdef DEBUG
74  dof_id_type pmax_elem_id = mesh->max_elem_id();
75  mesh->comm().max(pmax_elem_id);
76 
77  for (dof_id_type i = 0; i != pmax_elem_id; ++i)
78  {
79  Elem * elem = mesh->query_elem_ptr(i);
80  bool is_deleteable = elem && deleteable_elems.count(elem);
81 
82  libmesh_assert(mesh->comm().semiverify(elem ? &is_deleteable : libmesh_nullptr));
83  }
84 #endif
85 
86  // Get the BoundaryID from the mesh
87  boundary_id_type boundary_id = 0;
88  if (_assign_boundary)
89  boundary_id = MooseMeshUtils::getBoundaryIDs(*mesh, {_boundary_name}, true)[0];
90 
91  // Get a reference to our BoundaryInfo object for later use
92  BoundaryInfo & boundary_info = mesh->get_boundary_info();
93 
101  for (auto & elem : deleteable_elems)
102  {
103  // On distributed meshes, we'll need neighbor links to be useable
104  // shortly, so we can't just leave dangling pointers.
105  //
106  // FIXME - this could be made AMR-aware and refactored into
107  // libMesh - roystgnr
108  unsigned int n_sides = elem->n_sides();
109  for (unsigned int n = 0; n != n_sides; ++n)
110  {
111  Elem * neighbor = elem->neighbor_ptr(n);
112  if (!neighbor || neighbor == remote_elem)
113  continue;
114 
115  const unsigned int return_side = neighbor->which_neighbor_am_i(elem);
116 
117  if (neighbor->neighbor_ptr(return_side) == elem)
118  {
119  neighbor->set_neighbor(return_side, nullptr);
120 
121  // assign cut surface boundary
122  if (_assign_boundary)
123  boundary_info.add_side(neighbor, return_side, boundary_id);
124  }
125  }
126 
127  mesh->delete_elem(elem);
128  }
129 
136  if (!mesh->is_serial())
137  {
138  const processor_id_type my_n_proc = mesh->n_processors();
139  const processor_id_type my_proc_id = mesh->processor_id();
140  typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
141  std::vector<vec_type> queries(my_n_proc);
142 
143  // Loop over the elements looking for those with remote neighbors
144  // or interior parents.
145  // The ghost_elements iterators in libMesh need to be updated
146  // before we can use them safely here, so we'll test for
147  // ghost-vs-local manually.
148  for (const auto & elem : mesh->element_ptr_range())
149  {
150  const processor_id_type pid = elem->processor_id();
151  if (pid == my_proc_id)
152  continue;
153 
154  const unsigned int n_sides = elem->n_sides();
155  for (unsigned int n = 0; n != n_sides; ++n)
156  if (elem->neighbor_ptr(n) == remote_elem)
157  queries[pid].push_back(std::make_pair(elem->id(), n));
158 
159  // Use an OOB side index to encode "interior_parent". We will use this OOB index later
160  if (elem->interior_parent() == remote_elem)
161  queries[pid].push_back(std::make_pair(elem->id(), n_sides));
162  }
163 
164  const auto queries_tag = mesh->comm().get_unique_tag(),
165  replies_tag = mesh->comm().get_unique_tag();
166 
167  std::vector<Parallel::Request> query_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
168 
169  // Make all requests
170  for (processor_id_type p = 0; p != my_n_proc; ++p)
171  {
172  if (p == my_proc_id)
173  continue;
174 
175  Parallel::Request & request = query_requests[p - (p > my_proc_id)];
176 
177  mesh->comm().send(p, queries[p], request, queries_tag);
178  }
179 
180  // Reply to all requests
181  std::vector<vec_type> responses(my_n_proc - 1);
182 
183  for (processor_id_type p = 1; p != my_n_proc; ++p)
184  {
185  vec_type query;
186 
187  Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
188  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
189 
190  mesh->comm().receive(source_pid, query, queries_tag);
191 
192  Parallel::Request & request = reply_requests[p - 1];
193 
194  for (const auto & q : query)
195  {
196  const Elem * elem = mesh->elem_ptr(q.first);
197  const unsigned int side = q.second;
198  const Elem * target =
199  (side >= elem->n_sides()) ? elem->interior_parent() : elem->neighbor_ptr(side);
200 
201  if (target == nullptr) // linked element was deleted!
202  responses[p - 1].push_back(std::make_pair(elem->id(), side));
203  }
204 
205  mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
206  }
207 
208  // Process all incoming replies
209  for (processor_id_type p = 1; p != my_n_proc; ++p)
210  {
211  Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
212  const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
213 
214  vec_type response;
215 
216  this->comm().receive(source_pid, response, replies_tag);
217 
218  for (const auto & r : response)
219  {
220  Elem * elem = mesh->elem_ptr(r.first);
221  const unsigned int side = r.second;
222 
223  if (side < elem->n_sides())
224  {
225  mooseAssert(elem->neighbor_ptr(side) == remote_elem, "element neighbor != remote_elem");
226 
227  elem->set_neighbor(side, nullptr);
228 
229  // assign cut surface boundary
230  if (_assign_boundary)
231  boundary_info.add_side(elem, side, boundary_id);
232  }
233  else
234  {
235  mooseAssert(side == elem->n_sides(), "internal communication error");
236  mooseAssert(elem->interior_parent() == remote_elem, "interior parent != remote_elem");
237 
238  elem->set_interior_parent(nullptr);
239  }
240  }
241  }
242 
243  Parallel::wait(query_requests);
244  Parallel::wait(reply_requests);
245  }
246 
247  if (_assign_boundary)
248  {
249  boundary_info.sideset_name(boundary_id) = _boundary_name;
250  boundary_info.nodeset_name(boundary_id) = _boundary_name;
251  }
252 
259  mesh->contract();
260  mesh->prepare_for_use();
261 
262  return dynamic_pointer_cast<MeshBase>(mesh);
263 }
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:32
uint8_t dof_id_type
const RemoteElem * remote_elem