libMesh
Loading...
Searching...
No Matches
Public Member Functions | List of all members
BoundaryInfoTest Class Reference
Inheritance diagram for BoundaryInfoTest:
[legend]

Public Member Functions

 LIBMESH_CPPUNIT_TEST_SUITE (BoundaryInfoTest)
 This test ensures various aspects of the BoundaryInfo class work as expected.
 
 CPPUNIT_TEST (testNameCopying)
 
 CPPUNIT_TEST (testMesh)
 
 CPPUNIT_TEST (testRenumber)
 
 CPPUNIT_TEST (testInternalBoundary)
 
 CPPUNIT_TEST (testSelectiveRenumber)
 
 CPPUNIT_TEST (testBoundaryOnChildrenErrors)
 
 CPPUNIT_TEST (testBoundaryIDs)
 
 CPPUNIT_TEST (testBoundaryOnChildrenElementsRefineCoarsen)
 
 CPPUNIT_TEST (testBoundaryOnChildrenBoundaryIDs)
 
 CPPUNIT_TEST (testBoundaryOnChildrenBoundarySides)
 
 CPPUNIT_TEST (testBuildNodeListFromSideList)
 
 CPPUNIT_TEST (testBuildSideListFromNodeList)
 
 CPPUNIT_TEST (testShellFaceConstraints)
 
 CPPUNIT_TEST (testEdgeBoundaryConditions)
 
 CPPUNIT_TEST_SUITE_END ()
 
void setUp ()
 
void tearDown ()
 
void testMesh ()
 
void testRenumber ()
 
void testSelectiveRenumber ()
 
void testEdgeBoundaryConditions ()
 
void testNameCopying ()
 
void testShellFaceConstraints ()
 
void testBoundaryOnChildrenErrors ()
 
void testBoundaryIDs ()
 
void testBoundaryOnChildrenElementsRefineCoarsen ()
 
void testBoundaryOnChildrenBoundaryIDs ()
 
void testBoundaryOnChildrenBoundarySides ()
 
void testBuildNodeListFromSideList ()
 
void testBuildSideListFromNodeList ()
 
void testInternalBoundary ()
 

Detailed Description

Definition at line 20 of file boundary_info.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryIDs  )

◆ CPPUNIT_TEST() [2/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenBoundaryIDs  )

◆ CPPUNIT_TEST() [3/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenBoundarySides  )

◆ CPPUNIT_TEST() [4/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenElementsRefineCoarsen  )

◆ CPPUNIT_TEST() [5/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenErrors  )

◆ CPPUNIT_TEST() [6/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildNodeListFromSideList  )

◆ CPPUNIT_TEST() [7/14]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildSideListFromNodeList  )

◆ CPPUNIT_TEST() [8/14]

BoundaryInfoTest::CPPUNIT_TEST ( testEdgeBoundaryConditions  )

◆ CPPUNIT_TEST() [9/14]

BoundaryInfoTest::CPPUNIT_TEST ( testInternalBoundary  )

◆ CPPUNIT_TEST() [10/14]

BoundaryInfoTest::CPPUNIT_TEST ( testMesh  )

◆ CPPUNIT_TEST() [11/14]

BoundaryInfoTest::CPPUNIT_TEST ( testNameCopying  )

◆ CPPUNIT_TEST() [12/14]

BoundaryInfoTest::CPPUNIT_TEST ( testRenumber  )

◆ CPPUNIT_TEST() [13/14]

BoundaryInfoTest::CPPUNIT_TEST ( testSelectiveRenumber  )

◆ CPPUNIT_TEST() [14/14]

BoundaryInfoTest::CPPUNIT_TEST ( testShellFaceConstraints  )

◆ CPPUNIT_TEST_SUITE_END()

BoundaryInfoTest::CPPUNIT_TEST_SUITE_END ( )

◆ LIBMESH_CPPUNIT_TEST_SUITE()

BoundaryInfoTest::LIBMESH_CPPUNIT_TEST_SUITE ( BoundaryInfoTest  )

This test ensures various aspects of the BoundaryInfo class work as expected.

◆ setUp()

void BoundaryInfoTest::setUp ( )
inline

Definition at line 60 of file boundary_info.C.

61 {
62 }

◆ tearDown()

void BoundaryInfoTest::tearDown ( )
inline

Definition at line 64 of file boundary_info.C.

65 {
66 }

◆ testBoundaryIDs()

void BoundaryInfoTest::testBoundaryIDs ( )
inline

Definition at line 698 of file boundary_info.C.

699 {
700 LOG_UNIT_TEST;
701
702 // We create one cell only. The default boundaries of the cell are below.
703 // ___2___
704 // 3 | | 1
705 // |_____|
706 // 0
707
708 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
710 1, 1,
711 0., 1.,
712 0., 1.,
713 QUAD4);
714
716
717 // Now we add the extra boundary ID (5) to the element on side 3
718 auto elem = mesh->query_elem_ptr(0);
719 if (elem)
720 bi.add_side(elem, 3, 5);
722
723 // Check the element now
724 if (elem && elem->processor_id() == mesh->processor_id())
725 {
726 std::vector<boundary_id_type> container;
727 bi.boundary_ids(elem, 3, container);
728
729 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
730 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[0]);
731 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[1]);
732
733 std::vector<std::vector<boundary_id_type>> all_bids_container;
734 bi.side_boundary_ids(elem, all_bids_container);
735 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
736 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
737 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
738 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][1]);
739 // Check other sides
740 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[0].size());
741 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(0), all_bids_container[0][0]);
742 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
743 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(1), all_bids_container[1][0]);
744 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
745 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
746 }
747 }
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
void side_boundary_ids(const Elem *const elem, std::vector< std::vector< boundary_id_type > > &vec_to_fill) const
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.
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition mesh_base.h:170
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.
Definition mesh_base.C:824
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
int8_t boundary_id_type
Definition id_types.h:51

References libMesh::BoundaryInfo::add_side(), libMesh::BoundaryInfo::boundary_ids(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::MeshBase::prepare_for_use(), libMesh::ParallelObject::processor_id(), libMesh::QUAD4, libMesh::MeshBase::query_elem_ptr(), libMesh::BoundaryInfo::side_boundary_ids(), and TestCommWorld.

◆ testBoundaryOnChildrenBoundaryIDs()

void BoundaryInfoTest::testBoundaryOnChildrenBoundaryIDs ( )
inline

Definition at line 864 of file boundary_info.C.

865 {
866 LOG_UNIT_TEST;
867
868 // We create one cell only. The default boundaries of the cell are below.
869 // We will refine the mesh and add a new boundary id to the left side (side 3).
870 // Then will query the available boundary ids on the added side. It should return
871 // both the parent's and the child's boundaries.
872 // ___2___
873 // 3 | | 1
874 // |_____|
875 // 0
876
877 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
879 1, 1,
880 0., 1.,
881 0., 1.,
882 QUAD4);
883
885
886 // We only have one element, but for easy access we use the iterator
887 for (auto & elem : mesh->active_element_ptr_range())
888 elem->set_refinement_flag(Elem::REFINE);
890
892
893 // Now we add the extra boundary ID (5) to the element in the top
894 // left corner
895 for (auto & elem : mesh->active_element_ptr_range())
896 {
897 const Point c = elem->vertex_average();
898 if (c(0) < 0.5 && c(1) > 0.5)
899 bi.add_side(elem, 3, 5);
900 }
902
903 // Okay, now we query the boundary ids on side 3 of the child and check if it has
904 // the right elements
905 for (auto & elem : mesh->active_element_ptr_range())
906 {
907 const Point c = elem->vertex_average();
908 if (c(0) < 0.5 && c(1) > 0.5)
909 {
910 std::vector<boundary_id_type> container;
911 bi.boundary_ids(elem, 3, container);
912
913 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
914 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[0]);
915 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[1]);
916
917 std::vector<std::vector<boundary_id_type>> all_bids_container;
918 bi.side_boundary_ids(elem, all_bids_container);
919 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
920 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
921 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][0]);
922 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][1]);
923 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
924 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
925 // Check other sides
926 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[0].size());
927 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[1].size());
928
929 // This is against the spirit of the test, and undefined behavior which
930 // may be changed later. Setting allow_children_on_boundary_side(false) could
931 // be actively doing a transfer_boundary_ids_from_children() and then deleting the
932 // children's data, not leaving the children's data there-but-ignored.
934 bi.side_boundary_ids(elem, all_bids_container);
935 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
936 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[3].size());
937 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
938 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
939 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
940 }
941 }
942 }
void allow_children_on_boundary_side(const bool children_on_boundary)
Whether or not to allow directly setting boundary sides on child elements.
This is the base class from which all geometric element types are derived.
Definition elem.h:96
Implements (adaptive) mesh refinement algorithms for a MeshBase.
bool refine_elements()
Only refines the user-requested elements.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40

References libMesh::BoundaryInfo::add_side(), libMesh::BoundaryInfo::allow_children_on_boundary_side(), libMesh::BoundaryInfo::boundary_ids(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::MeshBase::prepare_for_use(), libMesh::QUAD4, libMesh::Elem::REFINE, libMesh::MeshRefinement::refine_elements(), libMesh::BoundaryInfo::side_boundary_ids(), and TestCommWorld.

◆ testBoundaryOnChildrenBoundarySides()

void BoundaryInfoTest::testBoundaryOnChildrenBoundarySides ( )
inline

Definition at line 944 of file boundary_info.C.

945 {
946 LOG_UNIT_TEST;
947
948 // We create one cell only. The default boundaries of the cell are below.
949 // We will refine mesh and see if we can get back the correct sides
950 // for a given boundary id on an internal boundary.
951 // ___2___
952 // 3 | | 1
953 // |_____|
954 // 0
955
956 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
958 1, 1,
959 0., 1.,
960 0., 1.,
961 QUAD4);
962
964
965
966 // We only have one element, but for easy access we use the iterator
967 for (auto & elem : mesh->active_element_ptr_range())
968 elem->set_refinement_flag(Elem::REFINE);
971
972 // Now we add the extra boundary ID (5) to two sides of
973 // the element in the bottom left corner. then we refine again
974 for (auto & elem : mesh->active_element_ptr_range())
975 {
976 const Point c = elem->vertex_average();
977 if (c(0) < 0.5 && c(1) < 0.5)
978 {
979 bi.add_side(elem, 1, 5);
980 bi.add_side(elem, 2, 5);
981 elem->set_refinement_flag(Elem::REFINE);
982 }
983 }
986
987 // Okay, now we add another boundary id (6) to the cell which is in the bottom
988 // right corner of the refined element
989 for (auto & elem : mesh->active_element_ptr_range())
990 {
991 const Point c = elem->vertex_average();
992 if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
993 bi.add_side(elem, 1, 6);
994 }
995
996 // Time to test if we can get back the boundary sides, first we
997 // check if we can get back boundary from the ancestors of (5) on
998 // the cell which only has boundary (6) registered. We also check
999 // if we can get boundary (6) back.
1000
1001 for (auto & elem : mesh->active_element_ptr_range())
1002 {
1003 const Point c = elem->vertex_average();
1004 if (c(0) < 0.5 && c(0) > 0.25 && c(1) < 0.25)
1005 {
1006 const auto side_5 = bi.side_with_boundary_id(elem, 5);
1007 const auto side_6 = bi.side_with_boundary_id(elem, 6);
1008 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_5);
1009 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), side_6);
1010 }
1011 }
1012
1013 // Now we go and try to query the sides with boundary id (5) using
1014 // the element which is at the top right corner of the bottom
1015 // right parent.
1016 for (auto & elem : mesh->active_element_ptr_range())
1017 {
1018 const Point c = elem->vertex_average();
1019 if (c(0) < 0.5 && c(0) > 0.25 && c(1) > 0.25 && c(1) < 0.5)
1020 {
1021 const auto sides = bi.sides_with_boundary_id(elem, 5);
1022 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long>(2), sides.size());
1023 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(1), sides[0]);
1024 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), sides[1]);
1025 }
1026 }
1027 }
unsigned int side_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
std::vector< unsigned int > sides_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const

References libMesh::BoundaryInfo::add_side(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::MeshBase::prepare_for_use(), libMesh::QUAD4, libMesh::Elem::REFINE, libMesh::MeshRefinement::refine_elements(), libMesh::BoundaryInfo::side_with_boundary_id(), libMesh::BoundaryInfo::sides_with_boundary_id(), and TestCommWorld.

◆ testBoundaryOnChildrenElementsRefineCoarsen()

void BoundaryInfoTest::testBoundaryOnChildrenElementsRefineCoarsen ( )
inline

Definition at line 749 of file boundary_info.C.

750 {
751 LOG_UNIT_TEST;
752
753 // Set subdomain ids for specific elements, we will refine/coarsen
754 // the cell on subdomain 1
755 // _____________
756 // | 1 | 2 |
757 // |_____|_____|
758
759 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
761 2, 1,
762 0., 2.,
763 0., 1.,
764 QUAD4);
765
767
768 for (auto & elem : mesh->active_element_ptr_range())
769 {
770 const Point c = elem->vertex_average();
771 if (c(0) < 1)
772 {
773 elem->subdomain_id() = 1;
774 elem->set_refinement_flag(Elem::REFINE);
775 }
776 else
777 elem->subdomain_id() = 2;
778 }
780
781 // Refine the elements once in subdomain 1, and
782 // add the right side subdomain 1 as boundary 5
785
786 for (auto & elem : mesh->active_element_ptr_range())
787 {
788 const Point c = elem->vertex_average();
789 if (c(0) < 1 && c(0) > 0.5)
790 bi.add_side(elem, 1, 5);
791 }
793
794 // Check the middle boundary, we expect to have two sides in boundary 5
795 unsigned int count = 0;
796 for (auto & elem : mesh->active_element_ptr_range())
797 if (bi.has_boundary_id(elem, 1, 5))
798 count++;
799
801 {
802 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), count);
803 CPPUNIT_ASSERT(bi.is_children_on_boundary_side());
804 }
805
806 // First, we will coarsen the the elements on subdomain 1. This
807 // is to check if the boundary information propagates upward upon
808 // coarsening.
809 for (auto & elem : mesh->active_element_ptr_range())
810 {
811 const Point c = elem->vertex_average();
812 if (c(0) < 1)
813 elem->set_refinement_flag(Elem::COARSEN);
814 }
816
817 // The coarsened element should have its side on boundary 5
818 // This is boundary info transferred from this child element
821
822 for (auto & elem : mesh->active_element_ptr_range())
823 {
824 const Point c = elem->vertex_average();
825 if (c(0) < 1)
826 {
827 CPPUNIT_ASSERT(bi.has_boundary_id(elem, 1, 5));
828 // We clean up this boundary ID for the next round of tests
829 bi.remove_side(elem, 1, 5);
830 // we will refine this element again
831 elem->set_refinement_flag(Elem::REFINE);
832 }
833 }
834
837
838 // This time we remove boundary 5 from one of the children. We expect
839 // the boundary not to propagate to the next level. Furthermore we
840 // expect boundary 5 to be deleted from the parent's boundaries
841 for (auto & elem : mesh->active_element_ptr_range())
842 {
843 const Point c = elem->vertex_average();
844 if (c(0) < 1)
845 elem->set_refinement_flag(Elem::COARSEN);
846 if (c(0) > 0.5 && c(0) < 1 && c(1) < 0.5)
847 bi.add_side(elem, 1, 5);
848 }
850
852
854
855 // The parent element should not have any side associated with boundary 5
856 for (auto & elem : mesh->active_element_ptr_range())
857 {
858 const Point c = elem->vertex_average();
859 if (c(0) < 1)
860 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, 1, 5));
861 }
862 }
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
bool is_children_on_boundary_side() const
void remove_side(const Elem *elem, const unsigned short int side)
Removes all boundary conditions associated with side side of element elem, if any exist.
dof_id_type n_active_local_elem() const
Definition mesh_base.h:714
bool coarsen_elements()
Only coarsens the user-requested elements.

References libMesh::BoundaryInfo::add_side(), libMesh::MeshTools::Generation::build_square(), libMesh::Elem::COARSEN, libMesh::MeshRefinement::coarsen_elements(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), libMesh::BoundaryInfo::is_children_on_boundary_side(), mesh, libMesh::MeshBase::n_active_local_elem(), libMesh::MeshBase::prepare_for_use(), libMesh::QUAD4, libMesh::Elem::REFINE, libMesh::MeshRefinement::refine_elements(), libMesh::BoundaryInfo::remove_side(), and TestCommWorld.

◆ testBoundaryOnChildrenErrors()

void BoundaryInfoTest::testBoundaryOnChildrenErrors ( )
inline

Definition at line 601 of file boundary_info.C.

602 {
603 LOG_UNIT_TEST;
604
605 // We create one cell only. The default boundaries of the cell are below.
606 // ___2___
607 // 3 | | 1
608 // |_____|
609 // 0
610
611 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
613 1, 1,
614 0., 1.,
615 0., 1.,
616 QUAD4);
617
619
620 // We only have one element, but for easy access we use the iterator
621 for (auto & elem : mesh->active_element_ptr_range())
622 elem->set_refinement_flag(Elem::REFINE);
624
627
628 // Now we try to add boundary id 3 to a child on side 3. This should
629 // result in a "not implemented" error message
630 bool threw_desired_exception = false;
631 try {
632 for (auto & elem : mesh->active_element_ptr_range())
633 {
634 const Point c = elem->vertex_average();
635 if (c(0) < 0.5 && c(1) > 0.5)
636 bi.add_side(elem, 3, 3);
637 }
638 }
639 catch (libMesh::NotImplemented & e) {
640 std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
641 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
642 threw_desired_exception = true;
643 }
644 // If we have more than 4 processors, or a poor partitioner, we
645 // might not get an exception on every processor
646 mesh->comm().max(threw_desired_exception);
647
648 CPPUNIT_ASSERT(threw_desired_exception);
649
650 threw_desired_exception = false;
651 try {
652 for (auto & elem : mesh->active_element_ptr_range())
653 {
654 const Point c = elem->vertex_average();
655 if (c(0) < 0.5 && c(1) > 0.5)
656 bi.add_side(elem, 3, {3,4});
657 }
658 }
659 catch (libMesh::NotImplemented & e) {
660 std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
661 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
662 threw_desired_exception = true;
663 }
664
665 // If we have more than 4 processors, or a poor partitioner, we
666 // might not get an exception on every processor
667 mesh->comm().max(threw_desired_exception);
668
669 CPPUNIT_ASSERT(threw_desired_exception);
670
671 // We tested the side addition errors, now we move to the removal parts.
672 // We will attempt the removal of boundary 3 through the child
673 threw_desired_exception = false;
675 try {
676 for (auto & elem : mesh->active_element_ptr_range())
677 {
678 const Point c = elem->vertex_average();
679 if (c(0) < 0.5 && c(1) > 0.5)
680 bi.remove_side(elem, 3, 3);
681 }
682 }
683 catch (libMesh::NotImplemented & e) {
684 std::regex msg_regex("We cannot delete boundary ID 3 using a child because it is inherited from an ancestor");
685 CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
686 threw_desired_exception = true;
687 }
688
689 // If we have more than 4 processors, or a poor partitioner, we
690 // might not get an exception on every processor
691 mesh->comm().max(threw_desired_exception);
692
693 CPPUNIT_ASSERT(threw_desired_exception);
694 }
void max(const T &r, T &o, Request &req) const
A class to stub for features that should be in libMesh, but haven't been written yet,...
const Parallel::Communicator & comm() const

References libMesh::BoundaryInfo::add_side(), libMesh::MeshTools::Generation::build_square(), libMesh::ParallelObject::comm(), libMesh::MeshBase::get_boundary_info(), libMesh::Parallel::Communicator::max(), mesh, libMesh::MeshBase::prepare_for_use(), libMesh::QUAD4, libMesh::Elem::REFINE, libMesh::MeshRefinement::refine_elements(), and TestCommWorld.

◆ testBuildNodeListFromSideList()

void BoundaryInfoTest::testBuildNodeListFromSideList ( )
inline

Definition at line 1031 of file boundary_info.C.

1032 {
1033 LOG_UNIT_TEST;
1034
1035 Mesh mesh(*TestCommWorld);
1036
1038 2, 2,
1039 0., 1.,
1040 0., 1.,
1041 QUAD4);
1042
1044
1045 // build_square gave us ids 0-3 as both side sets and node sets
1046 bi.remove_node_id(0);
1047 bi.remove_node_id(1);
1048 bi.remove_node_id(2);
1049 bi.remove_node_id(3);
1050
1051 CPPUNIT_ASSERT(bi.build_node_list().empty());
1052
1054
1055 for (const auto & elem : mesh.element_ptr_range())
1056 {
1057 for (auto n : elem->node_index_range())
1058 {
1059 const Node * node = elem->node_ptr(n);
1060 for (auto s : {0,2})
1061 if (elem->is_node_on_side(n, s) && !elem->neighbor_ptr(s))
1062 CPPUNIT_ASSERT(bi.has_boundary_id(node, s));
1063 for (auto s : {1,3})
1064 CPPUNIT_ASSERT(!bi.has_boundary_id(node, s));
1065 }
1066 }
1067 }
void remove_node_id(boundary_id_type id, bool global=false)
Removes all nodes with boundary id id from the BoundaryInfo object, removes it from the set of node b...
std::vector< NodeBCTuple > build_node_list(NodeBCTupleSortBy sort_by=NodeBCTupleSortBy::NODE_ID) const
void build_node_list_from_side_list(const std::set< boundary_id_type > &sideset_list={})
Adds nodes with boundary ids based on the side's boundary ids they are connected to.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
A Node is like a Point, but with more information.
Definition node.h:55

References libMesh::BoundaryInfo::build_node_list(), libMesh::BoundaryInfo::build_node_list_from_side_list(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), mesh, libMesh::QUAD4, libMesh::BoundaryInfo::remove_node_id(), and TestCommWorld.

◆ testBuildSideListFromNodeList()

void BoundaryInfoTest::testBuildSideListFromNodeList ( )
inline

Definition at line 1070 of file boundary_info.C.

1071 {
1072 LOG_UNIT_TEST;
1073
1074 Mesh mesh(*TestCommWorld);
1075
1077 2, 2,
1078 0., 1.,
1079 0., 1.,
1080 QUAD4);
1081
1083
1084 // build_square gave us ids 0-3 as both side sets and node sets
1085 bi.remove_side_id(0);
1086 bi.remove_side_id(1);
1087 bi.remove_side_id(2);
1088 bi.remove_side_id(3);
1089
1090 CPPUNIT_ASSERT(bi.build_side_list().empty());
1091
1093
1094 for (const auto & elem : mesh.element_ptr_range())
1095 {
1096 for (auto s : {0,2})
1097 {
1098 if (!elem->neighbor_ptr(s))
1099 {
1100 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, s));
1101 CPPUNIT_ASSERT_EQUAL(bi.n_boundary_ids(elem, s), 1u);
1102 }
1103 else
1104 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1105 }
1106 for (auto s : {1,3})
1107 {
1108 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, s));
1109 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1110 }
1111 }
1112 }
std::size_t n_boundary_ids() const
void build_side_list_from_node_list(const std::set< boundary_id_type > &nodeset_list={})
Adds sides to a sideset if every node on that side are in the same sideset.
std::vector< BCTuple > build_side_list(BCTupleSortBy sort_by=BCTupleSortBy::ELEM_ID) const
void remove_side_id(boundary_id_type id, bool global=false)
Removes all sides with boundary id id from the BoundaryInfo object, removes it from the set of side b...

References libMesh::BoundaryInfo::build_side_list(), libMesh::BoundaryInfo::build_side_list_from_node_list(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), mesh, libMesh::BoundaryInfo::n_boundary_ids(), libMesh::QUAD4, libMesh::BoundaryInfo::remove_side_id(), and TestCommWorld.

◆ testEdgeBoundaryConditions()

void BoundaryInfoTest::testEdgeBoundaryConditions ( )
inline

Definition at line 371 of file boundary_info.C.

372 {
373 LOG_UNIT_TEST;
374
375 const unsigned int n_elem = 5;
376 const std::string mesh_filename = "cube_mesh.xda";
377
378 {
379 Mesh mesh(*TestCommWorld);
381 n_elem, n_elem, n_elem,
382 0., 1.,
383 0., 1.,
384 0., 1.,
385 HEX8);
386
388
389 // build_cube does not add any edge boundary IDs
390 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_edge_conds());
391
392 // Let's now add some edge boundary IDs.
393 // We loop over all elements (not just local elements) so that
394 // all processors know about the boundary IDs
395 const boundary_id_type BOUNDARY_ID_MAX_X = 2;
396 const boundary_id_type BOUNDARY_ID_MIN_Y = 1;
397 const boundary_id_type EDGE_BOUNDARY_ID = 20;
398
399 for (const auto & elem : mesh.element_ptr_range())
400 {
401 unsigned short side_max_x = 0, side_min_y = 0;
402 bool found_side_max_x = false, found_side_min_y = false;
403
404 for (unsigned short side=0; side<elem->n_sides(); side++)
405 {
406 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MAX_X))
407 {
408 side_max_x = side;
409 found_side_max_x = true;
410 }
411
412 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MIN_Y))
413 {
414 side_min_y = side;
415 found_side_min_y = true;
416 }
417 }
418
419 // If elem has sides on boundaries
420 // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
421 // then let's set an edge boundary condition
422 if (found_side_max_x && found_side_min_y)
423 for (unsigned short e=0; e<elem->n_edges(); e++)
424 if (elem->is_edge_on_side(e, side_max_x) &&
425 elem->is_edge_on_side(e, side_min_y))
426 bi.add_edge(elem, e, EDGE_BOUNDARY_ID);
427 }
428
429 // Check that we have the expected number of edge boundary IDs after
430 // updating bi
431 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
432
433 // Let's test that edge BCIDs are preserved (in a relative
434 // sense) when we clone a mesh.
435 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
436 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
438
439 mesh.write(mesh_filename);
440 }
441
442 // Make sure all processors are done writing before we try to
443 // start reading
444 TestCommWorld->barrier();
445
446 Mesh mesh(*TestCommWorld);
447 mesh.read(mesh_filename);
448
449 // Check that writing and reading preserves the edge boundary IDs
451 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
452 }
void add_edge(const dof_id_type elem, const unsigned short int edge, const boundary_id_type id)
Add edge edge of element number elem with boundary id id to the boundary information data structure.
std::size_t n_edge_conds() const
virtual void write(const std::string &name) const =0
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
Communicator * TestCommWorld
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).

References libMesh::BoundaryInfo::add_edge(), libMesh::MeshTools::Generation::build_cube(), libMesh::MeshBase::clone(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), libMesh::HEX8, mesh, libMesh::BoundaryInfo::n_edge_conds(), libMesh::MeshBase::read(), TestCommWorld, and libMesh::MeshBase::write().

◆ testInternalBoundary()

void BoundaryInfoTest::testInternalBoundary ( )
inline

Definition at line 1115 of file boundary_info.C.

1116 {
1117 LOG_UNIT_TEST;
1118
1119 Mesh mesh(*TestCommWorld);
1120
1121 // Build a 2x2 QUAD4 structured mesh on [0,1]x[0,1].
1123 2, 2,
1124 0., 1.,
1125 0., 1.,
1126 QUAD4);
1127
1129
1130 const unsigned int internal_side = 1; // east side for left elems
1131 const boundary_id_type BID = 7;
1132
1134
1135 Elem * left_bottom_elem = nullptr;
1136 for (auto & elem : mesh.active_element_ptr_range())
1137 {
1138 if (elem->processor_id() != mesh.processor_id())
1139 continue;
1140
1141 const Point c = elem->vertex_average();
1142 if (c(0) < 0.5 && c(1) < 0.5 && elem->neighbor_ptr(internal_side) != nullptr)
1143 {
1144 left_bottom_elem = elem;
1145 break;
1146 }
1147 }
1148
1149
1150 if (left_bottom_elem)
1151 {
1152 bi.add_side(left_bottom_elem, internal_side, BID);
1153
1154 const unsigned int found_side = bi.side_with_boundary_id(left_bottom_elem, BID);
1155 CPPUNIT_ASSERT_EQUAL(internal_side, found_side);
1156 }
1157 }

References libMesh::BoundaryInfo::add_side(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::MeshBase::prepare_for_use(), libMesh::ParallelObject::processor_id(), libMesh::QUAD4, libMesh::BoundaryInfo::side_with_boundary_id(), and TestCommWorld.

◆ testMesh()

void BoundaryInfoTest::testMesh ( )
inline

Definition at line 68 of file boundary_info.C.

69 {
70 LOG_UNIT_TEST;
71
72 Mesh mesh(*TestCommWorld);
73
75 2, 2,
76 0., 1.,
77 0., 1.,
78 QUAD4);
79
81
82 // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
83 // top, and left sides, respectively.
84
85 // On a ReplicatedMesh, we should see all 4 ids on each processor
86 if (mesh.is_serial())
87 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), bi.n_boundary_ids());
88
89 // On any mesh, we should see each id on *some* processor
90 {
91 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
92 for (boundary_id_type i = 0 ; i != 4; ++i)
93 {
94 bool has_bcid = bc_ids.count(i);
95 mesh.comm().max(has_bcid);
96 CPPUNIT_ASSERT(has_bcid);
97 }
98 }
99
100 // Check that there are exactly 8 sides in the BoundaryInfo for a
101 // replicated mesh
102 auto bc_triples = bi.build_side_list();
103 if (mesh.is_serial())
104 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
105
106 // Let's test that they are preserved (in a relative sense) when
107 // we clone a mesh.
108 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
109 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
111
112 // Let's test that we can remove them successfully.
113 bi.remove_id(0);
114
115 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() !=
117
118 // Check that there are now only 3 boundary ids total on the Mesh.
119 if (mesh.is_serial())
120 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
121
122 {
123 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
124 CPPUNIT_ASSERT(!bc_ids.count(0));
125 for (boundary_id_type i = 1 ; i != 4; ++i)
126 {
127 bool has_bcid = bc_ids.count(i);
128 mesh.comm().max(has_bcid);
129 CPPUNIT_ASSERT(has_bcid);
130 }
131 }
132
133 // Build the side list again
134 bc_triples = bi.build_side_list();
135
136 // Check that there are now exactly 6 sides left in the
137 // BoundaryInfo on a replicated mesh
138 if (mesh.is_serial())
139 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bc_triples.size());
140
141 // Check that the removed ID is really removed
142 CPPUNIT_ASSERT(std::find_if(bc_triples.begin(), bc_triples.end(),
143 [](const auto & t) { return std::get<2>(t) == 0; }) == bc_triples.end());
144
145 // Remove the same id again, make sure nothing changes.
146 bi.remove_id(0);
147 if (mesh.is_serial())
148 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
149
150 // Remove the remaining IDs, verify that we have no sides left and
151 // that we can safely reuse the same vectors in the
152 // build_side_list() call.
153 bi.remove_id(1);
154 bi.remove_id(2);
155 bi.remove_id(3);
156 bc_triples = bi.build_side_list();
157
158 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
159 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
160 }
void remove_id(boundary_id_type id, bool global=false)
Removes all entities (nodes, sides, edges, shellfaces) with boundary id id from their respective cont...
const std::set< boundary_id_type > & get_boundary_ids() const
virtual bool is_serial() const
Definition mesh_base.h:357

References libMesh::BoundaryInfo::build_side_list(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::clone(), libMesh::ParallelObject::comm(), libMesh::BoundaryInfo::get_boundary_ids(), libMesh::MeshBase::get_boundary_info(), libMesh::MeshBase::is_serial(), libMesh::Parallel::Communicator::max(), mesh, libMesh::BoundaryInfo::n_boundary_ids(), libMesh::QUAD4, libMesh::BoundaryInfo::remove_id(), and TestCommWorld.

◆ testNameCopying()

void BoundaryInfoTest::testNameCopying ( )
inline

Definition at line 454 of file boundary_info.C.

455 {
456 LOG_UNIT_TEST;
457
458 Mesh mesh(*TestCommWorld);
460 8,
461 0., 1.,
462 EDGE2);
463
464 Mesh mesh2(mesh);
465
467 bi.sideset_name(0) = "zero";
468 bi.sideset_name(1) = "one";
469 bi.sideset_name(2) = "two";
470 bi.sideset_name(3) = "three";
471 bi.nodeset_name(0) = "ZERO";
472 bi.nodeset_name(1) = "ONE";
473
474 BoundaryInfo bi2 {bi};
475 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(0), std::string("zero"));
476 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(1), std::string("one"));
477 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(2), std::string("two"));
478 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(3), std::string("three"));
479 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(0), std::string("ZERO"));
480 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(1), std::string("ONE"));
481
482 BoundaryInfo & bi3 = mesh2.get_boundary_info();
483 bi3 = bi;
484 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(0), std::string("zero"));
485 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(1), std::string("one"));
486 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(2), std::string("two"));
487 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(3), std::string("three"));
488 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(0), std::string("ZERO"));
489 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(1), std::string("ONE"));
490 }
std::string & sideset_name(boundary_id_type id)
std::string & nodeset_name(boundary_id_type id)
const std::string & get_nodeset_name(boundary_id_type id) const
const std::string & get_sideset_name(boundary_id_type id) const
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.

References libMesh::MeshTools::Generation::build_line(), libMesh::EDGE2, libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::get_nodeset_name(), libMesh::BoundaryInfo::get_sideset_name(), mesh, libMesh::BoundaryInfo::nodeset_name(), libMesh::BoundaryInfo::sideset_name(), and TestCommWorld.

◆ testRenumber()

void BoundaryInfoTest::testRenumber ( )
inline

Definition at line 163 of file boundary_info.C.

164 {
165 LOG_UNIT_TEST;
166
167 Mesh mesh(*TestCommWorld);
168
170 2, 2,
171 0., 1.,
172 0., 1.,
173 QUAD4);
174
176
177 // build_square adds boundary_ids 0,1,2,3 for the bottom, right,
178 // top, and left sides, respectively. Let's remap those, not 1-1.
179 bi.renumber_id(0, 4);
180 bi.renumber_id(1, 5);
181 bi.renumber_id(2, 6);
182 bi.renumber_id(3, 6);
183
184 const std::map<boundary_id_type, std::string> expected_names =
185 {{4,"bottom"}, {5,"right"}, {6,"left"}};
186
187 // On a ReplicatedMesh, we should see ids 4,5,6 on each processor
188 if (mesh.is_serial())
189 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), bi.n_boundary_ids());
190
191 // On any mesh, we should see each new id on *some* processor, and
192 // shouldn't see old ids on *any* processor
193 {
194 const std::set<boundary_id_type> & bc_ids = bi.get_boundary_ids();
195 for (boundary_id_type i = 0 ; i != 4; ++i)
196 {
197 bool has_bcid = bc_ids.count(i);
198 mesh.comm().max(has_bcid);
199 CPPUNIT_ASSERT(!has_bcid);
200 }
201 for (boundary_id_type i = 4 ; i != 7; ++i)
202 {
203 bool has_bcid = bc_ids.count(i);
204
205 bool bad_name = false;
206 if (has_bcid)
207 {
208 const std::string & current_name = bi.sideset_name(i);
209
210 bad_name = (current_name != libmesh_map_find(expected_names, i));
211 }
212
213 // At least one proc should have each of these BCs
214 mesh.comm().max(has_bcid);
215 CPPUNIT_ASSERT(has_bcid);
216
217 // No proc should have the wrong name for a BC it has
218 mesh.comm().max(bad_name);
219 CPPUNIT_ASSERT(!bad_name);
220 }
221 }
222
223 // Check that there are still exactly 8 sides in the BoundaryInfo
224 // for a replicated mesh
225 auto bc_triples = bi.build_side_list();
226
227 if (mesh.is_serial())
228 {
229 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(8), bc_triples.size());
230 }
231
232 // Remove the new IDs, verify that we have no sides left
233 bi.remove_id(4);
234 bi.remove_id(5);
235 bi.remove_id(6);
236 bc_triples = bi.build_side_list();
237
238 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_boundary_ids());
239 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bc_triples.size());
240 }
void renumber_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all entities (nodes, sides, edges, shellfaces) with boundary id old_id to instead be labeled ...

References libMesh::BoundaryInfo::build_side_list(), libMesh::MeshTools::Generation::build_square(), libMesh::ParallelObject::comm(), libMesh::BoundaryInfo::get_boundary_ids(), libMesh::MeshBase::get_boundary_info(), libMesh::MeshBase::is_serial(), libMesh::Parallel::Communicator::max(), mesh, libMesh::BoundaryInfo::n_boundary_ids(), libMesh::QUAD4, libMesh::BoundaryInfo::remove_id(), libMesh::BoundaryInfo::renumber_id(), libMesh::BoundaryInfo::sideset_name(), and TestCommWorld.

◆ testSelectiveRenumber()

void BoundaryInfoTest::testSelectiveRenumber ( )
inline

Definition at line 243 of file boundary_info.C.

244 {
245 LOG_UNIT_TEST;
246
247 Mesh mesh(*TestCommWorld);
248
250 2, 2, 2,
251 0., 1.,
252 0., 1.,
253 0., 1.,
254 HEX8);
255
257
258 // build_cube adds boundary_ids 0-5 for "back", "bottom", "right",
259 // "top", "left", and "front" (as viewed facing the usual XY plane
260 // with the Z axis pointing toward the viewer) respectively.
261 // Let's scramble those, and scramble them differently on nodes vs
262 // sides.
263 bi.renumber_side_id(0, 6);
264 bi.renumber_side_id(5, 7);
265 bi.renumber_node_id(0, 7);
266 bi.renumber_node_id(5, 6);
267
268 Elem * elem = mesh.query_elem_ptr(0);
269
270 if (elem)
271 {
272 // Let's add a couple edges
273 bi.add_edge(elem, 2, 1);
274 bi.add_edge(elem, 3, 2);
275 bi.edgeset_name(1) = "firstedge";
276 bi.edgeset_name(2) = "secondedge";
277 // And scramble them
278 bi.renumber_edge_id(1, 3);
279 bi.renumber_edge_id(2, 4);
280 }
281
282 // We should get global ids squared away
284
285 const std::map<boundary_id_type, std::string> expected_basic_names =
286 {{1,"bottom"}, {2,"right"}, {3,"top"}, {4,"left"}};
287
288 std::map<boundary_id_type, std::string> expected_side_names =
289 expected_basic_names;
290 expected_side_names.insert({{6,"back"}, {7,"front"}});
291
292 std::map<boundary_id_type, std::string> expected_node_names =
293 expected_basic_names;
294 expected_node_names.insert({{6,"front"}, {7,"back"}});
295
296 const std::map<boundary_id_type, std::string> expected_edge_names =
297 {{3,"firstedge"}, {4,"secondedge"}};
298
299 // On a ReplicatedMesh, we should see ids 1-4,6,7 on each processor
300 if (mesh.is_serial())
301 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(6), bi.n_boundary_ids());
302
303 // On any mesh, we should see each new id on *some* processor, and
304 // shouldn't see old ids on *any* processor
305 {
306 auto & bc_ids = bi.get_boundary_ids();
307 auto & side_bc_ids = bi.get_side_boundary_ids();
308 auto & edge_bc_ids = bi.get_edge_boundary_ids();
309 auto & node_bc_ids = bi.get_node_boundary_ids();
310
311 for (boundary_id_type noid : {0, 5})
312 {
313 bool has_bcid = bc_ids.count(noid) ||
314 side_bc_ids.count(noid) ||
315 edge_bc_ids.count(noid) ||
316 node_bc_ids.count(noid);
317 mesh.comm().max(has_bcid);
318 CPPUNIT_ASSERT(!has_bcid);
319 }
320
321 for (boundary_id_type id : {1, 2, 3, 4, 6, 7})
322 {
323 bool has_bcid = bc_ids.count(id),
324 has_side_id = side_bc_ids.count(id),
325 has_edge_id = edge_bc_ids.count(id),
326 has_node_id = node_bc_ids.count(id);
327
328 bool bad_name = false;
329 if (has_side_id)
330 {
331 const std::string & side_name = bi.sideset_name(id);
332 bad_name = bad_name || (side_name != libmesh_map_find(expected_side_names, id));
333 }
334
335 if (has_edge_id)
336 {
337 const std::string & edge_name = bi.edgeset_name(id);
338 bad_name = bad_name || (edge_name != libmesh_map_find(expected_edge_names, id));
339 }
340
341 if (has_node_id)
342 {
343 const std::string & node_name = bi.nodeset_name(id);
344 bad_name = bad_name || (node_name != libmesh_map_find(expected_node_names, id));
345 }
346
347 // At least one proc should have each the BCs we expect
348 mesh.comm().max(has_bcid);
349 CPPUNIT_ASSERT(has_bcid);
350
351 mesh.comm().max(has_side_id);
352 CPPUNIT_ASSERT(has_side_id);
353
354 mesh.comm().max(has_edge_id);
355 if (id == 3 || id == 4)
356 CPPUNIT_ASSERT(has_edge_id);
357 else
358 CPPUNIT_ASSERT(!has_edge_id);
359
360 mesh.comm().max(has_node_id);
361 CPPUNIT_ASSERT(has_node_id);
362
363 // No proc should have the wrong name for a BC it has
364 mesh.comm().max(bad_name);
365 CPPUNIT_ASSERT(!bad_name);
366 }
367 }
368 }
void renumber_edge_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all edges with boundary id old_id to instead be labeled by boundary id new_id.
void synchronize_global_id_set()
Synchronizes the boundary_ids set on each processor to determine global_boundary_ids.
const std::set< boundary_id_type > & get_edge_boundary_ids() const
const std::set< boundary_id_type > & get_node_boundary_ids() const
std::string & edgeset_name(boundary_id_type id)
const std::set< boundary_id_type > & get_side_boundary_ids() const
void renumber_node_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all nodes with boundary id old_id to instead be labeled by boundary id new_id.
void renumber_side_id(boundary_id_type old_id, boundary_id_type new_id)
Changes all sides with boundary id old_id to instead be labeled by boundary id new_id.

References libMesh::BoundaryInfo::add_edge(), libMesh::MeshTools::Generation::build_cube(), libMesh::ParallelObject::comm(), libMesh::BoundaryInfo::edgeset_name(), libMesh::BoundaryInfo::get_boundary_ids(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::get_edge_boundary_ids(), libMesh::BoundaryInfo::get_node_boundary_ids(), libMesh::BoundaryInfo::get_side_boundary_ids(), libMesh::HEX8, libMesh::MeshBase::is_serial(), libMesh::Parallel::Communicator::max(), mesh, libMesh::BoundaryInfo::n_boundary_ids(), libMesh::BoundaryInfo::nodeset_name(), libMesh::MeshBase::query_elem_ptr(), libMesh::BoundaryInfo::renumber_edge_id(), libMesh::BoundaryInfo::renumber_node_id(), libMesh::BoundaryInfo::renumber_side_id(), libMesh::BoundaryInfo::sideset_name(), libMesh::BoundaryInfo::synchronize_global_id_set(), and TestCommWorld.

◆ testShellFaceConstraints()

void BoundaryInfoTest::testShellFaceConstraints ( )
inline

Definition at line 493 of file boundary_info.C.

494 {
495 LOG_UNIT_TEST;
496
497 // Make a simple two element mesh that we can use to test constraints
498 Mesh mesh(*TestCommWorld);
499
500 // (0,1) (1,1)
501 // x---------------x
502 // | |
503 // | |
504 // | |
505 // | |
506 // | |
507 // x---------------x
508 // (0,0) (1,0)
509 // | |
510 // | |
511 // | |
512 // | |
513 // x---------------x
514 // (0,-1) (1,-1)
515
516 mesh.add_point( Point(0.0,-1.0), 4 );
517 mesh.add_point( Point(1.0,-1.0), 5 );
518 mesh.add_point( Point(1.0, 0.0), 1 );
519 mesh.add_point( Point(1.0, 1.0), 2 );
520 mesh.add_point( Point(0.0, 1.0), 3 );
521 mesh.add_point( Point(0.0, 0.0), 0 );
522
523 Elem * elem_top = mesh.add_elem(Elem::build(QUADSHELL4));
524 elem_top->set_node(0, mesh.node_ptr(0));
525 elem_top->set_node(1, mesh.node_ptr(1));
526 elem_top->set_node(2, mesh.node_ptr(2));
527 elem_top->set_node(3, mesh.node_ptr(3));
528
529 Elem * elem_bottom = mesh.add_elem(Elem::build(QUADSHELL4));
530 elem_bottom->set_node(0, mesh.node_ptr(4));
531 elem_bottom->set_node(1, mesh.node_ptr(5));
532 elem_bottom->set_node(2, mesh.node_ptr(1));
533 elem_bottom->set_node(3, mesh.node_ptr(0));
534
536 bi.add_shellface(elem_top, 0, 10);
537 bi.add_shellface(elem_bottom, 1, 20);
538
541
542 // Let's test that shellface BCIDs are preserved (in a relative
543 // sense) when we clone a mesh.
544 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
545 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
547
548 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), bi.n_shellface_conds());
549
551 System & system = es.add_system<System> ("SimpleSystem");
552 system.add_variable("u", FIRST);
553
554 // Add a Dirichlet constraint to check that we impose constraints
555 // correctly on shell faces.
556 std::vector<unsigned int> variables;
557 variables.push_back(0);
558 std::set<boundary_id_type> shellface_ids;
559 shellface_ids.insert(20);
561 DirichletBoundary dirichlet_bc(shellface_ids,
562 variables,
563 &zf);
564 system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
565 es.init();
566
567 // Find elem_bottom again if we have it (it may have been deleted
568 // in a DistributedMesh or renumbered in theory)
569 elem_bottom = nullptr;
570 for (unsigned int e = 0; e != mesh.max_elem_id(); ++e)
571 {
572 Elem *elem = mesh.query_elem_ptr(e);
573 if (elem && elem->point(3) == Point(0,0))
574 elem_bottom = elem;
575 }
576
577 // We expect to have a dof constraint on all four dofs of
578 // elem_bottom
579 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), static_cast<std::size_t>(system.n_constrained_dofs()));
580
581 // But we may only know the details of that
582 // constraint on the processor which owns elem_bottom.
583 if (elem_bottom &&
584 elem_bottom->processor_id() == mesh.processor_id())
585 {
586 std::vector<dof_id_type> dof_indices;
587 system.get_dof_map().dof_indices(elem_bottom, dof_indices);
588 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), dof_indices.size());
589
590 for(unsigned int i=0; i<dof_indices.size(); i++)
591 {
592 dof_id_type dof_id = dof_indices[i];
593 CPPUNIT_ASSERT( system.get_dof_map().is_constrained_dof(dof_id) );
594 }
595 }
596 }
void add_shellface(const dof_id_type elem, const unsigned short int shellface, const boundary_id_type id)
Add shell face shellface of element number elem with boundary id id to the boundary information data ...
std::size_t n_shellface_conds() const
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
bool is_constrained_dof(const dof_id_type dof) const
Definition dof_map.h:2426
processor_id_type processor_id() const
Definition dof_object.h:881
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2567
const Point & point(const unsigned int i) const
Definition elem.h:2462
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
This is the EquationSystems class.
virtual const Node * node_ptr(const dof_id_type i) const =0
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use.
Definition mesh_base.h:1355
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)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
virtual dof_id_type max_elem_id() const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
dof_id_type n_constrained_dofs() const
Definition system.C:125
const DofMap & get_dof_map() const
Definition system.h:2417
ConstFunction that simply returns 0.
uint8_t dof_id_type
Definition id_types.h:67

References libMesh::DofMap::add_dirichlet_boundary(), libMesh::MeshBase::add_elem(), libMesh::MeshBase::add_point(), libMesh::BoundaryInfo::add_shellface(), libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), libMesh::MeshBase::allow_renumbering(), libMesh::Elem::build(), libMesh::MeshBase::clone(), libMesh::DofMap::dof_indices(), libMesh::FIRST, libMesh::MeshBase::get_boundary_info(), libMesh::System::get_dof_map(), libMesh::EquationSystems::init(), libMesh::DofMap::is_constrained_dof(), libMesh::MeshBase::max_elem_id(), mesh, libMesh::System::n_constrained_dofs(), libMesh::BoundaryInfo::n_shellface_conds(), libMesh::MeshBase::node_ptr(), libMesh::Elem::point(), libMesh::MeshBase::prepare_for_use(), libMesh::DofObject::processor_id(), libMesh::ParallelObject::processor_id(), libMesh::QUADSHELL4, libMesh::MeshBase::query_elem_ptr(), libMesh::Elem::set_node(), and TestCommWorld.


The documentation for this class was generated from the following file: