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.");
    43       "Level set used to achieve more accurate reverse projection compared to interpolation.");
    45       "max_level_set_correction_iterations",
    47       "Maximum number of iterations to correct the nodes based on the level set function.");
    49       "max_angle_deviation",
    51       "max_angle_deviation>0 & max_angle_deviation<90",
    52       "Maximum angle deviation from the global average normal vector in the input mesh.");
    55       "output_external_boundary_name",
    57       "The optional name of the external boundary of the mesh to generate. If not provided, the "    58       "external boundary will be have a trivial id of 0.");
    66     _input(getMesh(
"input")),
    67     _boundary_names(getParam<
std::vector<BoundaryName>>(
"boundary_names")),
    68     _hole_boundary_names(getParam<
std::vector<
std::vector<BoundaryName>>>(
"hole_boundary_names")),
    69     _max_level_set_correction_iterations(
    70         getParam<unsigned 
int>(
"max_level_set_correction_iterations")),
    71     _max_angle_deviation(getParam<
Real>(
"max_angle_deviation")),
    72     _output_external_boundary_name(getParam<BoundaryName>(
"output_external_boundary_name"))
    81                           getParam<std::vector<std::string>>(
"constant_names"),
    82                           getParam<std::vector<std::string>>(
"constant_expressions"));
    83     if (
_func_level_set->Parse(getParam<std::string>(
"level_set"), 
"x,y,z") >= 0)
    86                  "\nin CutMeshByLevelSetGenerator ",
    95 std::unique_ptr<MeshBase>
    98   std::unique_ptr<MeshBase> mesh_3d = std::move(
_input);
   109     if (((std::string)e.
what()).compare(0, 12, 
"The sideset ") == 0)
   116   std::vector<subdomain_id_type> hole_block_ids;
   123           mesh_3d, hole, hole_block_ids.back(), SubdomainName(), 
type());
   127       if (((std::string)e.
what()).compare(0, 12, 
"The sideset ") == 0)
   138   std::vector<std::unique_ptr<MeshBase>> hole_meshes_2d;
   139   for (
const auto & hole_block_id : hole_block_ids)
   143         mesh_3d, hole_meshes_2d.back(), {std::to_string(hole_block_id)});
   155   mooseAssert(elem.n_vertices() == 3 || elem.n_vertices() == 4, 
"unsupported element type.");
   157   const Point & p0 = *elem.node_ptr(0);
   158   const Point & p1 = *elem.node_ptr(1);
   159   const Point & p2 = *elem.node_ptr(2);
   161   if (elem.n_vertices() == 4)
   163     const Point & p3 = *elem.node_ptr(3);
   164     return ((p2 - p0).cross(p3 - p1)).unit();
   167   return ((p2 - p1).cross(p0 - p1)).unit();
   173   Point mesh_norm = Point(0.0, 0.0, 0.0);
   174   Real mesh_area = 0.0;
   177   for (
const auto & elem : 
mesh.active_local_element_ptr_range())
   179     const Real elem_area = elem->volume();
   181     mesh_area += elem_area;
   183   mesh.comm().sum(mesh_norm);
   184   mesh.comm().sum(mesh_area);
   185   mesh_norm /= mesh_area;
   186   return mesh_norm.unit();
   192   Real max_deviation(0.0);
   194   for (
const auto & elem : 
mesh.active_local_element_ptr_range())
   196     const Real elem_deviation = std::acos(global_norm * 
elemNormal(*elem)) / M_PI * 180.0;
   197     max_deviation = 
std::max(max_deviation, elem_deviation);
   199   mesh.comm().max(max_deviation);
   200   return max_deviation;
   221   const Point grad = Point((xp_eval - xm_eval) / (2.0 * diff),
   222                            (yp_eval - ym_eval) / (2.0 * diff),
   223                            (zp_eval - zm_eval) / (2.0 * diff));
   224   const Real xyz_diff = -original_eval / grad.contract(grad);
   225   node(0) += xyz_diff * grad(0);
   226   node(1) += xyz_diff * grad(1);
   227   node(2) += xyz_diff * grad(2);
   230 std::unique_ptr<MeshBase>
   232     std::unique_ptr<MeshBase> & mesh_2d, std::vector<std::unique_ptr<MeshBase>> & hole_meshes_2d)
   238     for (
const auto & node : mesh_2d->node_ptr_range())
   243                    "The level set function does not match the nodes in the given boundary of the "   251   mesh_2d->prepare_for_use();
   252   MeshTools::Modification::all_tri(*mesh_2d);
   254   for (
const auto & elem : mesh_2d->active_element_ptr_range())
   255     for (
const auto & i_side : elem->side_index_range())
   256       if (elem->neighbor_ptr(i_side) == 
nullptr)
   257         mesh_2d->get_boundary_info().add_side(elem, i_side, mesh_2d_ext_bdry);
   265       mesh_2d_dummy, {std::to_string(mesh_2d_ext_bdry)}, new_block_id_1d, SubdomainName(), 
type());
   270   mesh_2d_dummy->clear();
   273   std::vector<std::unique_ptr<MeshBase>> hole_meshes_1d;
   274   for (
auto & hole_mesh_2d : hole_meshes_2d)
   278     hole_mesh_2d->find_neighbors();
   280     for (
const auto & elem : hole_mesh_2d->active_element_ptr_range())
   281       for (
const auto & i_side : elem->side_index_range())
   282         if (elem->neighbor_ptr(i_side) == 
nullptr)
   283           hole_mesh_2d->get_boundary_info().add_side(elem, i_side, mesh_2d_ext_bdry);
   286                                                 {std::to_string(hole_mesh_2d_ext_bdry)},
   287                                                 new_hole_block_id_1d,
   293         hole_mesh_2d, hole_meshes_1d.back(), {std::to_string(new_hole_block_id_1d)});
   294     hole_mesh_2d->clear();
   304                "The normal vector of some elements in the 2D mesh deviates too much from the "   305                "global average normal vector. The maximum deviation is " +
   307                    ". Consider dividing the boundary into several parts to "   308                    "reduce the angle deviation.");
   311   MeshTools::Modification::translate(*mesh_1d, -centroid(0), -centroid(1), -centroid(2));
   312   MeshTools::Modification::translate(*mesh_2d, -centroid(0), -centroid(1), -centroid(2));
   314   for (
auto & hole_mesh_1d : hole_meshes_1d)
   315     MeshTools::Modification::translate(*hole_mesh_1d, -centroid(0), -centroid(1), -centroid(2));
   319   const Real theta = std::acos(mesh_norm(2)) / M_PI * 180.0;
   324   MeshTools::Modification::rotate(*mesh_1d, 90.0 - phi, theta, 0.0);
   325   MeshTools::Modification::rotate(*mesh_2d, 90.0 - phi, theta, 0.0);
   327   for (
auto & hole_mesh_1d : hole_meshes_1d)
   328     MeshTools::Modification::rotate(*hole_mesh_1d, 90.0 - phi, theta, 0.0);
   334   for (
const auto & node : mesh_2d->node_ptr_range())
   337   for (
const auto & node : mesh_1d->node_ptr_range())
   340   for (
auto & hole_mesh_1d : hole_meshes_1d)
   342     for (
const auto & node : hole_mesh_1d->node_ptr_range())
   346   std::vector<libMesh::TriangulatorInterface::MeshedHole> meshed_holes;
   347   std::vector<libMesh::TriangulatorInterface::Hole *> triangulator_hole_ptrs(hole_meshes_1d.size());
   348   meshed_holes.reserve(hole_meshes_1d.size());
   351     hole_meshes_1d[hole_i]->prepare_for_use();
   352     meshed_holes.emplace_back(*hole_meshes_1d[hole_i]);
   353     triangulator_hole_ptrs[hole_i] = &meshed_holes.back();
   357   std::unique_ptr<UnstructuredMesh> 
mesh =
   360   Poly2TriTriangulator poly2tri(*
mesh);
   361   poly2tri.triangulation_type() = TriangulatorInterface::PSLG;
   363   poly2tri.set_interpolate_boundary_points(0);
   364   poly2tri.set_refine_boundary_allowed(
false);
   365   poly2tri.set_verify_hole_boundaries(
false);
   366   poly2tri.desired_area() = 0;
   367   poly2tri.minimum_angle() = 0; 
   368   poly2tri.smooth_after_generating() = 
false;
   369   if (!triangulator_hole_ptrs.empty())
   370     poly2tri.attach_hole_list(&triangulator_hole_ptrs);
   373     poly2tri.set_auto_area_function(this->
comm(),
   378   poly2tri.triangulate();
   381   for (
const auto & node : 
mesh->node_ptr_range())
   383     bool node_mod = 
false;
   385     for (
const auto & elem : mesh_2d->active_element_ptr_range())
   387       if (elem->contains_point(Point((*node)(0), (*node)(1), 0.0)))
   390         const auto elem_id = elem->id();
   392         const Elem & elem_xyz = *mesh_2d_xyz->elem_ptr(elem_id);
   394         const Point elem_normal = 
elemNormal(elem_xyz);
   395         const Point & elem_p = *mesh_2d_xyz->elem_ptr(elem_id)->node_ptr(0);
   402           (*node)(2) = elem_p(2);
   408         (*node)(2) = elem_p(2) - (((*node)(0) - elem_p(0)) * elem_normal(0) +
   409                                   ((*node)(1) - elem_p(1)) * elem_normal(1)) /
   420   MeshTools::Modification::rotate(*
mesh, 0.0, -theta, phi - 90.0);
   422   MeshTools::Modification::translate(*
mesh, centroid(0), centroid(1), centroid(2));
   427     for (
const auto & node : 
mesh->node_ptr_range())
   429       unsigned int iter_ct = 0;
   442     const std::vector<BoundaryID> output_boundary_id =
   449   mesh->set_isnt_prepared();
 GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError. 
void addFParserConstants(SymFunctionPtr &parser, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions) const
add constants (which can be complex expressions) to the parser object 
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Boundary2DDelaunayGenerator(const InputParameters ¶meters)
virtual const char * what() const
Get out the error message. 
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance. 
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 createSubdomainFromSidesets(std::unique_ptr< 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...
const T & getParam(const std::string &name) const
Retrieve a parameter for the object. 
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. 
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 unsigned int _max_level_set_correction_iterations
Maximum number of iterations to correct the nodes based on the level set function. 
static InputParameters validParams()
auto max(const L &left, const R &right)
const bool _use_auto_area_func
Whether to use automatic desired area function. 
const std::string & name() const
Get the name of the class. 
std::unique_ptr< MeshBase > & _input
The input mesh name. 
virtual std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh. 
const Real _max_angle_deviation
Max angle deviation from the global average normal vector in the input mesh. 
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is less than another variable within an absolute tolerance...
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...
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. 
SymFunctionPtr _func_level_set
function parser object describing the level set 
registerMooseObject("MooseApp", Boundary2DDelaunayGenerator)
Provides a way for users to bail out of the current solve. 
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Point elemNormal(const Elem &elem)
Calculate the normal vector of a 2D element based the first three vertices. 
const Real _auto_area_function_power
Power of the polynomial used in the inverse distance interpolation for automatic area function...
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval. 
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...
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()
static InputParameters validParams()
Point meshNormal2D(const MeshBase &mesh)
Calculate the average normal vector of a 2D mesh based on the normal vectors of its elements using th...
void levelSetCorrection(Node &node)
Correct the position of a node based on the level set function. 
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid. 
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...
void convertBlockToMesh(std::unique_ptr< MeshBase > &source_mesh, std::unique_ptr< MeshBase > &target_mesh, const std::vector< SubdomainName > &target_blocks)
Convert a list of blocks in a given mesh to a standalone new mesh. 
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...
void ErrorVector unsigned int
auto index_range(const T &sizable)
const std::vector< BoundaryName > _boundary_names
The boundaries to be converted to a 2D mesh. 
void setParserFeatureFlags(SymFunctionPtr &) const
apply input parameters to internal feature flags of the parser object