Fix legacy graph indexing offset mismatch when boundary grid nodes are unconnected - #706
Fix legacy graph indexing offset mismatch when boundary grid nodes are unconnected#706GiGiKoneti wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Just a small problem here, also great eye for finding this issue ! Just a ping no tests are added till now however the descirption suggests there should be one. I would suggest the exact scenario from #699 (legacy format, grid-first layout, unconnected boundary grid node) has zero coverage before or after this PR you can add a regression test here with a synthetic legacy graph that has a diconneted top-indexed grid node, mirroring the reproduction in the issue.
Also the new parameter inserted before the existing one changes the public call signature. Both zero_index_m2g and zero_index_g2m are exported from neural_lam/utils/__init__.py (public API). The PR adds num_grid_nodes: int | None = None before the existing restore: bool = False parameter. All current in-repo callers use keywords, so nothing breaks internally, but any external caller invoking these positionally (e.g. zero_index_m2g(idx, features, mesh_first, True)) would now silently bind True to num_grid_nodes instead of restore, restore would default to False while num_grid_nodes becomes truthy, corrupting the result without raising. Safer to append new optional params after restore, or make them keyword-only.
| max_idx = max( | ||
| g2m_edge_index.max().item(), | ||
| m2g_edge_index.max().item(), | ||
| max(ei.max().item() for ei in m2m_edge_index), |
There was a problem hiding this comment.
m2m_edge_index gets reassigned to the locally zero-indexed version (each level independently rebased to start at 0 via zero_index_edge_index) several lines before the new max_idx block runs. So by the time it's used, it no longer lives in the same raw/combined grid+mesh index space as the still-raw g2m_edge_index/m2g_edge_index, mixing them in one max() is comparing apples to oranges. In practice this doesn't blow up on typical graphs, because grid counts vastly exceed mesh counts, so the raw g2m/m2g values dominate the max and the (small, rebased) m2m term is inert. But it means the m2m term contributes nothing to the robustness the fix is meant to provide, if the mesh's topmost-indexed node were ever the one lacking a g2m/m2g edge (the same failure mode as #699, just mirrored onto the mesh side), this fix wouldn't catch it either, silently.
There's also a smaller mismatch: the comment says "we determine total number of nodes at the bottom level," but the code does max(ei.max().item() for ei in m2m_edge_index) over the entire list (all mesh levels), not just m2m_edge_index[0]. For non-hierarchical graphs this is moot, but it's inconsistent with the stated intent and themesh_static_features[0] reference right below it.
Suggested fix to flag: compute max_idx from the raw m2m_edge_index (before the zero_index_edge_index reassignment) or move the whole num_grid_nodes computation up before that reassignment and use m2m_edge_index[0] explicitly to match the "bottom level" comment.
|
Thanks for the thorough review and catch @Sir-Sloth-The-Lazy!
All 250 tests and pre-commit checks are passing cleanly! |
Describe your changes
This PR fixes the offset mismatch in
zero_index_m2gandzero_index_g2mwhenmesh_firstisFalse.Specifically, instead of dynamically computing the number of grid nodes from the maximum active node index in the edge index (which is incorrect if some boundary grid nodes are unconnected to the GNN mesh), it computes the total number of nodes at the bottom level and subtracts the number of mesh nodes at that level:
max_idxis calculated overg2m,m2g, and the bottom levelm2medge indices.num_grid_nodesis calculated as(max_idx + 1) - num_mesh_nodes.num_grid_nodesdown to the zero-indexing helpers.Issue Link
closes #699
Type of change
Checklist before requesting a review
pullwith--rebaseoption if possible).Checklist for reviewers
Author checklist after completed review
- Fix offset mismatch in legacy graph zero-indexing...under## [unreleased]