# Fortran-to-JAX map For users coming from Fortran TRACMASS 7: where each piece of the Fortran code went. For the namelist variables see the [namelist-to-settings map](../configuration/settings.md#namelist-to-settings-map). ## Routines | Fortran (TRACMASS 7) | TRACMASS-JAX | |---|---| | `TRACMASS.F90` (main program) | `tracmass.run` (`driver.py`) | | `mod_init.F90 :: init_namelist` | `tracmass.config.settings`, `settings.setenv(env)` | | `mod_subdomain.F90 :: init_subdomain` | `[env.gcm] subset`, `config.apply_gcm_subset` | | `setup_grid.F90` (project) | adapter `fluxes()` → `new_grid` / `_grid_from_ds` | | `read_field.F90` (project) | adapter `fluxes()` (lazy) + `LazyFluxFields.compute()` | | `mod_getfile.F90` | the `tracmass.seagrid` modules (`open_dataset`, `grid_definition`) | | `mod_seed.F90 :: init_seed`, `seed` | `tracmass.seed.*`, `seed.from_settings` | | `mod_loop.F90 :: loop` | `time_dependent` / `_patched` / `_streaming` | | `intsTimeLoop` (GCM steps) | Python loop over windows | | `ntracLoop` (trajectories) | `jax.vmap` in `step_all` | | `niterLoop` (sub-steps) | `lax.while_loop` (`_run_window`), or a Python loop for streaming | | `mod_pos_tstep.F90 :: cross_time` | `advection_scheme.full_grid._cross_time_1d` | | `mod_pos_tstep.F90 :: calc_pos` | `advection_scheme.full_grid._calc_pos_1d` | | `mod_pos_tstep.F90 :: update_traj`, `update_bounce` | `advection_scheme.full_grid._subcycle_one_particle` | | `mod_pos_tanalytical.F90 :: cross_time` (`apos`, `aneg`, `azer`) | `_cross_time_analytical_1d` (`_apos_crossing`, `_aneg_crossing`, `_azer_crossing`) | | `mod_pos_tanalytical.F90 :: calc_pos` | `_calc_pos_analytical_1d` | | `mod_pos_tanalytical.F90 :: daw`, `erfexp` | `_dawson`, `_erfexp_val` | | `mod_swap.F90 :: swap_time` | `gcm.swap_fields`, `update_flux` | | `mod_swap.F90 :: swap_sign` (`nff = -1`) | `dtm_end < dtm_start` in `new_flux` (negates fluxes, `grid.reverse = True`) | | `mod_vertvel.F90` | not ported: `wflux` comes from the GCM; `move_vertically = false` for 2-D | | `mod_calendar.F90` | `pandas` timestamps (`dtm`, `dtm_start`, `dtm_end`) | | `mod_clock.F90` | `ts` / `tt` in `ParticleState`, `intrpg = frac(ts)` | | `mod_error.F90` | `ParticleState.reason` codes | | `kill_zones.F90` (project) | land, domain edges and `traj_max_time` only (see [Stopping trajectories](../tutorials/stopping.md)) | | `mod_print.F90` | `RunMonitor` | | `mod_write.F90` | `ParticleRecorder`, `write_trajectories_parquet` | | `mod_vars.F90` `trajectory` type | `ParticleState` (struct of arrays) | | `mod_postprocess.F90` | `tracmass.load` + `pandas` | | `mod_stream.F90` | not yet | | `mod_tracers.F90`, `mod_tracerf.F90` | not yet | | `mod_diffusion.F90` | not yet | | `mod_divergence.F90` | not yet | ## Variables | Fortran | TRACMASS-JAX | |---|---| | `x1`, `y1`, `z1` | `state.x`, `state.y`, `state.z` | | `ia`, `ja`, `ka` / `ib`, `jb`, `kb` | `state.ia`, `state.ja`, `state.ka` | | `tt`, `ts`, `t0` | `state.tt`, `state.ts`, `state.t0` | | `subvol` | `state.subvol` | | `niter` | `state.niter` | | `nrj(6, ntrac)` / exit flags | `state.active`, `state.reason` | | `uflux`, `vflux`, `wflux` (`imt, jmt, km, 2`) | `FluxFields.uflux`, … (`imt, jmt, km, 2`) | | `kmt`, `dxdy`, `dzt` | `GridFields.kmt`, `GridFields.dxdy`, `FluxFields.dzt` | | `intrpg`, `intrpr` | `intrpg`, `1 - intrpg` | | `ds`, `dse`, `dsw`, `dsn`, `dss`, `dsu`, `dsd`, `dsmin` | same names in `_subcycle_one_particle` | | `tseas` | `grid.timestep.total_seconds()` | | `iter` | `iter_sub` | | `UNDEF` | `advection_scheme.full_grid.UNDEF = 1e20` | ## Behavioural differences - **Particles in lock-step.** All particles advance together, one sub-cycle at a time. Fortran finishes one trajectory's sub-steps before moving to the next. The time-interpolation weight is shared across particles, as in Fortran (see [Time interpolation](schemes.md#time-interpolation)). `tests/test_fortran_comparison.py` checks the result against the Fortran *Theoretical* run. - **Single precision positions.** Positions and fluxes are 32-bit by default. Set `JAX_ENABLE_X64=True` (the pixi environment does) for 64-bit. - **Domain edges.** On non-periodic axes, entering the outermost row or column stops the particle (`out_of_bounds_h`), because the flux through the outer face of those cells is not part of the grid. - **Safety stops.** Particles that make no progress, fall far behind or hit the per-window sub-cycle limit are stopped, each with its own reason code.