diff --git a/README.md b/README.md index 81e706c..bc63d13 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,133 @@ -# PROPAGATOR: An Operational Cellular-Automata Based Wildfire Simulator +# PROPAGATOR: An Operational Cellular-Automata Wildfire Simulator -This repository contains the python implementation of the PROPAGATOR wildfire simulation algorithm, developed by CIMA Research Foundation. -The package contains the core simulation engine in the `core` module, I/O utilities in the `io` module, and a command line interface (CLI) in the `cli` module. +PROPAGATOR is an operational wildfire spread model developed by +[CIMA Research Foundation](https://www.cimafoundation.org). The project couples +a Numba-accelerated cellular automata core (`propagator.core`), reusable I/O +pipelines (`propagator.io`), and a configurable CLI for stochastic +fire propagation modeling. Comprehensive documentation lives under `docs/`, covering quick starts, API reference, and +programmatic guides. -Link to the research paper: [PROPAGATOR: An Operational Cellular-Automata Based Wildfire Simulator](https://www.mdpi.com/2571-6255/3/3/26) +## Quick Start -## How to use it as a library - -Install the package using pip, poetry, uv or any other tool that can install from a git repository. +Clone the repository and create an environment with the CLI and I/O extras: ```bash -pip install git+https://github.com/CIMAFOUNDATION/propagator_sim.git +uv sync --dev --all-extras ``` -Then, you can use the `propagator` package in your python code. -This command will install the latest version from the `main` branch. It will resolve to the minimal dependencies for the core simulation engine. -If you want to use the I/O utilities or the CLI, you need to install the extra dependencies as well. +or, using plain `pip`: ```bash -pip install git+https://github.com/CIMAFOUNDATION/propagator_sim.git[io,cli] +python -m venv .venv +source .venv/bin/activate +pip install -e '.[cli,io]' ``` -You can find an example of how to use the package in the `examples/example.py` file. +This installs the PROPAGATOR package in editable mode together with the optional +extras required for raster handling, the CLI, and documentation tooling. -## How to develop +## Running Simulations -Clone this repository. Use `uv sync --dev --all-extras` to create a virtual environment and install the required dependencies. +Launch the CLI over the bundled GeoTIFF sample: ```bash -uv sync +uv run propagator \ + --config example/config.json \ + --mode geotiff \ + --dem example/dem.tif \ + --fuel example/veg.tif \ + --output results/quickstart ``` -## Launch a simulation - - -```bash -uv run propagator +See `uv run propagator --help` or `docs/cli.md` for the full argument table. + +### Programmatic API + +You can embed PROPAGATOR directly into Python workflows: + +```python +import numpy as np +from propagator.core import BoundaryConditions, FUEL_SYSTEM_LEGACY, Propagator + +dem = np.zeros((2000, 2000), dtype=np.float32) +veg = np.full_like(dem, 5, dtype=np.int32) + +sim = Propagator( + dem=dem, + veg=veg, + realizations=10, + fuels=FUEL_SYSTEM_LEGACY, + do_spotting=False, + out_of_bounds_mode="raise", +) + +ignition_mask = np.zeros_like(dem, dtype=np.uint8) +ignition_mask[dem.shape[0] // 2, dem.shape[1] // 2] = 1 + +sim.set_boundary_conditions( + BoundaryConditions( + time=0, + ignition_mask=ignition_mask, + wind_speed=np.ones_like(dem) * 40, + wind_dir=np.ones_like(dem) * 90, + moisture=np.zeros_like(dem), + ) +) + +while (next_time := sim.next_time()) is not None and sim.time <= 3600: + sim.step() + if sim.time % 600 == 0: + fire_prob = sim.compute_fire_probability() + # Persist or visualise probability grids here. ``` -See `uv run propagator --help` for command line args. +For an end-to-end script that mirrors the CLI pipeline (including loaders and +writers), see `docs/programmatic.md` or the `example/example.py` file. ## Documentation -This repo uses MkDocs with the Material theme and mkdocstrings for API reference. +The MkDocs site covers: + +- **Getting Started** (`docs/getting-started.md`): prerequisites, environment + setup, quick run instructions, and programmatic usage tips. +- **CLI Usage** (`docs/cli.md`): operating modes, flag reference, output + products, and troubleshooting. +- **Programmatic Workflow** (`docs/programmatic.md`): loader/writer pipeline + example with `propagator.io`. +- **API Reference** (`docs/reference/`): mkdocstrings pages for the core, + I/O, and Numba packages. +- **Bibliography** (`docs/bibliography.md`): peer-reviewed work describing + PROPAGATOR and its operational deployments. + +Serve the docs locally: -- Serve locally: `uv run mkdocs serve` -- Build static site: `uv run mkdocs build` +```bash +uv run mkdocs serve +``` + +Build the static site: + +```bash +uv run mkdocs build +``` -Docs live under `docs/` and are configured by `mkdocs.yml`. +## How to Contribute + +We welcome issues and pull requests! To contribute: + +1. Fork the repository and create a feature branch (`git checkout -b feat/xyz`). +2. Set up the development environment with `uv sync --dev --all-extras`. +3. Make your changes, keeping module structure and style guidelines in mind. +4. Run the quality gates before submitting: + ```bash + uv run ruff check src tests + uv run pytest -q + uv run mkdocs build + ``` +5. Commit using Conventional Commit messages (e.g., `feat(core): add wind bias`). +6. Open a pull request describing the change, verification steps, and any + relevant screenshots or artefacts. + +For major features or architectural changes, please open an issue first to +discuss the proposal. Contributors are encouraged to reference the documentation +pages above when adding or modifying features. diff --git a/docs/bibliography.md b/docs/bibliography.md new file mode 100644 index 0000000..7f3fd85 --- /dev/null +++ b/docs/bibliography.md @@ -0,0 +1,27 @@ +# Bibliography + +Key references describing PROPAGATOR’s scientific background, operational use, +and applications to prescribed fire planning. + +## Core Simulator + +- A. Trucchia, M. D’Andrea, F. Baghino, P. Fiorucci, L. Ferraris, D. Negro, A. + Gollini, and M. Severino. “Propagator: An operational cellular-automata based + wildfire simulator.” *Fire* 3(3):26, 2020. + [doi:10.3390/fire3030026](https://doi.org/10.3390/fire3030026) + +## Operational Deployments + +- A. Trucchia, M. D’Andrea, F. Baghino, N. Perello, N. Rebora, and P. Fiorucci. + “Experiences and lessons learnt in wildfire management with PROPAGATOR, an + operational cellular-automata-based wildfire simulator.” In D. Sempere-Torres, + A. Karakostas, C. Rossi, and P. Quevauviller (eds.), *Responding to Extreme + Weather Events*, chapter 3. Wiley, 2024. + [doi:10.1002/9781119741374.ch3](https://doi.org/10.1002/9781119741374.ch3) + +## Prescribed Fire Planning + +- N. Perello, A. Trucchia, F. Baghino, B. S. Asif, L. Palmieri, N. Rebora, and + P. Fiorucci. “Cellular automata-based simulators for the design of prescribed + fire plans: the case study of Liguria, Italy.” *Fire Ecology* 20(7), 2024. + [doi:10.1186/s42408-023-00239-7](https://doi.org/10.1186/s42408-023-00239-7) diff --git a/docs/cli.md b/docs/cli.md index 4f10a33..c18ad05 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,24 +1,78 @@ # CLI Usage -The CLI entrypoint is `propagator` (defined in `project.scripts`). - -Show help: +The `propagator` command drives simulations from the terminal. It validates +input files, prepares rasters, runs the propagation loop, and writes outputs on +every reporting interval. ```bash uv run propagator --help ``` -Typical usage: +## Basic Invocation ```bash uv run propagator \ - -f ./example/params.json \ - -of ./example/output \ - -tl 86400 \ - -dem ./example/dem.tif \ - -veg ./example/veg.tif + --config example/config.json \ + --mode geotiff \ + --dem example/dem.tif \ + --fuel example/fuel.tif \ + --output results/run-2025-02-19 ``` -All time-related flags (`-tl`, etc.) are expressed in seconds. +CLI arguments are powered by `pydantic-settings`; required inputs raise clear +validation errors before the simulation starts. + +## Operating Modes + +- **GeoTIFF mode** (`--mode geotiff`): supply explicit DEM (`--dem`) and fuel + (`--fuel`) GeoTIFF rasters. Use this for bespoke datasets or the bundled + quickstart sample. +- **Tiles mode** (`--mode tiles`, default): point to a directory of tiled DEM + and vegetation rasters with `--tilespath` and choose a tileset via + `--tileset`. The simulator infers the geographic window from ignition + coordinates defined in the configuration. + +Switching between modes controls which arguments are required; passing both +`--dem` and `--fuel` automatically activates GeoTIFF mode even if `--mode` is +left at the default. + +## Argument Reference + +| Flag | Type / Default | Description | +| --- | --- | --- | +| `--config PATH` | required | JSON configuration file parsed into `PropagatorConfigurationLegacy`. | +| `--fuel-config PATH` | optional | YAML file defining a custom fuel system (`fuels` mapping). | +| `--mode {tiles,geotiff}` | `tiles` | Select how static rasters are loaded (see above). | +| `--dem PATH` | required in geotiff mode | DEM GeoTIFF when running in geotiff mode. | +| `--fuel PATH` | required in geotiff mode | Fuel/vegetation GeoTIFF when running in geotiff mode. | +| `--tilespath PATH` | required in tiles mode | Base directory containing tiled rasters. | +| `--tileset NAME` | optional | Tileset to use within `tilespath` (defaults to `default`). | +| `--output PATH` | required | Destination directory; created if missing. Stores GeoTIFF, GeoJSON, and JSON outputs. | +| `--isochrones FLOAT …` | `0.5 0.75 0.9` | Probability thresholds for GeoJSON isochrone export. Repeat the flag to set multiple values. | +| `--record` | flag, default off | When enabled, saves a Rich console log in the output directory. | +| `--ignore-out-of-bounds` | flag, default off | Continue the simulation when the fire reaches the DEM boundary. | +| `--verbose` | flag, default off | Print status tables, boundary conditions, and timing information. | + +Boolean switches use implicit flags: including `--verbose`, `--record`, or +`--ignore-out-of-bounds` turns each behaviour on. + +## Output Products + +During the run, the CLI periodically writes: +- GeoTIFF rasters for fire probability, fireline intensity (mean/max), and rate + of spread (mean/max). +- GeoJSON isochrones for configured probability thresholds. +- Metadata JSON capturing CLI arguments, execution time, and summary statistics. + +Set `--record` to capture the Rich console log alongside these artefacts, which +is useful for post-run audits. + +## Troubleshooting -See `propagator_cli/args_parser.py` for all flags and their meanings. +- Missing GeoTIFFs or tiles raise validation errors before the simulation + boots; check path spelling if you hit them. +- If dependency wheels complain about PROJ/GDAL, ensure the native libraries + are installed (see [Getting Started](getting-started.md#prerequisites)). +- For reproducible runs across multiple ignitions or meteorological scenarios, + adjust `realizations`, `time_limit`, and `boundary_conditions` inside the + JSON configuration file. diff --git a/docs/getting-started.md b/docs/getting-started.md index 8b3c24a..c000147 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,32 +1,137 @@ # Getting Started -## Install +Follow these steps to install PROPAGATOR, launch your first simulation, and +inspect the generated outputs. -Using uv (recommended): +## Prerequisites +- Python 3.11 or newer +- [uv](https://docs.astral.sh/uv/) 0.4+ (recommended) or another virtualenv + manager +- PROJ/GDAL libraries available on your system (needed by `rasterio`, + `fiona`, and other I/O extras used by the CLI) + +Clone the repository and switch into the project root before running the +commands below. + +## Install Dependencies + +Using uv (installs the core library, CLI, I/O extras, and development +tooling): ```bash -uv sync --all-extras +uv sync --dev --all-extras ``` -Using pip: +Using pip (creates a virtual environment and installs the package in editable +mode with CLI + I/O extras): ```bash -python -m venv .venv && source .venv/bin/activate -pip install -e .[dev] +python -m venv .venv +source .venv/bin/activate +pip install -e '.[cli,io]' ``` -## Quick Run +If you only need the simulation engine (without CLI/I/O helpers) drop the +extras from the install command. -Run the CLI entrypoint: +## First Simulation + +The repository ships with small GeoTIFF datasets and configuration files under +`example/`. Run a deterministic simulation in GeoTIFF mode with: ```bash -uv run propagator --help +uv run propagator \ + --config example/config.json \ + --mode geotiff \ + --dem example/dem.tif \ + --fuel example/fuel.tif \ + --output results/quickstart +``` + +The command will create the `results/quickstart` directory if it does not +already exist. Time-related settings in the configuration file (for example +`time_limit` and `time_resolution`) are expressed in seconds. + +### Optional inputs +- Provide a custom fuel model with `--fuel-config example/fuel_config.yaml`. +- Switch to tiles mode by supplying `--mode tiles --tilespath + [--tileset ]` when using staged tiled rasters instead of GeoTIFFs. +- Add `--verbose` to print progress tables and boundary-condition details. +- Add `--record` to save terminal logs alongside the simulation outputs. + +## Inspect the Outputs + +After the run completes, the output directory contains GeoTIFF rasters +(`fire_probability`, `fireline_intensity_*`, `ros_*`), GeoJSON isochrones, and +metadata JSON summarising the run. Visualise the rasters with any GIS tool or +load them back into Python using `rasterio` or `geopandas`. + +## Programmatic Usage + +You can embed PROPAGATOR directly in your Python workflows when you need custom +post-processing or bespoke integration logic. The snippet below mirrors +`example/example.py` and shows the essential steps: + +```python +import numpy as np +from propagator.core import BoundaryConditions, FUEL_SYSTEM_LEGACY, Propagator + +dem = np.zeros((2000, 2000), dtype=np.float32) +veg = np.full(dem.shape, 5, dtype=np.int32) + +sim = Propagator( + dem=dem, + veg=veg, + realizations=10, + fuels=FUEL_SYSTEM_LEGACY, + do_spotting=False, + out_of_bounds_mode="raise", +) + +ignition_mask = np.zeros_like(dem, dtype=np.uint8) +ignition_mask[dem.shape[0] // 2, dem.shape[1] // 2] = 1 + +sim.set_boundary_conditions( + BoundaryConditions( + time=0, + ignition_mask=ignition_mask, + wind_speed=np.ones_like(dem) * 40, + wind_dir=np.ones_like(dem) * 90, + moisture=np.zeros_like(dem), + ) +) + +while (next_time := sim.next_time()) is not None and sim.time <= 3600: + sim.step() + if sim.time % 600 == 0: + fire_prob = sim.compute_fire_probability() + # use fire_prob in your analytics stack (save to disk, visualise, etc.) ``` -Example with sample data: +Key points: +- Provide DEM/fuel rasters as NumPy arrays; no disk I/O is required unless you + need it. +- Boundary conditions can be updated over time—compute time-dependent wind or + moisture fields before calling `set_boundary_conditions`. +- The main loop alternates between `next_time()` to schedule time steps and + `step()` to advance the simulation. At chosen intervals, derive statistics + with methods like `compute_fire_probability()` or retrieve the full + `PropagatorOutput` via `get_output()`. + +For a complete runnable notebook-style walkthrough (including Matplotlib plots), +open `example/example.py`. For a production-style pipeline that loads rasters +and writes outputs via `propagator.io`, see the [Programmatic Workflow](programmatic.md) +guide. + +## Validate the Environment + +To confirm your setup, run the automated tests and a docs build: ```bash -uv run propagator -f ./example/params.json -of ./example/output -tl 86400 -dem ./example/dem.tif -veg ./example/veg.tif +uv run pytest -q +uv run ruff check src tests +uv run mkdocs build ``` -> Time-related configuration values and CLI switches expect seconds (e.g., `-tl 86400` for 24 hours). +All commands should finish without errors: if GDAL-related wheels fail to +install, verify that your system libraries are available to `pip`/`uv`. diff --git a/docs/img/cima.png b/docs/img/cima.png new file mode 100644 index 0000000..4faabe8 Binary files /dev/null and b/docs/img/cima.png differ diff --git a/docs/img/propagator.png b/docs/img/propagator.png new file mode 100644 index 0000000..4a6c809 Binary files /dev/null and b/docs/img/propagator.png differ diff --git a/docs/index.md b/docs/index.md index b7a85da..7e57f46 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,15 +1,34 @@ -# PROPAGATOR Sim +
+ +

PROPAGATOR Sim

+

+ An operational cellular-automata wildfire simulator developed by + CIMA Research Foundation. + PROPAGATOR couples a Numba-powered propagation core with reusable I/O pipelines + and a configurable CLI for deterministic or ensemble fire forecasting. +

+ +
-PROPAGATOR is an operational cellular‑automata based wildfire simulator developed by CIMA Research Foundation. +## What's Included +- **Simulation engine**: the `propagator.core` package evolves ignition grids, applies stochastic spread models, and handles boundary conditions. +- **Data access**: helpers under `propagator.io` prepare GeoTIFFs or tiled rasters and emit GeoTIFF, GeoJSON, and JSON outputs. +- **Command line tools**: the `propagator` CLI orchestrates runs, handles configuration files, and writes time-stepped products to disk. +- **Documentation + API reference**: MkDocs pages provide operator guides, while mkdocstrings renders the public Python API. -- Fast raster-based propagation core -- CLI for running simulations over DEM/vegetation layers -- Pydantic-based configuration and IO helpers - -Use the left navigation to explore usage and API details. +## Typical Workflow +1. Prepare a JSON configuration describing ignition geometry, simulation horizon, and model toggles (see `example/config*.json`). +2. Supply static data—either as GeoTIFF DEM/vegetation layers or a tileset directory—and optional YAML fuel definitions. +3. Launch the run via the CLI (`uv run propagator …`), enabling verbose or recording modes for richer logging. +4. Inspect the generated rasters, isochrones, and metadata in the configured output directory. ## Quick Links - -- [Getting started](getting-started.md): installation and a first run -- [CLI](cli.md): usage: flags and examples -- [API](reference/index.md): reference: Python modules and types +- [Getting started](getting-started.md): prerequisites, install, first simulation, and programmatic API tips +- [Programmatic Workflow](programmatic.md): end-to-end scripting with loaders and writers +- [CLI](cli.md): command options, modes, and logging +- [API](reference/index.md): Python package and Numba backend reference diff --git a/docs/javascripts/cima-brand.js b/docs/javascripts/cima-brand.js new file mode 100644 index 0000000..efc3244 --- /dev/null +++ b/docs/javascripts/cima-brand.js @@ -0,0 +1,8 @@ +document.addEventListener("DOMContentLoaded", () => { + const logoLink = document.querySelector(".md-header__button.md-logo"); + if (logoLink) { + logoLink.href = "https://www.cimafoundation.org"; + logoLink.target = "_blank"; + logoLink.rel = "noopener"; + } +}); diff --git a/docs/programmatic.md b/docs/programmatic.md new file mode 100644 index 0000000..e796972 --- /dev/null +++ b/docs/programmatic.md @@ -0,0 +1,131 @@ +# Programmatic Workflow + +This guide walks through a richer example that mirrors the CLI pipeline but is +implemented entirely in Python. It combines pieces from `propagator.core` and +`propagator.io` to load rasters, configure simulations, and write artefacts on +each reporting interval. + +## Scenario Overview + +We will: + +1. Parse a JSON configuration for ignition geometry and model options. +2. Load DEM and fuel rasters from GeoTIFF files using the high-level loader. +3. Instantiate the simulator with a custom fuel system. +4. Generate raster, GeoJSON, and metadata outputs with the writer utilities. + +The example uses the datasets under `example/` so you can run it without +additional downloads. + +## Complete Script + +```python +from pathlib import Path + +from pyproj import CRS + +from propagator.core import FUEL_SYSTEM_LEGACY, Propagator +from propagator.io.configuration import PropagatorConfigurationLegacy +from propagator.io.loader.geotiff import PropagatorDataFromGeotiffs +from propagator.io.writer import ( + GeoTiffWriter, + IsochronesGeoJSONWriter, + MetadataJSONWriter, + OutputWriter, +) + +ROOT = Path(__file__).resolve().parent +config_path = ROOT / "config.json" +dem_path = ROOT / "dem.tif" +fuel_path = ROOT / "fuel.tif" +output_dir = ROOT / "output-programmatic" + +cfg = PropagatorConfigurationLegacy.model_validate_json(config_path.read_text()) + +loader = PropagatorDataFromGeotiffs( + dem_file=str(dem_path), + veg_file=str(fuel_path), +) +dem = loader.get_dem() +veg = loader.get_veg() +geo_info = loader.get_geo_info() + +sim = Propagator( + dem=dem, + veg=veg, + realizations=cfg.realizations, + fuels=FUEL_SYSTEM_LEGACY, + do_spotting=cfg.do_spotting, + out_of_bounds_mode="ignore", + p_time_fn=cfg.p_time_fn, + p_moist_fn=cfg.p_moist_fn, +) + +writers = OutputWriter( + raster_writer=GeoTiffWriter( + start_date=cfg.init_date, + output_folder=output_dir, + geo_info=geo_info, + dst_crs=CRS.from_epsg(4326), + raster_variables_mapping={ + "fire_probability": lambda out: out.fire_probability, + "ros_mean": lambda out: out.ros_mean, + "ros_max": lambda out: out.ros_max, + }, + ), + metadata_writer=MetadataJSONWriter( + start_date=cfg.init_date, + output_folder=output_dir, + prefix="metadata", + ), + isochrones_writer=IsochronesGeoJSONWriter( + start_date=cfg.init_date, + output_folder=output_dir, + prefix="isochrones", + thresholds=[0.3, 0.6, 0.9], + geo_info=geo_info, + dst_crs=CRS.from_epsg(4326), + ), +) + +non_vegetated = sim.fuels.get_non_vegetated() +for bc in cfg.get_boundary_conditions(geo_info, non_vegetated): + sim.set_boundary_conditions(bc) + +while True: + next_time = sim.next_time() + if next_time is None or next_time > cfg.time_limit: + break + + sim.step() + if sim.time % cfg.time_resolution == 0: + output = sim.get_output() + writers.write_output(output) + +final_output = sim.get_output() +print(f"Final simulated time: {final_output.time} seconds") +``` + +### Key Elements + +- **Configuration parsing**: `PropagatorConfigurationLegacy.model_validate_json` + applies the same schema enforced by the CLI, ensuring you reuse existing + validation. +- **Raster loading**: `PropagatorDataFromGeotiffs` handles `rasterio` opening and + returns NumPy arrays along with spatial metadata in `geo_info`. +- **Output orchestration**: `OutputWriter` coordinates the specialized writers. + You can add or remove raster variables by editing the `raster_variables_mapping` + dictionary. +- **Simulation loop**: keep calling `next_time()` until it returns `None` or you + exceed `time_limit`, then advance with `step()`. Every reporting interval, + `get_output()` captures derived stats and raw fields ready for persistence. + +### Going Further + +- Swap `PropagatorDataFromGeotiffs` for `PropagatorDataFromTiles` when working + with tiled rasters and dynamic midpoints. +- Load a custom fuel system using `fuels_from_yaml` or programmatically (see `cli.main`) if the + legacy fuel system does not match your fuel types. +- Instead of the bundled writers, feed `PropagatorOutput` into your own + analytics pipeline—store arrays in cloud buckets, stream summaries to a + dashboard, or trigger scheduling logic for subsequent model runs. diff --git a/docs/reference/index.md b/docs/reference/index.md index 2bf959f..bf5aaec 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -1,14 +1,12 @@ # API Reference -Auto-generated reference for the public Python API. +Auto-generated documentation for the public Python APIs. Each section links to +mkdocstrings pages generated from the implementations under `src/`. -- Packages covered: +- [propagator core](propagator.md): high-level simulation interfaces and + scheduler utilities. +- [propagator io](io.md): data loaders, writers, and shared I/O protocols. +- [numba backend](numba.md): fast kernels and helper utilities powering the + simulation engine. - 1. [propagator](propagator.md) - - 2. [numba backend](numba.md) - - -- Pages are generated at build time from source under `src/`. - -Use the sidebar to navigate modules and subpackages. +Use the sidebar or the links above to explore additional submodules. diff --git a/docs/reference/io.md b/docs/reference/io.md new file mode 100644 index 0000000..bc0b028 --- /dev/null +++ b/docs/reference/io.md @@ -0,0 +1,27 @@ +# propagator.io + +The `propagator.io` package wraps raster loading routines and writer utilities +used by both the CLI and programmatic workflows. The sections below surface the +public classes and protocols that are exported via `propagator.io.__all__`. + +## Public Shortcuts + +::: propagator.io + +## Loaders + +::: propagator.io.loader.protocol + +::: propagator.io.loader.geotiff + +::: propagator.io.loader.tiles + +## Writers + +::: propagator.io.writer.protocol + +::: propagator.io.writer.raster_geotiff + +::: propagator.io.writer.metadata_json + +::: propagator.io.writer.isochrones_geojson diff --git a/docs/reference/numba.md b/docs/reference/numba.md index b3a006e..21f3151 100644 --- a/docs/reference/numba.md +++ b/docs/reference/numba.md @@ -1,7 +1,21 @@ -# NUMBA Backend +# propagator.core.numba + +Numba-accelerated kernels, models, and helper functions backing the simulation +engine. Use these interfaces when you need to customise the low-level spread +behaviour or integrate new stochastic components. + +## Public Facade ::: propagator.core.numba -::: propagator.core.numba.propagation +## Fuel and Model Definitions + +::: propagator.core.numba.models + +## Probability and Rate Functions ::: propagator.core.numba.functions + +## Propagation Kernels + +::: propagator.core.numba.propagation diff --git a/docs/reference/propagator.md b/docs/reference/propagator.md index b30d7e1..088bf32 100644 --- a/docs/reference/propagator.md +++ b/docs/reference/propagator.md @@ -1,5 +1,21 @@ -# Propagator Module +# propagator.core + +High-level simulation primitives and facades for running PROPAGATOR from Python. +The sections below cover the public API exposed by `propagator.core` along with +the supporting data models and scheduling helpers. + +## Public Facade ::: propagator.core +## Data Models + +::: propagator.core.models + +## Simulator Implementation + +::: propagator.core.propagator + +## Scheduler Helpers + ::: propagator.core.scheduler diff --git a/docs/stylesheets/cima-theme.css b/docs/stylesheets/cima-theme.css new file mode 100644 index 0000000..83e45af --- /dev/null +++ b/docs/stylesheets/cima-theme.css @@ -0,0 +1,131 @@ +:root { + --md-primary-fg-color: #002d4b; + --md-primary-fg-color--light: #1f4f6e; + --md-primary-fg-color--dark: #001829; + + --md-accent-fg-color: #dd7600; + --md-accent-fg-color--light: #f29b3d; + --md-accent-fg-color--dark: #a85400; + --md-accent-fg-color--transparent: rgba(221, 118, 0, 0.18); + + --md-default-bg-color: #f5f7fa; + --md-default-fg-color: #1f2d3a; +} + +.md-header, +.md-tabs { + background-color: var(--md-primary-fg-color); +} + +.md-header__title { + font-weight: 600; + letter-spacing: 0.04em; +} + +.md-header__button.md-logo img { + height: 3.6rem; + width: auto; +} + +.md-main { + background: var(--md-default-bg-color); +} + +.md-nav__item .md-nav__link { + font-weight: 500; +} + +.md-nav__item .md-nav__link--active, +.md-nav__item .md-nav__link:focus, +.md-nav__item .md-nav__link:hover { + color: var(--md-accent-fg-color); +} + +.md-footer { + background-color: var(--md-primary-fg-color--dark); +} + +.hero { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 1.75rem; + padding: 2.5rem; + margin-bottom: 3rem; + border-radius: 20px; + background: linear-gradient(140deg, #002d4b 0%, #13496b 55%, #021a2c 100%); + color: #f5fbff; + box-shadow: 0 18px 40px rgba(0, 45, 75, 0.25); +} + +.hero__logo { + width: 150px; + max-width: 60%; + border-radius: 18px; + box-shadow: 0 16px 32px rgba(0, 0, 0, 0.3); + border: 2px solid rgba(255, 255, 255, 0.2); +} + +.hero__title { + margin: 0; + font-size: clamp(2.8rem, 5vw, 4rem); + color: #ffffff; +} + +.hero__lead { + margin: 0; + font-size: 1.1rem; + line-height: 1.65; + color: rgba(245, 251, 255, 0.9); +} + +.hero__lead a { + color: #ffffff; + text-decoration: underline; +} + +.hero__actions { + display: flex; + flex-wrap: wrap; + gap: 1rem; +} + +.hero__actions .md-button { + font-weight: 600; + letter-spacing: 0.02em; +} + +.hero__actions .md-button--primary { + background-color: var(--md-accent-fg-color); + color: #0e1a24; +} + +.hero__actions .md-button--primary:hover { + background-color: var(--md-accent-fg-color--dark); + color: #0e1a24; +} + +.hero__actions .md-button:not(.md-button--primary) { + color: #f5fbff; + border-color: rgba(255, 255, 255, 0.35); +} + +.hero__actions .md-button:not(.md-button--primary):hover { + border-color: rgba(255, 255, 255, 0.7); + color: #ffffff; +} + +@media screen and (max-width: 640px) { + .hero { + padding: 1.75rem; + gap: 1.35rem; + } + + .hero__logo { + width: 120px; + } + + .hero__actions { + gap: 0.75rem; + } +} diff --git a/mkdocs.yml b/mkdocs.yml index e1dfa4b..71dc592 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,6 +5,7 @@ site_url: "" theme: name: material + logo: img/cima.png features: - navigation.sections - navigation.indexes @@ -19,8 +20,14 @@ extra: nav: - Home: index.md - Getting Started: getting-started.md + - Programmatic Workflow: programmatic.md - CLI Usage: cli.md - - API Reference: reference/index.md + - API Reference: + - Overview: reference/index.md + - Core: reference/propagator.md + - I/O: reference/io.md + - Numba Backend: reference/numba.md + - Bibliography: bibliography.md plugins: @@ -46,3 +53,9 @@ plugins: show_signature: true merge_init_into_class: true show_submodules: false # keep pages focused unless you want them listed + +extra_css: + - stylesheets/cima-theme.css + +extra_javascript: + - javascripts/cima-brand.js diff --git a/src/propagator/cli/console.py b/src/propagator/cli/console.py index a04f98b..3f6df09 100644 --- a/src/propagator/cli/console.py +++ b/src/propagator/cli/console.py @@ -138,6 +138,7 @@ def status_propagator_msg( init_date: datetime, time: int, stats: PropagatorStats, + *, verbose: bool = False, ) -> None: """ @@ -155,21 +156,25 @@ def status_propagator_msg( "%Y-%m-%d %H:%M:%S" ) msg = ( - f"Time: {timedelta(seconds=time)!s:>8} | " - f"Date: {date_str} | " - f"Active: {stats.n_active:>3} | " - f"Mean area: {(stats.area_mean / 10000):>7.2f} ha | " + f"Time: {format_timedelta(timedelta(seconds=time))!s:>9} | " + + (f"Date: {date_str} | " if verbose else "") + + f"Active: {stats.n_active:>3} | " + + f"Mean area: {(stats.area_mean / 10000):>7.2f} ha" ) if verbose: msg += ( - f"Area 50%: {(stats.area_50 / 10000):>7.2f} ha | " + f" | Area 50%: {(stats.area_50 / 10000):>7.2f} ha | " f"Area 75%: {(stats.area_75 / 10000):>7.2f} ha | " f"Area 90%: {(stats.area_90 / 10000):>7.2f} ha" ) get_console().print(msg) -# ---------- printers ---------- +def format_timedelta(td: timedelta) -> str: + total_seconds = int(td.total_seconds()) + hours, remainder = divmod(total_seconds, 3600) + minutes, seconds = divmod(remainder, 60) + return f"{hours:02}:{minutes:02}:{seconds:02}" def _geom_to_custom_str(geom: Any) -> str: diff --git a/src/propagator/cli/main.py b/src/propagator/cli/main.py index a1d9126..ad74d89 100644 --- a/src/propagator/cli/main.py +++ b/src/propagator/cli/main.py @@ -319,9 +319,9 @@ def main() -> None: status_propagator_msg( cfg.init_date, - simulator.time, + output.time, output.stats, - cli.verbose, + verbose=cli.verbose, ) writer.write_output(output) diff --git a/src/propagator/core/propagator.py b/src/propagator/core/propagator.py index 6604e75..cabec0b 100644 --- a/src/propagator/core/propagator.py +++ b/src/propagator/core/propagator.py @@ -548,7 +548,7 @@ def get_output(self) -> PropagatorOutput: stats = self.compute_stats(fire_probability) return PropagatorOutput( - time=self.time, + time=int(self.time), fire_probability=fire_probability, ros_mean=ros_mean, ros_max=ros_max,