15 #include "libmesh/boundary_info.h" 16 #include "libmesh/poly2tri_triangulator.h" 17 #include "libmesh/mesh_triangle_holes.h" 18 #include "libmesh/mesh_modification.h" 19 #include "libmesh/parallel_algebra.h" 30 "Mesh generator that convert a 2D surface given as one or a few boundaries of a 3D mesh into " 31 "a 2D mesh using Delaunay triangulation.");
32 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The mesh we want to modify");
33 params.
addRequiredParam<std::vector<BoundaryName>>(
"boundary_names",
"The boundaries to be used");
34 params.
addParam<std::vector<std::vector<BoundaryName>>>(
35 "hole_boundary_names",
36 std::vector<std::vector<BoundaryName>>(),
37 "The optional boundaries to be used as the holes in the mesh during triangulation. Note that " 38 "this is a vector of vectors, which allows each hole to be defined as a combination of " 39 "multiple boundaries.");
42 "output_external_boundary_name",
44 "The optional name of the external boundary of the mesh to generate. If not provided, the " 45 "external boundary will be have a trivial id of 0.");
53 _input(getMesh(
"input")),
54 _boundary_names(getParam<
std::vector<BoundaryName>>(
"boundary_names")),
55 _hole_boundary_names(getParam<
std::vector<
std::vector<BoundaryName>>>(
"hole_boundary_names")),
56 _output_external_boundary_name(getParam<BoundaryName>(
"output_external_boundary_name"))
60 std::unique_ptr<MeshBase>
63 std::unique_ptr<MeshBase> mesh_3d = std::move(
_input);
74 if (((std::string)e.
what()).compare(0, 12,
"The sideset ") == 0)
81 std::vector<subdomain_id_type> hole_block_ids;
88 *mesh_3d, hole, hole_block_ids.back(), SubdomainName(),
type());
92 if (((std::string)e.
what()).compare(0, 12,
"The sideset ") == 0)
103 std::vector<std::unique_ptr<MeshBase>> hole_meshes_2d;
104 for (
const auto & hole_block_id : hole_block_ids)
108 *mesh_3d, *hole_meshes_2d.back(), {std::to_string(hole_block_id)});
117 std::unique_ptr<MeshBase>
119 std::unique_ptr<MeshBase> & mesh_2d, std::vector<std::unique_ptr<MeshBase>> & hole_meshes_2d)
125 for (
const auto & node : mesh_2d->node_ptr_range())
130 "The level set function does not match the nodes in the given boundary of the " 138 mesh_2d->prepare_for_use();
139 MeshTools::Modification::all_tri(*mesh_2d);
141 for (
const auto & elem : mesh_2d->active_element_ptr_range())
142 for (
const auto & i_side : elem->side_index_range())
143 if (elem->neighbor_ptr(i_side) ==
nullptr)
144 mesh_2d->get_boundary_info().add_side(elem, i_side, mesh_2d_ext_bdry);
152 *mesh_2d_dummy, {std::to_string(mesh_2d_ext_bdry)}, new_block_id_1d, SubdomainName(),
type());
157 mesh_2d_dummy->clear();
160 std::vector<std::unique_ptr<MeshBase>> hole_meshes_1d;
161 for (
auto & hole_mesh_2d : hole_meshes_2d)
165 hole_mesh_2d->find_neighbors();
167 for (
const auto & elem : hole_mesh_2d->active_element_ptr_range())
168 for (
const auto & i_side : elem->side_index_range())
169 if (elem->neighbor_ptr(i_side) ==
nullptr)
170 hole_mesh_2d->get_boundary_info().add_side(elem, i_side, hole_mesh_2d_ext_bdry);
173 {std::to_string(hole_mesh_2d_ext_bdry)},
174 new_hole_block_id_1d,
180 *hole_mesh_2d, *hole_meshes_1d.back(), {std::to_string(new_hole_block_id_1d)});
181 hole_mesh_2d->clear();
191 "The normal vector of some elements in the 2D mesh deviates too much from the " 192 "global average normal vector. The maximum deviation is " +
194 ". Consider dividing the boundary into several parts to " 195 "reduce the angle deviation.");
198 MeshTools::Modification::translate(*mesh_1d, -centroid(0), -centroid(1), -centroid(2));
199 MeshTools::Modification::translate(*mesh_2d, -centroid(0), -centroid(1), -centroid(2));
201 for (
auto & hole_mesh_1d : hole_meshes_1d)
202 MeshTools::Modification::translate(*hole_mesh_1d, -centroid(0), -centroid(1), -centroid(2));
206 const Real theta = std::acos(mesh_norm(2)) / M_PI * 180.0;
208 (MooseUtils::absoluteFuzzyLessThan(mesh_norm(2), 1.0) ? std::atan2(mesh_norm(1), mesh_norm(0))
211 MeshTools::Modification::rotate(*mesh_1d, 90.0 - phi, theta, 0.0);
212 MeshTools::Modification::rotate(*mesh_2d, 90.0 - phi, theta, 0.0);
214 for (
auto & hole_mesh_1d : hole_meshes_1d)
215 MeshTools::Modification::rotate(*hole_mesh_1d, 90.0 - phi, theta, 0.0);
221 for (
const auto & node : mesh_2d->node_ptr_range())
224 for (
const auto & node : mesh_1d->node_ptr_range())
227 for (
auto & hole_mesh_1d : hole_meshes_1d)
229 for (
const auto & node : hole_mesh_1d->node_ptr_range())
233 std::vector<libMesh::TriangulatorInterface::MeshedHole> meshed_holes;
234 std::vector<libMesh::TriangulatorInterface::Hole *> triangulator_hole_ptrs(hole_meshes_1d.size());
235 meshed_holes.reserve(hole_meshes_1d.size());
238 hole_meshes_1d[hole_i]->prepare_for_use();
239 meshed_holes.emplace_back(*hole_meshes_1d[hole_i]);
240 triangulator_hole_ptrs[hole_i] = &meshed_holes.back();
244 std::unique_ptr<UnstructuredMesh>
mesh =
247 Poly2TriTriangulator poly2tri(*
mesh);
248 poly2tri.triangulation_type() = TriangulatorInterface::PSLG;
250 poly2tri.set_interpolate_boundary_points(0);
251 poly2tri.set_refine_boundary_allowed(
false);
252 poly2tri.set_verify_hole_boundaries(
false);
253 poly2tri.desired_area() = 0;
254 poly2tri.minimum_angle() = 0;
255 poly2tri.smooth_after_generating() =
false;
256 if (!triangulator_hole_ptrs.empty())
257 poly2tri.attach_hole_list(&triangulator_hole_ptrs);
260 poly2tri.set_auto_area_function(this->
comm(),
265 poly2tri.triangulate();
268 for (
const auto & node :
mesh->node_ptr_range())
270 bool node_mod =
false;
272 for (
const auto & elem : mesh_2d->active_element_ptr_range())
274 if (elem->contains_point(Point((*node)(0), (*node)(1), 0.0)))
277 const auto elem_id = elem->id();
279 const Elem & elem_xyz = *mesh_2d_xyz->elem_ptr(elem_id);
281 const Point elem_normal =
elemNormal(elem_xyz);
282 const Point & elem_p = *mesh_2d_xyz->elem_ptr(elem_id)->node_ptr(0);
286 if (MooseUtils::absoluteFuzzyEqual((*node)(0), elem_p(0)) &&
287 MooseUtils::absoluteFuzzyEqual((*node)(1), elem_p(1)))
289 (*node)(2) = elem_p(2);
295 (*node)(2) = elem_p(2) - (((*node)(0) - elem_p(0)) * elem_normal(0) +
296 ((*node)(1) - elem_p(1)) * elem_normal(1)) /
307 MeshTools::Modification::rotate(*
mesh, 0.0, -theta, phi - 90.0);
309 MeshTools::Modification::translate(*
mesh, centroid(0), centroid(1), centroid(2));
314 for (
const auto & node :
mesh->node_ptr_range())
316 unsigned int iter_ct = 0;
329 const std::vector<BoundaryID> output_boundary_id =
336 mesh->unset_is_prepared();
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Boundary2DDelaunayGenerator(const InputParameters ¶meters)
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...
virtual const char * what() const
Get out the error message.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
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.
const std::vector< std::vector< BoundaryName > > _hole_boundary_names
The boundaries to be used as holes.
static constexpr Real TOLERANCE
Base class for Delaunay mesh generators applied to a surface.
const Parallel::Communicator & comm() const
BoundaryName _output_external_boundary_name
The name of the external boundary of the mesh to generate.
Point meshNormal2D(const MeshBase &mesh)
Calculate the average normal vector of a 2D mesh based on the normal vectors of its elements using th...
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.
Helper class to define, parameterize and create a level set function used in meshing, often to correct the position of nodes on a surface.
static InputParameters validParams()
static InputParameters validParams()
const bool _use_auto_area_func
Whether to use automatic desired area function.
std::unique_ptr< MeshBase > & _input
The input mesh name.
virtual std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
const std::string & type() const
Get the type of this class.
std::unique_ptr< MeshBase > General2DDelaunay(std::unique_ptr< MeshBase > &mesh_2d, std::vector< std::unique_ptr< MeshBase >> &hole_meshes_2d)
Generate a 2D mesh using Delaunay triangulation based on the input 2D boundary mesh and the 2D hole m...
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.
const unsigned int _auto_area_function_num_points
Maximum number of points to use for the inverse distance interpolation for automatic area function...
SymFunctionPtr _func_level_set
function parser object describing the level set
void levelSetCorrection(Node &node)
Correct the position of a node based on the level set function.
Real levelSetEvaluator(const Point &point)
Evaluate the level set function at a given point.
const Real _auto_area_func_default_size_dist
Background size's effective distance for automatic desired area function.
registerMooseObject("MooseApp", Boundary2DDelaunayGenerator)
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...
Provides a way for users to bail out of the current solve.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _max_angle_deviation
Max angle deviation from the global average normal vector in the input mesh.
const Real _auto_area_function_power
Power of the polynomial used in the inverse distance interpolation for automatic area function...
const unsigned int _max_level_set_correction_iterations
Maximum number of iterations to correct the nodes based on the level set function.
Mesh generator to remesh a boundary of a volumetric mesh using triangle elements. ...
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
static InputParameters validParams()
Point meshCentroidCalculator(const MeshBase &mesh)
Calculates the centroid of a MeshBase.
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 Real _auto_area_func_default_size
Background size for automatic desired area function.
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
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...
auto index_range(const T &sizable)
const std::vector< BoundaryName > _boundary_names
The boundaries to be converted to a 2D mesh.
Point elemNormal(const Elem &elem)
Calculate the normal vector of a 2D element based the first three vertices.