Running TARSA

For most users, the recommended TARSA workflow is the high-level API in src/TARSA.jl. The practical pattern is:

  1. prepare or reuse meteorology,
  2. load it into TARSA.InputFields,
  3. build emissions,
  4. choose a solver,
  5. build the simulation,
  6. run and save results.

If you want the shortest runnable entry point first, start with Guide / Quickstart.

The high-level entry points are:

  • TARSA.prepare_input_data(...)
  • TARSA.load_input_data(...)
  • TARSA.zero_emissions(...)
  • TARSA.add_ground_source!(...)
  • TARSA.add_point_source!(...)
  • TARSA.build_ground_source_emissions(...)
  • TARSA.build_point_source_emissions(...)
  • TARSA.build_custom_emissions(...)
  • TARSA.build_wildfire_emissions(...)
  • TARSA.load_aerosol_inputs(...)
  • TARSA.AerosolTracer(...)
  • TARSA.WetDeposition(...)
  • TARSA.DryDeposition(...)
  • TARSA.DryDepositionSurface(...)
  • TARSA.AerosolProcesses(...)
  • TARSA.load_so2_chemistry_inputs(...)
  • TARSA.OHOxidation(...)
  • TARSA.CloudOxidation(...)
  • TARSA.SO2Chemistry(...)
  • TARSA.ExplicitSolver(...)
  • TARSA.ImplicitSolver(...)
  • TARSA.build_simulation(...)
  • TARSA.build_aerosol_simulation(...)
  • TARSA.build_so2_simulation(...)
  • TARSA.run!(sim)
  • TARSA.save_results(...)

This is the API used by the new ERA5 tutorial and it is the clearest way to start a new case. For signatures, keyword defaults, and return types, see the API reference.

Minimal real-meteorology example

The example below is the same quickstart script used in examples/tutorial/minimal_code.jl.

#!/usr/bin/env julia
using TARSA

# Minimal TARSA quickstart:
# - uses a small ERA5 domain around Etna for 2024-04-01 to 2024-04-02,
# - reuses cached files from examples/tutorial/data or downloads them from Copernicus CDS,
# - injects a simple point source near Etna,
# - runs the explicit transport solver,
# - saves the result to examples/tutorial/out/quickstart_etna.nc.
# Optional: set Copernicus CDS credentials here instead of ~/.cdsapirc
# ENV["CDSAPI_URL"] = "https://cds.climate.copernicus.eu/api"
# ENV["CDSAPI_KEY"] = "<uid>:<api-token>"


levels_file, surface_file, _, _ = TARSA.prepare_input_data(
    34.0, 40.0,  # lat_min, lat_max
    12.0, 18.0,  # lon_min, lon_max
    2024,        # year
    4,           # month
    [1, 2];      # days
    download_cams=false,
    data_dir=joinpath(@__DIR__, "data"),
)
input = TARSA.load_input_data(levels_file, surface_file)
emissions = TARSA.zero_emissions(input)
TARSA.add_point_source!(
    emissions,
    input,
    15.0,   # source_lon
    37.75;  # source_lat
    rate_kg_s=8.0, injection_height=2500.0, sigma_z=600.0,
)
mixing_ratio = TARSA.run!(TARSA.build_simulation(
    input,
    emissions;
    solver=TARSA.ExplicitSolver(cfl=0.7, scheme=:dst_koren_rk3, dt=3600.0),
    lateral_bc=:neumann0,
    bottom_bc=:neumann0,
))

output_file = joinpath(@__DIR__, "out", "quickstart_etna.nc")
rm(output_file; force=true)
TARSA.save_results(
    output_file,
    input,
    mixing_ratio,
    emissions;
    template_file=levels_file,
    variables=["concentration"],
    save_emissions=false,
)

This is the main TARSA run pattern.

Step-by-step meaning

Prepare meteorology

TARSA.prepare_input_data(...) downloads ERA5 to local NetCDF files if they are not already present. For a pure transport case, download_cams=false is enough.

Typical outputs are:

  • ERA5 pressure-level file
  • ERA5 single-level file
  • ERA5 precipitation file

ERA5 download requires Copernicus credentials, either through ~/.cdsapirc or through the CDSAPI_URL and CDSAPI_KEY environment variables. The exact setup is described in Data Access.

Load the input fields

TARSA.load_input_data(levels_file, surface_file) converts the ERA5 files into a structured InputFields object.

That object contains:

  • u, v, w
  • temperature, humidity
  • geopotential, density
  • pbl_height
  • longitude, latitude
  • dx, dy
  • Nx, Ny, Nz, Nt

Build emissions

For a composable emissions field, start with:

emissions = TARSA.zero_emissions(input)

Then add a ground source with:

TARSA.add_ground_source!(emissions, input, lon, lat; rate_kg_s=...)

Or add an elevated / time-varying point source with:

TARSA.add_point_source!(emissions, input, lon, lat; rate_kg_s=..., injection_height=..., sigma_z=...)

For a fully custom 4D emissions field, use:

emissions = TARSA.build_custom_emissions(input) do E, input
    # Fill E[i, j, k, t] in kg/m^3/s
end

For wildfire fluxes already prepared on the ERA5 grid, use:

emissions = TARSA.build_wildfire_emissions(...)

All of these paths produce the same thing: a 4D emissions array on the model grid.

Choose a solver

The two main choices are:

  • TARSA.ExplicitSolver(...)
  • TARSA.ImplicitSolver(...)

Use the explicit solver when you want the standard high-order advection setup. Use the implicit solver for replay-style cases or when you want the more robust fully implicit path.

Build and run

TARSA.build_simulation(...) combines:

  • meteorology
  • emissions
  • boundary conditions
  • optional scavenging
  • optional chemistry
  • solver settings

TARSA.run!(sim) then returns the simulated 4D mixing-ratio field.

Aerosol runs

For aerosol tracers with sedimentation and deposition, keep the user-facing path:

aerosol_inputs = TARSA.load_aerosol_inputs(levels_file, precip_file; surface_file=surface_file)
lai = fill(2.0f0, input.Nx, input.Ny)

processes = TARSA.AerosolProcesses(
    sedimentation=true,
    wet_deposition=TARSA.WetDeposition(),
    dry_deposition=TARSA.DryDeposition(lai=lai),
)

sim = TARSA.build_aerosol_simulation(
    input,
    emissions;
    aerosol=TARSA.AerosolTracer(radius_m=0.11e-6, density_kg_m3=1700.0),
    aerosol_inputs=aerosol_inputs,
    processes=processes,
    solver=TARSA.ExplicitSolver(cfl=0.7, scheme=:dst_koren_rk3),
    lateral_bc=:neumann0,
    bottom_bc=:neumann0,
)

This keeps the public workflow compact:

  • load_aerosol_inputs(...) loads precipitation, cloud fields, and optionally ERA5 friction velocity
  • AerosolTracer(...) describes the particle
  • AerosolProcesses(...) turns sedimentation, wet deposition, and dry deposition on or off
  • build_aerosol_simulation(...) converts that configuration into the internal transport inputs

WetDeposition() uses belowcloud_scheme=:power_law by default. The other below-cloud options are :laakso and :wang2014.

The dry-deposition API supports the simplified fine-particle a1*u_* branch by default and also the full Zhang-type coarse/giant branches when you pass explicit DryDepositionSurface(...) presets or custom coefficient sets.

Save outputs

TARSA.save_results(...) writes standard NetCDF outputs.

The most common variables are:

  • "mixing_ratio" in kg/kg
  • "concentration" in kg/m^3
  • "mass_loading" in ug/m^3

When creating a new NetCDF output file, pass template_file=levels_file so TARSA can copy the ERA5 dimensions before appending the new variables.

Reusing existing meteorology

If the ERA5 files already exist, you can skip the download step and start from:

input = TARSA.load_input_data(levels_file, surface_file)

That is often the best pattern when running many sensitivity tests with the same meteorology.

When to use the lower-level API

Validation scripts and some older examples still use the lower-level params_model path:

  • TARSA.read_input_data(...)
  • TARSA.read_airdensity(...)
  • TARSA.run_explicit(...)
  • TARSA.run_implicit(...)

That path is still useful for internal experiments and detailed control, but it is not the best entry point for a new user.

Where to start next

If you want the clearest runnable example, go to:

  • Examples / Tutorial

If you want a larger applied workflow, browse the case folders under examples/ (e.g. the FENNEC Saharan-dust case), each with its own README describing the required data and credentials.