diff --git a/include/mesh/boundary_info.h b/include/mesh/boundary_info.h index 3d122a81397..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: /** @@ -924,6 +936,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..d278f76a74b 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); @@ -1228,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) { @@ -1276,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. @@ -1426,8 +1440,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 +1457,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 +1506,23 @@ 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()); + else if (!_children_on_boundary) + searched_elem_vec.push_back(elem); - // 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 +1553,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 +1568,22 @@ 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()); + else if (!_children_on_boundary) + searched_elem_vec.push_back(elem); - // 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 +1618,7 @@ BoundaryInfo::sides_with_boundary_id(const Elem * const elem, returnval.push_back(side); } } - + } return returnval; } @@ -1794,7 +1833,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 +2196,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