Skip to content

Commit 36a1acf

Browse files
committed
Safeguard boundary ID addition and removal.
1 parent 40a4dfc commit 36a1acf

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed

src/mesh/boundary_info.C

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,12 +963,26 @@ void BoundaryInfo::add_side(const Elem * elem,
963963
{
964964
libmesh_assert(elem);
965965

966+
#ifdef LIBMESH_ENABLE_AMR
966967
// Users try to mark boundary on child elements
967968
// If this happens, we will allow users to remove
968969
// side from child elements as well
969970
if (elem->level())
971+
{
970972
_children_on_boundary = true;
971973

974+
// Here we have to stop and check if we already have this boundary defined on the
975+
// parent (if yes, no need to add)
976+
std::vector<boundary_id_type> bd_ids;
977+
this->boundary_ids(elem,side,bd_ids);
978+
979+
if(std::find(bd_ids.begin(), bd_ids.end(), id) != bd_ids.end())
980+
libmesh_not_implemented_msg("Trying to add boundary ID "
981+
+ std::to_string(id)
982+
+ " which already exists on the ancestors.");
983+
}
984+
#endif
985+
972986
libmesh_error_msg_if(id == invalid_id, "ERROR: You may not set a boundary ID of "
973987
<< invalid_id
974988
<< "\n That is reserved for internal use.");
@@ -995,12 +1009,27 @@ void BoundaryInfo::add_side(const Elem * elem,
9951009

9961010
libmesh_assert(elem);
9971011

1012+
#ifdef LIBMESH_ENABLE_AMR
9981013
// Users try to mark boundary on child elements
9991014
// If this happens, we will allow users to remove
10001015
// side from child elements as well
10011016
if (elem->level())
1017+
{
10021018
_children_on_boundary = true;
10031019

1020+
// Here we have to stop and check if we already have this boundary defined on the
1021+
// parent (if yes, no need to add)
1022+
std::vector<boundary_id_type> bd_ids;
1023+
this->boundary_ids(elem,side,bd_ids);
1024+
1025+
for (const auto id : ids)
1026+
if(std::find(bd_ids.begin(), bd_ids.end(), id) != bd_ids.end())
1027+
libmesh_not_implemented_msg("Trying to add boundary ID "
1028+
+ std::to_string(id)
1029+
+ " which already exists on the ancestors.");
1030+
}
1031+
#endif
1032+
10041033
// Don't add the same ID twice
10051034
auto bounds = _boundary_side_id.equal_range(elem);
10061035

@@ -1504,6 +1533,25 @@ void BoundaryInfo::remove_side (const Elem * elem,
15041533
{
15051534
libmesh_assert(elem);
15061535

1536+
#ifdef LIBMESH_ENABLE_AMR
1537+
// Here we have to stop and check if somebody tries to remove an ancestor's boundary ID
1538+
// through a child
1539+
if (elem->level() && _children_on_boundary)
1540+
{
1541+
std::vector<boundary_id_type> bd_ids;
1542+
this->boundary_ids(elem,side,bd_ids);
1543+
if(std::find(bd_ids.begin(), bd_ids.end(), id) != bd_ids.end())
1544+
{
1545+
std::vector<boundary_id_type> raw_bd_ids;
1546+
this->raw_boundary_ids(elem, side, raw_bd_ids);
1547+
if(std::find(raw_bd_ids.begin(), raw_bd_ids.end(), id) == raw_bd_ids.end())
1548+
libmesh_not_implemented_msg("We cannot delete boundary ID "
1549+
+ std::to_string(id) +
1550+
" using a child because it is inherited from an ancestor.");
1551+
}
1552+
}
1553+
#endif
1554+
15071555
// Erase (elem, side, id) entries from map.
15081556
erase_if(_boundary_side_id, elem,
15091557
[side, id](decltype(_boundary_side_id)::mapped_type & pr)

tests/mesh/boundary_info.C

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "test_comm.h"
1414
#include "libmesh_cppunit.h"
1515

16+
#include <regex>
1617

1718
using namespace libMesh;
1819

@@ -29,6 +30,7 @@ public:
2930
CPPUNIT_TEST( testMesh );
3031
CPPUNIT_TEST( testRenumber );
3132
#ifdef LIBMESH_ENABLE_AMR
33+
CPPUNIT_TEST( testBoundaryOnChildrenErrors );
3234
CPPUNIT_TEST( testBoundaryOnChildrenElementsRefineCoarsen );
3335
CPPUNIT_TEST( testBoundaryOnChildrenBoundaryIDs );
3436
CPPUNIT_TEST( testBoundaryOnChildrenBoundarySides );
@@ -481,6 +483,101 @@ public:
481483
#endif // LIBMESH_ENABLE_DIRICHLET
482484

483485
#ifdef LIBMESH_ENABLE_AMR
486+
void testBoundaryOnChildrenErrors()
487+
{
488+
LOG_UNIT_TEST;
489+
490+
// We create one cell only. The default boundaries of the cell are below.
491+
// ___2___
492+
// 3 | | 1
493+
// |_____|
494+
// 0
495+
496+
auto mesh = std::make_unique<Mesh>(*TestCommWorld);
497+
MeshTools::Generation::build_square(*mesh,
498+
1, 1,
499+
0., 1.,
500+
0., 1.,
501+
QUAD4);
502+
503+
BoundaryInfo & bi = mesh->get_boundary_info();
504+
505+
// We only have one element, but for easy access we use the iterator
506+
for (auto & elem : mesh->active_element_ptr_range())
507+
elem->set_refinement_flag(Elem::REFINE);
508+
mesh->prepare_for_use();
509+
510+
MeshRefinement(*mesh).refine_elements();
511+
mesh->prepare_for_use();
512+
513+
// Now we try to add boundary id 3 to a child on side 3. This should
514+
// result in a "not implemented" error message
515+
bool threw_desired_exception = false;
516+
try {
517+
for (auto & elem : mesh->active_element_ptr_range())
518+
{
519+
const Point c = elem->vertex_average();
520+
if (c(0) < 0.5 && c(1) > 0.5)
521+
bi.add_side(elem, 3, 3);
522+
}
523+
}
524+
catch (libMesh::NotImplemented & e) {
525+
std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
526+
CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
527+
threw_desired_exception = true;
528+
}
529+
// If we have more than 4 processors, or a poor partitioner, we
530+
// might not get an exception on every processor
531+
mesh->comm().max(threw_desired_exception);
532+
533+
CPPUNIT_ASSERT(threw_desired_exception);
534+
535+
threw_desired_exception = false;
536+
try {
537+
for (auto & elem : mesh->active_element_ptr_range())
538+
{
539+
const Point c = elem->vertex_average();
540+
if (c(0) < 0.5 && c(1) > 0.5)
541+
bi.add_side(elem, 3, {3,4});
542+
}
543+
}
544+
catch (libMesh::NotImplemented & e) {
545+
std::regex msg_regex("Trying to add boundary ID 3 which already exists on the ancestors");
546+
CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
547+
threw_desired_exception = true;
548+
}
549+
550+
// If we have more than 4 processors, or a poor partitioner, we
551+
// might not get an exception on every processor
552+
mesh->comm().max(threw_desired_exception);
553+
554+
CPPUNIT_ASSERT(threw_desired_exception);
555+
556+
// We tested the side addition errors, now we move to the removal parts.
557+
// We will attempt the removal of boundary 3 through the child
558+
threw_desired_exception = false;
559+
bi.allow_children_on_boundary_side(true);
560+
try {
561+
for (auto & elem : mesh->active_element_ptr_range())
562+
{
563+
const Point c = elem->vertex_average();
564+
if (c(0) < 0.5 && c(1) > 0.5)
565+
bi.remove_side(elem, 3, 3);
566+
}
567+
}
568+
catch (libMesh::NotImplemented & e) {
569+
std::regex msg_regex("We cannot delete boundary ID 3 using a child because it is inherited from an ancestor");
570+
CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
571+
threw_desired_exception = true;
572+
}
573+
574+
// If we have more than 4 processors, or a poor partitioner, we
575+
// might not get an exception on every processor
576+
mesh->comm().max(threw_desired_exception);
577+
578+
CPPUNIT_ASSERT(threw_desired_exception);
579+
}
580+
484581
void testBoundaryOnChildrenElementsRefineCoarsen()
485582
{
486583
LOG_UNIT_TEST;
@@ -618,8 +715,6 @@ public:
618715

619716
BoundaryInfo & bi = mesh->get_boundary_info();
620717

621-
std::ostringstream mystream;
622-
623718
// We only have one element, but for easy access we use the iterator
624719
for (auto & elem : mesh->active_element_ptr_range())
625720
elem->set_refinement_flag(Elem::REFINE);

0 commit comments

Comments
 (0)