Add sharding support and fix the world axis - #99
Merged
Merged
Conversation
ratheron
reviewed
Aug 18, 2026
Collaborator
Author
|
This new merge reworks the mechanism to use This is important, because the metadata is a class variable. We cannot change the metadata for a single simulation, because that would break any other existing simulation that has not batched a particular field. With |
ratheron
reviewed
Aug 19, 2026
ratheron
approved these changes
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rationale
We want to support sharding of the simulation so that we can run on multiple devices. Multi-device support unlocks performance improvements on the CPU and might be interesting for future parallel GPU simulations. This PR adds the tools for sharding.
What was previously broken
While working on this, I noticed that some of our functions are fundamentally broken. This mostly affects resets and sharding. When we reset our data, we previously made a shape check if the array matches the number of worlds in its leading dimension. This leads to wrong positives, i.e. the
gravity_vectorwithshape=(3,)would get picked up forn_worlds=3. This is obviously wrong. There is no way to tell which array just happens to coincide with the simulation n_worlds, and which ones are truly parallel across worlds.Design
The world axis
We have two realistic options: either we keep an explicit list of all arrays that are batched over worlds somewhere, or we somehow mark each array.
The first option feels clunky, since we would store information about the data in two places, and users would have to use a separate registration mechanism for plugins.
The second option needs some way to attach metadata to arrays. Luckily,
flax.struct.fieldalready has ametadatafield. We now use this for every array that has a world axis. Fields are marked usingfield(metadata={WORLD_INDEXED_KEY: True}).While adding this, I noticed that many arrays document false shape information. This is now also fixed.
Checking which arrays are world-indexed
We have a new utils function,
world_mask, that maps out (possibly nested) structs. It replicates their structure exactly, but replaces leaves with a bool flag that indicates if they have a per-world axis. For each array with theWORLD_INDEXED_KEYflag set, it inserts a True.Proper reset policies
The world axis allows us to formulate proper policies around resets. Obviously, masked resets can only reset arrays that are replicated per-world. Shared arrays cannot be decided. The new
resetfunction uses a revised version ofpytree_replace()that takes theworld_maskPyTree and only resets the proper fields. Importantly, this also applies for all-True masks.If
Noneis passed, we instead reset everything, including the shared data, because the case is trivially decidable, and the behavior is what users would expect.Support for sharding across devices
Having introduced all this machinery, sharding, luckily, becomes largely trivial. We shard all world-axis arrays evenly across devices and replicate shared arrays. Selecting world-batched arrays is trivial with the new
world_maskfunction.One caveat is that we currently cannot support sharing in explicit mode. SciPy introduces some scatter operations that cannot be resolved in explicit mode, so we pre-select
jax.sharding.AxisType.Auto(see https://docs.jax.dev/en/latest/parallel.html#auto-sharding-mode-decides-shardings-automatically-during-compilation). Fixing this will require work upstream in SciPy and is out of scope for now.Related to efficient sharding: #98