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