Quickstart

Run your first Josh simulation with joshpy in under 5 minutes.

1. Install joshpy

pip install joshpy[all]

2. Run a Simulation

joshpy’s SweepManager is the standard way to run simulations — even for single runs. It handles execution, result loading, and DuckDB registry tracking in one workflow:

from pathlib import Path
from joshpy.jobs import JobConfig
from joshpy.sweep import SweepManager
from joshpy.cli import JoshCLI
from joshpy.jar import JarMode

config = JobConfig(
    source_path=Path("../../examples/quickstart.josh"),
    simulation="Main",
    replicates=1,
)

manager = (
    SweepManager.builder(config)
    .with_registry(":memory:", experiment_name="quickstart")
    .with_cli(JoshCLI(josh_jar=JarMode.DEV))
    .build()
)

results = manager.run()
print(f"Success: {results.succeeded}, Failed: {results.failed}")

if results.failed > 0:
    for job, result in results:
        if not result.success:
            raise RuntimeError(f"Simulation failed:\n{result.stderr}")
Running 1 jobs (1 total replicates)
[1/1] Running (local): {}
  [OK] Completed successfully
Completed: 1 succeeded, 0 failed
Success: 1, Failed: 0

3. Load and Query Results

load_results() discovers output CSVs and imports them into the DuckDB registry. Then query with SQL or convenience methods:

manager.load_results()

# What's in the registry?
summary = manager.registry.get_data_summary()
print(summary)
Loading patch results from: /tmp/quickstart_output.csv
  Loaded 34782 rows from quickstart_output.csv

Results:
  Jobs in sweep: 1
  Jobs with results loaded: 1
  Total rows loaded: 34782
Registry Data Summary
========================================
Sessions: 1
Configs:  1
Runs:     1
Rows:     34,782

Variables: averageAge, averageHeight, treeCount
Entity types: patch
Parameters: (none)
Steps: 0 - 10
Replicates: 0 - 0
Spatial extent: lon [-115.39, -114.40], lat [33.40, 33.70]
# Query results as a DataFrame
df = manager.query("averageHeight")
df.head(10)
step mean std ci_low ci_high n_replicates
0 0 0.498607 NaN NaN NaN 1
1 1 0.995242 NaN NaN NaN 1
2 2 1.494352 NaN NaN NaN 1
3 3 1.993218 NaN NaN NaN 1
4 4 2.493141 NaN NaN NaN 1
5 5 2.990562 NaN NaN NaN 1
6 6 3.490755 NaN NaN NaN 1
7 7 3.992197 NaN NaN NaN 1
8 8 4.493923 NaN NaN NaN 1
9 9 4.994910 NaN NaN NaN 1

4. Visualize

from joshpy.diagnostics import SimulationDiagnostics

diag = SimulationDiagnostics(manager.registry)
diag.plot_timeseries(
    "averageHeight",
    run_hash=manager.job_set.jobs[0].run_hash,
    title="Tree Growth Over Time",
)
(a) Average tree height increases over time
(b)
Figure 1

What Just Happened?

The quickstart.josh simulation:

  1. Creates a grid spanning ~30km x 100km in the Mojave Desert
  2. Places 10 trees in each patch (grid cell)
  3. Each tree grows randomly 0-1 meters per timestep
  4. Exports average height and tree count at each step

View the simulation source:

print(Path("../../examples/quickstart.josh").read_text())
# Quickstart simulation - a minimal Josh example
# Simulates tree growth over 10 timesteps on a small grid

start simulation Main

  grid.size = 1000 m
  grid.low = 33.7 degrees latitude, -115.4 degrees longitude
  grid.high = 34.0 degrees latitude, -116.4 degrees longitude
  grid.patch = "Default"

  steps.low = 0 count
  steps.high = 10 count

  exportFiles.patch = "file:///tmp/quickstart_output.csv"

end simulation

start patch Default

  ForeverTree.init = create 10 count of ForeverTree

  export.treeCount.step = count(ForeverTree)
  export.averageAge.step = mean(ForeverTree.age)
  export.averageHeight.step = mean(ForeverTree.height)

end patch

start organism ForeverTree

  age.init = 0 year
  age.step = prior.age + 1 year

  height.init = 0 meters
  height.step = prior.height + sample uniform from 0 meters to 1 meters

end organism

start unit year

  alias years
  alias yr
  alias yrs

end unit

What’s Next?

Feature Tutorial
Parameter Sweeps SweepManager Workflow
Project Organization Project Organization — directory layout, .josh.j2 templates, data helpers
External Data Preprocessing and Data Sweeps
Analysis Analysis & Visualization
Best Practices Registry design, error diagnosis

Cleanup

manager.cleanup()
manager.close()