1414from torch .profiler import record_function
1515
1616from fairchem .core .common import gp_utils
17+ from fairchem .core .common .parallelism .graph_partition import (
18+ PartitionStrategy ,
19+ partition_atoms_index_split ,
20+ partition_atoms_spatial ,
21+ )
1722
1823
1924def _safe_all_to_all (
@@ -61,8 +66,6 @@ class GPContext:
6166 Graph parallel context holding communication metadata for all-to-all.
6267
6368 Runtime-only struct: every field is needed for the forward/backward pass.
64- Construction intermediates (node_partition, rank_assignments, needed_atoms,
65- global_to_local, etc.) are computed in build_gp_context but not stored.
6669
6770 Attributes:
6871 rank: Current GP rank.
@@ -79,6 +82,7 @@ class GPContext:
7982 total_recv: Total number of embeddings to receive (sum of recv_splits).
8083 local_edge_idx: Indices into edge_index_local where source is a local atom.
8184 remote_edge_idx: Indices into edge_index_local where source is a remote atom.
85+ rank_assignments: Rank owner for each atom, shape (total_atoms,).
8286 """
8387
8488 rank : int
@@ -93,6 +97,7 @@ class GPContext:
9397 total_recv : int
9498 local_edge_idx : torch .Tensor
9599 remote_edge_idx : torch .Tensor
100+ rank_assignments : torch .Tensor
96101
97102
98103def _sparse_index_exchange (
@@ -191,6 +196,41 @@ def _sparse_index_exchange(
191196 return send_counts , send_indices_global
192197
193198
199+ @torch .compiler .disable
200+ def compute_a2a_partition (
201+ pos : torch .Tensor ,
202+ total_atoms : int ,
203+ device : torch .device ,
204+ world_size : int ,
205+ rank : int ,
206+ strategy : PartitionStrategy ,
207+ ) -> tuple [torch .Tensor , torch .Tensor ]:
208+ """Compute rank assignments and local node partition for A2A graph parallel.
209+
210+ Args:
211+ pos: Atom positions, shape (N, 3).
212+ total_atoms: Total number of atoms.
213+ device: Device for output tensors.
214+ world_size: Number of GP ranks.
215+ rank: Current GP rank.
216+ strategy: Partitioning strategy (SPATIAL or INDEX_SPLIT).
217+
218+ Returns:
219+ Tuple of (rank_assignments, node_partition) where rank_assignments
220+ is shape (N,) mapping each atom to a rank, and node_partition is
221+ the indices of atoms belonging to this rank.
222+ """
223+ with record_function ("a2a_partition" ):
224+ if strategy == PartitionStrategy .SPATIAL :
225+ rank_assignments = partition_atoms_spatial (pos , world_size )
226+ else :
227+ rank_assignments = partition_atoms_index_split (
228+ total_atoms , world_size , device
229+ )
230+ node_partition = (rank_assignments == rank ).nonzero (as_tuple = True )[0 ]
231+ return rank_assignments , node_partition
232+
233+
194234@torch .compiler .disable
195235def build_gp_context (
196236 edge_index : torch .Tensor ,
@@ -313,6 +353,7 @@ def build_gp_context(
313353 total_recv = total_recv ,
314354 local_edge_idx = local_edge_idx ,
315355 remote_edge_idx = remote_edge_idx ,
356+ rank_assignments = rank_assignments ,
316357 )
317358
318359
@@ -524,7 +565,6 @@ def backward(ctx, grad_received: torch.Tensor):
524565def all_to_all_collect (
525566 x_local : torch .Tensor ,
526567 gp_ctx : GPContext ,
527- send_indices : torch .Tensor ,
528568) -> torch .Tensor :
529569 """
530570 High-level function to collect remote embeddings via all-to-all.
@@ -536,15 +576,14 @@ def all_to_all_collect(
536576 Args:
537577 x_local: Local atom embeddings, shape (local_atoms, *features).
538578 gp_ctx: Graph parallel context.
539- send_indices: Local indices of atoms to send.
540579
541580 Returns:
542581 x_received: Remote atom embeddings,
543582 shape (total_needed, *features).
544583 """
545584 return AllToAllCollect .apply (
546585 x_local ,
547- send_indices ,
586+ gp_ctx . send_indices ,
548587 gp_ctx .send_counts ,
549588 gp_ctx .recv_counts ,
550589 gp_utils .get_gp_group (),
0 commit comments