Quick start#
This page runs the theoretical test case. It is a synthetic double gyre on a 100 × 80 × 30 grid of 250 m cells with hourly fields, built in memory. It needs no data files, so it is the right first run to check that everything works, just like the Theoretical project of the Fortran code.
1. A first run#
Save this as first_run.py:
import tracmass
from tracmass import gcm, seed
# Static grid + lazy flux buffer. The theoretical adapter has hourly
# snapshots, so ten hours is ten GCM windows.
grid, lazy = tracmass.new_flux(
gcm.theoretical.fluxes, dtm_start="2007-06-01", dtm_end="2007-06-01 10:00"
)
# One particle at the centre of every cell in a 21 x 21 box at level 5
# (1-based TRACMASS indices).
state = seed.ijk(40, 60, 30, 50, 5, 5, grid=grid)
# Integrate all windows, 4 sub-steps per window, progress printed per window.
result = tracmass.time_dependent(state, grid, lazy, iter_sub=4, monitor="print")
print(grid.imt, grid.jmt, grid.km, grid.timestep, lazy.n_windows)
print("active:", int(result.active.sum()), "/", len(result.active))
and run it:
uv run python first_run.py # or: pixi run python first_run.py
2. The output#
If everything works you get one line per GCM window, then a summary:
GPU: 11870 MiB free / 12282 MiB total
001/010 2007-06-01 441 active, #sub:6, wall:2.2s [io:0ms jax:2.2s py:74ms]
002/010 2007-06-01 441 active, #sub:7, wall:452ms [io:56ms jax:353ms py:44ms]
003/010 2007-06-01 441 active, #sub:7, wall:459ms [io:55ms jax:360ms py:44ms]
004/010 2007-06-01 441 active, #sub:7, wall:463ms [io:55ms jax:363ms py:44ms]
005/010 2007-06-01 441 active, #sub:8, wall:460ms [io:55ms jax:360ms py:45ms]
006/010 2007-06-01 441 active, #sub:7, wall:465ms [io:58ms jax:361ms py:46ms]
007/010 2007-06-01 441 active, #sub:8, wall:471ms [io:55ms jax:367ms py:49ms]
008/010 2007-06-01 441 active, #sub:7, wall:446ms [io:53ms jax:347ms py:46ms]
009/010 2007-06-01 441 active, #sub:7, wall:451ms [io:54ms jax:351ms py:46ms]
010/010 2007-06-01 441 active, #sub:7, wall:459ms [io:60ms jax:361ms py:38ms]
--- total wall:6.4s [io:500ms 8% jax:5.4s 85% py:476ms 7%]
100 80 30 1:00:00 10
active: 441 / 441
Each window line shows:
Field |
Meaning |
|---|---|
|
Window number and total number of windows (from |
|
Date of the window’s first snapshot |
|
Particles still being integrated at the end of the window |
|
Sub-cycles (calls of the compiled kernel) needed for the window |
|
Wall-clock time for the window |
|
Time reading fluxes, in the JAX kernel, and in Python bookkeeping |
The first window is slower because it includes the JIT compilation of the
kernel. If particles stop during a window the line also lists how many
stopped and why, e.g. stopped:3 (land:2, out_of_bounds_h:1) (see
Stopping trajectories).
monitor="rich" gives a live table instead, and monitor=None turns
progress output off. See Monitoring.
3. The same run from settings#
The run above was set up in Python. The same run can be described in a
tracmass.toml file next to the script:
[quickstart]
dtm_start = "2007-06-01"
dtm_end = "2007-06-01 10:00"
runmonitor_backend = "print"
[quickstart.gcm]
name = "theoretical"
[quickstart.seed]
approach = "ijk"
box = { i1 = 40, i2 = 60, j1 = 30, j2 = 50, k1 = 5, k2 = 5 }
import tracmass
result = tracmass.run(env="quickstart", iter_sub=4)
tracmass.run activates the [quickstart] environment, builds the grid
and the flux buffer, seeds from the [quickstart.seed] table and calls the
integrator. Anything you pass as an argument wins over the settings. The
next page, Setting up an experiment, goes through this
step by step.
4. Saving trajectories#
Add a recorder to write positions at every window boundary to a Parquet file:
result = tracmass.time_dependent(
state, grid, lazy, iter_sub=4, recorder="first_run.parquet"
)
df = tracmass.load("first_run.parquet") # columns id, x, y, dtm
See Output for the file layout.
Next steps#
Try the other synthetic case,
gcm.fabboni, which has an analytical solution and is used to validate the schemes.Read Setting up an experiment, then the Tutorials.