From bc82e9af2a5a1fa8118e34632935e97dd32befa3 Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Tue, 16 Jun 2026 14:51:12 -0700 Subject: [PATCH 1/2] Add preparation flag related to sub id to name map And make sure we do sync the map when we're completing preparation --- include/mesh/mesh_base.h | 17 +++++++++++++++-- src/mesh/mesh_base.C | 19 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/mesh/mesh_base.h b/include/mesh/mesh_base.h index e5c4594d6a..c90bb54daf 100644 --- a/include/mesh/mesh_base.h +++ b/include/mesh/mesh_base.h @@ -340,6 +340,16 @@ class MeshBase : public ParallelObject void unset_has_boundary_id_sets() { _preparation.has_boundary_id_sets = false; } + /** + * Tells this we have done some operation which may have left the + * subdomain id to name map inconsistent across processors. + * + * User code which adds or changes subdomain names should call this + * method. + */ + void unset_has_synched_subdomain_name_map() + { _preparation.has_synched_subdomain_name_map = false; } + /** * \returns \p true if all elements and nodes of the mesh * exist on the current processor, \p false otherwise @@ -1892,7 +1902,7 @@ class MeshBase : public ParallelObject * \returns A writable reference to the whole subdomain name map */ std::map & set_subdomain_name_map () - { return _block_id_to_name; } + { this->unset_has_synched_subdomain_name_map(); return _block_id_to_name; } const std::map & get_subdomain_name_map () const { return _block_id_to_name; } @@ -1988,7 +1998,9 @@ class MeshBase : public ParallelObject * subdomain ids, but distributed mesh generators may only know * about part of a mesh when creating names. This method can * synchronize the subdomain id to name map across processors, - * assuming no conflicts exist. + * assuming no conflicts exist. It is called automatically during + * complete_preparation() unless the map is already known to be + * synchronized. */ void sync_subdomain_name_map(); @@ -2077,6 +2089,7 @@ class MeshBase : public ParallelObject bool has_removed_orphaned_nodes; bool has_boundary_id_sets; bool has_reinit_ghosting_functors; + bool has_synched_subdomain_name_map; }; protected: diff --git a/src/mesh/mesh_base.C b/src/mesh/mesh_base.C index 83667a9fae..60a6a5e8de 100644 --- a/src/mesh/mesh_base.C +++ b/src/mesh/mesh_base.C @@ -938,6 +938,13 @@ void MeshBase::complete_preparation() if (!_preparation.has_cached_elem_data) this->cache_elem_data(); + // libMesh expects every processor to know about every subdomain + // name, but distributed mesh generators may only have set names for + // the part of the mesh they know about, so make sure the map is + // consistent everywhere. + if (!_preparation.has_synched_subdomain_name_map) + this->sync_subdomain_name_map(); + // Search the mesh for elements that have a neighboring element // of dim+1 and set that element as the interior parent if (!_preparation.has_interior_parent_ptrs) @@ -1879,6 +1886,7 @@ bool MeshBase::get_count_lower_dim_elems_in_point_locator() const std::string & MeshBase::subdomain_name(subdomain_id_type id) { + this->unset_has_synched_subdomain_name_map(); return _block_id_to_name[id]; } @@ -2043,6 +2051,8 @@ void MeshBase::sync_subdomain_name_map() parallel_object_only(); this->comm().set_union(_block_id_to_name); + + _preparation.has_synched_subdomain_name_map = true; } @@ -2809,7 +2819,8 @@ MeshBase::Preparation::Preparation() : has_removed_remote_elements(false), has_removed_orphaned_nodes(false), has_boundary_id_sets(false), - has_reinit_ghosting_functors(false) + has_reinit_ghosting_functors(false), + has_synched_subdomain_name_map(false) {} MeshBase::Preparation::operator bool() const @@ -2822,7 +2833,8 @@ MeshBase::Preparation::operator bool() const has_removed_remote_elements && has_removed_orphaned_nodes && has_reinit_ghosting_functors && - has_boundary_id_sets; + has_boundary_id_sets && + has_synched_subdomain_name_map; } MeshBase::Preparation & @@ -2837,6 +2849,7 @@ MeshBase::Preparation::operator= (bool set_all) has_removed_orphaned_nodes = set_all; has_reinit_ghosting_functors = set_all; has_boundary_id_sets = set_all; + has_synched_subdomain_name_map = set_all; return *this; } @@ -2862,6 +2875,8 @@ MeshBase::Preparation::operator== (const Preparation & other) const return false; if (has_boundary_id_sets != other.has_boundary_id_sets) return false; + if (has_synched_subdomain_name_map != other.has_synched_subdomain_name_map) + return false; return true; } From d48e801729944c2395b6a31f4816bbc78e4da1fb Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Tue, 16 Jun 2026 21:07:26 -0700 Subject: [PATCH 2/2] Move preparation copy construction after map copy constrution --- src/mesh/distributed_mesh.C | 4 ++-- src/mesh/replicated_mesh.C | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/distributed_mesh.C b/src/mesh/distributed_mesh.C index 768d4884e8..f2676ea1a1 100644 --- a/src/mesh/distributed_mesh.C +++ b/src/mesh/distributed_mesh.C @@ -202,8 +202,6 @@ DistributedMesh::DistributedMesh (const MeshBase & other_mesh) : this->copy_constraint_rows(other_mesh); - this->_preparation = other_mesh.preparation(); - auto & this_boundary_info = this->get_boundary_info(); const auto & other_boundary_info = other_mesh.get_boundary_info(); @@ -211,6 +209,8 @@ DistributedMesh::DistributedMesh (const MeshBase & other_mesh) : this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map(); + this->_preparation = other_mesh.preparation(); + #ifdef LIBMESH_ENABLE_UNIQUE_ID _next_unique_id = other_mesh.parallel_max_unique_id() + this->processor_id(); diff --git a/src/mesh/replicated_mesh.C b/src/mesh/replicated_mesh.C index d74dfdea6f..f533c48c75 100644 --- a/src/mesh/replicated_mesh.C +++ b/src/mesh/replicated_mesh.C @@ -112,8 +112,6 @@ ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) : this->copy_constraint_rows(other_mesh); - this->_preparation = other_mesh.preparation(); - auto & this_boundary_info = this->get_boundary_info(); const auto & other_boundary_info = other_mesh.get_boundary_info(); @@ -121,6 +119,8 @@ ReplicatedMesh::ReplicatedMesh (const MeshBase & other_mesh) : this->set_subdomain_name_map() = other_mesh.get_subdomain_name_map(); + this->_preparation = other_mesh.preparation(); + // If other_mesh is distributed, then we've got parts of it on each // processor but we're not replicated yet; fix that. if (!other_mesh.is_serial())