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 (testBuildSideListFromNodeListDistributedMesh)
 
 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 (testBuildSideListFromNodeListThinMesh)
 
 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 testBuildSideListFromNodeListThinMesh ()
 
void testBuildSideListFromNodeListDistributedMesh ()
 
void testInternalBoundary ()
 

Detailed Description

Definition at line 22 of file boundary_info.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryIDs  )

◆ CPPUNIT_TEST() [2/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenBoundaryIDs  )

◆ CPPUNIT_TEST() [3/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenBoundarySides  )

◆ CPPUNIT_TEST() [4/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenElementsRefineCoarsen  )

◆ CPPUNIT_TEST() [5/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBoundaryOnChildrenErrors  )

◆ CPPUNIT_TEST() [6/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildNodeListFromSideList  )

◆ CPPUNIT_TEST() [7/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildSideListFromNodeList  )

◆ CPPUNIT_TEST() [8/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildSideListFromNodeListDistributedMesh  )

◆ CPPUNIT_TEST() [9/16]

BoundaryInfoTest::CPPUNIT_TEST ( testBuildSideListFromNodeListThinMesh  )

◆ CPPUNIT_TEST() [10/16]

BoundaryInfoTest::CPPUNIT_TEST ( testEdgeBoundaryConditions  )

◆ CPPUNIT_TEST() [11/16]

BoundaryInfoTest::CPPUNIT_TEST ( testInternalBoundary  )

◆ CPPUNIT_TEST() [12/16]

BoundaryInfoTest::CPPUNIT_TEST ( testMesh  )

◆ CPPUNIT_TEST() [13/16]

BoundaryInfoTest::CPPUNIT_TEST ( testNameCopying  )

◆ CPPUNIT_TEST() [14/16]

BoundaryInfoTest::CPPUNIT_TEST ( testRenumber  )

◆ CPPUNIT_TEST() [15/16]

BoundaryInfoTest::CPPUNIT_TEST ( testSelectiveRenumber  )

◆ CPPUNIT_TEST() [16/16]

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 64 of file boundary_info.C.

65 {
66 }

◆ tearDown()

void BoundaryInfoTest::tearDown ( )
inline

Definition at line 68 of file boundary_info.C.

69 {
70 }

◆ testBoundaryIDs()

void BoundaryInfoTest::testBoundaryIDs ( )
inline

Definition at line 702 of file boundary_info.C.

703 {
704 LOG_UNIT_TEST;
705
706 // We create one cell only. The default boundaries of the cell are below.
707 // ___2___
708 // 3 | | 1
709 // |_____|
710 // 0
711
712 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
714 1, 1,
715 0., 1.,
716 0., 1.,
717 QUAD4);
718
720
721 // Now we add the extra boundary ID (5) to the element on side 3
722 auto elem = mesh->query_elem_ptr(0);
723 if (elem)
724 bi.add_side(elem, 3, 5);
726
727 // Check the element now
728 if (elem && elem->processor_id() == mesh->processor_id())
729 {
730 std::vector<boundary_id_type> container;
731 bi.boundary_ids(elem, 3, container);
732
733 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
734 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[0]);
735 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[1]);
736
737 std::vector<std::vector<boundary_id_type>> all_bids_container;
738 bi.side_boundary_ids(elem, all_bids_container);
739 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
740 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
741 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
742 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][1]);
743 // Check other sides
744 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[0].size());
745 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(0), all_bids_container[0][0]);
746 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
747 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(1), all_bids_container[1][0]);
748 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[1].size());
749 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
750 }
751 }
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 868 of file boundary_info.C.

869 {
870 LOG_UNIT_TEST;
871
872 // We create one cell only. The default boundaries of the cell are below.
873 // We will refine the mesh and add a new boundary id to the left side (side 3).
874 // Then will query the available boundary ids on the added side. It should return
875 // both the parent's and the child's boundaries.
876 // ___2___
877 // 3 | | 1
878 // |_____|
879 // 0
880
881 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
883 1, 1,
884 0., 1.,
885 0., 1.,
886 QUAD4);
887
889
890 // We only have one element, but for easy access we use the iterator
891 for (auto & elem : mesh->active_element_ptr_range())
892 elem->set_refinement_flag(Elem::REFINE);
894
896
897 // Now we add the extra boundary ID (5) to the element in the top
898 // left corner
899 for (auto & elem : mesh->active_element_ptr_range())
900 {
901 const Point c = elem->vertex_average();
902 if (c(0) < 0.5 && c(1) > 0.5)
903 bi.add_side(elem, 3, 5);
904 }
906
907 // Okay, now we query the boundary ids on side 3 of the child and check if it has
908 // the right elements
909 for (auto & elem : mesh->active_element_ptr_range())
910 {
911 const Point c = elem->vertex_average();
912 if (c(0) < 0.5 && c(1) > 0.5)
913 {
914 std::vector<boundary_id_type> container;
915 bi.boundary_ids(elem, 3, container);
916
917 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), container.size());
918 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), container[0]);
919 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), container[1]);
920
921 std::vector<std::vector<boundary_id_type>> all_bids_container;
922 bi.side_boundary_ids(elem, all_bids_container);
923 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
924 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), all_bids_container[3].size());
925 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(5), all_bids_container[3][0]);
926 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][1]);
927 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
928 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
929 // Check other sides
930 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[0].size());
931 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), all_bids_container[1].size());
932
933 // This is against the spirit of the test, and undefined behavior which
934 // may be changed later. Setting allow_children_on_boundary_side(false) could
935 // be actively doing a transfer_boundary_ids_from_children() and then deleting the
936 // children's data, not leaving the children's data there-but-ignored.
938 bi.side_boundary_ids(elem, all_bids_container);
939 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(elem->n_sides()), all_bids_container.size());
940 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[3].size());
941 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(3), all_bids_container[3][0]);
942 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), all_bids_container[2].size());
943 CPPUNIT_ASSERT_EQUAL(static_cast<boundary_id_type>(2), all_bids_container[2][0]);
944 }
945 }
946 }
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:41

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 948 of file boundary_info.C.

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

754 {
755 LOG_UNIT_TEST;
756
757 // Set subdomain ids for specific elements, we will refine/coarsen
758 // the cell on subdomain 1
759 // _____________
760 // | 1 | 2 |
761 // |_____|_____|
762
763 auto mesh = std::make_unique<Mesh>(*TestCommWorld);
765 2, 1,
766 0., 2.,
767 0., 1.,
768 QUAD4);
769
771
772 for (auto & elem : mesh->active_element_ptr_range())
773 {
774 const Point c = elem->vertex_average();
775 if (c(0) < 1)
776 {
777 elem->subdomain_id() = 1;
778 elem->set_refinement_flag(Elem::REFINE);
779 }
780 else
781 elem->subdomain_id() = 2;
782 }
784
785 // Refine the elements once in subdomain 1, and
786 // add the right side subdomain 1 as boundary 5
789
790 for (auto & elem : mesh->active_element_ptr_range())
791 {
792 const Point c = elem->vertex_average();
793 if (c(0) < 1 && c(0) > 0.5)
794 bi.add_side(elem, 1, 5);
795 }
797
798 // Check the middle boundary, we expect to have two sides in boundary 5
799 unsigned int count = 0;
800 for (auto & elem : mesh->active_element_ptr_range())
801 if (bi.has_boundary_id(elem, 1, 5))
802 count++;
803
805 {
806 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(2), count);
807 CPPUNIT_ASSERT(bi.is_children_on_boundary_side());
808 }
809
810 // First, we will coarsen the the elements on subdomain 1. This
811 // is to check if the boundary information propagates upward upon
812 // coarsening.
813 for (auto & elem : mesh->active_element_ptr_range())
814 {
815 const Point c = elem->vertex_average();
816 if (c(0) < 1)
817 elem->set_refinement_flag(Elem::COARSEN);
818 }
820
821 // The coarsened element should have its side on boundary 5
822 // This is boundary info transferred from this child element
825
826 for (auto & elem : mesh->active_element_ptr_range())
827 {
828 const Point c = elem->vertex_average();
829 if (c(0) < 1)
830 {
831 CPPUNIT_ASSERT(bi.has_boundary_id(elem, 1, 5));
832 // We clean up this boundary ID for the next round of tests
833 bi.remove_side(elem, 1, 5);
834 // we will refine this element again
835 elem->set_refinement_flag(Elem::REFINE);
836 }
837 }
838
841
842 // This time we remove boundary 5 from one of the children. We expect
843 // the boundary not to propagate to the next level. Furthermore we
844 // expect boundary 5 to be deleted from the parent's boundaries
845 for (auto & elem : mesh->active_element_ptr_range())
846 {
847 const Point c = elem->vertex_average();
848 if (c(0) < 1)
849 elem->set_refinement_flag(Elem::COARSEN);
850 if (c(0) > 0.5 && c(0) < 1 && c(1) < 0.5)
851 bi.add_side(elem, 1, 5);
852 }
854
856
858
859 // The parent element should not have any side associated with boundary 5
860 for (auto & elem : mesh->active_element_ptr_range())
861 {
862 const Point c = elem->vertex_average();
863 if (c(0) < 1)
864 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, 1, 5));
865 }
866 }
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:711
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 605 of file boundary_info.C.

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

1036 {
1037 LOG_UNIT_TEST;
1038
1039 Mesh mesh(*TestCommWorld);
1040
1042 2, 2,
1043 0., 1.,
1044 0., 1.,
1045 QUAD4);
1046
1048
1049 // build_square gave us ids 0-3 as both side sets and node sets
1050 bi.remove_node_id(0);
1051 bi.remove_node_id(1);
1052 bi.remove_node_id(2);
1053 bi.remove_node_id(3);
1054
1055 CPPUNIT_ASSERT(bi.build_node_list().empty());
1056
1058
1059 for (const auto & elem : mesh.element_ptr_range())
1060 {
1061 for (auto n : elem->node_index_range())
1062 {
1063 const Node * node = elem->node_ptr(n);
1064 for (auto s : {0,2})
1065 if (elem->is_node_on_side(n, s) && !elem->neighbor_ptr(s))
1066 CPPUNIT_ASSERT(bi.has_boundary_id(node, s));
1067 for (auto s : {1,3})
1068 CPPUNIT_ASSERT(!bi.has_boundary_id(node, s));
1069 }
1070 }
1071 }
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 1074 of file boundary_info.C.

1075 {
1076 LOG_UNIT_TEST;
1077
1078 Mesh mesh(*TestCommWorld);
1079
1081 2, 2,
1082 0., 1.,
1083 0., 1.,
1084 QUAD4);
1085
1087
1088 // build_square gave us ids 0-3 as both side sets and node sets
1089 bi.remove_side_id(0);
1090 bi.remove_side_id(1);
1091 bi.remove_side_id(2);
1092 bi.remove_side_id(3);
1093
1094 CPPUNIT_ASSERT(bi.build_side_list().empty());
1095
1097
1098 for (const auto & elem : mesh.element_ptr_range())
1099 {
1100 for (auto s : {0,2})
1101 {
1102 if (!elem->neighbor_ptr(s))
1103 {
1104 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, s));
1105 CPPUNIT_ASSERT_EQUAL(bi.n_boundary_ids(elem, s), 1u);
1106 }
1107 else
1108 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1109 }
1110 for (auto s : {1,3})
1111 {
1112 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, s));
1113 CPPUNIT_ASSERT(!bi.n_boundary_ids(elem, s));
1114 }
1115 }
1116 }
std::size_t n_boundary_ids() const
void build_side_list_from_node_list(const std::set< boundary_id_type > &nodeset_list={}, bool skip_interior_sides=false)
Adds sides to a sideset if every node on that side is in the same nodeset.
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.

◆ testBuildSideListFromNodeListDistributedMesh()

void BoundaryInfoTest::testBuildSideListFromNodeListDistributedMesh ( )
inline

Definition at line 1203 of file boundary_info.C.

1204 {
1205 LOG_UNIT_TEST;
1206
1207 DistributedMesh mesh(*TestCommWorld);
1208
1210
1212
1213 // Only the two domain endpoint nodes are in the nodeset, like a
1214 // Neumann-BC-at-the-ends use case. With enough processors, most
1215 // ranks won't locally own or ghost either endpoint.
1216 //
1217 // Pick the endpoints out geometrically rather than by node id:
1218 // prepare_for_use() renumbers a DistributedMesh's nodes so that
1219 // each processor's are contiguous, so the ids the line was built
1220 // with don't survive, and with enough processors ids 0 and 40
1221 // land on interior nodes.
1222 const boundary_id_type nodeset_id = 100;
1223 for (const auto & node : mesh.node_ptr_range())
1224 if (std::abs((*node)(0) - 0.) < TOLERANCE ||
1225 std::abs((*node)(0) - 1.) < TOLERANCE)
1226 bi.add_node(node, nodeset_id);
1227
1228 bi.build_side_list_from_node_list({nodeset_id}, /*skip_interior_sides=*/true);
1229
1230 for (const auto & elem : mesh.active_local_element_ptr_range())
1231 for (auto s : elem->side_index_range())
1232 {
1233 // Only the two exterior sides, at the physical ends of the
1234 // line, should have been added to the sideset; every other
1235 // side is interior to the (single) subdomain, whether or
1236 // not its neighbor was a RemoteElem that had to be resolved
1237 // via communication.
1238 if (!elem->neighbor_ptr(s))
1239 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, nodeset_id));
1240 else
1241 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, nodeset_id));
1242 }
1243 }
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
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.
static constexpr Real TOLERANCE

References libMesh::BoundaryInfo::add_node(), libMesh::MeshTools::Generation::build_line(), libMesh::BoundaryInfo::build_side_list_from_node_list(), libMesh::EDGE2, libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), mesh, TestCommWorld, and libMesh::TOLERANCE.

◆ testBuildSideListFromNodeListThinMesh()

void BoundaryInfoTest::testBuildSideListFromNodeListThinMesh ( )
inline

Definition at line 1119 of file boundary_info.C.

1120 {
1121 LOG_UNIT_TEST;
1122
1123 Mesh mesh(*TestCommWorld);
1124
1125 // A mesh that is only one element deep in y: every node in the
1126 // mesh lies on either the bottom (y=0) or top (y=1) exterior
1127 // face, so a nodeset containing "the top and bottom nodes" ends
1128 // up containing *every* node, including those on the interior
1129 // sides between elements.
1131 8, 1,
1132 0., 1.,
1133 0., 1.,
1134 QUAD4);
1135
1137
1138 const boundary_id_type nodeset_id = 100;
1139 for (const auto & node : mesh.node_ptr_range())
1140 bi.add_node(node, nodeset_id);
1141
1142 // Sanity check: every node in this thin mesh is in the nodeset.
1143 for (const auto & node : mesh.node_ptr_range())
1144 CPPUNIT_ASSERT(bi.has_boundary_id(node, nodeset_id));
1145
1146 // build_side_list_from_node_list() is purely additive (it never
1147 // removes a side once added), so we must run the strict
1148 // skip_interior_sides = true check first, before any call adds
1149 // the interior side to the sideset.
1150 //
1151 // Passing skip_interior_sides = true should skip the interior
1152 // side, even though all of its nodes are (trivially) in the
1153 // nodeset.
1154 bi.build_side_list_from_node_list({nodeset_id}, /*skip_interior_sides=*/true);
1155
1156 // We only examine local elements here: a ghost element's neighbor
1157 // may be a RemoteElem, whose subdomain_id() tells us nothing about
1158 // the subdomain of the element it stands in for, so we couldn't
1159 // predict the correct answer for its sides.
1160 for (const auto & elem : mesh.active_local_element_ptr_range())
1161 for (auto s : elem->side_index_range())
1162 {
1163 const Elem * neigh = elem->neighbor_ptr(s);
1164 libmesh_assert(neigh != remote_elem);
1165 if (neigh && neigh->subdomain_id() == elem->subdomain_id())
1166 CPPUNIT_ASSERT(!bi.has_boundary_id(elem, s, nodeset_id));
1167 else
1168 CPPUNIT_ASSERT(bi.has_boundary_id(elem, s, nodeset_id));
1169 }
1170
1171 // Default behavior (skip_interior_sides = false) should preserve
1172 // the old, unconditional behavior, adding the interior side even
1173 // though it isn't a true boundary. Since add_side() is additive,
1174 // this call only needs to add the interior side; the exterior
1175 // sides are already present from the call above.
1176 bi.build_side_list_from_node_list({nodeset_id});
1177
1178 bool found_interior_side = false;
1179 for (const auto & elem : mesh.active_local_element_ptr_range())
1180 for (auto s : elem->side_index_range())
1181 {
1182 const Elem * neigh = elem->neighbor_ptr(s);
1183 libmesh_assert(neigh != remote_elem);
1184 if (neigh && neigh->subdomain_id() == elem->subdomain_id() &&
1185 bi.has_boundary_id(elem, s, nodeset_id))
1186 found_interior_side = true;
1187 }
1188
1189 // A processor with no local elements of its own can't find one.
1190 mesh.comm().max(found_interior_side);
1191 CPPUNIT_ASSERT(found_interior_side);
1192 }
subdomain_id_type subdomain_id() const
Definition elem.h:2712
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2736
libmesh_assert(ctx)
const RemoteElem * remote_elem
Definition remote_elem.C:57

References libMesh::BoundaryInfo::add_node(), libMesh::BoundaryInfo::build_side_list_from_node_list(), libMesh::MeshTools::Generation::build_square(), libMesh::ParallelObject::comm(), libMesh::MeshBase::get_boundary_info(), libMesh::BoundaryInfo::has_boundary_id(), libMesh::libmesh_assert(), libMesh::Parallel::Communicator::max(), mesh, libMesh::Elem::neighbor_ptr(), libMesh::QUAD4, libMesh::remote_elem, libMesh::Elem::subdomain_id(), and TestCommWorld.

◆ testEdgeBoundaryConditions()

void BoundaryInfoTest::testEdgeBoundaryConditions ( )
inline

Definition at line 375 of file boundary_info.C.

376 {
377 LOG_UNIT_TEST;
378
379 const unsigned int n_elem = 5;
380 const std::string mesh_filename = "cube_mesh.xda";
381
382 {
383 Mesh mesh(*TestCommWorld);
385 n_elem, n_elem, n_elem,
386 0., 1.,
387 0., 1.,
388 0., 1.,
389 HEX8);
390
392
393 // build_cube does not add any edge boundary IDs
394 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), bi.n_edge_conds());
395
396 // Let's now add some edge boundary IDs.
397 // We loop over all elements (not just local elements) so that
398 // all processors know about the boundary IDs
399 const boundary_id_type BOUNDARY_ID_MAX_X = 2;
400 const boundary_id_type BOUNDARY_ID_MIN_Y = 1;
401 const boundary_id_type EDGE_BOUNDARY_ID = 20;
402
403 for (const auto & elem : mesh.element_ptr_range())
404 {
405 unsigned short side_max_x = 0, side_min_y = 0;
406 bool found_side_max_x = false, found_side_min_y = false;
407
408 for (unsigned short side=0; side<elem->n_sides(); side++)
409 {
410 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MAX_X))
411 {
412 side_max_x = side;
413 found_side_max_x = true;
414 }
415
416 if (mesh.get_boundary_info().has_boundary_id(elem, side, BOUNDARY_ID_MIN_Y))
417 {
418 side_min_y = side;
419 found_side_min_y = true;
420 }
421 }
422
423 // If elem has sides on boundaries
424 // BOUNDARY_ID_MAX_X and BOUNDARY_ID_MIN_Y
425 // then let's set an edge boundary condition
426 if (found_side_max_x && found_side_min_y)
427 for (unsigned short e=0; e<elem->n_edges(); e++)
428 if (elem->is_edge_on_side(e, side_max_x) &&
429 elem->is_edge_on_side(e, side_min_y))
430 bi.add_edge(elem, e, EDGE_BOUNDARY_ID);
431 }
432
433 // Check that we have the expected number of edge boundary IDs after
434 // updating bi
435 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
436
437 // Let's test that edge BCIDs are preserved (in a relative
438 // sense) when we clone a mesh.
439 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
440 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
442
443 mesh.write(mesh_filename);
444 }
445
446 // Make sure all processors are done writing before we try to
447 // start reading
448 TestCommWorld->barrier();
449
450 Mesh mesh(*TestCommWorld);
451 mesh.read(mesh_filename);
452
453 // Check that writing and reading preserves the edge boundary IDs
455 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(n_elem), bi.n_edge_conds());
456 }
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 1246 of file boundary_info.C.

1247 {
1248 LOG_UNIT_TEST;
1249
1250 Mesh mesh(*TestCommWorld);
1251
1252 // Build a 2x2 QUAD4 structured mesh on [0,1]x[0,1].
1254 2, 2,
1255 0., 1.,
1256 0., 1.,
1257 QUAD4);
1258
1260
1261 const unsigned int internal_side = 1; // east side for left elems
1262 const boundary_id_type BID = 7;
1263
1265
1266 Elem * left_bottom_elem = nullptr;
1267 for (auto & elem : mesh.active_element_ptr_range())
1268 {
1269 if (elem->processor_id() != mesh.processor_id())
1270 continue;
1271
1272 const Point c = elem->vertex_average();
1273 if (c(0) < 0.5 && c(1) < 0.5 && elem->neighbor_ptr(internal_side) != nullptr)
1274 {
1275 left_bottom_elem = elem;
1276 break;
1277 }
1278 }
1279
1280
1281 if (left_bottom_elem)
1282 {
1283 bi.add_side(left_bottom_elem, internal_side, BID);
1284
1285 const unsigned int found_side = bi.side_with_boundary_id(left_bottom_elem, BID);
1286 CPPUNIT_ASSERT_EQUAL(internal_side, found_side);
1287 }
1288 }

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 72 of file boundary_info.C.

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

459 {
460 LOG_UNIT_TEST;
461
462 Mesh mesh(*TestCommWorld);
464 8,
465 0., 1.,
466 EDGE2);
467
468 Mesh mesh2(mesh);
469
471 bi.sideset_name(0) = "zero";
472 bi.sideset_name(1) = "one";
473 bi.sideset_name(2) = "two";
474 bi.sideset_name(3) = "three";
475 bi.nodeset_name(0) = "ZERO";
476 bi.nodeset_name(1) = "ONE";
477
478 BoundaryInfo bi2 {bi};
479 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(0), std::string("zero"));
480 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(1), std::string("one"));
481 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(2), std::string("two"));
482 CPPUNIT_ASSERT_EQUAL(bi2.get_sideset_name(3), std::string("three"));
483 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(0), std::string("ZERO"));
484 CPPUNIT_ASSERT_EQUAL(bi2.get_nodeset_name(1), std::string("ONE"));
485
486 BoundaryInfo & bi3 = mesh2.get_boundary_info();
487 bi3 = bi;
488 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(0), std::string("zero"));
489 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(1), std::string("one"));
490 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(2), std::string("two"));
491 CPPUNIT_ASSERT_EQUAL(bi3.get_sideset_name(3), std::string("three"));
492 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(0), std::string("ZERO"));
493 CPPUNIT_ASSERT_EQUAL(bi3.get_nodeset_name(1), std::string("ONE"));
494 }
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

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 167 of file boundary_info.C.

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

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

498 {
499 LOG_UNIT_TEST;
500
501 // Make a simple two element mesh that we can use to test constraints
502 Mesh mesh(*TestCommWorld);
503
504 // (0,1) (1,1)
505 // x---------------x
506 // | |
507 // | |
508 // | |
509 // | |
510 // | |
511 // x---------------x
512 // (0,0) (1,0)
513 // | |
514 // | |
515 // | |
516 // | |
517 // x---------------x
518 // (0,-1) (1,-1)
519
520 mesh.add_point( Point(0.0,-1.0), 4 );
521 mesh.add_point( Point(1.0,-1.0), 5 );
522 mesh.add_point( Point(1.0, 0.0), 1 );
523 mesh.add_point( Point(1.0, 1.0), 2 );
524 mesh.add_point( Point(0.0, 1.0), 3 );
525 mesh.add_point( Point(0.0, 0.0), 0 );
526
527 Elem * elem_top = mesh.add_elem(Elem::build(QUADSHELL4));
528 elem_top->set_node(0, mesh.node_ptr(0));
529 elem_top->set_node(1, mesh.node_ptr(1));
530 elem_top->set_node(2, mesh.node_ptr(2));
531 elem_top->set_node(3, mesh.node_ptr(3));
532
533 Elem * elem_bottom = mesh.add_elem(Elem::build(QUADSHELL4));
534 elem_bottom->set_node(0, mesh.node_ptr(4));
535 elem_bottom->set_node(1, mesh.node_ptr(5));
536 elem_bottom->set_node(2, mesh.node_ptr(1));
537 elem_bottom->set_node(3, mesh.node_ptr(0));
538
540 bi.add_shellface(elem_top, 0, 10);
541 bi.add_shellface(elem_bottom, 1, 20);
542
545
546 // Let's test that shellface BCIDs are preserved (in a relative
547 // sense) when we clone a mesh.
548 std::unique_ptr<MeshBase> mesh_clone = mesh.clone();
549 CPPUNIT_ASSERT(mesh_clone->get_boundary_info() ==
551
552 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), bi.n_shellface_conds());
553
555 System & system = es.add_system<System> ("SimpleSystem");
556 system.add_variable("u", FIRST);
557
558 // Add a Dirichlet constraint to check that we impose constraints
559 // correctly on shell faces.
560 std::vector<unsigned int> variables;
561 variables.push_back(0);
562 std::set<boundary_id_type> shellface_ids;
563 shellface_ids.insert(20);
565 DirichletBoundary dirichlet_bc(shellface_ids,
566 variables,
567 &zf);
568 system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
569 es.init();
570
571 // Find elem_bottom again if we have it (it may have been deleted
572 // in a DistributedMesh or renumbered in theory)
573 elem_bottom = nullptr;
574 for (unsigned int e = 0; e != mesh.max_elem_id(); ++e)
575 {
576 Elem *elem = mesh.query_elem_ptr(e);
577 if (elem && elem->point(3) == Point(0,0))
578 elem_bottom = elem;
579 }
580
581 // We expect to have a dof constraint on all four dofs of
582 // elem_bottom
583 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), static_cast<std::size_t>(system.n_constrained_dofs()));
584
585 // But we may only know the details of that
586 // constraint on the processor which owns elem_bottom.
587 if (elem_bottom &&
588 elem_bottom->processor_id() == mesh.processor_id())
589 {
590 std::vector<dof_id_type> dof_indices;
591 system.get_dof_map().dof_indices(elem_bottom, dof_indices);
592 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(4), dof_indices.size());
593
594 for(unsigned int i=0; i<dof_indices.size(); i++)
595 {
596 dof_id_type dof_id = dof_indices[i];
597 CPPUNIT_ASSERT( system.get_dof_map().is_constrained_dof(dof_id) );
598 }
599 }
600 }
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:2203
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:2439
processor_id_type processor_id() const
Definition dof_object.h:895
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2688
const Point & point(const unsigned int i) const
Definition elem.h:2583
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:382
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:1359
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: