Line data Source code
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 :
10 : // MOOSE includes
11 : #include "MooseMeshUtils.h"
12 :
13 : #include "libmesh/elem.h"
14 : #include "libmesh/boundary_info.h"
15 : #include "libmesh/parallel.h"
16 : #include "libmesh/parallel_algebra.h"
17 : #include "libmesh/utility.h"
18 :
19 : using namespace libMesh;
20 :
21 : namespace MooseMeshUtils
22 : {
23 :
24 : void
25 209 : mergeBoundaryIDsWithSameName(MeshBase & mesh)
26 : {
27 : // We check if we have the same boundary name with different IDs. If we do, we assign the
28 : // first ID to every occurrence.
29 209 : const auto & side_bd_name_map = mesh.get_boundary_info().get_sideset_name_map();
30 209 : const auto & node_bd_name_map = mesh.get_boundary_info().get_nodeset_name_map();
31 209 : std::map<boundary_id_type, boundary_id_type> same_name_ids;
32 :
33 418 : auto populate_map = [](const std::map<boundary_id_type, std::string> & map,
34 : std::map<boundary_id_type, boundary_id_type> & same_ids)
35 : {
36 2425 : for (const auto & pair_outer : map)
37 16200 : for (const auto & pair_inner : map)
38 : // The last condition is needed to make sure we only store one combination
39 15589 : if (pair_outer.second == pair_inner.second && pair_outer.first != pair_inner.first &&
40 15589 : same_ids.find(pair_inner.first) == same_ids.end())
41 698 : same_ids[pair_outer.first] = pair_inner.first;
42 418 : };
43 :
44 209 : populate_map(side_bd_name_map, same_name_ids);
45 209 : populate_map(node_bd_name_map, same_name_ids);
46 :
47 594 : for (const auto & [id1, id2] : same_name_ids)
48 385 : mesh.get_boundary_info().renumber_id(id2, id1);
49 209 : }
50 :
51 : void
52 439 : changeBoundaryId(MeshBase & mesh,
53 : const boundary_id_type old_id,
54 : const boundary_id_type new_id,
55 : bool delete_prev)
56 : {
57 : // Get a reference to our BoundaryInfo object, we will use it several times below...
58 439 : BoundaryInfo & boundary_info = mesh.get_boundary_info();
59 :
60 : // Container to catch ids passed back from BoundaryInfo
61 439 : std::vector<boundary_id_type> old_ids;
62 :
63 : // Only level-0 elements store BCs. Loop over them.
64 661567 : for (auto & elem : as_range(mesh.level_elements_begin(0), mesh.level_elements_end(0)))
65 : {
66 330564 : unsigned int n_sides = elem->n_sides();
67 2280150 : for (const auto s : make_range(n_sides))
68 : {
69 1949586 : boundary_info.boundary_ids(elem, s, old_ids);
70 1949586 : if (std::find(old_ids.begin(), old_ids.end(), old_id) != old_ids.end())
71 : {
72 18299 : std::vector<boundary_id_type> new_ids(old_ids);
73 18299 : std::replace(new_ids.begin(), new_ids.end(), old_id, new_id);
74 18299 : if (delete_prev)
75 : {
76 18299 : boundary_info.remove_side(elem, s);
77 18299 : boundary_info.add_side(elem, s, new_ids);
78 : }
79 : else
80 0 : boundary_info.add_side(elem, s, new_ids);
81 18299 : }
82 : }
83 439 : }
84 :
85 : // Remove any remaining references to the old ID from the
86 : // BoundaryInfo object. This prevents things like empty sidesets
87 : // from showing up when printing information, etc.
88 439 : if (delete_prev)
89 439 : boundary_info.remove_id(old_id);
90 :
91 : // global information may now be out of sync
92 439 : mesh.set_isnt_prepared();
93 439 : }
94 :
95 : std::vector<boundary_id_type>
96 9874 : getBoundaryIDs(const MeshBase & mesh,
97 : const std::vector<BoundaryName> & boundary_name,
98 : bool generate_unknown)
99 : {
100 : return getBoundaryIDs(
101 9874 : mesh, boundary_name, generate_unknown, mesh.get_boundary_info().get_boundary_ids());
102 : }
103 :
104 : std::vector<boundary_id_type>
105 130950 : getBoundaryIDs(const MeshBase & mesh,
106 : const std::vector<BoundaryName> & boundary_name,
107 : bool generate_unknown,
108 : const std::set<BoundaryID> & mesh_boundary_ids)
109 : {
110 130950 : const BoundaryInfo & boundary_info = mesh.get_boundary_info();
111 130950 : const std::map<BoundaryID, std::string> & sideset_map = boundary_info.get_sideset_name_map();
112 130950 : const std::map<BoundaryID, std::string> & nodeset_map = boundary_info.get_nodeset_name_map();
113 :
114 130950 : BoundaryID max_boundary_local_id = 0;
115 : /* It is required to generate a new ID for a given name. It is used often in mesh modifiers such
116 : * as SideSetsBetweenSubdomains. Then we need to check the current boundary ids since they are
117 : * changing during "mesh modify()", and figure out the right max boundary ID. Most of mesh
118 : * modifiers are running in serial, and we won't involve a global communication.
119 : */
120 130950 : if (generate_unknown)
121 : {
122 126117 : const auto & bids = mesh.is_prepared() ? mesh.get_boundary_info().get_global_boundary_ids()
123 830 : : mesh.get_boundary_info().get_boundary_ids();
124 126117 : max_boundary_local_id = bids.empty() ? 0 : *(bids.rbegin());
125 : /* We should not hit this often */
126 126117 : if (!mesh.is_prepared() && !mesh.is_serial())
127 91 : mesh.comm().max(max_boundary_local_id);
128 : }
129 :
130 130950 : BoundaryID max_boundary_id = mesh_boundary_ids.empty() ? 0 : *(mesh_boundary_ids.rbegin());
131 :
132 130950 : max_boundary_id =
133 130950 : max_boundary_id > max_boundary_local_id ? max_boundary_id : max_boundary_local_id;
134 :
135 130950 : std::vector<BoundaryID> ids(boundary_name.size());
136 296216 : for (const auto i : index_range(boundary_name))
137 : {
138 165393 : if (boundary_name[i] == "ANY_BOUNDARY_ID")
139 : {
140 127 : ids.assign(mesh_boundary_ids.begin(), mesh_boundary_ids.end());
141 127 : if (i)
142 0 : mooseWarning("You passed \"ANY_BOUNDARY_ID\" in addition to other boundary_names. This "
143 : "may be a logic error.");
144 127 : break;
145 : }
146 :
147 165266 : if (boundary_name[i].empty() && !generate_unknown)
148 0 : mooseError("Incoming boundary name is empty and we are not generating unknown boundary IDs. "
149 : "This is invalid.");
150 :
151 : BoundaryID id;
152 :
153 165266 : if (boundary_name[i].empty() || !MooseUtils::isDigits(boundary_name[i]))
154 : {
155 : /**
156 : * If the conversion from a name to a number fails, that means that this must be a named
157 : * boundary. We will look in the complete map for this sideset and create a new name/ID pair
158 : * if requested.
159 : */
160 327644 : if (generate_unknown &&
161 234109 : !MooseUtils::doesMapContainValue(sideset_map, std::string(boundary_name[i])) &&
162 121441 : !MooseUtils::doesMapContainValue(nodeset_map, std::string(boundary_name[i])))
163 8538 : id = ++max_boundary_id;
164 : else
165 104130 : id = boundary_info.get_id_by_name(boundary_name[i]);
166 : }
167 : else
168 52598 : id = getIDFromName<BoundaryName, BoundaryID>(boundary_name[i]);
169 :
170 165266 : ids[i] = id;
171 : }
172 :
173 261900 : return ids;
174 0 : }
175 :
176 : std::set<BoundaryID>
177 188 : getBoundaryIDSet(const MeshBase & mesh,
178 : const std::vector<BoundaryName> & boundary_name,
179 : bool generate_unknown)
180 : {
181 188 : auto boundaries = getBoundaryIDs(mesh, boundary_name, generate_unknown);
182 376 : return std::set<BoundaryID>(boundaries.begin(), boundaries.end());
183 188 : }
184 :
185 : std::vector<subdomain_id_type>
186 249699 : getSubdomainIDs(const MeshBase & mesh, const std::vector<SubdomainName> & subdomain_names)
187 : {
188 249699 : std::vector<SubdomainID> ids(subdomain_names.size());
189 :
190 367664 : for (const auto i : index_range(subdomain_names))
191 117965 : ids[i] = MooseMeshUtils::getSubdomainID(subdomain_names[i], mesh);
192 :
193 249699 : return ids;
194 0 : }
195 :
196 : std::set<subdomain_id_type>
197 0 : getSubdomainIDs(const MeshBase & mesh, const std::set<SubdomainName> & subdomain_names)
198 : {
199 0 : std::set<SubdomainID> ids;
200 0 : for (const auto & name : subdomain_names)
201 0 : ids.insert(MooseMeshUtils::getSubdomainID(name, mesh));
202 0 : return ids;
203 0 : }
204 :
205 : BoundaryID
206 545003 : getBoundaryID(const BoundaryName & boundary_name, const MeshBase & mesh)
207 : {
208 545003 : BoundaryID id = Moose::INVALID_BOUNDARY_ID;
209 545003 : if (boundary_name.empty())
210 0 : return id;
211 :
212 545003 : if (!MooseUtils::isDigits(boundary_name))
213 348453 : id = mesh.get_boundary_info().get_id_by_name(boundary_name);
214 : else
215 196550 : id = getIDFromName<BoundaryName, BoundaryID>(boundary_name);
216 :
217 544999 : return id;
218 : }
219 :
220 : SubdomainID
221 648789 : getSubdomainID(const SubdomainName & subdomain_name, const MeshBase & mesh)
222 : {
223 648789 : if (subdomain_name == "ANY_BLOCK_ID")
224 0 : mooseError("getSubdomainID() does not work with \"ANY_BLOCK_ID\"");
225 :
226 648789 : SubdomainID id = Moose::INVALID_BLOCK_ID;
227 648789 : if (subdomain_name.empty())
228 0 : return id;
229 :
230 648789 : if (!MooseUtils::isDigits(subdomain_name))
231 379612 : id = mesh.get_id_by_name(subdomain_name);
232 : else
233 269177 : id = getIDFromName<SubdomainName, SubdomainID>(subdomain_name);
234 :
235 648789 : return id;
236 : }
237 :
238 : void
239 0 : changeSubdomainId(MeshBase & mesh, const subdomain_id_type old_id, const subdomain_id_type new_id)
240 : {
241 0 : for (const auto & elem : mesh.element_ptr_range())
242 0 : if (elem->subdomain_id() == old_id)
243 0 : elem->subdomain_id() = new_id;
244 :
245 : // global cached information may now be out of sync
246 0 : mesh.set_isnt_prepared();
247 0 : }
248 :
249 : Point
250 288 : meshCentroidCalculator(const MeshBase & mesh)
251 : {
252 288 : Point centroid_pt = Point(0.0, 0.0, 0.0);
253 288 : Real vol_tmp = 0.0;
254 288 : for (const auto & elem :
255 4880 : as_range(mesh.active_local_elements_begin(), mesh.active_local_elements_end()))
256 : {
257 4304 : Real elem_vol = elem->volume();
258 4304 : centroid_pt += (elem->true_centroid()) * elem_vol;
259 4304 : vol_tmp += elem_vol;
260 288 : }
261 288 : mesh.comm().sum(centroid_pt);
262 288 : mesh.comm().sum(vol_tmp);
263 288 : centroid_pt /= vol_tmp;
264 576 : return centroid_pt;
265 : }
266 :
267 : std::unordered_map<dof_id_type, dof_id_type>
268 278 : getExtraIDUniqueCombinationMap(const MeshBase & mesh,
269 : const std::set<SubdomainID> & block_ids,
270 : std::vector<ExtraElementIDName> extra_ids)
271 : {
272 : // check block restriction
273 278 : const bool block_restricted = !block_ids.empty();
274 : // get element id name of interest in recursive parsing algorithm
275 278 : ExtraElementIDName id_name = extra_ids.back();
276 278 : extra_ids.pop_back();
277 278 : const auto id_index = mesh.get_elem_integer_index(id_name);
278 :
279 : // create base parsed id set
280 278 : if (extra_ids.empty())
281 : {
282 : // get set of extra id values;
283 162 : std::vector<dof_id_type> ids;
284 : {
285 162 : std::set<dof_id_type> ids_set;
286 1128302 : for (const auto & elem : mesh.active_element_ptr_range())
287 : {
288 564070 : if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
289 578 : continue;
290 563492 : const auto id = elem->get_extra_integer(id_index);
291 563492 : ids_set.insert(id);
292 162 : }
293 162 : mesh.comm().set_union(ids_set);
294 162 : ids.assign(ids_set.begin(), ids_set.end());
295 162 : }
296 :
297 : // determine new extra id values;
298 162 : std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
299 1128302 : for (auto & elem : mesh.active_element_ptr_range())
300 : {
301 564070 : if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
302 578 : continue;
303 563492 : parsed_ids[elem->id()] = std::distance(
304 1126984 : ids.begin(), std::lower_bound(ids.begin(), ids.end(), elem->get_extra_integer(id_index)));
305 162 : }
306 162 : return parsed_ids;
307 162 : }
308 :
309 : // if extra_ids is not empty, recursively call getExtraIDUniqueCombinationMap
310 : const auto base_parsed_ids =
311 116 : MooseMeshUtils::getExtraIDUniqueCombinationMap(mesh, block_ids, extra_ids);
312 : // parsing extra ids based on ref_parsed_ids
313 116 : std::vector<std::pair<dof_id_type, dof_id_type>> unique_ids;
314 : {
315 116 : std::set<std::pair<dof_id_type, dof_id_type>> unique_ids_set;
316 856308 : for (const auto & elem : mesh.active_element_ptr_range())
317 : {
318 428096 : if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
319 528 : continue;
320 427568 : const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
321 427568 : const dof_id_type id2 = elem->get_extra_integer(id_index);
322 427568 : const std::pair<dof_id_type, dof_id_type> ids = std::make_pair(id1, id2);
323 427568 : unique_ids_set.insert(ids);
324 116 : }
325 116 : mesh.comm().set_union(unique_ids_set);
326 116 : unique_ids.assign(unique_ids_set.begin(), unique_ids_set.end());
327 116 : }
328 :
329 116 : std::unordered_map<dof_id_type, dof_id_type> parsed_ids;
330 :
331 856308 : for (const auto & elem : mesh.active_element_ptr_range())
332 : {
333 428096 : if (block_restricted && block_ids.find(elem->subdomain_id()) == block_ids.end())
334 528 : continue;
335 427568 : const dof_id_type id1 = libmesh_map_find(base_parsed_ids, elem->id());
336 427568 : const dof_id_type id2 = elem->get_extra_integer(id_index);
337 427568 : const dof_id_type new_id = std::distance(
338 : unique_ids.begin(),
339 427568 : std::lower_bound(unique_ids.begin(), unique_ids.end(), std::make_pair(id1, id2)));
340 427568 : parsed_ids[elem->id()] = new_id;
341 116 : }
342 :
343 116 : return parsed_ids;
344 278 : }
345 :
346 : bool
347 306 : isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec, const Point fixed_pt)
348 : {
349 2661 : for (const auto & pt : vec_pts)
350 2359 : if (!MooseUtils::absoluteFuzzyEqual((pt - fixed_pt) * plane_nvec, 0.0))
351 4 : return false;
352 302 : return true;
353 : }
354 :
355 : bool
356 0 : isCoPlanar(const std::vector<Point> vec_pts, const Point plane_nvec)
357 : {
358 0 : return isCoPlanar(vec_pts, plane_nvec, vec_pts.front());
359 : }
360 :
361 : bool
362 0 : isCoPlanar(const std::vector<Point> vec_pts)
363 : {
364 : // Assuming that overlapped Points are allowed, the Points that are overlapped with vec_pts[0] are
365 : // removed before further calculation.
366 0 : std::vector<Point> vec_pts_nonzero{vec_pts[0]};
367 0 : for (const auto i : index_range(vec_pts))
368 0 : if (!MooseUtils::absoluteFuzzyEqual((vec_pts[i] - vec_pts[0]).norm(), 0.0))
369 0 : vec_pts_nonzero.push_back(vec_pts[i]);
370 : // 3 or fewer points are always coplanar
371 0 : if (vec_pts_nonzero.size() <= 3)
372 0 : return true;
373 : else
374 : {
375 0 : for (const auto i : make_range(vec_pts_nonzero.size() - 1))
376 : {
377 0 : const Point tmp_pt = (vec_pts_nonzero[i] - vec_pts_nonzero[0])
378 0 : .cross(vec_pts_nonzero[i + 1] - vec_pts_nonzero[0]);
379 : // if the three points are not collinear, use cross product as the normal vector of the plane
380 0 : if (!MooseUtils::absoluteFuzzyEqual(tmp_pt.norm(), 0.0))
381 0 : return isCoPlanar(vec_pts_nonzero, tmp_pt.unit());
382 : }
383 : }
384 : // If all the points are collinear, they are also coplanar
385 0 : return true;
386 0 : }
387 :
388 : SubdomainID
389 409 : getNextFreeSubdomainID(MeshBase & input_mesh)
390 : {
391 : // Call this to get most up to date block id information
392 409 : input_mesh.cache_elem_data();
393 :
394 409 : std::set<SubdomainID> preexisting_subdomain_ids;
395 409 : input_mesh.subdomain_ids(preexisting_subdomain_ids);
396 409 : if (preexisting_subdomain_ids.empty())
397 0 : return 0;
398 : else
399 : {
400 : const auto highest_subdomain_id =
401 409 : *std::max_element(preexisting_subdomain_ids.begin(), preexisting_subdomain_ids.end());
402 : mooseAssert(highest_subdomain_id < std::numeric_limits<SubdomainID>::max(),
403 : "A SubdomainID with max possible value was found");
404 409 : return highest_subdomain_id + 1;
405 : }
406 409 : }
407 :
408 : BoundaryID
409 545 : getNextFreeBoundaryID(MeshBase & input_mesh)
410 : {
411 545 : auto boundary_ids = input_mesh.get_boundary_info().get_boundary_ids();
412 545 : if (boundary_ids.empty())
413 31 : return 0;
414 514 : return (*boundary_ids.rbegin() + 1);
415 545 : }
416 :
417 : bool
418 12741 : hasSubdomainID(const MeshBase & input_mesh, const SubdomainID & id)
419 : {
420 12741 : std::set<SubdomainID> mesh_blocks;
421 12741 : input_mesh.subdomain_ids(mesh_blocks);
422 :
423 : // On a distributed mesh we may have sideset IDs that only exist on
424 : // other processors
425 12741 : if (!input_mesh.is_replicated())
426 1238 : input_mesh.comm().set_union(mesh_blocks);
427 :
428 25482 : return mesh_blocks.count(id) && (id != Moose::INVALID_BLOCK_ID);
429 12741 : }
430 :
431 : bool
432 10475 : hasSubdomainName(const MeshBase & input_mesh, const SubdomainName & name)
433 : {
434 10475 : const auto id = getSubdomainID(name, input_mesh);
435 20950 : return hasSubdomainID(input_mesh, id);
436 : }
437 :
438 : bool
439 3956 : hasBoundaryID(const MeshBase & input_mesh, const BoundaryID id)
440 : {
441 3956 : const BoundaryInfo & boundary_info = input_mesh.get_boundary_info();
442 3956 : std::set<boundary_id_type> boundary_ids = boundary_info.get_boundary_ids();
443 :
444 : // On a distributed mesh we may have boundary IDs that only exist on
445 : // other processors
446 3956 : if (!input_mesh.is_replicated())
447 718 : input_mesh.comm().set_union(boundary_ids);
448 :
449 7912 : return boundary_ids.count(id) && (id != Moose::INVALID_BOUNDARY_ID);
450 3956 : }
451 :
452 : bool
453 3782 : hasBoundaryName(const MeshBase & input_mesh, const BoundaryName & name)
454 : {
455 3782 : const auto id = getBoundaryID(name, input_mesh);
456 3782 : return hasBoundaryID(input_mesh, id);
457 : }
458 :
459 : void
460 496 : makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
461 : std::vector<dof_id_type> & elem_id_list,
462 : std::vector<dof_id_type> & midpoint_node_list,
463 : std::vector<dof_id_type> & ordered_node_list,
464 : std::vector<dof_id_type> & ordered_elem_id_list)
465 : {
466 : // a flag to indicate if the ordered_node_list has been reversed
467 496 : bool is_flipped = false;
468 : // Start from the first element, try to find a chain of nodes
469 : mooseAssert(node_assm.size(), "Node list must not be empty");
470 496 : ordered_node_list.push_back(node_assm.front().first);
471 496 : if (midpoint_node_list.front() != DofObject::invalid_id)
472 0 : ordered_node_list.push_back(midpoint_node_list.front());
473 496 : ordered_node_list.push_back(node_assm.front().second);
474 496 : ordered_elem_id_list.push_back(elem_id_list.front());
475 : // Remove the element that has just been added to ordered_node_list
476 496 : node_assm.erase(node_assm.begin());
477 496 : midpoint_node_list.erase(midpoint_node_list.begin());
478 496 : elem_id_list.erase(elem_id_list.begin());
479 496 : const unsigned int node_assm_size_0 = node_assm.size();
480 2889 : for (unsigned int i = 0; i < node_assm_size_0; i++)
481 : {
482 : // Find nodes to expand the chain
483 2397 : dof_id_type end_node_id = ordered_node_list.back();
484 8058 : auto isMatch1 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
485 8058 : { return old_id_pair.first == end_node_id; };
486 2146 : auto isMatch2 = [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair)
487 2146 : { return old_id_pair.second == end_node_id; };
488 2397 : auto result = std::find_if(node_assm.begin(), node_assm.end(), isMatch1);
489 : bool match_first;
490 2397 : if (result == node_assm.end())
491 : {
492 1214 : match_first = false;
493 1214 : result = std::find_if(node_assm.begin(), node_assm.end(), isMatch2);
494 : }
495 : else
496 : {
497 1183 : match_first = true;
498 : }
499 : // If found, add the node to boundary_ordered_node_list
500 2397 : if (result != node_assm.end())
501 : {
502 2139 : const auto elem_index = std::distance(node_assm.begin(), result);
503 2139 : if (midpoint_node_list[elem_index] != DofObject::invalid_id)
504 0 : ordered_node_list.push_back(midpoint_node_list[elem_index]);
505 2139 : ordered_node_list.push_back(match_first ? (*result).second : (*result).first);
506 2139 : node_assm.erase(result);
507 2139 : midpoint_node_list.erase(midpoint_node_list.begin() + elem_index);
508 2139 : ordered_elem_id_list.push_back(elem_id_list[elem_index]);
509 2139 : elem_id_list.erase(elem_id_list.begin() + elem_index);
510 : }
511 : // If there are still elements in node_assm and result ==
512 : // node_assm.end(), this means the curve is not a loop, the
513 : // ordered_node_list is flipped and try the other direction that has not
514 : // been examined yet.
515 : else
516 : {
517 258 : if (is_flipped)
518 : // Flipped twice; this means the node list has at least two segments.
519 4 : throw MooseException("The node list provided has more than one segments.");
520 :
521 : // mark the first flip event.
522 254 : is_flipped = true;
523 254 : std::reverse(ordered_node_list.begin(), ordered_node_list.end());
524 254 : std::reverse(midpoint_node_list.begin(), midpoint_node_list.end());
525 254 : std::reverse(ordered_elem_id_list.begin(), ordered_elem_id_list.end());
526 : // As this iteration is wasted, set the iterator backward
527 254 : i--;
528 : }
529 : }
530 492 : }
531 :
532 : void
533 234 : makeOrderedNodeList(std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
534 : std::vector<dof_id_type> & elem_id_list,
535 : std::vector<dof_id_type> & ordered_node_list,
536 : std::vector<dof_id_type> & ordered_elem_id_list)
537 : {
538 234 : std::vector<dof_id_type> dummy_midpoint_node_list(node_assm.size(), DofObject::invalid_id);
539 234 : makeOrderedNodeList(
540 : node_assm, elem_id_list, dummy_midpoint_node_list, ordered_node_list, ordered_elem_id_list);
541 234 : }
542 :
543 : void
544 9036 : swapNodesInElem(Elem & elem, const unsigned int nd1, const unsigned int nd2)
545 : {
546 9036 : Node * n_temp = elem.node_ptr(nd1);
547 9036 : elem.set_node(nd1, elem.node_ptr(nd2));
548 9036 : elem.set_node(nd2, n_temp);
549 9036 : }
550 :
551 : void
552 214 : extraElemIntegerSwapParametersProcessor(
553 : const std::string & class_name,
554 : const unsigned int num_sections,
555 : const unsigned int num_integers,
556 : const std::vector<std::vector<std::vector<dof_id_type>>> & elem_integers_swaps,
557 : std::vector<std::unordered_map<dof_id_type, dof_id_type>> & elem_integers_swap_pairs)
558 : {
559 214 : elem_integers_swap_pairs.reserve(num_sections * num_integers);
560 240 : for (const auto i : make_range(num_integers))
561 : {
562 26 : const auto & elem_integer_swaps = elem_integers_swaps[i];
563 26 : std::vector<std::unordered_map<dof_id_type, dof_id_type>> elem_integer_swap_pairs;
564 : try
565 : {
566 26 : MooseMeshUtils::idSwapParametersProcessor(class_name,
567 : "elem_integers_swaps",
568 : elem_integer_swaps,
569 : elem_integer_swap_pairs,
570 : i * num_sections);
571 : }
572 0 : catch (const MooseException & e)
573 : {
574 0 : throw MooseException(e.what());
575 0 : }
576 :
577 26 : elem_integers_swap_pairs.insert(elem_integers_swap_pairs.end(),
578 : elem_integer_swap_pairs.begin(),
579 : elem_integer_swap_pairs.end());
580 26 : }
581 214 : }
582 :
583 : std::unique_ptr<ReplicatedMesh>
584 0 : buildBoundaryMesh(const ReplicatedMesh & input_mesh, const boundary_id_type boundary_id)
585 : {
586 0 : auto poly_mesh = std::make_unique<ReplicatedMesh>(input_mesh.comm());
587 :
588 0 : auto side_list = input_mesh.get_boundary_info().build_side_list();
589 :
590 0 : std::unordered_map<dof_id_type, dof_id_type> old_new_node_map;
591 0 : for (const auto & bside : side_list)
592 : {
593 0 : if (std::get<2>(bside) != boundary_id)
594 0 : continue;
595 :
596 0 : const Elem * elem = input_mesh.elem_ptr(std::get<0>(bside));
597 0 : const auto side = std::get<1>(bside);
598 0 : auto side_elem = elem->build_side_ptr(side);
599 0 : auto copy = side_elem->build(side_elem->type());
600 :
601 0 : for (const auto i : side_elem->node_index_range())
602 : {
603 0 : auto & n = side_elem->node_ref(i);
604 :
605 0 : if (old_new_node_map.count(n.id()))
606 0 : copy->set_node(i, poly_mesh->node_ptr(old_new_node_map[n.id()]));
607 : else
608 : {
609 0 : Node * node = poly_mesh->add_point(side_elem->point(i));
610 0 : copy->set_node(i, node);
611 0 : old_new_node_map[n.id()] = node->id();
612 : }
613 : }
614 0 : poly_mesh->add_elem(copy.release());
615 0 : }
616 0 : poly_mesh->skip_partitioning(true);
617 0 : poly_mesh->prepare_for_use();
618 0 : if (poly_mesh->n_elem() == 0)
619 0 : mooseError("The input mesh does not have a boundary with id ", boundary_id);
620 :
621 0 : return poly_mesh;
622 0 : }
623 : }
|