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" 26 #include "libmesh/node.h" 38 (
const std::vector<std::shared_ptr<Polygon>> & sides, std::unique_ptr<Node> & mid_elem_node,
Elem * p) :
40 _has_mid_elem_node(
false)
42 this->retriangulate();
45 if (_has_mid_elem_node)
46 mid_elem_node.reset(this->_nodelinks_data.back());
59 std::unique_ptr<Node> mid_elem_node;
60 std::unique_ptr<Elem> returnval = std::make_unique<C0Polyhedron>(sides, mid_elem_node);
65 returnval->set_node(returnval->n_nodes() - 1, this->
_nodelinks_data.back());
68 returnval->set_id() = this->
id();
69 #ifdef LIBMESH_ENABLE_UNIQUE_ID 71 returnval->set_unique_id(this->
unique_id());
75 returnval->add_extra_integers(n_elem_ints);
76 for (
unsigned int i = 0; i != n_elem_ints; ++i)
77 returnval->set_extra_integer(i, this->get_extra_integer(i));
79 returnval->inherit_data_from(*
this);
96 libmesh_assert_less (i, this->
n_nodes());
108 libmesh_assert_less (i, this->
n_nodes());
117 libmesh_assert_less (i, this->
n_nodes());
125 const unsigned int s)
const 127 libmesh_assert_less (n, this->
n_nodes());
128 libmesh_assert_less (s, this->
n_sides());
130 const std::vector<unsigned int> & node_map =
133 const auto it = std::find(node_map.begin(), node_map.end(), n);
135 return (it != node_map.end());
138 std::vector<unsigned int>
141 libmesh_assert_less(s, this->
n_sides());
145 std::vector<unsigned int>
150 const std::vector<unsigned int> & node_map =
162 const unsigned int e)
const 168 const std::vector<unsigned int> & node_map =
173 if (node_map[noe] == n)
181 std::vector<unsigned int>
193 std::vector<dof_id_type> & )
const 195 libmesh_not_implemented();
218 const Point v01 = p1 - p0;
219 const Point v02 = p2 - p0;
220 const Point v03 = p3 - p0;
225 return six_vol * (1./6.);
237 Point six_vol_weighted_centroid;
245 const Point v01 = p1 - p0;
246 const Point v02 = p2 - p0;
247 const Point v03 = p3 - p0;
251 const Point tet_centroid = (p0 + p1 + p2 + p3) * 0.25;
253 six_vol += six_tet_vol;
255 six_vol_weighted_centroid += six_tet_vol * tet_centroid;
258 return six_vol_weighted_centroid / six_vol;
263 std::pair<unsigned short int, unsigned short int>
266 libmesh_not_implemented();
267 return std::pair<unsigned short int, unsigned short int> (0,0);
274 libmesh_assert_less (s, this->
n_sides());
283 libmesh_assert_less (s, this->
n_sides());
285 const auto poly_side_ptr = this->
side_ptr(s);
286 const auto n_side_edges = poly_side_ptr->n_sides();
291 Point current_edge = poly_side_ptr->point(1) - poly_side_ptr->point(0);
294 const Point next_edge = poly_side_ptr->point((i + 2) % n_side_edges) -
295 poly_side_ptr->point((i + 1) % n_side_edges);
296 const Point normal_at_vertex = current_edge.
cross(next_edge);
297 normal += normal_at_vertex;
301 current_edge = next_edge;
304 return (outward_normal ? 1. : -1.) * normal.
unit();
317 bool zero_in = std::find(sd_nodes.begin(), sd_nodes.end(), tet_nodes[0]) != sd_nodes.end();
318 bool one_in = std::find(sd_nodes.begin(), sd_nodes.end(), tet_nodes[1]) != sd_nodes.end();
319 bool two_in = std::find(sd_nodes.begin(), sd_nodes.end(), tet_nodes[2]) != sd_nodes.end();
320 bool three_in = std::find(sd_nodes.begin(), sd_nodes.end(), tet_nodes[3]) != sd_nodes.end();
329 sides[0] = poly_side;
331 sides[1] = poly_side;
333 else if (two_in && three_in)
334 sides[3] = poly_side;
336 else if (three_in && two_in && one_in)
337 sides[2] = poly_side;
359 std::unordered_map<Node *, unsigned int> poly_node_to_id;
363 const auto & [side, inward_normal, node_map] = this->
_sidelinks_data[s];
365 for (
auto t :
make_range(side->n_subtriangles()))
369 const std::array<int, 3> subtri = side->subtriangle(t);
376 libmesh_assert_less(
side_id, node_map.size());
377 const unsigned int local_id = node_map[
side_id];
381 libmesh_assert_equal_to(*(
const Point*)poly_node,
382 *(
const Point*)surf_node);
384 surf_node = surface.
add_point(*poly_node, local_id);
388 const int tri_node = inward_normal ? i : 2-i;
400 auto verify_surface = [& surface] ()
402 for (
const Elem * elem : surface.element_ptr_range())
408 libmesh_assert_equal_to(neigh,
411 libmesh_assert_less(ns, 3);
412 libmesh_assert_equal_to(elem->node_ptr(s),
414 libmesh_assert_equal_to(elem->node_ptr((s+1)%3),
427 #ifdef LIBMESH_ENABLE_EXCEPTIONS 432 std::vector<std::vector<dof_id_type>> nodes_to_elem_vec_map;
438 std::vector<std::set<dof_id_type>> nodes_to_elem_map;
440 nodes_to_elem_map.emplace_back
441 (nodes_to_elem_vec_map[i].begin(),
442 nodes_to_elem_vec_map[i].end());
451 auto surroundings_of =
452 [&nodes_to_elem_map, & surface]
454 std::vector<Elem *> * surrounding_elems)
456 const std::set<dof_id_type> & elems_by_node =
457 nodes_to_elem_map[node.id()];
459 const unsigned int n_surrounding = elems_by_node.size();
460 libmesh_assert_greater_equal(n_surrounding, 3);
462 if (surrounding_elems)
465 surrounding_elems->resize(n_surrounding);
468 std::vector<Node *> surrounding_nodes(n_surrounding);
476 surrounding_nodes[i] = next_node;
477 if (surrounding_elems)
478 (*surrounding_elems)[i] = elem;
481 libmesh_assert_equal_to(elem, surface.
elem_ptr(elem->
id()));
486 libmesh_assert_equal_to
487 (std::count(surrounding_nodes.begin(),
488 surrounding_nodes.end(), next_node),
494 libmesh_assert_equal_to
495 (elem, surface.
elem_ptr(*elems_by_node.begin()));
497 return surrounding_nodes;
500 auto geometry_at = [&surroundings_of](
const Node & node)
502 const std::vector<Node *> surrounding_nodes =
503 surroundings_of(node,
nullptr);
507 Real total_solid_angle = 0;
508 const int n_surrounding =
509 cast_int<int>(surrounding_nodes.size());
514 v01 =
static_cast<Point>(*surrounding_nodes[n]) - node,
515 v02 = static_cast<Point>(*surrounding_nodes[n+1]) - node,
516 v03 =
static_cast<Point>(*surrounding_nodes[n+2]) - node;
521 return std::make_pair(n_surrounding, total_solid_angle);
533 typedef std::multimap<std::pair<int, Real>,
Node*> node_map_type;
534 node_map_type nodes_by_geometry;
535 std::map<Node *, node_map_type::iterator> node_index;
537 for (
auto node : surface.node_ptr_range())
539 nodes_by_geometry.emplace(geometry_at(*node), node);
547 for (
auto i :
make_range(nodes_by_geometry.size()-3))
549 auto geometry_it = nodes_by_geometry.begin();
550 auto geometry_key = geometry_it->first;
551 auto [valence, angle] = geometry_key;
552 Node * node = geometry_it->second;
560 nodes_by_geometry.upper_bound
561 (std::make_pair(valence,
Real(100)));
564 std::tie(geometry_key, node) = *geometry_it;
565 std::tie(valence, angle) = geometry_key;
568 std::vector<Elem *> surrounding_elems;
569 std::vector<Node *> surrounding_nodes =
570 surroundings_of(*node, &surrounding_elems);
572 const std::size_t n_surrounding = surrounding_nodes.size();
577 auto find_valid_nodes_around =
578 [n_surrounding, & surrounding_nodes]
581 unsigned int jnext = (j+1)%n_surrounding;
582 while (!surrounding_nodes[jnext])
583 jnext = (jnext+1)%n_surrounding;
585 unsigned int jprev = (j+n_surrounding-1)%n_surrounding;
586 while (!surrounding_nodes[jprev])
587 jprev = (jprev+n_surrounding-1)%n_surrounding;
589 return std::make_pair(jprev, jnext);
601 std::vector<Real> local_tet_quality(n_surrounding, 1);
619 auto find_new_tet_nodes =
620 [& local_tet_quality, & find_valid_nodes_around]
623 unsigned int jbest = 0;
624 auto [jminus, jplus] = find_valid_nodes_around(jbest);
625 Real qneighbest = std::min(local_tet_quality[jminus],
626 local_tet_quality[jplus]);
628 local_tet_quality.size()))
631 if (local_tet_quality[j] <= 0)
634 std::tie(jminus, jplus) = find_valid_nodes_around(j);
635 Real qneighj = std::min(local_tet_quality[jminus],
636 local_tet_quality[jplus]);
640 if (qneighbest <= 0 &&
645 if ((local_tet_quality[j] - qneighj) >
646 (local_tet_quality[jbest] - qneighj))
649 qneighbest = qneighj;
654 (local_tet_quality[jbest] <= 0,
655 "Cannot build non-singular non-inverted tet");
657 std::tie(jminus, jplus) = find_valid_nodes_around(jbest);
659 return std::make_tuple(jbest, jminus, jplus);
662 if (n_surrounding > 3)
667 constexpr
Real far_node = -1e6;
672 std::vector<Point> v0s(n_surrounding);
674 v0s[j] = *(
Point *)surrounding_nodes[j] - *node;
678 auto local_tet_quality_of =
679 [& surrounding_nodes, & v0s, & find_valid_nodes_around]
682 auto [jminus, jplus] = find_valid_nodes_around(j);
688 const Real total_len =
689 v0s[j].norm() + v0s[jminus].norm() + v0s[jplus].norm() +
690 (*(
Point *)surrounding_nodes[jplus] -
692 (*(
Point *)surrounding_nodes[j] -
693 *(
Point *)surrounding_nodes[jminus]).
norm() +
694 (*(
Point *)surrounding_nodes[jminus] -
695 *(
Point *)surrounding_nodes[jplus]).
norm();
702 return six_vol / (total_len * total_len * total_len);
706 local_tet_quality[j] = local_tet_quality_of(j);
715 auto [jbest, jminus, jplus] = find_new_tet_nodes();
718 Node * nbest = surrounding_nodes[jbest],
719 * nminus = surrounding_nodes[jminus],
720 * nplus = surrounding_nodes[jplus];
721 this->
add_tet(nminus->id(), nbest->
id(), nplus->id(),
726 Elem * oldtri1 = surrounding_elems[jminus],
727 * oldtri2 = surrounding_elems[jbest],
732 c2 = oldtri2->get_node_index(node);
734 newtri1->set_node(0, node);
735 newtri1->set_node(1, nminus);
736 newtri1->set_node(2, nplus);
738 surrounding_elems[jminus] = newtri1;
744 newtri1->set_neighbor(1, newtri2);
745 newtri1->set_neighbor(2, neigh12);
748 newtri2->set_node(0, nplus);
749 newtri2->set_node(1, nminus);
750 newtri2->set_node(2, nbest);
755 newtri2->set_neighbor(1, neigh21);
757 newtri2->set_neighbor(2, neigh22);
762 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
763 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
764 nodes_to_elem_map[newtri1->node_id(p)].insert(newtri1->id());
765 nodes_to_elem_map[newtri2->node_id(p)].insert(newtri2->id());
775 Node * & nbestref = surrounding_nodes[jbest];
776 nodes_by_geometry.erase(node_index[nbestref]);
777 node_index[nbestref] =
778 nodes_by_geometry.emplace(geometry_at(*nbestref), nbestref);
783 local_tet_quality[jbest] = far_node;
789 local_tet_quality[jminus] =
790 local_tet_quality_of(jminus);
792 local_tet_quality[jplus] =
793 local_tet_quality_of(jplus);
801 auto [j2, j1, j3] = find_new_tet_nodes();
804 Node * n1 = surrounding_nodes[j1],
805 * n2 = surrounding_nodes[j2],
806 * n3 = surrounding_nodes[j3];
807 this->
add_tet(n1->
id(), n2->id(), n3->id(), node->
id());
811 Elem * oldtri1 = surrounding_elems[j1],
812 * oldtri2 = surrounding_elems[j2],
813 * oldtri3 = surrounding_elems[j3],
817 c2 = oldtri2->get_node_index(node),
818 c3 = oldtri3->get_node_index(node);
820 newtri->set_node(0, n1);
821 newtri->set_node(1, n2);
822 newtri->set_node(2, n3);
835 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
836 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
837 nodes_to_elem_map[oldtri3->node_id(p)].erase(oldtri3->id());
838 nodes_to_elem_map[newtri->node_id(p)].insert(newtri->id());
850 surrounding_nodes[j1] =
nullptr;
851 surrounding_nodes[j2] =
nullptr;
852 surrounding_nodes[j3] =
nullptr;
854 for (
auto ltq : surrounding_nodes)
860 for (
const Elem * elem : surface.element_ptr_range())
862 libmesh_assert_not_equal_to
863 (elem->node_ptr(p), node);
868 nodes_by_geometry.erase(geometry_it);
871 libmesh_assert_equal_to(surface.
n_elem(), 2);
888 Node * mid_elem_node =
new Node(v_avg);
901 const auto & [side, inward_normal, node_map] = this->
_sidelinks_data[s];
903 for (
auto t :
make_range(side->n_subtriangles()))
906 const auto & n1 = node_map[side->subtriangle(t)[0]];
907 const auto & n2 = node_map[side->subtriangle(t)[1]];
908 const auto & n3 = node_map[side->subtriangle(t)[2]];
927 const auto nn = this->
n_nodes();
928 libmesh_assert_less(n1, nn);
929 libmesh_assert_less(n2, nn);
930 libmesh_assert_less(n3, nn);
931 libmesh_assert_less(n4, nn);
940 libmesh_error_msg_if(six_vol <= 0,
"Creating flat tet");
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.
virtual unsigned int n_vertices() const override final
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
std::vector< Node * > _nodelinks_data
Data for links to nodes.
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.
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (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.
C0Polyhedron(const std::vector< std::shared_ptr< Polygon >> &sides, std::unique_ptr< Node > &mid_elem_node, Elem *p=nullptr)
Constructor.
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 &...)
virtual Real volume() const override
An optimized method for calculating the area of a C0Polyhedron.
const int invalid_int
A number which is used quite often to represent an invalid or uninitialized value for an integer...
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
unsigned int n_subelements() const
bool _has_mid_elem_node
Whether we have a mid element node.
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
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
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
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 std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
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
virtual std::array< int, 4 > subelement_sides_to_poly_sides(unsigned int i) const
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
Point vertex_average() const
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.