https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
40std::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;
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
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
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
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}
const bool _delete_exteriors
Delete elements whose interior parents are slated for deletion?
ElementDeletionGeneratorBase(const InputParameters &parameters)
std::unique_ptr< MeshBase > & _input
const BoundaryName _boundary_name
Name of the boundary name to assign to the cut surface.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
virtual bool shouldDelete(const Elem *elem)=0
Method that returns a Boolean indicating whether an element should be removed from the mesh.
const bool _assign_boundary
Assign a boundary name to the cut surface?
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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 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...
MeshGenerators are objects that can modify or add to an existing mesh.
static InputParameters validParams()
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
const Parallel::Communicator & comm() const
query_obj query
MeshBase & mesh
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.