From 82491b1192de181f36d35db0a2252e8c0ff3b2c2 Mon Sep 17 00:00:00 2001 From: Fande Kong Date: Mon, 29 Nov 2021 10:00:19 -0700 Subject: [PATCH 1/3] Allow boundary be associated with child elements Use case: moving boundary with AMR. Boundary needs to be defined on child elements --- include/mesh/boundary_info.h | 7 +++ src/mesh/boundary_info.C | 84 ++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/include/mesh/boundary_info.h b/include/mesh/boundary_info.h index 3d122a81397..98d51e820b5 100644 --- a/include/mesh/boundary_info.h +++ b/include/mesh/boundary_info.h @@ -924,6 +924,13 @@ class BoundaryInfo : public ParallelObject std::pair> _boundary_side_id; + /* + * Whether or not children elements are associated to any boundary + * It is false by default. The flag will be turnned on if add_side + * function is called with a child element + */ + bool _children_on_boundary; + /** * A collection of user-specified boundary ids for sides, edges, nodes, * and shell faces. diff --git a/src/mesh/boundary_info.C b/src/mesh/boundary_info.C index 6443e894308..231c218c01e 100644 --- a/src/mesh/boundary_info.C +++ b/src/mesh/boundary_info.C @@ -89,7 +89,8 @@ const boundary_id_type BoundaryInfo::invalid_id = -123; // BoundaryInfo functions BoundaryInfo::BoundaryInfo(MeshBase & m) : ParallelObject(m.comm()), - _mesh (&m) + _mesh (&m), + _children_on_boundary(false) { } @@ -950,8 +951,11 @@ void BoundaryInfo::add_side(const Elem * elem, { libmesh_assert(elem); - // Only add BCs for level-0 elements. - libmesh_assert_equal_to (elem->level(), 0); + // Users try to mark boundary on child elements + // If this happens, we will allow users to remove + // side from child elements as well + if (elem->level()) + _children_on_boundary = true; libmesh_error_msg_if(id == invalid_id, "ERROR: You may not set a boundary ID of " << invalid_id @@ -979,8 +983,11 @@ void BoundaryInfo::add_side(const Elem * elem, libmesh_assert(elem); - // Only add BCs for level-0 elements. - libmesh_assert_equal_to (elem->level(), 0); + // Users try to mark boundary on child elements + // If this happens, we will allow users to remove + // side from child elements as well + if (elem->level()) + _children_on_boundary = true; // Don't add the same ID twice auto bounds = _boundary_side_id.equal_range(elem); @@ -1357,8 +1364,8 @@ void BoundaryInfo::remove_edge (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements are stored in BoundaryInfo. - libmesh_assert_equal_to (elem->level(), 0); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level()==0 || _children_on_boundary); // Erase (elem, edge, *) entries from map. erase_if(_boundary_edge_id, elem, @@ -1374,8 +1381,8 @@ void BoundaryInfo::remove_edge (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements are stored in BoundaryInfo. - libmesh_assert_equal_to (elem->level(), 0); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level() == 0 || _children_on_boundary); // Erase (elem, edge, id) entries from map. erase_if(_boundary_edge_id, elem, @@ -1389,8 +1396,8 @@ void BoundaryInfo::remove_shellface (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements are stored in BoundaryInfo. - libmesh_assert_equal_to (elem->level(), 0); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level() == 0 || _children_on_boundary); // Shells only have 2 faces libmesh_assert_less(shellface, 2); @@ -1409,8 +1416,8 @@ void BoundaryInfo::remove_shellface (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements are stored in BoundaryInfo. - libmesh_assert_equal_to (elem->level(), 0); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level() == 0 || _children_on_boundary); // Shells only have 2 faces libmesh_assert_less(shellface, 2); @@ -1426,8 +1433,8 @@ void BoundaryInfo::remove_side (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements are stored in BoundaryInfo. - libmesh_assert_equal_to (elem->level(), 0); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level() == 0 || _children_on_boundary); // Erase (elem, side, *) entries from map. erase_if(_boundary_side_id, elem, @@ -1443,6 +1450,9 @@ void BoundaryInfo::remove_side (const Elem * elem, { libmesh_assert(elem); + // Only level 0 elements unless the flag "_children_on_boundary" is on. + libmesh_assert(elem->level() == 0 || _children_on_boundary); + // Erase (elem, side, id) entries from map. erase_if(_boundary_side_id, elem, [side, id](decltype(_boundary_side_id)::mapped_type & pr) @@ -1489,12 +1499,21 @@ void BoundaryInfo::remove_id (boundary_id_type id) unsigned int BoundaryInfo::side_with_boundary_id(const Elem * const elem, const boundary_id_type boundary_id_in) const { - const Elem * searched_elem = elem; + std::vector searched_elem_vec; + // If elem has boundary information, we return that when + // the flag "_children_on_boundary" is on + if (_children_on_boundary) + searched_elem_vec.push_back(elem); + // Otherwise, we return boundary information of its + // parent if any if (elem->level() != 0) - searched_elem = elem->top_parent(); + searched_elem_vec.push_back(elem->top_parent()); - // elem may have zero or multiple occurrences - for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem))) + for (auto it = searched_elem_vec.begin(); it != searched_elem_vec.end(); ++it) + { + const Elem * searched_elem = *it; + // elem may have zero or multiple occurrences + for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem))) { // if this is true we found the requested boundary_id // of the element and want to return the side @@ -1525,7 +1544,8 @@ unsigned int BoundaryInfo::side_with_boundary_id(const Elem * const elem, if (!p) return side; } - } + } + } // if we get here, we found elem in the data structure but not // the requested boundary id, so return the default value @@ -1539,12 +1559,20 @@ BoundaryInfo::sides_with_boundary_id(const Elem * const elem, { std::vector returnval; - const Elem * searched_elem = elem; + std::vector searched_elem_vec; + // If elem has boundary information, that is part of return when + // the flag "_children_on_boundary" is on + if (_children_on_boundary) + searched_elem_vec.push_back(elem); + // Return boundary information of its parent as well if (elem->level() != 0) - searched_elem = elem->top_parent(); + searched_elem_vec.push_back(elem->top_parent()); - // elem may have zero or multiple occurrences - for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem))) + for (auto it = searched_elem_vec.begin(); it != searched_elem_vec.end(); ++it) + { + const Elem * searched_elem = *it; + // elem may have zero or multiple occurrences + for (const auto & pr : as_range(_boundary_side_id.equal_range(searched_elem))) { // if this is true we found the requested boundary_id // of the element and want to return the side @@ -1579,7 +1607,7 @@ BoundaryInfo::sides_with_boundary_id(const Elem * const elem, returnval.push_back(side); } } - + } return returnval; } @@ -1794,7 +1822,8 @@ BoundaryInfo::build_node_list_from_side_list() // Need to loop over the sides of any possible children std::vector family; #ifdef LIBMESH_ENABLE_AMR - elem->active_family_tree_by_side (family, id_pair.first); + if (!elem->subactive()) + elem->active_family_tree_by_side (family, id_pair.first); #else family.push_back(elem); #endif @@ -2156,7 +2185,8 @@ BoundaryInfo::build_active_side_list () const // Loop over the sides of possible children std::vector family; #ifdef LIBMESH_ENABLE_AMR - elem->active_family_tree_by_side(family, id_pair.first); + if (!elem->subactive()) + elem->active_family_tree_by_side(family, id_pair.first); #else family.push_back(elem); #endif From 471836f975898415470bcaabaf3c18f43674977e Mon Sep 17 00:00:00 2001 From: Fande Kong Date: Wed, 23 Feb 2022 14:55:30 -0700 Subject: [PATCH 2/3] Added APIs to allow users set the flag: _children_on_boundary The motivaiton is that: "automatic" way might not work for cases. For example, if the flag is on on a subset of processor cores, and then we do reparitioning, and then we might hit trouble because the flag is off on the other processors I try to avoid having a global reduction to have everyone on the same page. In fact, we know when we want to allow children on boundary in MOOSE. In this case, we should set the flag to make the code more robust --- include/mesh/boundary_info.h | 12 ++++++++++++ src/mesh/boundary_info.C | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/mesh/boundary_info.h b/include/mesh/boundary_info.h index 98d51e820b5..d1cf40b5c7a 100644 --- a/include/mesh/boundary_info.h +++ b/include/mesh/boundary_info.h @@ -874,6 +874,18 @@ class BoundaryInfo : public ParallelObject const std::multimap> & get_sideset_map() const { return _boundary_side_id; } + /** + * \returns Whether or not there are some children on boundary sides + */ + bool is_children_on_boundary_side() const + { return _children_on_boundary; } + + /** + * Whether or not to allow set boundary sides on children elements + */ + void allow_children_on_boundary_side(const bool children_on_boundary) + { _children_on_boundary = children_on_boundary; } + private: /** diff --git a/src/mesh/boundary_info.C b/src/mesh/boundary_info.C index 231c218c01e..af6f0850065 100644 --- a/src/mesh/boundary_info.C +++ b/src/mesh/boundary_info.C @@ -1364,8 +1364,8 @@ void BoundaryInfo::remove_edge (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements unless the flag "_children_on_boundary" is on. - libmesh_assert(elem->level()==0 || _children_on_boundary); + // Only level 0 elements are stored in BoundaryInfo. + libmesh_assert_equal_to (elem->level(), 0); // Erase (elem, edge, *) entries from map. erase_if(_boundary_edge_id, elem, @@ -1381,8 +1381,8 @@ void BoundaryInfo::remove_edge (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements unless the flag "_children_on_boundary" is on. - libmesh_assert(elem->level() == 0 || _children_on_boundary); + // Only level 0 elements are stored in BoundaryInfo. + libmesh_assert_equal_to (elem->level(), 0); // Erase (elem, edge, id) entries from map. erase_if(_boundary_edge_id, elem, @@ -1396,8 +1396,8 @@ void BoundaryInfo::remove_shellface (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements unless the flag "_children_on_boundary" is on. - libmesh_assert(elem->level() == 0 || _children_on_boundary); + // Only level 0 elements are stored in BoundaryInfo. + libmesh_assert_equal_to (elem->level(), 0); // Shells only have 2 faces libmesh_assert_less(shellface, 2); @@ -1416,8 +1416,8 @@ void BoundaryInfo::remove_shellface (const Elem * elem, { libmesh_assert(elem); - // Only level 0 elements unless the flag "_children_on_boundary" is on. - libmesh_assert(elem->level() == 0 || _children_on_boundary); + // Only level 0 elements are stored in BoundaryInfo. + libmesh_assert_equal_to (elem->level(), 0); // Shells only have 2 faces libmesh_assert_less(shellface, 2); @@ -1508,6 +1508,8 @@ unsigned int BoundaryInfo::side_with_boundary_id(const Elem * const elem, // parent if any if (elem->level() != 0) searched_elem_vec.push_back(elem->top_parent()); + else if (!_children_on_boundary) + searched_elem_vec.push_back(elem); for (auto it = searched_elem_vec.begin(); it != searched_elem_vec.end(); ++it) { @@ -1567,6 +1569,8 @@ BoundaryInfo::sides_with_boundary_id(const Elem * const elem, // Return boundary information of its parent as well if (elem->level() != 0) searched_elem_vec.push_back(elem->top_parent()); + else if (!_children_on_boundary) + searched_elem_vec.push_back(elem); for (auto it = searched_elem_vec.begin(); it != searched_elem_vec.end(); ++it) { From 4be946d2c100a262c5b104d34b8af3e14915f006 Mon Sep 17 00:00:00 2001 From: Fande Kong Date: Thu, 24 Feb 2022 14:41:38 -0700 Subject: [PATCH 3/3] Made BoundaryInfo::boundary_ids for _children_on_boundary --- src/mesh/boundary_info.C | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mesh/boundary_info.C b/src/mesh/boundary_info.C index af6f0850065..d278f76a74b 100644 --- a/src/mesh/boundary_info.C +++ b/src/mesh/boundary_info.C @@ -1235,8 +1235,15 @@ void BoundaryInfo::boundary_ids (const Elem * const elem, // Clear out any previous contents vec_to_fill.clear(); - // Only level-0 elements store BCs. If this is not a level-0 - // element get its level-0 parent and infer the BCs. + // Search BC on the current element. If we find anything, we should return + for (const auto & pr : as_range(_boundary_side_id.equal_range(elem))) + if (pr.second.first == side) + vec_to_fill.push_back(pr.second.second); + + if (vec_to_fill.size()) + return; + + // We check the top parent now const Elem * searched_elem = elem; if (elem->level() != 0) { @@ -1283,7 +1290,7 @@ void BoundaryInfo::raw_boundary_ids (const Elem * const elem, vec_to_fill.clear(); // Only level-0 elements store BCs. - if (elem->parent()) + if (elem->parent() && !_children_on_boundary) return; // Check each element in the range to see if its side matches the requested side.