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());
261 std::unordered_map<Node *, unsigned int> poly_node_to_id;
265 const auto & [side, inward_normal, node_map] = this->
_sidelinks_data[s];
267 for (
auto t :
make_range(side->n_subtriangles()))
271 const std::array<int, 3> subtri = side->subtriangle(t);
278 libmesh_assert_less(
side_id, node_map.size());
279 const unsigned int local_id = node_map[
side_id];
283 libmesh_assert_equal_to(*(
const Point*)poly_node,
284 *(
const Point*)surf_node);
286 surf_node = surface.
add_point(*poly_node, local_id);
290 const int tri_node = inward_normal ? i : 2-i;
302 auto verify_surface = [& surface] ()
304 for (
const Elem * elem : surface.element_ptr_range())
310 libmesh_assert_equal_to(neigh,
313 libmesh_assert_less(ns, 3);
314 libmesh_assert_equal_to(elem->node_ptr(s),
316 libmesh_assert_equal_to(elem->node_ptr((s+1)%3),
327 std::vector<std::vector<dof_id_type>> nodes_to_elem_vec_map;
333 std::vector<std::set<dof_id_type>> nodes_to_elem_map;
335 nodes_to_elem_map.emplace_back
336 (nodes_to_elem_vec_map[i].begin(),
337 nodes_to_elem_vec_map[i].end());
346 auto surroundings_of =
347 [&nodes_to_elem_map, & surface]
349 std::vector<Elem *> * surrounding_elems)
351 const std::set<dof_id_type> & elems_by_node =
352 nodes_to_elem_map[node.id()];
354 const unsigned int n_surrounding = elems_by_node.size();
355 libmesh_assert_greater_equal(n_surrounding, 3);
357 if (surrounding_elems)
360 surrounding_elems->resize(n_surrounding);
363 std::vector<Node *> surrounding_nodes(n_surrounding);
371 surrounding_nodes[i] = next_node;
372 if (surrounding_elems)
373 (*surrounding_elems)[i] = elem;
376 libmesh_assert_equal_to(elem, surface.
elem_ptr(elem->
id()));
381 libmesh_assert_equal_to
382 (std::count(surrounding_nodes.begin(),
383 surrounding_nodes.end(), next_node),
389 libmesh_assert_equal_to
390 (elem, surface.
elem_ptr(*elems_by_node.begin()));
392 return surrounding_nodes;
395 auto geometry_at = [&surroundings_of](
const Node & node)
397 const std::vector<Node *> surrounding_nodes =
398 surroundings_of(node,
nullptr);
402 Real total_solid_angle = 0;
403 const int n_surrounding =
404 cast_int<int>(surrounding_nodes.size());
409 v01 =
static_cast<Point>(*surrounding_nodes[n]) - node,
410 v02 = static_cast<Point>(*surrounding_nodes[n+1]) - node,
411 v03 =
static_cast<Point>(*surrounding_nodes[n+2]) - node;
416 return std::make_pair(n_surrounding, total_solid_angle);
428 typedef std::multimap<std::pair<int, Real>,
Node*> node_map_type;
429 node_map_type nodes_by_geometry;
430 std::map<Node *, node_map_type::iterator> node_index;
432 for (
auto node : surface.node_ptr_range())
434 nodes_by_geometry.emplace(geometry_at(*node), node);
442 for (
auto i :
make_range(nodes_by_geometry.size()-3))
444 auto geometry_it = nodes_by_geometry.begin();
445 auto geometry_key = geometry_it->first;
446 auto [valence, angle] = geometry_key;
447 Node * node = geometry_it->second;
455 nodes_by_geometry.upper_bound
456 (std::make_pair(valence,
Real(100)));
459 std::tie(geometry_key, node) = *geometry_it;
460 std::tie(valence, angle) = geometry_key;
463 std::vector<Elem *> surrounding_elems;
464 std::vector<Node *> surrounding_nodes =
465 surroundings_of(*node, &surrounding_elems);
467 const std::size_t n_surrounding = surrounding_nodes.size();
472 auto find_valid_nodes_around =
473 [n_surrounding, & surrounding_nodes]
476 unsigned int jnext = (j+1)%n_surrounding;
477 while (!surrounding_nodes[jnext])
478 jnext = (jnext+1)%n_surrounding;
480 unsigned int jprev = (j+n_surrounding-1)%n_surrounding;
481 while (!surrounding_nodes[jprev])
482 jprev = (jprev+n_surrounding-1)%n_surrounding;
484 return std::make_pair(jprev, jnext);
496 std::vector<Real> local_tet_quality(n_surrounding, 1);
514 auto find_new_tet_nodes =
515 [& local_tet_quality, & find_valid_nodes_around]
518 unsigned int jbest = 0;
519 auto [jminus, jplus] = find_valid_nodes_around(jbest);
520 Real qneighbest = std::min(local_tet_quality[jminus],
521 local_tet_quality[jplus]);
523 local_tet_quality.size()))
526 if (local_tet_quality[j] <= 0)
529 std::tie(jminus, jplus) = find_valid_nodes_around(j);
530 Real qneighj = std::min(local_tet_quality[jminus],
531 local_tet_quality[jplus]);
535 if (qneighbest <= 0 &&
540 if ((local_tet_quality[j] - qneighj) >
541 (local_tet_quality[jbest] - qneighj))
544 qneighbest = qneighj;
549 (local_tet_quality[jbest] <= 0,
550 "Cannot build non-singular non-inverted tet");
552 std::tie(jminus, jplus) = find_valid_nodes_around(jbest);
554 return std::make_tuple(jbest, jminus, jplus);
557 if (n_surrounding > 3)
562 constexpr
Real far_node = -1e6;
567 std::vector<Point> v0s(n_surrounding);
569 v0s[j] = *(
Point *)surrounding_nodes[j] - *node;
573 auto local_tet_quality_of =
574 [& surrounding_nodes, & v0s, & find_valid_nodes_around]
577 auto [jminus, jplus] = find_valid_nodes_around(j);
583 const Real total_len =
584 v0s[j].norm() + v0s[jminus].norm() + v0s[jplus].norm() +
585 (*(
Point *)surrounding_nodes[jplus] -
587 (*(
Point *)surrounding_nodes[j] -
588 *(
Point *)surrounding_nodes[jminus]).
norm() +
589 (*(
Point *)surrounding_nodes[jminus] -
590 *(
Point *)surrounding_nodes[jplus]).
norm();
597 return six_vol / (total_len * total_len * total_len);
601 local_tet_quality[j] = local_tet_quality_of(j);
610 auto [jbest, jminus, jplus] = find_new_tet_nodes();
613 Node * nbest = surrounding_nodes[jbest],
614 * nminus = surrounding_nodes[jminus],
615 * nplus = surrounding_nodes[jplus];
616 this->
add_tet(nminus->id(), nbest->
id(), nplus->id(),
621 Elem * oldtri1 = surrounding_elems[jminus],
622 * oldtri2 = surrounding_elems[jbest],
627 c2 = oldtri2->get_node_index(node);
629 newtri1->set_node(0, node);
630 newtri1->set_node(1, nminus);
631 newtri1->set_node(2, nplus);
633 surrounding_elems[jminus] = newtri1;
639 newtri1->set_neighbor(1, newtri2);
640 newtri1->set_neighbor(2, neigh12);
643 newtri2->set_node(0, nplus);
644 newtri2->set_node(1, nminus);
645 newtri2->set_node(2, nbest);
650 newtri2->set_neighbor(1, neigh21);
652 newtri2->set_neighbor(2, neigh22);
657 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
658 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
659 nodes_to_elem_map[newtri1->node_id(p)].insert(newtri1->id());
660 nodes_to_elem_map[newtri2->node_id(p)].insert(newtri2->id());
670 Node * & nbestref = surrounding_nodes[jbest];
671 nodes_by_geometry.erase(node_index[nbestref]);
672 node_index[nbestref] =
673 nodes_by_geometry.emplace(geometry_at(*nbestref), nbestref);
678 local_tet_quality[jbest] = far_node;
684 local_tet_quality[jminus] =
685 local_tet_quality_of(jminus);
687 local_tet_quality[jplus] =
688 local_tet_quality_of(jplus);
696 auto [j2, j1, j3] = find_new_tet_nodes();
699 Node * n1 = surrounding_nodes[j1],
700 * n2 = surrounding_nodes[j2],
701 * n3 = surrounding_nodes[j3];
702 this->
add_tet(n1->
id(), n2->id(), n3->id(), node->
id());
706 Elem * oldtri1 = surrounding_elems[j1],
707 * oldtri2 = surrounding_elems[j2],
708 * oldtri3 = surrounding_elems[j3],
712 c2 = oldtri2->get_node_index(node),
713 c3 = oldtri3->get_node_index(node);
715 newtri->set_node(0, n1);
716 newtri->set_node(1, n2);
717 newtri->set_node(2, n3);
730 nodes_to_elem_map[oldtri1->node_id(p)].erase(oldtri1->id());
731 nodes_to_elem_map[oldtri2->node_id(p)].erase(oldtri2->id());
732 nodes_to_elem_map[oldtri3->node_id(p)].erase(oldtri3->id());
733 nodes_to_elem_map[newtri->node_id(p)].insert(newtri->id());
745 surrounding_nodes[j1] =
nullptr;
746 surrounding_nodes[j2] =
nullptr;
747 surrounding_nodes[j3] =
nullptr;
749 for (
auto ltq : surrounding_nodes)
755 for (
const Elem * elem : surface.element_ptr_range())
757 libmesh_assert_not_equal_to
758 (elem->node_ptr(p), node);
763 nodes_by_geometry.erase(geometry_it);
767 libmesh_assert_equal_to(surface.
n_elem(), 2);
777 const auto nn = this->
n_nodes();
778 libmesh_assert_less(n1, nn);
779 libmesh_assert_less(n2, nn);
780 libmesh_assert_less(n3, nn);
781 libmesh_assert_less(n4, nn);
787 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.
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)
void libmesh_ignore(const Args &...)
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
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.
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.