Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve handling of mesh stitching for non-conforming meshes #3599

Merged
merged 4 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 39 additions & 26 deletions include/mesh/unstructured_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,16 @@ class UnstructuredMesh : public MeshBase
* at dealing with slightly misaligned meshes).
* If \p enforce_all_nodes_match_on_boundaries is true, we throw an error if the number of
* nodes on the specified boundaries don't match the number of nodes that were merged.
* This is a helpful error check in some cases.
* This is a helpful error check in some cases. If this is true, it overrides the value of
* \p merge_boundary_nodes_all_or_nothing.
* If \p skip_find_neighbors is true, a faster stitching method is used, where the lists of
* neighbors for each elements are copied as well and patched, without calling the time-consuming
* find_neighbors() function.
* find_neighbors() function. This option is now hard-coded to true.
* If \p merge_boundary_nodes_all_or_nothing is true, instead of throwing an error
* like \p enforce_all_nodes_match_on_boundaries, the meshes are combined anyway but coincident
* nodes are not merged into single nodes. This is useful in cases where you are not sure if the
* boundaries are fully conforming beforehand and you want to handle the non-conforming cases
* differently.
*
* Note that the element IDs for elements in the stitched mesh corresponding to "this" mesh
* will be unchanged. The IDs for elements corresponding to \p other_mesh will be incremented
Expand All @@ -192,26 +198,32 @@ class UnstructuredMesh : public MeshBase
* There is no simple a priori relationship between node IDs in "this" mesh
* and other_mesh and node IDs in the stitched mesh because the number of nodes (and hence
* the node IDs) in the stitched mesh depend on how many nodes are stitched.
*
* \returns the count of how many nodes were merged between the two meshes.
* This can be zero in the case of no matching nodes or if
* \p merge_boundary_nodes_all_or_nothing was active and relevant.
*/
void stitch_meshes (const MeshBase & other_mesh,
boundary_id_type this_mesh_boundary,
boundary_id_type other_mesh_boundary,
Real tol=TOLERANCE,
bool clear_stitched_boundary_ids=false,
bool verbose=true,
bool use_binary_search=true,
bool enforce_all_nodes_match_on_boundaries=false);
std::size_t stitch_meshes (const MeshBase & other_mesh,
boundary_id_type this_mesh_boundary,
boundary_id_type other_mesh_boundary,
Real tol=TOLERANCE,
bool clear_stitched_boundary_ids=false,
bool verbose=true,
bool use_binary_search=true,
bool enforce_all_nodes_match_on_boundaries=false,
bool merge_boundary_nodes_all_or_nothing=false);

/**
* Similar to stitch_meshes, except that we stitch two adjacent surfaces within this mesh.
*/
void stitch_surfaces (boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol=TOLERANCE,
bool clear_stitched_boundary_ids=false,
bool verbose=true,
bool use_binary_search=true,
bool enforce_all_nodes_match_on_boundaries=false);
std::size_t stitch_surfaces (boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol=TOLERANCE,
bool clear_stitched_boundary_ids=false,
bool verbose=true,
bool use_binary_search=true,
bool enforce_all_nodes_match_on_boundaries=false,
bool merge_boundary_nodes_all_or_nothing=false);

/**
* Deep copy of nodes and elements from another mesh object (used by
Expand Down Expand Up @@ -256,15 +268,16 @@ class UnstructuredMesh : public MeshBase
* Helper function for stitch_meshes and stitch_surfaces
* that does the mesh stitching.
*/
void stitching_helper (const MeshBase * other_mesh,
boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool skip_find_neighbors);
std::size_t stitching_helper (const MeshBase * other_mesh,
boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool skip_find_neighbors,
bool merge_boundary_nodes_all_or_nothing);
};


Expand Down
116 changes: 74 additions & 42 deletions src/mesh/unstructured_mesh.C
Original file line number Diff line number Diff line change
Expand Up @@ -1721,57 +1721,66 @@ void UnstructuredMesh::all_complete_order ()
}


void UnstructuredMesh::stitch_meshes (const MeshBase & other_mesh,
boundary_id_type this_mesh_boundary_id,
boundary_id_type other_mesh_boundary_id,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries)
std::size_t
UnstructuredMesh::stitch_meshes (const MeshBase & other_mesh,
boundary_id_type this_mesh_boundary_id,
boundary_id_type other_mesh_boundary_id,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool merge_boundary_nodes_all_or_nothing)
{
LOG_SCOPE("stitch_meshes()", "UnstructuredMesh");
stitching_helper(&other_mesh,
this_mesh_boundary_id,
other_mesh_boundary_id,
tol,
clear_stitched_boundary_ids,
verbose,
use_binary_search,
enforce_all_nodes_match_on_boundaries,
true);
return stitching_helper(&other_mesh,
this_mesh_boundary_id,
other_mesh_boundary_id,
tol,
clear_stitched_boundary_ids,
verbose,
use_binary_search,
enforce_all_nodes_match_on_boundaries,
true,
merge_boundary_nodes_all_or_nothing);
}


void UnstructuredMesh::stitch_surfaces (boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries)
std::size_t
UnstructuredMesh::stitch_surfaces (boundary_id_type boundary_id_1,
boundary_id_type boundary_id_2,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool merge_boundary_nodes_all_or_nothing)

{
stitching_helper(nullptr,
boundary_id_1,
boundary_id_2,
tol,
clear_stitched_boundary_ids,
verbose,
use_binary_search,
enforce_all_nodes_match_on_boundaries,
true);
return stitching_helper(nullptr,
boundary_id_1,
boundary_id_2,
tol,
clear_stitched_boundary_ids,
verbose,
use_binary_search,
enforce_all_nodes_match_on_boundaries,
true,
merge_boundary_nodes_all_or_nothing);
}


void UnstructuredMesh::stitching_helper (const MeshBase * other_mesh,
boundary_id_type this_mesh_boundary_id,
boundary_id_type other_mesh_boundary_id,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool skip_find_neighbors)
std::size_t
UnstructuredMesh::stitching_helper (const MeshBase * other_mesh,
boundary_id_type this_mesh_boundary_id,
boundary_id_type other_mesh_boundary_id,
Real tol,
bool clear_stitched_boundary_ids,
bool verbose,
bool use_binary_search,
bool enforce_all_nodes_match_on_boundaries,
bool skip_find_neighbors,
bool merge_boundary_nodes_all_or_nothing)
{
#ifdef DEBUG
// We rely on neighbor links here
Expand Down Expand Up @@ -2109,6 +2118,26 @@ void UnstructuredMesh::stitching_helper (const MeshBase * other_mesh,
libmesh_error_msg_if((n_matching_nodes != this_mesh_n_nodes) || (n_matching_nodes != other_mesh_n_nodes),
"Error: We expected the number of nodes to match.");
}

if (merge_boundary_nodes_all_or_nothing)
{
std::size_t n_matching_nodes = node_to_node_map.size();
std::size_t this_mesh_n_nodes = this_boundary_node_ids.size();
std::size_t other_mesh_n_nodes = other_boundary_node_ids.size();
if ((n_matching_nodes != this_mesh_n_nodes) || (n_matching_nodes != other_mesh_n_nodes))
{
if (verbose)
{
libMesh::out << "Skipping node merging in "
"UnstructuredMesh::stitch_meshes because not "
"all boundary nodes were matched."
<< std::endl;
}
node_to_node_map.clear();
other_to_this_node_map.clear();
node_to_elems_map.clear();
}
}
}
else
{
Expand Down Expand Up @@ -2395,6 +2424,9 @@ void UnstructuredMesh::stitching_helper (const MeshBase * other_mesh,
this->get_boundary_info().clear_stitched_boundary_side_ids(
this_mesh_boundary_id, other_mesh_boundary_id, /*clear_nodeset_data=*/true);
}

// Return the number of nodes which were merged.
return node_to_node_map.size();
}


Expand Down