19#include "libmesh/libmesh_config.h"
23#include "libmesh/enforce_ieee754.h"
26#include "libmesh/mesh_triangle_interface.h"
27#include "libmesh/unstructured_mesh.h"
28#include "libmesh/face_tri3.h"
29#include "libmesh/face_tri6.h"
30#include "libmesh/mesh_generation.h"
31#include "libmesh/mesh_smoother_laplace.h"
32#include "libmesh/boundary_info.h"
33#include "libmesh/mesh_triangle_holes.h"
34#include "libmesh/mesh_triangle_wrapper.h"
35#include "libmesh/enum_elem_type.h"
36#include "libmesh/enum_order.h"
37#include "libmesh/enum_to_string.h"
38#include "libmesh/utility.h"
40#include "libmesh/meshfree_interpolation.h"
55 const unsigned int num_nearest_pts,
56 const unsigned int power,
57 const Real background_value,
58 const Real background_eff_dist):
60 _num_nearest_pts(num_nearest_pts),
62 _background_value(background_value),
63 _background_eff_dist(background_eff_dist),
74 const std::vector<Real> & input_vals)
76 std::vector<std::string> field_vars{
"f"};
79#ifdef LIBMESH_USE_COMPLEX_NUMBERS
80 std::vector<Number> input_complex_vals;
81 for (
const auto & input_val : input_vals)
82 input_complex_vals.push_back(
Complex (input_val, 0.0));
96 std::vector<Point> target_pts;
97 std::vector<Number> target_vals;
99 target_pts.push_back(p);
100 target_vals.resize(1);
119 _minimum_angle(20.0),
120 _triangulation_type(GENERATE_CONVEX_HULL),
121 _insert_extra_points(false),
122 _smooth_after_generating(true),
124 _fixup_tri7_center_nodes(false),
125 _auto_area_function(nullptr)
169 std::map<Point, dof_id_type> point_id_map;
171 for (
Node * node :
_mesh.node_ptr_range())
175 (point_id_map.count(*node),
176 "TriangulatorInterface does not support overlapping nodes found at "
177 <<
static_cast<Point&
>(*node));
179 point_id_map.emplace(*node, node->id());
186 for (
Elem * elem :
_mesh.element_ptr_range())
187 for (
auto n :
make_range(elem->n_vertices(), elem->n_nodes()))
188 point_id_map.erase(elem->point(n));
203 std::unordered_set<Node *> nodes_to_delete;
205 for (
Elem * elem :
_mesh.element_ptr_range())
206 for (
auto n :
make_range(elem->n_vertices(), elem->n_nodes()))
207 nodes_to_delete.insert(elem->node_ptr(n));
211 for (
auto & node :
_mesh.node_ptr_range())
212 if (!mh.contains(*node))
213 nodes_to_delete.insert(node);
222 const std::size_t np = mh.n_points();
225 const Point pt = mh.point(i);
226 const dof_id_type id0 = libmesh_map_find(point_id_map, pt);
228 const Point next_pt = mh.point((np+i+1)%np);
229 const dof_id_type id1 = libmesh_map_find(point_id_map, next_pt);
230 this->
segments.emplace_back(id0, id1);
238 for (
Node * node : nodes_to_delete)
255 for (
auto node_it =
_mesh.nodes_begin(),
256 node_end =
_mesh.nodes_end();
257 node_it != node_end;)
259 Node * node = *node_it;
263 if (node->
id() >= max_node_id)
268 Node * next_node = (node_it == node_end) ?
269 *
_mesh.nodes_begin() : *node_it;
271 this->
segments.emplace_back(node->
id(), next_node->
id());
276 std::vector<Point> outer_pts;
278 outer_pts.push_back(
_mesh.
point(segment.first));
304 std::vector<std::pair<unsigned int, unsigned int>> old_segments =
317 for (
auto old_segment : old_segments)
325 const Point new_point =
326 ((n_interpolated-i) * *(
Point *)(begin_node) +
327 (i+1) * *(
Point *)(end_node)) /
328 (n_interpolated + 1);
330 this->
segments.emplace_back(current_id,
332 current_id = next_node->
id();
334 this->
segments.emplace_back(current_id,
355 libmesh_not_implemented();
362 std::map<std::pair<Point, unsigned int>,
Point> all_midpoints;
363 unsigned int n_midpoints =
365 libmesh_assert_equal_to(this->
segments.size() * n_midpoints,
366 this->segment_midpoints.size());
371 all_midpoints[{p,m}] =
378 if (!hole->n_midpoints())
381 n_midpoints = hole->n_midpoints();
382 else if (hole->n_midpoints() != n_midpoints)
383 libmesh_not_implemented_msg
384 (
"Differing boundary midpoint counts " <<
385 hole->n_midpoints() <<
" and " << n_midpoints);
392 const auto n_hole_points = hole->n_points();
398 const Point & p = hole->point(i+1);
399 all_midpoints[{p,m}] = hole->midpoint(n_midpoints-m-1, i);
401 const Point & p = hole->point(0);
402 all_midpoints[{p,m}] = hole->midpoint(n_midpoints-m-1, n_hole_points-1);
409 libmesh_not_implemented_msg
410 (
"Cannot construct triangles with more than 1 midpoint per edge");
415 for (
Elem * elem :
_mesh.element_ptr_range())
419 libmesh_assert_equal_to(elem->n_vertices(), 3);
420 libmesh_assert_not_equal_to(elem->default_order(),
FIRST);
425 if (elem->neighbor_ptr(n))
428 const Point & p = elem->point(n);
430 if (
const auto it = all_midpoints.find({p,0});
431 it != all_midpoints.end())
432 elem->point(n+3) = it->second;
458 for (
Elem * elem :
_mesh.element_ptr_range())
460 libmesh_assert_equal_to(elem->n_vertices(), 3);
461 libmesh_assert_equal_to(elem->n_nodes(), 7u);
463 elem->point(6) = wv * (elem->point(0) +
466 wm * (elem->point(3) +
487 for (
Elem * elem :
_mesh.element_ptr_range())
489 libmesh_assert_equal_to(elem->n_vertices(), 3);
490 libmesh_assert_greater_equal(elem->n_nodes(), 6u);
492 const Point & x0 = elem->point(0);
493 const Point & x1 = elem->point(1);
494 const Point & x2 = elem->point(2);
495 const Point & x3 = elem->point(3);
496 const Point & x4 = elem->point(4);
497 const Point & x5 = elem->point(5);
501 const Point a1 = 4*x0 + 4*x1 - 8*x3;
502 const Point b1 = 4*x0 - 4*x3 + 4*x4 - 4*x5;
503 const Point c1 = -3*x0 - 1*x1 + 4*x3;
504 const Point b2 = 4*x0 + 4*x2 - 8*x5;
505 const Point c2 = -3*x0 - 1*x2 + 4*x5;
512 Real min_jac = std::numeric_limits<Real>::max();
513 unsigned int worst_sample = 0;
514 for (
unsigned int s = 0; s != 7; ++s)
516 const Real xi = xi_samples[s];
517 const Real eta = eta_samples[s];
518 const Point dxi = xi*a1 + eta*b1 + c1;
519 const Point deta = xi*b1 + eta*b2 + c2;
521 const Real jac = dxi(0)*deta(1) - dxi(1)*deta(0);
529 if (min_jac > jac_tol)
535 std::ostringstream sides;
536 for (
unsigned int n = 0; n != 3; ++n)
537 if (!elem->neighbor_ptr(n))
539 const Point straight =
540 0.5 * (elem->point(n) + elem->point((n+1) % 3));
541 sides <<
" (boundary side " << n
542 <<
": straight midpoint " << straight
543 <<
", snapped midpoint " << elem->point(n+3) <<
")";
547 "TriangulatorInterface: snapping a boundary midpoint produced a "
548 "tangled quadratic triangle (element " << elem->id()
549 <<
", non-positive Jacobian " << min_jac
550 <<
" at reference sample (" << xi_samples[worst_sample] <<
", "
551 << eta_samples[worst_sample] <<
"); reference triangle area "
552 << ref_area <<
")." << sides.str()
553 <<
" Refine the boundary discretization so that recorded "
554 "midpoints lie closer to their straight-line midpoints, "
570 if (hole->contains(hole2->point(i)))
572 (
"Found point " << hole2->point(i) <<
573 " on one hole boundary and another's interior");
577 if (!outer_bdy.
contains(hole->point(i)))
579 (
"Found point " << hole->point(i) <<
580 " on hole boundary but outside outer boundary");
592 unsigned int n_hole_points = 0;
595 for (
const auto & hole : *
_holes)
597 n_hole_points += hole->n_points();
602 libmesh_assert_greater(hole->segment_indices().size(), 1);
603 libmesh_assert_equal_to(hole->segment_indices().back(), hole->n_points());
606 return n_hole_points;
610 const unsigned int num_nearest_pts,
611 const unsigned int power,
612 const Real background_value,
613 const Real background_eff_dist)
615 _auto_area_function = std::make_unique<AutoAreaFunction>(comm, num_nearest_pts, power, background_value, background_eff_dist);
623 std::vector<Point> function_points;
624 std::vector<Real> function_sizes;
632 std::vector<Real> & function_sizes,
633 const Real & area_factor)
640 for (
unsigned int i = 0; i < bdry_mh.n_points(); i++)
642 function_points.push_back((bdry_mh.point(i) + bdry_mh.point((i + 1) % bdry_mh.n_points())) /
644 function_sizes.push_back(
645 (bdry_mh.point(i) - bdry_mh.point((i + 1) % bdry_mh.n_points())).norm());
651 for (
unsigned int i = 0; i < hole->n_points(); i++)
653 function_points.push_back(
654 (hole->point(i) + hole->point((i + 1) % hole->n_points())) /
Real(2.0));
655 function_sizes.push_back(
656 (hole->point(i) - hole->point((i + 1) % hole->n_points())).norm());
661 function_sizes.begin(), function_sizes.end(), [&area_factor](
Real & a) { a = a * a * area_factor * std::sqrt(3.0) / 4.0; });
669#include "libmesh/restore_ieee754.h"
AutoAreaFunction(const Parallel::Communicator &comm, const unsigned int num_nearest_pts, const unsigned int power, const Real background_value, const Real background_eff_dist)
void init_mfi(const std::vector< Point > &input_pts, const std::vector< Real > &input_vals)
std::unique_ptr< InverseDistanceInterpolation< 3 > > _auto_area_mfi
virtual Real operator()(const Point &p, const Real) override
virtual ~AutoAreaFunction()
This is the base class from which all geometric element types are derived.
Base class for functors that can be evaluated at a point and (optionally) time.
bool _initialized
When init() was called so that everything is ready for calls to operator() (...), then this bool is t...
bool _is_time_dependent
Cache whether or not this function is actually time-dependent.
Inverse distance interpolation.
virtual const Point & point(const dof_id_type i) const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh.
virtual void delete_node(Node *n)=0
Removes the Node n from the mesh.
virtual dof_id_type max_node_id() const =0
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual void clear_elems()=0
Deletes all the element data that is currently stored.
virtual void all_complete_order()
Calls the range-based version of this function with a range consisting of all elements in the mesh.
A Node is like a Point, but with more information.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Another concrete instantiation of the hole, this one should be sufficiently general for most non-poly...
An abstract class for defining a 2-dimensional hole.
bool contains(Point p) const
Return true iff p lies inside the hole.
Another concrete instantiation of the hole, as general as ArbitraryHole, but based on an existing 1D ...
void increase_triangle_order()
Helper function to upconvert Tri3 to any higher order triangle type if requested via _elem_type.
bool _verify_hole_boundaries
Flag which tells if we want to check hole geometry.
ElemType _elem_type
The type of elements to generate.
void nodes_to_segments(dof_id_type max_node_id)
Helper function to create PSLG segments from our node ordering, up to the maximum node id,...
std::set< std::size_t > _bdy_ids
A set of ids to allow on the outer boundary loop.
void elems_to_segments()
Helper function to create PSLG segments from our other boundary-defining options (1D mesh edges,...
void fixup_tri7_center_nodes()
Helper called at the end of increase_triangle_order() for TRI7 to reposition the interior node to the...
int _interpolate_boundary_points
Flag which tells how many additional nodes should be inserted between each pair of original mesh poin...
void insert_any_extra_boundary_points()
Helper function to add extra points (midpoints of initial segments) to a PSLG triangulation.
unsigned int total_hole_points()
Helper function to count points in and verify holes.
@ PSLG
Triangulate the interior of a Planar Straight Line Graph, which is defined implicitly by the order of...
const std::vector< Hole * > * _holes
A pointer to a vector of Hole*s.
TriangulatorInterface(UnstructuredMesh &mesh)
The constructor.
bool _fixup_tri7_center_nodes
Flag which tells if we want to relocate TRI7 interior nodes to the curved-mapping centroid after snap...
std::vector< std::pair< unsigned int, unsigned int > > segments
When constructing a PSLG, if the node numbers do not define the desired boundary segments implicitly ...
UnstructuredMesh & _mesh
Reference to the mesh which is to be created by triangle.
int get_interpolate_boundary_points() const
Complicated getter, for compatibility with insert_extra_points()
void verify_holes(const Hole &outer_bdy)
Helper function to check holes for intersections if requested.
void calculate_auto_desired_area_samples(std::vector< Point > &function_points, std::vector< Real > &function_sizes, const Real &area_factor=1.5)
The external boundary and all hole boundaries are collected.
std::vector< Point > segment_midpoints
When constructing a second-order triangulation from a second-order boundary, we may do the triangulat...
TriangulationType _triangulation_type
The type of triangulation to perform: choices are: convex hull PSLG.
std::vector< Point > segment_midpoints_keys
When saving the midpoint location data, we need to save the corresponding segment information too.
void verify_quadratic_elements()
Helper called at the end of increase_triangle_order() to verify that no boundary-midpoint snap has ta...
std::unique_ptr< AutoAreaFunction > _auto_area_function
The auto area function based on the spacing of boundary points.
bool _insert_extra_points
Flag which tells whether or not to insert additional nodes before triangulation.
void set_auto_area_function(const Parallel::Communicator &comm, const unsigned int num_nearest_pts, const unsigned int power, const Real background_value, const Real background_eff_dist)
Generate an auto area function based on spacing of boundary points.
FunctionBase< Real > * get_auto_area_function()
Get the auto area function.
void set_interpolate_boundary_points(int n_points)
Complicated setter, for compatibility with insert_extra_points()
The UnstructuredMesh class is derived from the MeshBase class.
The libMesh namespace provides an interface to certain functionality in the library.
std::complex< Real > Complex
T cross_norm(const TypeVector< T > &b, const TypeVector< T > &c)
Calls cross_norm_sq() and takes the square root of the result.
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...