3 #include <libmesh/boundary_info.h> 4 #include <libmesh/enum_elem_quality.h> 5 #include <libmesh/elem_side_builder.h> 6 #include <libmesh/mesh_modification.h> 7 #include <libmesh/mesh_refinement.h> 8 #include <libmesh/parallel_implementation.h> 9 #include <libmesh/enum_to_string.h> 13 template <ElemType elem_type>
20 for (
const auto & elem :
21 this->_mesh->active_local_element_ptr_range())
23 const BoundingBox bbox = elem->loose_bounding_box();
29 BoundingBox wide_bbox(elem->point(0), elem->point(0));
31 for (
unsigned int n = 0; n != elem->n_nodes(); ++n)
33 const Point & p = elem->point(n);
35 if (!elem->infinite())
42 wide_bbox.scale(1. / 3.);
44 if (!elem->infinite() && elem->dim())
56 for (
const auto & elem : this->_mesh->active_local_element_ptr_range())
63 CPPUNIT_ASSERT_LESSEQUAL(edge_length_ratio,
Real(1));
70 CPPUNIT_ASSERT_LESSEQUAL(
Real(2+
TOLERANCE), edge_length_ratio);
85 CPPUNIT_ASSERT_LESSEQUAL(135 +
TOLERANCE, max_angle);
113 CPPUNIT_ASSERT_LESSEQUAL (90 +
TOLERANCE, max_dihedral_angle);
120 CPPUNIT_ASSERT_GREATEREQUAL(45 -
TOLERANCE, min_dihedral_angle);
131 if (elem->infinite())
132 CPPUNIT_ASSERT_LESSEQUAL (64 +
TOLERANCE, jac);
134 CPPUNIT_ASSERT_LESSEQUAL (8 +
TOLERANCE, jac);
143 CPPUNIT_ASSERT_GREATEREQUAL(1 -
TOLERANCE, jac);
145 CPPUNIT_ASSERT_GREATEREQUAL(0.5 -
TOLERANCE, jac);
147 CPPUNIT_ASSERT_GREATEREQUAL(2 -
TOLERANCE, jac);
155 CPPUNIT_ASSERT_LESSEQUAL (1 +
TOLERANCE, scaled_jac);
156 CPPUNIT_ASSERT_GREATEREQUAL(
Real(0.4), scaled_jac);
170 for (
const auto & elem :
171 this->_mesh->active_local_element_ptr_range())
173 for (
const auto edge : elem->edge_index_range())
174 for (
const auto side_on_edge : elem->sides_on_edge(edge))
175 for (
const auto node_on_edge : elem->nodes_on_edge(edge))
176 CPPUNIT_ASSERT(elem->is_node_on_side(node_on_edge, side_on_edge));
178 for (
const auto side : elem->side_index_range())
179 for (
const auto node_on_side : elem->nodes_on_side(side))
180 CPPUNIT_ASSERT(elem->is_node_on_side(node_on_side, side));
182 for (
const auto edge : elem->edge_index_range())
183 for (
const auto node_on_edge : elem->nodes_on_edge(edge))
184 CPPUNIT_ASSERT(elem->is_node_on_edge(node_on_edge, edge));
186 for (
const auto edge : elem->edge_index_range())
187 for (
const auto side_on_edge : elem->sides_on_edge(edge))
188 CPPUNIT_ASSERT(elem->is_edge_on_side(edge, side_on_edge));
196 for (
const auto & elem :
197 this->_mesh->active_local_element_ptr_range())
201 const ElemType etype = elem->type();
203 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(elem->dim()),
205 CPPUNIT_ASSERT_EQUAL(elem->default_order(),
211 if (!elem->runtime_topology())
230 for (
const auto & elem :
231 this->_mesh->active_local_element_ptr_range())
233 if (elem->infinite())
236 for (
const auto n : elem->node_index_range())
237 #ifndef LIBMESH_ENABLE_EXCEPTIONS
246 CPPUNIT_ASSERT(elem->contains_point(elem->point(n)));
254 for (
const auto & elem :
255 this->_mesh->active_local_element_ptr_range())
257 if (elem->infinite())
260 const Point centroid = elem->true_centroid();
261 const Point vertex_avg = elem->vertex_average();
264 quasicc = elem->quasicircumcenter();
269 CPPUNIT_ASSERT(elem->has_invertible_map());
270 const Point new_centroid = elem->true_centroid();
271 const Point new_vertex_avg = elem->vertex_average();
274 new_quasicc = elem->quasicircumcenter();
278 LIBMESH_ASSERT_FP_EQUAL(centroid(d), new_centroid(d),
280 LIBMESH_ASSERT_FP_EQUAL(vertex_avg(d), new_vertex_avg(d),
282 LIBMESH_ASSERT_FP_EQUAL(quasicc(d), new_quasicc(d),
293 BoundaryInfo & boundary_info = this->_mesh->get_boundary_info();
295 for (
const auto & elem :
296 this->_mesh->active_local_element_ptr_range())
298 if (elem->infinite())
304 const Point vertex_avg = elem->vertex_average();
306 const unsigned int n_sides = elem->n_sides();
307 std::vector<std::set<Point*>> side_nodes(n_sides);
308 std::vector<Elem*> neighbors(n_sides);
309 std::vector<std::vector<boundary_id_type>> bcids(n_sides);
312 for (
auto n : elem->nodes_on_side(s))
313 side_nodes[s].insert(elem->node_ptr(n));
314 neighbors[s] = elem->neighbor_ptr(s);
318 elem->flip(&boundary_info);
324 if ((elem->dim() < 3 ||
325 elem->n_vertices() != 5) &&
327 CPPUNIT_ASSERT(elem->has_affine_map());
329 CPPUNIT_ASSERT(!elem->has_affine_map());
333 bool something_changed =
false;
336 std::set<Point*> new_side_nodes;
337 for (
auto n : elem->nodes_on_side(s))
338 new_side_nodes.insert(elem->node_ptr(n));
340 std::vector<boundary_id_type> new_bcids;
345 if (new_side_nodes == side_nodes[os])
349 something_changed =
true;
353 CPPUNIT_ASSERT(neighbors[old_side] ==
354 elem->neighbor_ptr(s));
356 CPPUNIT_ASSERT(bcids[old_side] == new_bcids);
358 CPPUNIT_ASSERT(!elem->dim() || something_changed);
360 const Point new_vertex_avg = elem->vertex_average();
362 LIBMESH_ASSERT_FP_EQUAL(vertex_avg(d), new_vertex_avg(d),
371 BoundaryInfo & boundary_info = this->_mesh->get_boundary_info();
373 for (
const auto & elem :
374 this->_mesh->active_local_element_ptr_range())
376 if (elem->infinite())
379 const Point vertex_avg = elem->vertex_average();
381 const unsigned int n_sides = elem->n_sides();
382 std::vector<std::set<Point*>> side_nodes(n_sides);
383 std::vector<Elem*> neighbors(n_sides);
384 std::vector<std::vector<boundary_id_type>> bcids(n_sides);
387 for (
auto n : elem->nodes_on_side(s))
388 side_nodes[s].insert(elem->node_ptr(n));
389 neighbors[s] = elem->neighbor_ptr(s);
393 CPPUNIT_ASSERT(!elem->is_flipped());
397 elem->flip(&boundary_info);
398 CPPUNIT_ASSERT(elem->is_flipped());
401 elem->orient(&boundary_info);
402 CPPUNIT_ASSERT(!elem->is_flipped());
409 if ((elem->dim() < 3 ||
410 elem->n_vertices() != 5) &&
413 CPPUNIT_ASSERT(elem->has_affine_map());
416 CPPUNIT_ASSERT(!elem->has_affine_map());
422 std::set<Point*> new_side_nodes;
423 for (
auto n : elem->nodes_on_side(s))
424 new_side_nodes.insert(elem->node_ptr(n));
426 std::vector<boundary_id_type> new_bcids;
429 CPPUNIT_ASSERT(side_nodes[s] ==
432 CPPUNIT_ASSERT(neighbors[s] ==
433 elem->neighbor_ptr(s));
435 CPPUNIT_ASSERT(bcids[s] == new_bcids);
438 const Point new_vertex_avg = elem->vertex_average();
440 LIBMESH_ASSERT_FP_EQUAL(vertex_avg(d), new_vertex_avg(d),
449 const Mesh old_mesh {*this->_mesh};
451 BoundaryInfo & boundary_info = this->_mesh->get_boundary_info();
452 const BoundaryInfo & old_boundary_info = old_mesh.get_boundary_info();
453 CPPUNIT_ASSERT(&boundary_info != &old_boundary_info);
455 for (
const auto & elem :
456 this->_mesh->active_local_element_ptr_range())
458 if (elem->infinite())
463 elem->flip(&boundary_info);
464 CPPUNIT_ASSERT(elem->is_flipped());
471 for (
const auto & elem :
472 this->_mesh->active_local_element_ptr_range())
474 const Elem & old_elem = old_mesh.elem_ref(elem->id());
476 CPPUNIT_ASSERT(!elem->is_flipped());
479 CPPUNIT_ASSERT(*elem == old_elem);
481 const unsigned int n_sides = elem->n_sides();
484 std::vector<boundary_id_type> bcids, old_bcids;
486 old_boundary_info.
boundary_ids(&old_elem, s, old_bcids);
487 CPPUNIT_ASSERT(bcids == old_bcids);
489 if (elem->neighbor_ptr(s))
492 CPPUNIT_ASSERT_EQUAL(elem->neighbor_ptr(s)->id(),
505 for (
const auto & elem :
506 this->_mesh->active_local_element_ptr_range())
507 for (
const auto s : elem->side_index_range())
509 if (elem->type() ==
EDGE2 || elem->type() ==
EDGE3 || elem->type() ==
EDGE4)
510 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s), elem->center_node_on_side(s));
511 else if (elem->type() ==
TRI6 || elem->type() ==
TRI7)
512 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 3), elem->center_node_on_side(s));
513 else if (elem->type() ==
QUAD8 || elem->type() ==
QUAD9 ||
515 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 4), elem->center_node_on_side(s));
516 else if (elem->type() ==
HEX27)
517 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 20), elem->center_node_on_side(s));
518 else if (elem->type() ==
PRISM18 && s >= 1 && s <= 3)
519 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 14), elem->center_node_on_side(s));
520 else if ((elem->type() ==
PRISM20 ||
521 elem->type() ==
PRISM21) && s >= 1 && s <= 3)
522 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 14), elem->center_node_on_side(s));
523 else if (elem->type() ==
PRISM20 ||
525 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(18 + (s == 4)), elem->center_node_on_side(s));
526 else if (elem->type() ==
PYRAMID14 && s == 4)
527 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(13), elem->center_node_on_side(s));
531 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(s + 14), elem->center_node_on_side(s));
533 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(13), elem->center_node_on_side(s));
536 CPPUNIT_ASSERT_EQUAL(
invalid_uint, elem->center_node_on_side(s));
544 for (
const auto & elem :
545 this->_mesh->active_local_element_ptr_range())
546 for (
const auto s : elem->side_index_range())
547 CPPUNIT_ASSERT_EQUAL(elem->build_side_ptr(s)->type(), elem->side_type(s));
554 for (
const auto & elem :
555 this->_mesh->active_local_element_ptr_range())
557 std::unique_ptr<const Elem> side;
559 for (
const auto s : elem->side_index_range())
561 CPPUNIT_ASSERT_EQUAL(elem->build_side_ptr(s)->subdomain_id(), elem->subdomain_id());
563 elem->build_side_ptr(side, s);
564 CPPUNIT_ASSERT_EQUAL(side->subdomain_id(), elem->subdomain_id());
578 for (
auto & elem : this->_mesh->active_local_element_ptr_range())
579 for (
const auto s : elem->side_index_range())
581 const auto side = elem->build_side_ptr(s);
583 auto & cached_side = cache(*elem, s);
584 CPPUNIT_ASSERT_EQUAL(side->type(), cached_side.type());
585 for (
const auto n : side->node_index_range())
586 CPPUNIT_ASSERT_EQUAL(side->node_ref(n), cached_side.node_ref(n));
588 const auto & const_cached_side = cache(const_cast<const Elem &>(*elem), s);
589 CPPUNIT_ASSERT_EQUAL(side->type(), const_cached_side.type());
590 for (
const auto n : side->node_index_range())
591 CPPUNIT_ASSERT_EQUAL(side->node_ref(n), const_cached_side.node_ref(n));
597 #ifdef LIBMESH_ENABLE_AMR 599 if (elem_type ==
EDGE4 ||
609 auto refining_mesh = this->_mesh->clone();
614 std::set<std::pair<dof_id_type, unsigned int>> parent_node_was_touched;
615 std::set<std::pair<dof_id_type, unsigned int>> parent_child_was_touched;
617 for (
const Elem * elem : refining_mesh->active_element_ptr_range())
619 CPPUNIT_ASSERT_EQUAL(elem->level(), n);
620 CPPUNIT_ASSERT(!elem->ancestor());
621 CPPUNIT_ASSERT(elem->active());
622 CPPUNIT_ASSERT(!elem->subactive());
623 CPPUNIT_ASSERT(!elem->has_children());
624 CPPUNIT_ASSERT(!elem->has_ancestor_children());
625 CPPUNIT_ASSERT(!elem->interior_parent());
628 CPPUNIT_ASSERT(parent);
629 CPPUNIT_ASSERT(parent->ancestor());
630 CPPUNIT_ASSERT(!parent->active());
631 CPPUNIT_ASSERT(!parent->subactive());
632 CPPUNIT_ASSERT(parent->has_children());
633 CPPUNIT_ASSERT(!parent->has_ancestor_children());
634 CPPUNIT_ASSERT(!parent->interior_parent());
637 CPPUNIT_ASSERT_EQUAL(parent, elem->top_parent());
638 CPPUNIT_ASSERT_EQUAL(parent, parent->top_parent());
642 CPPUNIT_ASSERT(parent != elem->top_parent());
643 CPPUNIT_ASSERT(parent != parent->top_parent());
644 CPPUNIT_ASSERT_EQUAL(elem->top_parent(), parent->top_parent());
647 CPPUNIT_ASSERT(parent->is_ancestor_of(elem));
648 const unsigned int c = parent->which_child_am_i(elem);
649 CPPUNIT_ASSERT(c < parent->n_children());
650 CPPUNIT_ASSERT_EQUAL(elem, parent->child_ptr(c));
651 parent_child_was_touched.emplace(parent->id(), c);
653 CPPUNIT_ASSERT_EQUAL(parent->n_nodes_in_child(c), elem->n_nodes());
656 CPPUNIT_ASSERT_EQUAL(parent->is_vertex_on_child(c, n), elem->is_vertex(n));
658 auto pn = parent->as_parent_node(c, n);
659 CPPUNIT_ASSERT_EQUAL(pn, parent->get_node_index(elem->node_ptr(n)));
662 CPPUNIT_ASSERT_EQUAL(parent->is_vertex_on_parent(c, n), parent->is_vertex(pn));
663 parent_node_was_touched.emplace(parent->id(), pn);
668 if (parent->is_child_on_side(c,s))
670 auto parent_side = parent->build_side_ptr(s);
675 auto child_side = elem->build_side_ptr(s);
678 if (!parent_side->infinite())
679 for (
const Node & node : child_side->node_ref_range())
680 CPPUNIT_ASSERT(parent_side->contains_point(node));
682 if (elem->neighbor_ptr(s) && !elem->neighbor_ptr(s)->is_remote())
683 CPPUNIT_ASSERT_EQUAL(parent->child_neighbor(elem->neighbor_ptr(s)), elem);
689 if (parent->is_child_on_edge(c,e))
691 auto parent_edge = parent->build_edge_ptr(e);
696 auto child_edge = elem->build_edge_ptr(e);
699 if (!parent_edge->infinite())
700 for (
const Node & node : child_edge->node_ref_range())
701 CPPUNIT_ASSERT(parent_edge->contains_point(node));
705 if (parent->has_affine_map())
706 CPPUNIT_ASSERT(elem->has_affine_map());
714 for (
const Elem * elem : refining_mesh->local_element_ptr_range())
724 std::vector<const Elem *> family;
725 elem->family_tree(family);
726 CPPUNIT_ASSERT_EQUAL(family.size(),
727 std::size_t(elem->n_children() + 1));
730 elem->total_family_tree(family);
731 CPPUNIT_ASSERT_EQUAL(family.size(),
732 std::size_t(elem->n_children() + 1));
735 elem->active_family_tree(family);
736 CPPUNIT_ASSERT_EQUAL(family.size(),
737 std::size_t(elem->n_children()));
742 elem->active_family_tree_by_side(family,s);
743 if (!elem->build_side_ptr(s)->infinite())
744 CPPUNIT_ASSERT_EQUAL(
double(family.size()),
747 CPPUNIT_ASSERT_EQUAL(
double(family.size()),
749 for (
const Elem * child : family)
751 if (child->is_remote())
754 unsigned int c = elem->which_child_am_i(child);
755 CPPUNIT_ASSERT(elem->is_child_on_side(c, s));
760 if (elem->level() + 1 == n)
764 auto it = parent_child_was_touched.find(std::make_pair(elem->id(), c));
765 CPPUNIT_ASSERT(it != parent_child_was_touched.end());
770 auto it = parent_node_was_touched.find(std::make_pair(elem->id(), n));
771 CPPUNIT_ASSERT(it != parent_node_was_touched.end());
782 test_n_refinements(1);
789 test_n_refinements(2);
796 for (
const auto & elem :
797 this->_mesh->active_local_element_ptr_range())
798 for (
const auto nd : elem->node_index_range())
800 if ((elem->type() ==
EDGE3 || elem->type() ==
EDGE4) && nd >= 2)
801 CPPUNIT_ASSERT(elem->is_internal(nd));
802 else if (elem->type() ==
HEX27 && nd == 26)
803 CPPUNIT_ASSERT(elem->is_internal(nd));
804 else if (elem->type() ==
PRISM21 && nd == 20)
805 CPPUNIT_ASSERT(elem->is_internal(nd));
806 else if ((elem->type() ==
QUAD9 || elem->type() ==
QUADSHELL9) && nd == 8)
807 CPPUNIT_ASSERT(elem->is_internal(nd));
808 else if (elem->type() ==
TRI7 && nd == 6)
809 CPPUNIT_ASSERT(elem->is_internal(nd));
810 else if (elem->type() ==
INFHEX18 && nd == 17)
811 CPPUNIT_ASSERT(elem->is_internal(nd));
812 else if (elem->type() ==
INFQUAD6 && nd == 5)
813 CPPUNIT_ASSERT(elem->is_internal(nd));
815 CPPUNIT_ASSERT(!elem->is_internal(nd));
823 for (
const auto & elem : this->_mesh->active_local_element_ptr_range())
825 for (
const auto nd : elem->node_index_range())
827 auto adjacent_edge_ids = elem->edges_adjacent_to_node(nd);
834 CPPUNIT_ASSERT(adjacent_edge_ids.empty());
841 for (
const auto & edge_id : adjacent_edge_ids)
843 auto node_ids_on_edge = elem->nodes_on_edge(edge_id);
844 CPPUNIT_ASSERT(std::find(node_ids_on_edge.begin(), node_ids_on_edge.end(), nd) != node_ids_on_edge.end());
854 CPPUNIT_TEST( test_bounding_box ); \ 855 CPPUNIT_TEST( test_quality ); \ 856 CPPUNIT_TEST( test_node_edge_map_consistency ); \ 857 CPPUNIT_TEST( test_maps ); \ 858 CPPUNIT_TEST( test_static_data ); \ 859 CPPUNIT_TEST( test_permute ); \ 860 CPPUNIT_TEST( test_flip ); \ 861 CPPUNIT_TEST( test_orient ); \ 862 CPPUNIT_TEST( test_orient_elements ); \ 863 CPPUNIT_TEST( test_contains_point_node ); \ 864 CPPUNIT_TEST( test_center_node_on_side ); \ 865 CPPUNIT_TEST( test_side_type ); \ 866 CPPUNIT_TEST( test_side_subdomain ); \ 867 CPPUNIT_TEST( test_elem_side_builder ); \ 868 CPPUNIT_TEST( test_refinement ); \ 869 CPPUNIT_TEST( test_double_refinement ); \ 870 CPPUNIT_TEST( test_is_internal ) 872 #define INSTANTIATE_ELEMTEST(elemtype) \ 873 class ElemTest_##elemtype : public ElemTest<elemtype> { \ 875 ElemTest_##elemtype() : \ 876 ElemTest<elemtype>() { \ 877 if (unitlog->summarized_logs_enabled()) \ 878 this->libmesh_suite_name = "ElemTest"; \ 880 this->libmesh_suite_name = "ElemTest_" #elemtype; \ 882 CPPUNIT_TEST_SUITE( ElemTest_##elemtype ); \ 884 CPPUNIT_TEST_SUITE_END(); \ 887 CPPUNIT_TEST_SUITE_REGISTRATION( ElemTest_##elemtype ) 914 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 918 #endif // LIBMESH_DIM > 1 938 #ifdef LIBMESH_ENABLE_EXCEPTIONS 945 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS 953 #endif // LIBMESH_DIM > 2
void test_center_node_on_side()
static const Order type_to_default_order_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the default approximation order of...
void test_orient_elements()
ElemType
Defines an enum for geometric element types.
const Elem * parent() const
A Node is like a Point, but with more information.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
static const unsigned int type_to_n_sides_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of sides on the element...
void test_elem_side_builder()
void test_n_refinements(unsigned int n)
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
bool contains_point(const Point &) const
libMesh::Parallel::Communicator * TestCommWorld
static constexpr Real TOLERANCE
void test_node_edge_map_consistency()
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
This is the base class from which all geometric element types are derived.
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
The libMesh namespace provides an interface to certain functionality in the library.
void test_side_subdomain()
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
void test_double_refinement()
Implements (adaptive) mesh refinement algorithms for a MeshBase.
static const unsigned int type_to_n_edges_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of edges on the element...
The BoundaryInfo class contains information relevant to boundary conditions including storing faces...
INSTANTIATE_ELEMTEST(NODEELEM)
Helper for building element sides that minimizes the construction of new elements.
void test_contains_point_node()
Defines a Cartesian bounding box by the two corner extremum.
const Elem * neighbor_ptr(unsigned int i) const
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...
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
A Point defines a location in LIBMESH_DIM dimensional Real space.
static const unsigned int max_n_nodes
The maximum number of nodes any element can contain.
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
void set_union(T &data, const unsigned int root_id) const