19 #include "libmesh/cell_c0polyhedron.h" 21 #include "libmesh/enum_order.h" 22 #include "libmesh/face_polygon.h" 23 #include "libmesh/mesh_tools.h" 24 #include "libmesh/replicated_mesh.h" 25 #include "libmesh/tensor_value.h" 37 (
const std::vector<std::shared_ptr<Polygon>> & sides,
Elem * p) :
40 this->retriangulate();
53 std::unique_ptr<Elem> returnval =
54 std::make_unique<C0Polyhedron>(sides);
56 returnval->set_id() = this->
id();
57 #ifdef LIBMESH_ENABLE_UNIQUE_ID 59 returnval->set_unique_id(this->
unique_id());
63 returnval->add_extra_integers(n_elem_ints);
64 for (
unsigned int i = 0; i != n_elem_ints; ++i)
65 returnval->set_extra_integer(i, this->get_extra_integer(i));
67 returnval->inherit_data_from(*
this);
85 libmesh_assert_less (i, this->
n_nodes());
94 libmesh_assert_less (i, this->
n_nodes());
102 const unsigned int s)
const 104 libmesh_assert_less (n, this->
n_nodes());
105 libmesh_assert_less (s, this->
n_sides());
107 const std::vector<unsigned int> & node_map =
110 const auto it = std::find(node_map.begin(), node_map.end(), n);
112 return (it != node_map.end());
115 std::vector<unsigned int>
118 libmesh_assert_less(s, this->
n_sides());
122 std::vector<unsigned int>
127 const std::vector<unsigned int> & node_map =
139 const unsigned int e)
const 145 const std::vector<unsigned int> & node_map =
150 if (node_map[noe] == n)
160 std::vector<dof_id_type> & )
const 162 libmesh_not_implemented();
183 const Point v01 = p1 - p0;
184 const Point v02 = p2 - p0;
185 const Point v03 = p3 - p0;
190 return six_vol * (1./6.);
202 Point six_vol_weighted_centroid;
210 const Point v01 = p1 - p0;
211 const Point v02 = p2 - p0;
212 const Point v03 = p3 - p0;
216 const Point tet_centroid = (p0 + p1 + p2 + p3) * 0.25;
218 six_vol += six_tet_vol;
220 six_vol_weighted_centroid += six_tet_vol * tet_centroid;
223 return six_vol_weighted_centroid / six_vol;
228 std::pair<unsigned short int, unsigned short int>
231 libmesh_not_implemented();
232 return std::pair<unsigned short int, unsigned short int> (0,0);
239 libmesh_assert_less (s, this->
n_sides());
248 libmesh_assert_less (s, this->
n_sides());
250 const auto poly_side_ptr = this->
side_ptr(s);
251 const auto n_side_edges = poly_side_ptr->n_sides();
256 Point current_edge = poly_side_ptr->point(1) - poly_side_ptr->point(0);
259 const Point next_edge = poly_side_ptr->point((i + 2) % n_side_edges) -
260 poly_side_ptr->point((i + 1) % n_side_edges);
261 const Point normal_at_vertex = current_edge.
cross(next_edge);
262 normal += normal_at_vertex;
266 current_edge = next_edge;
269 return (outward_normal ? 1. : -1.) * normal.
unit();
290 std::unordered_map<Node *, unsigned int> poly_node_to_id;
294 const auto & [side, inward_normal, node_map] = this->
_sidelinks_data[s];
296 for (
auto t :
make_range(side->n_subtriangles()))
300 const std::array<int, 3> subtri = side->subtriangle(t);
307 libmesh_assert_less(
side_id, node_map.size());
308 const unsigned int local_id = node_map[
side_id];
312 libmesh_assert_equal_to(*(
const Point*)poly_node,
313 *(
const Point*)surf_node);
315 surf_node = surface.
add_point(*poly_node, local_id);
319 const int tri_node = inward_normal ? i : 2-i;
331 auto verify_surface = [& surface] ()
333 for (
const Elem * elem : surface.element_ptr_range())
339 libmesh_assert_equal_to(neigh,
342 libmesh_assert_less(ns, 3);
343 libmesh_assert_equal_to(elem->node_ptr(s),
345 libmesh_assert_equal_to(elem->node_ptr((s+1)%3),
356 std::vector<std::vector<dof_id_type>> nodes_to_elem_vec_map;
362 std::vector<std::set<dof_id_type>> nodes_to_elem_map;
364 nodes_to_elem_map.emplace_back
365 (nodes_to_elem_vec_map[i].begin(),
366 nodes_to_elem_vec_map[i].end());
375 auto surroundings_of =
376 [&nodes_to_elem_map, & surface]
378 std::vector<Elem *> * surrounding_elems)
380 const std::set<dof_id_type> & elems_by_node =
381 nodes_to_elem_map[node.id()];
383 const unsigned int n_surrounding = elems_by_node.size();
384 libmesh_assert_greater_equal(n_surrounding, 3);
386 if (surrounding_elems)
389 surrounding_elems->resize(n_surrounding);
392 std::vector<Node *> surrounding_nodes(n_surrounding);
400 surrounding_nodes[i] = next_node;
401 if (surrounding_elems)
402 (*surrounding_elems)[i] = elem;
405 libmesh_assert_equal_to(elem, surface.
elem_ptr(elem->
id()));
410 libmesh_assert_equal_to
411 (std::count(surrounding_nodes.begin(),
412 surrounding_nodes.end(), next_node),
418 libmesh_assert_equal_to
419 (elem, surface.
elem_ptr(*elems_by_node.begin()));
421 return surrounding_nodes;
424 auto geometry_at = [&surroundings_of](
const Node & node)
426 const std::vector<Node *> surrounding_nodes =
427 surroundings_of(node,
nullptr);
431 Real total_solid_angle = 0;
432 const int n_surrounding =
433 cast_int<int>(surrounding_nodes.size());
438 v01 =
static_cast<Point>(*surrounding_nodes[n]) - node,
439 v02 = static_cast<Point>(*surrounding_nodes[n+1]) - node,
440 v03 =
static_cast<Point>(*surrounding_nodes[n+2]) - node;
445 return std::make_pair(n_surrounding, total_solid_angle);
457 typedef std::multimap<std::pair<int, Real>,
Node*> node_map_type;
458 node_map_type nodes_by_geometry;
459 std::map<Node *, node_map_type::iterator> node_index;
461 for (
auto node : surface.node_ptr_range())
463 nodes_by_geometry.emplace(geometry_at(*node), node);
471 for (
auto i :
make_range(nodes_by_geometry.size()-3))
473 auto geometry_it = nodes_by_geometry.begin();
474 auto geometry_key = geometry_it->first;
475 auto [valence, angle] = geometry_key;
476 Node * node = geometry_it->second;
484 nodes_by_geometry.upper_bound
485 (std::make_pair(valence,
Real(100)));
488 std::tie(geometry_key, node) = *geometry_it;
489 std::tie(valence, angle) = geometry_key;
492 std::vector<Elem *> surrounding_elems;
493 std::vector<Node *> surrounding_nodes =
494 surroundings_of(*node, &surrounding_elems);
496 const std::size_t n_surrounding = surrounding_nodes.size();
501 auto find_valid_nodes_around =
502 [n_surrounding, & surrounding_nodes]
505 unsigned int jnext = (j+1)%n_surrounding;
506 while (!surrounding_nodes[jnext])
507 jnext = (jnext+1)%n_surrounding;
509 unsigned int jprev = (j+n_surrounding-1)%n_surrounding;
510 while (!surrounding_nodes[jprev])
511 jprev = (jprev+n_surrounding-1)%n_surrounding;
513 return std::make_pair(jprev, jnext);
525 std::vector<Real> local_tet_quality(n_surrounding, 1);
543 auto find_new_tet_nodes =
544 [& local_tet_quality, & find_valid_nodes_around]
547 unsigned int jbest = 0;
548 auto [jminus, jplus] = find_valid_nodes_around(jbest);
549 Real qneighbest = std::min(local_tet_quality[jminus],
550 local_tet_quality[jplus]);
552 local_tet_quality.size()))
555 if (local_tet_quality[j] <= 0)
558 std::tie(jminus, jplus) = find_valid_nodes_around(j);
559 Real qneighj = std::min(local_tet_quality[jminus],
560 local_tet_quality[jplus]);
564 if (qneighbest <= 0 &&
569 if ((local_tet_quality[j] - qneighj) >
570 (local_tet_quality[jbest] - qneighj))
573 qneighbest = qneighj;
578 (local_tet_quality[jbest] <= 0,
579 "Cannot build non-singular non-inverted tet");
581 std::tie(jminus, jplus) = find_valid_nodes_around(jbest);
583 return std::make_tuple(jbest, jminus, jplus);
586 if (n_surrounding > 3)
591 constexpr
Real far_node = -1e6;
596 std::vector<Point> v0s(n_surrounding);
598 v0s[j] = *(
Point *)surrounding_nodes[j] - *node;
602 auto local_tet_quality_of =
603 [& surrounding_nodes, & v0s, & find_valid_nodes_around]
606 auto [jminus, jplus] = find_valid_nodes_around(j);
612 const Real total_len =
613 v0s[j].norm() + v0s[jminus].norm() + v0s[jplus].norm() +
614 (*(
Point *)surrounding_nodes[jplus] -
616 (*(
Point *)surrounding_nodes[j] -
617 *(
Point *)surrounding_nodes[jminus]).
norm() +
618 (*(
Point *)surrounding_nodes[jminus] -
619 *(
Point *)surrounding_nodes[jplus]).
norm();
626 return six_vol / (total_len * total_len * total_len);
630 local_tet_quality[j] = local_tet_quality_of(j);
639 auto [jbest, jminus, jplus] = find_new_tet_nodes();
642 Node * nbest = surrounding_nodes[jbest],
643 * nminus = surrounding_nodes[jminus],
644 * nplus = surrounding_nodes[jplus];
645 this->
add_tet(nminus->id(), nbest->
id(), nplus->id(),
650 Elem * oldtri1 = surrounding_elems[jminus],
651 * oldtri2 = surrounding_elems[jbest],
656 c2 = oldtri2->get_node_index(node);
658 newtri1->set_node(0, node);
659 newtri1->set_node(1, nminus);
660 newtri1->set_node(2, nplus);
662 surrounding_elems[jminus] = newtri1;
668 newtri1->set_neighbor(1, newtri2);
669 newtri1->set_neighbor(2, neigh12);
672 newtri2->set_node(0, nplus);
673 newtri2->set_node(1, nminus);
674 newtri2->set_node(2, nbest);
679 newtri2->set_neighbor(1, neigh21);
681 newtri2->set_neighbor(2, neigh22);
686 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
687 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
688 nodes_to_elem_map[newtri1->node_id(p)].insert(newtri1->id());
689 nodes_to_elem_map[newtri2->node_id(p)].insert(newtri2->id());
699 Node * & nbestref = surrounding_nodes[jbest];
700 nodes_by_geometry.erase(node_index[nbestref]);
701 node_index[nbestref] =
702 nodes_by_geometry.emplace(geometry_at(*nbestref), nbestref);
707 local_tet_quality[jbest] = far_node;
713 local_tet_quality[jminus] =
714 local_tet_quality_of(jminus);
716 local_tet_quality[jplus] =
717 local_tet_quality_of(jplus);
725 auto [j2, j1, j3] = find_new_tet_nodes();
728 Node * n1 = surrounding_nodes[j1],
729 * n2 = surrounding_nodes[j2],
730 * n3 = surrounding_nodes[j3];
731 this->
add_tet(n1->
id(), n2->id(), n3->id(), node->
id());
735 Elem * oldtri1 = surrounding_elems[j1],
736 * oldtri2 = surrounding_elems[j2],
737 * oldtri3 = surrounding_elems[j3],
741 c2 = oldtri2->get_node_index(node),
742 c3 = oldtri3->get_node_index(node);
744 newtri->set_node(0, n1);
745 newtri->set_node(1, n2);
746 newtri->set_node(2, n3);
759 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
760 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
761 nodes_to_elem_map[oldtri3->node_id(p)].erase(oldtri3->id());
762 nodes_to_elem_map[newtri->node_id(p)].insert(newtri->id());
774 surrounding_nodes[j1] =
nullptr;
775 surrounding_nodes[j2] =
nullptr;
776 surrounding_nodes[j3] =
nullptr;
778 for (
auto ltq : surrounding_nodes)
784 for (
const Elem * elem : surface.element_ptr_range())
786 libmesh_assert_not_equal_to
787 (elem->node_ptr(p), node);
792 nodes_by_geometry.erase(geometry_it);
796 libmesh_assert_equal_to(surface.
n_elem(), 2);
806 const auto nn = this->
n_nodes();
807 libmesh_assert_less(n1, nn);
808 libmesh_assert_less(n2, nn);
809 libmesh_assert_less(n3, nn);
810 libmesh_assert_less(n4, nn);
816 libmesh_assert_greater(six_vol,
Real(0));
virtual Point true_centroid() const
virtual unsigned int n_nodes() const override
ElemType
Defines an enum for geometric element types.
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const override
T solid_angle(const TypeVector< T > &v01, const TypeVector< T > &v02, const TypeVector< T > &v03)
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual Node *& set_node(const unsigned int i)
A Node is like a Point, but with more information.
ElemType side_type(const unsigned int s) const override final
virtual dof_id_type n_elem() const override final
The Polyhedron is an element in 3D with an arbitrary number of polygonal faces.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
unsigned int get_node_index(const Node *node_ptr) const
virtual const Node * query_node_ptr(const dof_id_type i) const override final
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
static constexpr Real TOLERANCE
std::vector< std::tuple< std::shared_ptr< Polygon >, bool, std::vector< unsigned int > > > _sidelinks_data
Data for links to sides.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
IOPackage
libMesh interfaces with several different software packages for the purposes of creating, reading, and writing mesh files.
const boundary_id_type side_id
This is the base class from which all geometric element types are derived.
unique_id_type unique_id() const
virtual void retriangulate() override final
Create a triangulation (tetrahedralization) based on the current sides' triangulations.
The libMesh namespace provides an interface to certain functionality in the library.
virtual unsigned int n_sides() const override final
virtual void delete_elem(Elem *e) override final
Removes element e from the mesh.
std::vector< std::pair< unsigned int, unsigned int > > _edge_lookup
One entry for each polyhedron edge, a pair indicating the side number and the edge-of-side number whi...
virtual Point true_centroid() const override
An optimized method for calculating the centroid of a C0Polyhedron.
Point side_vertex_average_normal(const unsigned int s) const override final
virtual const Elem * elem_ptr(const dof_id_type i) const override final
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
TypeVector< T > unit() const
void libmesh_ignore(const Args &...)
auto norm_sq() const -> decltype(std::norm(T()))
virtual Real volume() const override
An optimized method for calculating the area of a C0Polyhedron.
ElemMappingType mapping_type() const
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
virtual bool is_vertex(const unsigned int i) const override
The Polygon is an element in 2D with an arbitrary (but fixed) number of sides.
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
bool valid_unique_id() const
TypeVector< typename CompareTypes< T, T2 >::supertype > cross(const TypeVector< T2 > &v) const
void set_neighbor(const unsigned int i, Elem *n)
Assigns n as the neighbor.
virtual Elem * add_elem(Elem *e) override final
Add elem e to the end of the element array.
std::vector< std::shared_ptr< Polygon > > side_clones() const
C0Polyhedron(const std::vector< std::shared_ptr< Polygon >> &sides, Elem *p=nullptr)
Constructor.
const Elem * neighbor_ptr(unsigned int i) const
std::unique_ptr< Elem > disconnected_clone() const override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Node * node_ptr(const unsigned int i) const
virtual Real volume() const
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...
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) override final
functions for adding /deleting nodes elements.
virtual bool is_face(const unsigned int i) const override
unsigned int n_extra_integers() const
Returns how many extra integers are associated to the DofObject.
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
void add_tet(int n1, int n2, int n3, int n4)
Add to our triangulation (tetrahedralization).
virtual bool is_edge(const unsigned int i) const override
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
std::vector< std::array< int, 4 > > _triangulation
Data for a triangulation (tetrahedralization) of the polyhedron.
virtual std::vector< unsigned int > nodes_on_edge(const unsigned int e) const override
A Point defines a location in LIBMESH_DIM dimensional Real space.
const Point & point(const unsigned int i) const
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
virtual std::vector< unsigned int > nodes_on_side(const unsigned int) const =0
virtual std::pair< unsigned short int, unsigned short int > second_order_child_vertex(const unsigned int n) const override
Element refinement is not implemented for polyhedra.