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.