-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add distributed mesh support and fake neighbor handling in BreakMeshByBlock #31636
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
base: next
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some early comments.
| const Elem * neighbor_ptr = elem->neighbor_ptr(side); | ||
| const Elem * neighbor = | ||
| (neighbor_ptr) ? neighbor_ptr : _mesh.neighbor_fake_ptr(elem, side); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const Elem * neighbor_ptr = elem->neighbor_ptr(side); | |
| const Elem * neighbor = | |
| (neighbor_ptr) ? neighbor_ptr : _mesh.neighbor_fake_ptr(elem, side); | |
| const auto * neighbor_ptr = elem->neighbor_ptr(side) || _mesh.neighbor_fake_ptr(elem, side); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might have to add an assertion below to make sure it's nullptr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing this out.
Using || in this context does not work because in C++ it always evaluates to a bool, not a pointer.
As a result, I go with
const auto * neighbor = elem->neighbor_ptr(side)
? elem->neighbor_ptr(side)
: _mesh.neighbor_fake_ptr(elem, side);
framework/include/mesh/MooseMesh.h
Outdated
| void | ||
| setElemSideToFakeNeighborElemSideMap(std::unordered_map<std::pair<dof_id_type, unsigned int>, | ||
| std::pair<dof_id_type, unsigned int>> map) | ||
| { | ||
| _elemid_side_to_fake_neighbor_elemid_side = std::move(map); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need a more fine-grained API to modify the map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion! I’ve extended the interface to provide a more fine-grained API:
- addFakeNeighbor: add or update a single (elem, side) entry
- removeFakeNeighbor: remove a single entry if it exists
- hasFakeNeighbor: check whether a mapping exists
- getFakeNeighborMap: accessor for read-only access to the whole map
- setFakeNeighborMap: still available for bulk replacement
framework/include/mesh/MooseMesh.h
Outdated
| _elemid_side_to_fake_neighbor_elemid_side.clear(); | ||
| } | ||
|
|
||
| const Elem * neighbor_fake_ptr(const Elem * elem, unsigned int side) const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const Elem * neighbor_fake_ptr(const Elem * elem, unsigned int side) const | |
| const Elem * fake_neighbor_ptr(const Elem * elem, unsigned int side) const |
Also, perhaps we should come up with a better name than "fake". Perhaps "additional_neighbor_ptr"? I'll take suggestions from @roystgnr and @lindsayad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently just rename it to be fake_neighbor_ptr . Let's wait for the suggestions.
framework/include/mesh/MooseMesh.h
Outdated
| return nullptr; | ||
| } | ||
|
|
||
| int neighbor_fake_side(const Elem * elem, unsigned int side) const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similar comment on naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change it to be fake_neighbor_side
| std::unordered_map<ElemIDSidePair, ElemIDSidePair> _elemid_side_to_fake_neighbor_elemid_side; | ||
|
|
||
| /// generate the new boundary interface | ||
| void addInterfaceBoundary(MeshBase & mesh); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest renaming this to addInterface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
| std::map<dof_id_type, std::set<subdomain_id_type>> _nodeid_to_connected_blocks; | ||
|
|
||
| /// @brief a set of pairs of block ids between which new boundary sides are created | ||
| std::set<std::pair<subdomain_id_type, subdomain_id_type>> _new_boundary_sides_list; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the old name _neighboring_block_list. Why was the renaming, is it now serving different purposes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name I grabbed from Roy's implementation: roystgnr@2583950. I will use _neighboring_block_list to replace this.
| void findBoundaryName(MeshBase & mesh, | ||
| const subdomain_id_type & /*primaryBlockID*/, | ||
| const subdomain_id_type & /*secondaryBlockID*/, | ||
| std::string & /*boundaryName*/, | ||
| const boundary_id_type & /*boundaryID*/, | ||
| BoundaryInfo & /*boundary_info*/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| void findBoundaryName(MeshBase & mesh, | |
| const subdomain_id_type & /*primaryBlockID*/, | |
| const subdomain_id_type & /*secondaryBlockID*/, | |
| std::string & /*boundaryName*/, | |
| const boundary_id_type & /*boundaryID*/, | |
| BoundaryInfo & /*boundary_info*/); | |
| BoundaryID getBoundaryIDFromBlockPair(MeshBase & mesh, | |
| const subdomain_id_type & /*primaryBlockID*/, | |
| const subdomain_id_type & /*secondaryBlockID*/); |
| // Used to temporarily store information about which lower-dimensional | ||
| // sides to add and what subdomain id to use for the added sides. | ||
| struct ElemSidePair | ||
| struct ElemIDSidePair |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See if you are reinventing BndElement...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually wrongly changed here. This is the original implementation inside MOOSE. I will revert this back, and on my side, I will try to use BndElement .
| if (type == "BreakMeshByBlockGenerator") | ||
| _has_bmbb = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯
690fb02 to
b7d4c86
Compare
|
Job Documentation, step Docs: sync website on 9f29e32 wanted to post the following: View the site here This comment will be updated on new commits. |
0ddb2cf to
9f29e32
Compare
…hbor RM
1. Distributed mesh fixes
- Node ID assignment: using `mesh->n_nodes()` fails for distributed meshes (IDs are sparse). Switch to `max_node_id` with a stride.
- Ghost node handling:
- *Phase 0*: Each rank computes locally connected blocks for its owned nodes and sends them to the node owner.
- *Phase 1*: Node owners aggregate connected block info and broadcast the global set to all ranks.
- Boundary ID assignment aligned with Roy’s fix ([commit link](roystgnr@2583950)).
2. New FakeNeighbor datastructure
- Introduce a RelationshipManager for ghosted fake neighbors (CZM discontinuous neighbors, not topological).
- Robust initialization:
- Override `set_mesh` to ensure `_functor` is created JIT on first use.
- Rebuild `_functor` in `internalInitWithMesh` if the neighbor map was populated after an early empty init.
- Handles mesh cloning (`SetupMeshAction`) cases where `set_mesh` is called before initialization.
3. Simplifications
- Since we now call `prepare_for_use()` at the end of BMBb, remove BreakMeshByBlockGenerator-specific hacks.
- Simplify node ID handling.
- Drop `MeshGeneratorSystem::_has_bmbb` flag and `hasBreakMeshByBlockGenerator()` API.
# Conflicts:
# framework/src/base/MeshGeneratorSystem.C
Fixes crashes from map::at when nodes had no valid blocks. Each node now gets an entry (even empty), keeping the map consistent with node_to_elem_map.
…ributed mode. The crash was caused by an incorrect decision on node duplication, which stemmed from using incomplete, processor-local data (`node_to_elem_map`). The fix ensures the decision is based on globally synchronized data (`_nodeid_to_connected_blocks`), guaranteeing a consistent and correct outcome across all processors.
… node is in a junction with more than two blocks that share the node. It only happens that the node is in the interface of two blocks and has the block IDs equal to what the user set.
…estriction for bmbb tests (2) regold for the bmbb tests
Refactors the disconnected neighbor mechanism to be robust and safe under parallel (MPI) execution. Previously, the implementation stored raw `Elem*` pointers in a map, which was fundamentally unsafe in a distributed environment. Pointers are only valid on the local rank and become meaningless across MPI processes, leading to segmentation faults in multi-process runs. This commit resolves the issue by transitioning to an ID-based design: - Core map (`_disconnected_neighbors_by_id`) now stores `dof_id_type` pairs instead of raw `ConstBndElement` pointers, ensuring portability and serializability across ranks. - The `disconnectedNeighbor` accessor now returns a `std::optional<ConstBndElement>`, replacing unsafe raw pointers with a safer C++ interface that naturally handles missing neighbors. **Key Learning:** For parallel-safe design, always **store globally unique IDs** and resolve them into rank-local pointers, which avoids pointer validity issues and ensures correctness across distributed executions.
- Replaced raw Elem* usage with ID-based ElemSide pairs for safer parallel handling - Added cache (_cached_disconnected_neighbors) to speed up repeated lookups - Modified neighbor queries across loops (NonlinearThread, ComputeUserObjectsThread, ComputeMaterialsObjectThread, FEProblemBase, etc.) to use disconnectedNeighborPtr
1. MooseMesh: Introduced `_has_incomplete_interface_pairs` flag with getter/setter, initialized in the constructor to detect missing reverse boundary pairs. 2. BreakMeshByBlockGenerator: Set `add_interface_on_two_sides = true` and `split_interface = true` by default; detects incomplete boundary pairs and outputs a warning if the user attempts to run CZM with such configurations. 3. CohesiveZoneAction & Tests: Added runtime error for incomplete CZM interfaces; updated test inputs to use explicit block-pair boundaries (replacing the unsupported single `interface` setup) and added the `boundary_pair_not_found` failure test
9f29e32 to
040fb48
Compare
|
Job Precheck, step Clang format on 040fb48 wanted to post the following: Your code requires style changes. A patch was auto generated and copied here
Alternatively, with your repository up to date and in the top level of your repository:
|
| @@ -1 +1 @@ | |||
| Subproject commit 910736a3a20aded528c3ba99371ce65980dc8e2c | |||
| Subproject commit f956256a7b2b96dc0df2852e4f54f506ef20b062 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution! This contains a submodule update
|
Job Precheck, step Versioner verify on 040fb48 wanted to post the following: Versioner templatesFound 14 templates, 0 failed Versioner influential filesFound 58 influential files, 1 changed, 0 added, 0 removed
Versioner versionsFound 9 packages, 2 changed, 2 failed
Verification failed. |
closes #12033
closes #21161
Reason
Currently, BreakMeshByBlock (bmbb) uses a hacky approach to prepare the mesh.
When nodes are duplicated by bmbb, their former neighbors are no longer neighbors (since neighborhood is based on shared nodes). As a result:
prepare_for_use()at the end of bmbb, because it would erase the discontinuous neighbor information.Another limitation is that bmbb cannot run with distributed meshes. This PR addresses that.
Design
Preserving discontinuous neighbors
prepare_for_use()wipes out discontinuous neighbor data, we introduce a new data structure to store this information (referred to as fake neighbors).Support for distributed meshes
Following Roy’s suggestions:
-> Solution: use communication between processors and assign deterministic IDs based on
max_node_idstrides.Impact
prepare_for_use()can be safely called at the end of bmbb.