Description
BoundaryInfo::build_side_list_from_node_list() adds a side to a sideset whenever every node of that side belongs to the nodeset, with no check for whether the side is actually on the mesh exterior or on a subdomain interface:
// src/mesh/boundary_info.C
for (const auto & elem : _mesh->active_element_ptr_range())
for (auto side : elem->side_index_range())
{
...
for (const auto & pr : nodesets_node_count)
if (pr.second == side_elem->n_nodes())
add_side(elem, side, pr.first);
}
On a mesh that is only one element deep in some direction, a nodeset spanning both exterior faces normal to that direction will cause every node of the interior sides between layers to also satisfy this condition, so those interior sides get added to the sideset alongside the intended exterior ones.
Reproduction
- A 3D mesh one element layer deep in one direction (or a thin shell-like mesh in general)
- A nodeset containing nodes on both faces normal to that direction
- Call
build_side_list_from_node_list() (or build_side_list_from_node_list(nodeset_list))
Expected behavior
Only sides that are actually exterior (no neighbor) or on a genuine interface between different subdomains should be added. A side whose neighbor is in the same subdomain is interior to a block and shouldn't be pulled into the sideset just because its nodes happen to overlap the nodeset.
Context
This surfaced downstream in idaholab/moose#30917 and was worked around in idaholab/moose#33826 with a MOOSE-side post-processing pass (MooseMeshUtils::removeInteriorSides) that strips sides whose neighbor is in the same subdomain. That fix requires a second full pass over the mesh and an opt-in flag; it would be better handled here, where neighbor/subdomain information is already available during the same traversal (e.g. an optional exterior_only-style parameter, or as new default behavior with a flag to restore the old unconditional behavior for back-compat).
Description
BoundaryInfo::build_side_list_from_node_list()adds a side to a sideset whenever every node of that side belongs to the nodeset, with no check for whether the side is actually on the mesh exterior or on a subdomain interface:On a mesh that is only one element deep in some direction, a nodeset spanning both exterior faces normal to that direction will cause every node of the interior sides between layers to also satisfy this condition, so those interior sides get added to the sideset alongside the intended exterior ones.
Reproduction
build_side_list_from_node_list()(orbuild_side_list_from_node_list(nodeset_list))Expected behavior
Only sides that are actually exterior (no neighbor) or on a genuine interface between different subdomains should be added. A side whose neighbor is in the same subdomain is interior to a block and shouldn't be pulled into the sideset just because its nodes happen to overlap the nodeset.
Context
This surfaced downstream in idaholab/moose#30917 and was worked around in idaholab/moose#33826 with a MOOSE-side post-processing pass (
MooseMeshUtils::removeInteriorSides) that strips sides whose neighbor is in the same subdomain. That fix requires a second full pass over the mesh and an opt-in flag; it would be better handled here, where neighbor/subdomain information is already available during the same traversal (e.g. an optionalexterior_only-style parameter, or as new default behavior with a flag to restore the old unconditional behavior for back-compat).