npx skills add ...
npx skills add nvidia/nvalchemi-toolkit --skill nvalchemi-dynamics-api
How to configure and run dynamics simulations, compose multi-stage pipelines (FusedStage, DistributedPipeline), use inflight batching, and manage data sinks. Use when writing any simulation script — molecular dynamics (NVE/NVT), structure relaxation or geometry optimization (e.g. FIRE), equation-of-state or adsorption scans — or orchestrating many structures through a batched GPU pipeline.
npx skills add nvidia/nvalchemi-toolkit --skill nvalchemi-dynamics-api
The dynamics API provides tools to discover available dynamics classes, configure them, and scale simulations up (single GPU) and out (multi-rank pipelines).
| Class | Description |
|---|---|
BaseDynamics | Abstract base — subclass to create integrators |
DemoDynamics | Velocity Verlet reference implementation (testing only) |
To find all dynamics classes in a codebase, search for subclasses of BaseDynamics.
Shorthand for force-based convergence:
FusedStage composes multiple dynamics stages on one GPU with a single shared
model forward pass per step. Samples migrate between stages via convergence.
+ operatorIf a sub-stage needs freshly computed forces before it starts integrating
(e.g. its AFTER_COMPUTE hooks differ from the stage the sample came from),
pass its status code in reprime_on_entry. Newly entering samples skip one
pre_update/post_update cycle while the shared compute and that stage's
AFTER_COMPUTE hooks refresh their forces, then integrate normally the
following iteration. This is separate from the initial batch-wide force
prime and does not affect samples already in that status.
with vs bare run()Prefer to use context manager:
As best pattern, even without explicit CUDA stream usage, as it in turn
supports compile(mode="reduce-overhead")
Calling dynamics.run(batch) without context manager will reuse the current stream.
status field (integer)ConvergenceHook fires, converged samples' status incrementsexit_status are graduated (no longer updated)run() loops until all samples reach exit_status or sampler is exhaustedDistributedPipeline chains dynamics stages across multiple ranks using
torch.distributed. Each rank runs one stage; converged samples are sent
to the next rank. This is pipeline parallelism for dynamics, distinct from
data-parallel multi-GPU training (DDP).
| operatorControl how inter-rank buffers synchronize:
The default comm_mode is "async_recv". The three modes differ in when
blocking occurs:
"sync": irecv completes inline in _prestep_sync_buffers; simplest
and good for debugging."async_recv": irecv is posted in _prestep_sync_buffers, but
wait() is deferred to _complete_pending_recv for communication
overlap."fully_async": send and receive are both deferred for maximum
overlap. Pending sends from the prior step are drained at the start of
the next _prestep_sync_buffers.For high-throughput pipelines, pre-allocate send/recv buffers:
Buffers are lazily initialized on the first step using the first concrete batch as a template for attribute keys, dtypes, and shapes. This means the first step has slightly more overhead.
Adjacent stages must use identical BufferConfig values. This is
validated in DistributedPipeline.setup().
The dynamics framework manages data flow through three layers:
| Layer | Location | Purpose |
|---|---|---|
| Active batch | _CommunicationMixin.active_batch | Working set being integrated |
| Communication buffers | send_buffer / recv_buffer | Pre-allocated Batch.empty() for zero-copy inter-rank transfer |
| Overflow sinks | DataSink list (priority-ordered) | Staging when active batch is full |
Each pipeline step follows a four-phase protocol:
_prestep_sync_buffers() zeros the send buffer and posts irecv
from the prior rank._complete_pending_recv() waits on deferred receive, routes into
the active batch, and drains overflow sinks.step() runs dynamics integration._poststep_sync_buffers(converged_indices) extracts converged
samples into the send buffer and sends them to the next rank.Deadlock prevention: when no samples converge, an empty send buffer
is still sent so the downstream irecv completes.
When send_buffer has limited capacity (via BufferConfig):
min(converged_count, remaining_capacity) samples are extractedBufferConfig, all converged samples are sent without
constraints (backward compatible).Important: Batch.put() uses Warp GPU kernels that only handle
float32 attributes. Adjacent pipeline stages must have identical
BufferConfig values.
| Method | Purpose |
|---|---|
_recv_to_batch(incoming) | Route received data through recv buffer into active batch |
_buffer_to_batch(incoming) | Append to active batch, overflow to sinks if full |
_batch_to_buffer(mask) | Copy graduated samples into send buffer, defrag active batch |
_overflow_to_sinks(batch) | Write to first non-full sink in priority order |
_drain_sinks_to_batch() | Pull from sinks back into active batch when room available |
For streaming workflows, SizeAwareSampler manages dataset access with
bin-packing for size-matched batching. As samples converge and leave
the batch, new samples are pulled from the dataset.
_refill_check)When refill_frequency triggers (every N steps), _refill_check():
status >= exit_status)Batch.index_selectBatch.appendstatus (replacements get 0) and fmax (replacements get inf) tensorsThis produces a new Batch object, not an in-place mutation. It
returns None when the sampler is exhausted and no active samples remain.
Sinks store graduated/snapshot data. Used by SnapshotHook and the communication layer.
GPUBuffer — GPU-resident, pre-allocated.
HostMemory — CPU-resident list.
ZarrData — Disk-backed persistent storage.