https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SurfaceSubdomainsDelaunayRemesher.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
12#include "MooseMeshUtils.h"
13#include "CastUniquePointer.h"
14
15#include "libmesh/boundary_info.h"
16#include "libmesh/mesh_triangle_holes.h"
17#include "libmesh/mesh_modification.h"
18#include "libmesh/parallel_algebra.h"
19#include "libmesh/poly2tri_triangulator.h"
20#include "libmesh/unstructured_mesh.h"
21
22#include "libmesh/mesh_base.h"
23#include "libmesh/replicated_mesh.h"
24
26
29{
32 params.renameParameterGroup("Parsed expression advanced", "Level set shape parsed expression");
33
35 "Mesh generator that re-meshes a 2D surface mesh given as one or more subdomains into "
36 "a 2D surface mesh using Delaunay triangulation.");
37
38 // Definition of the region to re-mesh
39 params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
40 params.addParam<std::vector<std::vector<SubdomainName>>>(
41 "subdomain_names", {}, "The surface mesh subdomains to be re-meshed");
42 params.addParam<std::vector<SubdomainName>>(
43 "exclude_subdomain_names", {}, "The surface mesh subdomains that should not be re-meshed");
44
45 // Surface re-meshing parameters
46 params.addRangeCheckedParam<Real>(
47 "max_edge_length",
48 "max_edge_length>0",
49 "Maximum length of an edge in the 1D meshes around each subdomain. Only a single value is "
50 "currently allowed as the boundary refinement must be consistent between all subdomains.");
51 // NOTE: we could make this a per-included-subdomain parameter, we would just need to identify
52 // interfaces between each subdomain and use the minimum (or average or maximum, just needs to
53 // be consistent) edge length on those interfaces.
54 params.addParam<std::vector<unsigned int>>(
55 "interpolate_boundaries",
56 {1},
57 "Ratio of points to add to the boundaries. Can be set to a single value for all groups at "
58 "once, or specified individually. A single value is recommended as the boundary refinement "
59 "must be consistent between all subdomains.");
60 params.addParam<std::vector<Real>>(
61 "desired_areas",
62 {0},
63 "Target element size when triangulating projection of the subdomain group. Can be set to a "
64 "single value for all groups at once, or specified individually. Default of 0 means no "
65 "constraint.");
66 params.addParamNamesToGroup("max_edge_length interpolate_boundaries desired_areas",
67 "Delaunay triangulation");
68
69 // Parameters for stitching meshes at the end
70 params.addParam<bool>("avoid_merging_subdomains",
71 false,
72 "Whether to prevent merging subdomains by offsetting ids. The first mesh "
73 "in the input will keep the same subdomains ids, the others will have "
74 "offsets. All subdomain names will remain valid");
75 params.addParam<bool>("clear_stitching_boundaries",
76 true,
77 "Whether to clear the boundaries between the subdomains being stitched "
78 "together after they were re-meshed with triangles");
79 MooseEnum algorithm("BINARY EXHAUSTIVE", "BINARY");
80 params.addParam<MooseEnum>(
81 "stitching_algorithm",
82 algorithm,
83 "Control the use of binary search for the nodes of the stitched surfaces.");
84 params.addParam<bool>(
85 "verbose_stitching", false, "Whether mesh stitching should have verbose output.");
87 "avoid_merging_subdomains clear_stitching_boundaries stitching_algorithm verbose_stitching",
88 "Stitching triangularized meshes");
89
90 return params;
91}
92
94 const InputParameters & parameters)
95 : SurfaceDelaunayGeneratorBase(parameters),
96 LevelSetMeshingHelper(parameters),
97 _input(getMesh("input")),
98 _subdomain_names(getParam<std::vector<std::vector<SubdomainName>>>("subdomain_names")),
99 _interpolate_boundaries(getParam<std::vector<unsigned int>>("interpolate_boundaries")),
100 _desired_areas(getParam<std::vector<Real>>("desired_areas"))
101{
102 if (isParamSetByUser("subdomain_names") && isParamSetByUser("exclude_subdomain_names"))
103 paramError("exclude_subdomain_names",
104 "Excluding subdomain names is only to be set when 'subdomain_names' is not set");
105}
106
107std::unique_ptr<MeshBase>
109{
110 std::unique_ptr<MeshBase> mesh_3d = std::move(_input);
111
112 // Select subdomain names if it has not been selected by the user
113 // We form 1 group per subdomain by default (easiest to mesh)
114 if (_subdomain_names.empty() || _subdomain_names[0].empty())
115 {
116 if (_subdomain_names.size())
117 _subdomain_names.erase(_subdomain_names.begin());
118
119 // Get all subdomains from the mesh
120 std::set<subdomain_id_type> sub_ids;
121 mesh_3d->subdomain_ids(sub_ids);
122
123 // Copy only the ones that are not excluded
124 const auto & excluded = getParam<std::vector<SubdomainName>>("exclude_subdomain_names");
125 for (const auto & sub_id : sub_ids)
126 {
127 const auto & sn = mesh_3d->subdomain_name(sub_id) == "" ? std::to_string(sub_id)
128 : mesh_3d->subdomain_name(sub_id);
129 if (excluded.empty() || std::find(excluded.begin(), excluded.end(), sn) == excluded.end())
130 _subdomain_names.push_back({sn});
131 }
132 }
134 if (_interpolate_boundaries.size() == 1)
136 if (_desired_areas.size() == 1)
139 paramError("interpolate_boundaries",
140 "Should be the same size as 'subdomain_names' or of size 1");
141 if (_desired_areas.size() != _num_groups)
142 paramError("desired_areas", "Should be the same size as 'subdomain_names' or of size 1");
143
144 // Re-create surface meshes from each of the subdomains
145 std::vector<std::unique_ptr<UnstructuredMesh>> remeshed_2d;
146
147 for (const auto i : make_range(_num_groups))
148 {
149 auto mesh_2d = buildReplicatedMesh();
151
152 // Mesh the subdomains by groups
153 // TODO: holes for each subdomain are not currently supported
154 std::vector<std::unique_ptr<UnstructuredMesh>> no_holes = {};
155 auto new_mesh = General2DDelaunay(*mesh_2d, /*holes*/ no_holes, i);
156
157 // Keep the remeshed subdomains 2D meshes
158 remeshed_2d.push_back(std::move(new_mesh));
159 }
160
161 // TODO: can we gain efficiency by using different boundary ids for each stitch?
162 const auto primary_bcid = 1;
163 // Prevent deleting a legitimate ID if we start conserving boundary IDs from the input mesh
164 // to the output mesh
165 const auto starting_stitching_id = MooseMeshUtils::getNextFreeBoundaryID(*mesh_3d);
166 auto paired_bcid = starting_stitching_id;
167 const auto verbose_stitching = getParam<bool>("verbose_stitching");
168 const auto use_binary_search = getParam<MooseEnum>("stitching_algorithm") == "BINARY";
169
170 // Stitch all the parts to the first one
171 std::unique_ptr<UnstructuredMesh> full_mesh;
172 full_mesh = std::move(remeshed_2d[0]);
173
174 // Build a subdomain map
175 auto & main_subdomain_map = full_mesh->set_subdomain_name_map();
176
177 for (auto remesh_i : index_range(remeshed_2d))
178 {
179 if (remesh_i == 0)
180 continue;
181
182 UnstructuredMesh & remeshed = dynamic_cast<UnstructuredMesh &>(*remeshed_2d[remesh_i]);
183
184 // NOTE: we cannot use MeshedHole because the meshes are no longer in the XY plane
185 // Potential optimization: instead of using the full mesh outer boundary for stitching
186 // use what is done in the XYDelaunayGenerator and re-build only the boundary near the
187 // mesh that we are stitching
188 // Potential optimization: we could keep the external boundaries from the triangulation phase
189
190 // Create the boundary outside the remeshed mesh
191 bool rem_has_external_bdy = false;
192 MooseMeshUtils::addExternalBoundary(remeshed, paired_bcid, rem_has_external_bdy);
193 mooseAssert(rem_has_external_bdy, "Subdomain mesh should have an external boundary");
194
195 // We need to re-create the boundary outside the parent mesh because we are clearing
196 // it on every stitch
197 bool base_has_external_bdy = false;
198 MooseMeshUtils::addExternalBoundary(*full_mesh, primary_bcid, base_has_external_bdy);
199 if (!base_has_external_bdy)
201 "Full mesh should have an external boundary. This could occur if the surface mesh is "
202 "disconnected in several parts and a part's surface mesh has just been fully remeshed");
203
204 // Retrieve subdomain name map from the mesh to be stitched and insert it into the main
205 // subdomain map
206 const auto & increment_subdomain_map = remeshed.get_subdomain_name_map();
207 main_subdomain_map.insert(increment_subdomain_map.begin(), increment_subdomain_map.end());
208
209 full_mesh->stitch_meshes(remeshed,
210 primary_bcid,
211 paired_bcid,
212 TOLERANCE,
213 /*clear_stitched_bcids*/ getParam<bool>("clear_stitching_boundaries"),
214 verbose_stitching,
215 use_binary_search,
216 /*enforce_all_nodes_match_on_boundaries*/ false,
217 /*merge_boundary_nodes_all_or_nothing*/ false,
218 /*remap_subdomain_ids*/ !getParam<bool>("avoid_merging_subdomains"));
219
220 // If we want to keep track of the stitching boundaries
221 paired_bcid++;
222 // TODO: when implementing hole meshes, we might want to also stitch the hole meshes
223 }
224
225 // We do not need the 3D mesh anymore
226 mesh_3d->clear();
227 // The stitching boundary should be removed by the stitcher, but this does not hurt
228 if (getParam<bool>("clear_stitching_boundaries"))
229 for (const auto bcid : make_range(starting_stitching_id, paired_bcid))
230 full_mesh->get_boundary_info().remove_id(bcid);
231 // Mesh is not prepared after stitching (TODO: fix this)
232 full_mesh->unset_is_prepared();
233
234 return full_mesh;
235}
236
237std::unique_ptr<UnstructuredMesh>
239 UnstructuredMesh & mesh_2d,
240 std::vector<std::unique_ptr<UnstructuredMesh>> & hole_meshes_2d,
241 unsigned int group_i)
242{
243 if (_verbose)
244 {
245 if (!mesh_2d.preparation().has_cached_elem_data)
246 mesh_2d.cache_elem_data();
247 _console << "Re-meshing mesh\n " << mesh_2d << std::endl;
248 _console << "with subdomains " << Moose::stringify(mesh_2d.get_subdomain_name_map())
249 << std::endl;
250 if (hole_meshes_2d.size())
251 _console << "With " << hole_meshes_2d.size() << " holes:" << std::endl;
252 for (const auto & hole_m : hole_meshes_2d)
253 {
254 if (!hole_m->preparation().has_cached_elem_data)
255 hole_m->cache_elem_data();
256 _console << "Hole subdomains " << Moose::stringify(hole_m->get_subdomain_name_map())
257 << std::endl;
258 _console << *hole_m << std::endl;
259 }
260 }
261 // If a level set is provided, we need to check if the nodes in the original 2D mesh match the
262 // level set
263 if (_func_level_set)
264 {
265 for (const auto & node : mesh_2d.node_ptr_range())
266 {
267 if (std::abs(levelSetEvaluator(*node)) > libMesh::TOLERANCE)
268 {
269 paramError("level_set",
270 "The level set function does not match the nodes in the given boundary of the "
271 "input mesh. Level set evaluates at: " +
272 std::to_string(levelSetEvaluator(*node)) + " at node: " + node->get_info());
273 }
274 }
275 }
276
277 // Create the external boundary of the 2D mesh
278 // Easier to work with a TRI3 mesh
279 // all_tri() also prepares the mesh for use
280 mesh_2d.prepare_for_use();
281 bool has_external_side = false;
282 MeshTools::Modification::all_tri(mesh_2d);
283 const auto mesh_2d_ext_bdry = MooseMeshUtils::getNextFreeBoundaryID(mesh_2d);
284 for (const auto elem : mesh_2d.active_element_ptr_range())
285 for (const auto i_side : elem->side_index_range())
286 if (elem->neighbor_ptr(i_side) == nullptr)
287 {
288 mesh_2d.get_boundary_info().add_side(elem, i_side, mesh_2d_ext_bdry);
289 has_external_side = true;
290 }
291
292 // Create a clone of the 2D mesh to be used for the 1D mesh generation
293 auto mesh_2d_dummy = mesh_2d.clone();
294 // Generate a new 1D block based on the external boundary
295 const auto new_block_id_1d = MooseMeshUtils::getNextFreeSubdomainID(*mesh_2d_dummy);
296
297 if (has_external_side)
299 {std::to_string(mesh_2d_ext_bdry)},
300 new_block_id_1d,
301 SubdomainName(),
302 type());
303
304 // Create a 1D mesh from the 1D block
305 auto mesh_1d = buildMeshBaseObject();
306 if (has_external_side)
307 MooseMeshUtils::convertBlockToMesh(*mesh_2d_dummy, *mesh_1d, {std::to_string(new_block_id_1d)});
308 mesh_2d_dummy->clear();
309
310 // Add more nodes in the 1D mesh
311 // We need to do this BEFORE the mesh is projected to avoid distortion in the node distances
312 // The distortion is not the same for each subdomain, so we would end up with a non-conformal mesh
313 if (isParamValid("max_edge_length"))
314 {
315 // We need to extract the points in the order of the boundary. This utility will build the
316 // boundary as a loop
317 // Add the nodeset from the sideset
318 // NOTE: this is redoing the 1D mesh from the boundary
319 mesh_2d.get_boundary_info().build_node_list_from_side_list({mesh_2d_ext_bdry});
320 const auto boundary_1d = MooseMeshUtils::buildLoopBoundaryOf2DMesh(mesh_2d, mesh_2d_ext_bdry);
321 // Extract the points
322 std::vector<Point> mesh_1d_points;
323 mesh_1d_points.reserve(boundary_1d->n_nodes());
324 for (const auto & node : boundary_1d->node_ptr_range())
325 mesh_1d_points.push_back(*node);
326
327 // Re-create the 1D mesh with a polyline with a maximum edge length
328 mesh_1d->clear();
329 // we add a tiny offset to avoid roundoff differences
331 *mesh_1d, mesh_1d_points, true, "", "", getParam<Real>("max_edge_length") + 1e-8);
332 }
333
334 // Find centroid of the 2D mesh
335 const Point centroid = MooseMeshUtils::meshCentroidCalculator(mesh_2d);
336 // calculate an average normal vector of the 2D mesh
337 const Point mesh_norm = meshNormal2D(mesh_2d);
338 // Check the deviation of the mesh normal vector from the global average normal vector
339 if (meshNormalDeviation2D(mesh_2d, mesh_norm) > _max_angle_deviation)
340 paramError("subdomain_names",
341 "The normal vector of some elements in the 2D mesh deviates too much from the "
342 "global average normal vector. The maximum deviation found / allowed is " +
343 std::to_string(meshNormalDeviation2D(mesh_2d, mesh_norm)) + " / " +
344 std::to_string(_max_angle_deviation) +
345 ". Consider dividing the boundary into several parts to "
346 "reduce the angle deviation.");
347
348 // Move both 2d and 1d meshes to the centroid of the 2D mesh
349 MeshTools::Modification::translate(*mesh_1d, -centroid(0), -centroid(1), -centroid(2));
350 MeshTools::Modification::translate(mesh_2d, -centroid(0), -centroid(1), -centroid(2));
351
352 // Calculate the Euler angles to rotate the meshes so that the 2D mesh is close to the XY plane
353 // (i.e., the normal vector of the 2D mesh is aligned with the Z axis)
354 const Real theta = std::acos(mesh_norm(2)) / M_PI * 180.0;
355 const Real phi =
356 (MooseUtils::absoluteFuzzyLessThan(mesh_norm(2), 1.0) ? std::atan2(mesh_norm(1), mesh_norm(0))
357 : 0.0) /
358 M_PI * 180.0;
359 MeshTools::Modification::rotate(*mesh_1d, 90.0 - phi, theta, 0.0);
360 MeshTools::Modification::rotate(mesh_2d, 90.0 - phi, theta, 0.0);
361
362 // Clone the 2D mesh to be used for reverse projection later
363 auto mesh_2d_xyz = dynamic_pointer_cast<MeshBase>(mesh_2d.clone());
364
365 // Project the 2D mesh to the XY plane so that XYDelaunay can be used
366 for (const auto & node : mesh_2d.node_ptr_range())
367 (*node)(2) = 0;
368 // Project the 1D mesh to the XY plane as well
369 for (const auto & node : mesh_1d->node_ptr_range())
370 (*node)(2) = 0;
371
372 // Finally, triangulation
373 std::unique_ptr<UnstructuredMesh> mesh =
374 dynamic_pointer_cast<UnstructuredMesh>(std::move(mesh_1d));
375
376 Poly2TriTriangulator poly2tri(*mesh);
377 poly2tri.triangulation_type() = TriangulatorInterface::PSLG;
378
379 poly2tri.set_interpolate_boundary_points(_interpolate_boundaries[group_i]);
380 poly2tri.set_verify_hole_boundaries(false);
381 poly2tri.desired_area() = _desired_areas[group_i];
382 poly2tri.minimum_angle() = 0; // Not yet supported
383 poly2tri.smooth_after_generating() = false;
384 // Future TODO: correct the area function based on the local normal vector
386 poly2tri.set_auto_area_function(this->comm(),
391 poly2tri.triangulate();
392
393 // Reverse the projection based on the original 2D mesh
394 for (const auto & node : mesh->node_ptr_range())
395 {
396 bool node_mod = false;
397 // Try to find the element in mesh_2d that contains the new node
398 for (const auto & elem : mesh_2d.active_element_ptr_range())
399 {
400 if (elem->contains_point(Point((*node)(0), (*node)(1), 0.0)))
401 {
402 // Element id
403 const auto elem_id = elem->id();
404 // element in xyz_in_xyz
405 const Elem & elem_xyz = *mesh_2d_xyz->elem_ptr(elem_id);
406
407 const Point elem_normal = elemNormal(elem_xyz);
408 const auto & elem_p = mesh_2d_xyz->elem_ptr(elem_id)->point(0);
409
410 // if the x and y values of the node is the same as the elem_p's first node, we can just
411 // move it to that node's position
412 if (MooseUtils::absoluteFuzzyEqual((*node)(0), elem_p(0)) &&
413 MooseUtils::absoluteFuzzyEqual((*node)(1), elem_p(1)))
414 {
415 (*node)(2) = elem_p(2);
416 node_mod = true;
417 break;
418 }
419 // Otherwise, we need to find a position inside the 2D element
420 // It has the same x and y coordinates as the node in the projected mesh;
421 (*node)(2) = elem_p(2) - (((*node)(0) - elem_p(0)) * elem_normal(0) +
422 ((*node)(1) - elem_p(1)) * elem_normal(1)) /
423 elem_normal(2);
424 node_mod = true;
425 break;
426 }
427 }
428 if (!node_mod)
429 mooseError("Node not found in mesh_in_xy");
430 }
431
432 // Rotate the mesh back
433 MeshTools::Modification::rotate(*mesh, 0.0, -theta, phi - 90.0);
434 // Translate the mesh back
435 MeshTools::Modification::translate(*mesh, centroid(0), centroid(1), centroid(2));
436
437 // Correct the nodes based on the level set function
438 if (_func_level_set)
439 {
440 for (const auto & node : mesh->node_ptr_range())
441 {
442 unsigned int iter_ct = 0;
443 while (iter_ct < _max_level_set_correction_iterations &&
445 {
446 levelSetCorrection(*node);
447 ++iter_ct;
448 }
449 }
450 }
451
452 // get_mesh_subdomains() pulls from a cache, and can scream at us
453 // if the Mesh thinks the element caches have been invalidated by
454 // Modification.
455 if (!mesh_2d.preparation().has_cached_elem_data)
456 mesh_2d.cache_elem_data();
457
458 // Give the old subdomain to all elements
459 const auto common_id = mesh_2d.get_mesh_subdomains().begin();
460 for (auto & elem : mesh->active_element_ptr_range())
461 elem->subdomain_id() = *common_id;
462
463 // Pass the subdomain names
464 mesh->set_subdomain_name_map() = mesh_2d.get_subdomain_name_map();
465 // Remove the boundaries, they get re-added (with a known ID) when stitching the pieces together
466 mesh->get_boundary_info().remove_id(mesh_2d_ext_bdry);
467 // Elements have changed, neighbors, ids etc
468 mesh->unset_is_prepared();
469
470 return mesh;
471}
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
registerMooseObject("MooseApp", SurfaceSubdomainsDelaunayRemesher)
void ErrorVector unsigned int
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
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...
void renameParameterGroup(const std::string &old_name, const std::string &new_name)
This method renames a parameter group.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
Helper class to define, parameterize and create a level set function used in meshing,...
void levelSetCorrection(Node &node)
Correct the position of a node based on the level set function.
static InputParameters validParams()
const unsigned int _max_level_set_correction_iterations
Maximum number of iterations to correct the nodes based on the level set function.
SymFunctionPtr _func_level_set
function parser object describing the level set
Real levelSetEvaluator(const Point &point)
Evaluate the level set function at a given point.
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
Build a replicated mesh.
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
Build a MeshBase object whose underlying type will be determined by the Mesh input file block.
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition MooseBase.h:205
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
Base class for Delaunay mesh generators applied to a surface.
const bool _verbose
Whether the generator should be verbose.
Real meshNormalDeviation2D(const MeshBase &mesh, const Point &global_norm)
Calculate the maximum deviation of the normal vectors in a given mesh from a global average normal ve...
Point meshNormal2D(const MeshBase &mesh)
Calculate the average normal vector of a 2D mesh based on the normal vectors of its elements using th...
const Real _auto_area_func_default_size_dist
Background size's effective distance for automatic desired area function.
const Real _auto_area_func_default_size
Background size for automatic desired area function.
Point elemNormal(const Elem &elem)
Calculate the normal vector of a 2D element based the first three vertices.
const Real _max_angle_deviation
Max angle deviation from the global average normal vector in the input mesh.
const bool _use_auto_area_func
Whether to use automatic desired area function.
const Real _auto_area_function_power
Power of the polynomial used in the inverse distance interpolation for automatic area function.
const unsigned int _auto_area_function_num_points
Maximum number of points to use for the inverse distance interpolation for automatic area function.
Class to remesh surface subdomains using a triangle mesh inside the subdomain boundaries.
std::vector< Real > _desired_areas
Target areas for the triangulation for each group of surface subdomains.
std::unique_ptr< UnstructuredMesh > General2DDelaunay(UnstructuredMesh &mesh_2d, std::vector< std::unique_ptr< UnstructuredMesh > > &hole_meshes_2d, unsigned int group_i)
Generate a 2D mesh using Delaunay triangulation based on the input 2D surface mesh and the 2D hole me...
std::vector< std::vector< SubdomainName > > _subdomain_names
The subdomains to be converted to a 2D mesh.
std::vector< unsigned int > _interpolate_boundaries
Number of points added to boundaries around each group of surface subdomains.
virtual std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
SurfaceSubdomainsDelaunayRemesher(const InputParameters &parameters)
std::unique_ptr< MeshBase > & _input
The input mesh name.
unsigned int _num_groups
Number of groups of subdomains, also number of times we will call the Delaunay generator.
const Parallel::Communicator & comm() const
MeshBase & mesh
void buildPolyLineMesh(MeshBase &mesh, const std::vector< Point > &points, const bool loop, const BoundaryName &start_boundary, const BoundaryName &end_boundary, const std::vector< unsigned int > &nums_edges_between_points)
Generates meshes from edges connecting a list of points.
BoundaryID getNextFreeBoundaryID(MeshBase &input_mesh)
Checks input mesh and returns the largest boundary ID in the mesh plus one, which is a boundary ID in...
void addExternalBoundary(MeshBase &mesh, const BoundaryID extern_bid, bool &has_external_bid)
Adds a sideset for the external boundary of the mesh (e.g.
void convertBlockToMesh(MeshBase &source_mesh, MeshBase &target_mesh, const std::vector< SubdomainName > &target_blocks)
Convert a list of blocks in a given mesh to a standalone new mesh.
void createSubdomainFromSidesets(MeshBase &mesh, std::vector< BoundaryName > boundary_names, const SubdomainID new_subdomain_id, const SubdomainName new_subdomain_name, const std::string type_name)
Create a new subdomain by generating new side elements from a list of sidesets in a given mesh.
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
std::unique_ptr< ReplicatedMesh > buildLoopBoundaryOf2DMesh(const MeshBase &input_mesh, const boundary_id_type boundary_id)
Build a loop mesh of edges from the contiguous 2D boundary of 2D input mesh Note: The lower-dimension...
Point meshCentroidCalculator(const MeshBase &mesh)
Calculates the centroid of a MeshBase.
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
static constexpr Real TOLERANCE