diff --git a/CHANGELOG.md b/CHANGELOG.md index f2389b4..2b018b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,10 @@ history, so they summarise each release rather than list every change. The - `plot[...;filename=*.asc]` writes a valid ESRI ASCII grid: one row per y, north first, at full precision. It used to write one row per x and round values to six significant digits. +- Documentation: removed `defaultFuelType`, which nothing reads, and the + `Kcurv`/`beta` columns from the WindDriven examples, which only use + `vv_coeff`. `minSpeed`, `relax` and `smoothing` now describe what the code + does, and Windows pip users are pointed to WSL. ## [v2.6.0] — 2026-10-26 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48a1812..be44e2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,6 +62,10 @@ We welcome code contributions, from bug fixes to new features. 5. **Make Changes:** Implement your code changes, following existing coding style and conventions where possible. + * Changes to propagation or flux models and their physics start as an issue: the maintainers decide those. + * A change that moves simulation results goes in its own PR, and at the top of its CHANGELOG entry. + * Never regenerate a `.ref` file to make a test pass. + * Report security problems through [private vulnerability reporting](https://github.com/forefireAPI/forefire/security/advisories/new), never in a public issue. 6. **Add Tests (if applicable):** For new features or significant bug fixes, please add corresponding tests or update existing ones. See [TESTING.md](TESTING.md) for what each suite covers, how to run it, and which ones CI validates. Ensure all tests pass locally. @@ -70,7 +74,10 @@ We welcome code contributions, from bug fixes to new features. cmake -S . -B build && cmake --build build -j ctest --test-dir build --output-on-failure - # The script-driven suites (runff, runANN) + # Regression check: compares a real case against the .ref files + cd tests/runff && bash ff-run.bash + + # Every script-driven suite your environment allows cd tests && bash run.bash ``` 7. **Record the Change:** @@ -91,7 +98,7 @@ We welcome code contributions, from bug fixes to new features. ``` 10. **Open a Pull Request (PR):** - Go to the `forefireAPI/forefire` repository on GitHub and open a Pull Request from your branch to the `dev` branch (or `master` if that's the target). + Go to the `forefireAPI/forefire` repository on GitHub and open a Pull Request from your branch to the `dev` branch. * Provide a clear description of the changes in the PR. * Link any relevant issues (e.g., "Fixes #123"). * Ensure the CI checks pass on your PR. The maintainers will review your code, provide feedback, and merge it once approved. diff --git a/README.md b/README.md index 5e33a1f..88dc523 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ import pyforefire as forefire from pyforefire.helpers import printToPathe ff = forefire.ForeFire() -ff["fuelsTable"] = "Index;vv_coeff;Kcurv;beta\n1;1.0;1.0;1.0" -ff["defaultFuelType"] = 1 +ff["fuelsTable"] = "Index;vv_coeff\n1;1.0" ff["propagationModel"] = "WindDriven" ff.execute("FireDomain[sw=(0,0,0);ne=(4000,4000,0);t=0]") diff --git a/TESTING.md b/TESTING.md index 30e259a..0e04817 100644 --- a/TESTING.md +++ b/TESTING.md @@ -40,6 +40,10 @@ The primary physics regression test, validated in CI by `main.yml` and `macos.ym 2. Navigate to the test directory: `cd tests/runff` 3. Execute the test script: `bash ff-run.bash` +The test data and `.ref` files are stored in Git LFS. Fetch them first with +`git lfs pull --include tests/runff` (or `git lfs pull` for every case). +Configure checks the LFS files; `-DFOREFIRE_CHECK_LFS=OFF` skips that check. + **Test Logic:** The `ff-run.bash` script: diff --git a/app/forefire/commands.md b/app/forefire/commands.md index 0406c80..1d8d630 100644 --- a/app/forefire/commands.md +++ b/app/forefire/commands.md @@ -48,12 +48,15 @@ std::string commandHelp = R"( ## startFire startFire[loc=(x,y,z)|lonlat=(lon,lat,z);t=seconds|date=YYYY-MM-DDTHH:MM:SSZ] - Creates the smallest possible triangular fire front at the specified location and time + startFire[geojson=] + Creates the smallest possible triangular fire front at the specified location and time, or a front along a GeoJSON polygon Example: startFire[loc=(0.0,0.0,0.0);t=0.] + Example: startFire[geojson=ignition.geojson] Arguments: - 'loc': Starting location of the fire (coordinates x,y,z) - 'lonlat': WGS coordinates of the ignition point (lon,lat,z); all three values are required - - 't': Time when the fire is started (in seconds or as an absolute ISO GMT date); + - 't': Time when the fire is started (in seconds or as an absolute ISO GMT date) + - 'geojson': GeoJSON file or inline text (Polygon/MultiPolygon in lon,lat,z); a top-level "valid_at" date sets the time; ## step step[dt=seconds] diff --git a/bindings/python/README.md b/bindings/python/README.md index a55725b..4cb79d0 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -44,9 +44,10 @@ If you need either, build from source (below). ### Building from source -Any platform without a published wheel — Windows, musl-based Linux, or an -unusual architecture — falls back to compiling the sdist, which needs a C++ -compiler, CMake ≥ 3.15, and the NetCDF C and legacy C++4 libraries: +On Linux or macOS without a published wheel (musl-based Linux or an unusual +architecture), pip compiles the sdist, which needs a C++ compiler, CMake ≥ 3.18, +and the NetCDF C and legacy C++4 libraries. Native Windows is not supported; +use WSL. ```bash # Debian/Ubuntu diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md index 80c528e..4962a53 100644 --- a/bindings/wasm/README.md +++ b/bindings/wasm/README.md @@ -8,8 +8,8 @@ This is an experimental build, not a supported one yet. It answers the three questions the issue left open: does it link, does it run, how big is it. `.github/workflows/wasm.yml` builds the module and runs `smoke.mjs` on every -pull request, and `.github/workflows/wasm-pages.yml` publishes the browser -demo to GitHub Pages on every push to `dev`. The `.wasm` is built in CI rather +pull request, and the same workflow publishes the browser demo to GitHub Pages +on every push to `dev`. The `.wasm` is built in CI rather than committed: it is a megabyte of generated output, and a stale binary sitting next to live sources is worse than a two minute build. diff --git a/docs/source/reference/commands.rst b/docs/source/reference/commands.rst index 5329f18..b29c66e 100644 --- a/docs/source/reference/commands.rst +++ b/docs/source/reference/commands.rst @@ -123,14 +123,16 @@ startFire .. code-block:: none startFire[loc=(x,y,z)|lonlat=(lon,lat,z);t=seconds|date=YYYY-MM-DDTHH:MM:SSZ] + startFire[geojson=] -Ignites a minimal clockwise triangular fire front (3 ``FireNode`` markers) at the given location and time. +Ignites a minimal clockwise triangular fire front (3 ``FireNode`` markers) at the given location and time, or a front along a GeoJSON polygon. **Arguments:** * ``loc=(x,y,z)``: Ignition point in Cartesian domain coordinates (meters). * ``lonlat=(lon,lat,z)``: Ignition point in WGS84 coordinates (longitude, latitude, elevation). All three components are required (``lonlat=(lon,lat)`` is ignored). * ``t=seconds`` or ``date=YYYY-MM-DDTHH:MM:SSZ``: Ignition time in seconds or ISO 8601 UTC format. +* ``geojson=``: Path to a GeoJSON file, or the GeoJSON text inline between triple quotes. The ``Polygon`` or ``MultiPolygon`` coordinates are ``[lon, lat, z]``. A top-level ``"valid_at"`` date, if present, sets the ignition time. See ``tests/runff/rungeojson.ff``. **Example:** @@ -138,6 +140,7 @@ Ignites a minimal clockwise triangular fire front (3 ``FireNode`` markers) at th startFire[loc=(5000,5000,0);t=0] startFire[lonlat=(9.0,42.0,0);date=2024-07-15T10:00:00Z] + startFire[geojson=ignition.geojson] .. _cmd-step: diff --git a/docs/source/reference/parameters.rst b/docs/source/reference/parameters.rst index 0360ebb..4e407d0 100644 --- a/docs/source/reference/parameters.rst +++ b/docs/source/reference/parameters.rst @@ -32,7 +32,7 @@ propagationSpeedAdjustmentFactor minSpeed ~~~~~~~~ -* **Description:** Minimum propagation speed floor (in m/s) enforced when advancing a ``FireNode``. +* **Description:** A ``FireNode`` whose speed (in m/s) is at or below this value stops advancing. It is a stopping threshold, not a floor on the speed. * **Default:** ``0.005`` maxSpeed @@ -111,12 +111,12 @@ curvatureScheme smoothing ~~~~~~~~~ -* **Description:** Smoothing weight applied during normal vector computation. +* **Description:** Read but not used by the current node update. * **Default:** ``1`` relax ~~~~~ -* **Description:** Relaxation factor (:math:`0\text{–}1`) used when updating node normal vectors and front depth. +* **Description:** Relaxation factor (:math:`0\text{–}1`) that blends a node's previous speed and front depth with the newly computed ones. * **Default:** ``0.5`` frontDepthComputation diff --git a/docs/source/user_guide/ensembles.rst b/docs/source/user_guide/ensembles.rst index edc9d00..0ae50c6 100644 --- a/docs/source/user_guide/ensembles.rst +++ b/docs/source/user_guide/ensembles.rst @@ -30,8 +30,7 @@ against a ``pip``-installed ForeFire. L = 4000.0 def setup(ff): - ff["fuelsTable"] = "Index;vv_coeff;Kcurv;beta\n1;1.0;1.0;1.0" - ff["defaultFuelType"] = 1. + ff["fuelsTable"] = "Index;vv_coeff\n1;1.0" ff["windReductionFactor"] = 1.0 ff["propagationModel"] = "WindDriven" ff.execute(f"FireDomain[sw=(0,0,0);ne=({L},{L},0);t=0]") diff --git a/docs/source/user_guide/forefire_script.rst b/docs/source/user_guide/forefire_script.rst index 0fe3cba..7735352 100644 --- a/docs/source/user_guide/forefire_script.rst +++ b/docs/source/user_guide/forefire_script.rst @@ -31,9 +31,9 @@ Grammar & Syntax Rules .. code-block:: none - setParameter[fuelsTable="""Index;vv_coeff;Kcurv;beta - 1;1.0;1.0;1.0 - 2;0.3;1.0;1.0"""] + setParameter[fuelsTable="""Index;vv_coeff + 1;1.0 + 2;0.3"""] 5. **Parameter Substitution** (``*param*``) **and Protected Values** (``!``): diff --git a/docs/source/user_guide/fuels_and_models.rst b/docs/source/user_guide/fuels_and_models.rst index 15c625e..a6be58f 100644 --- a/docs/source/user_guide/fuels_and_models.rst +++ b/docs/source/user_guide/fuels_and_models.rst @@ -37,7 +37,7 @@ Model Families and Their Fuel Columns * - ``Iso`` - **None.** Spreads at the constant speed given by ``setParameter[Iso.speed=0.5]`` (m/s) in all directions. * - ``WindDriven`` - - ``Index;vv_coeff;Kcurv;beta`` (idealized wind-driven model used in :doc:`python_arrays` and :doc:`ensembles`). + - ``Index;vv_coeff``: the rate of spread is ``vv_coeff × normal wind`` (idealized wind-driven model used in :doc:`python_arrays` and :doc:`ensembles`). * - ``Rothermel``, ``BalbiNov2011``, ``Balbi2020``, ``Balbi2015`` - The standard 23-column Rothermel/Balbi fuel table detailed in :ref:`rothermel-fuel-file` below. * - ``RothermelAndrews2018`` diff --git a/docs/source/user_guide/mesonh.rst b/docs/source/user_guide/mesonh.rst index ee88fc7..c798e74 100644 --- a/docs/source/user_guide/mesonh.rst +++ b/docs/source/user_guide/mesonh.rst @@ -80,6 +80,7 @@ While it runs, open ``http://localhost:8080/mnh3d.html``. The page displays the terrain, fuel, fire perimeter, plume top and surface wind. The browser needs internet access to load its JavaScript dependencies. -This is a live view of the calculation: it does not provide a replay or -fast-forward control. Use one viewer tab at a time. For comparisons of +The page follows the run live. Once it has steps to show, a Timeline slider +lets you scrub or play them back. For this bundled case, opening the page +after the run replays the steps saved in ``ForeFire/Outputs`` and ``MODEL2``. Use one viewer tab at a time. For comparisons of simulation outputs, leave the viewer closed, as explained in the guide. diff --git a/docs/source/user_guide/python_arrays.rst b/docs/source/user_guide/python_arrays.rst index ee0682f..84c1143 100644 --- a/docs/source/user_guide/python_arrays.rst +++ b/docs/source/user_guide/python_arrays.rst @@ -45,8 +45,7 @@ against a ``pip``-installed ForeFire. # Fuel table, inline — no CSV file needed. The columns depend on the # propagation model: the WindDriven model used here only needs vv_coeff # (see "Choosing a fuel table" below). - ff["fuelsTable"] = "Index;vv_coeff;Kcurv;beta\n1;1.0;1.0;1.0\n2;0.3;1.0;1.0" - ff["defaultFuelType"] = 1. + ff["fuelsTable"] = "Index;vv_coeff\n1;1.0\n2;0.3" # Solver parameters. for key, value in { @@ -122,7 +121,7 @@ The columns of ``fuelsTable`` are read by the propagation model, so they change with the model you select: * ``WindDriven`` — a minimal table with ``vv_coeff`` (the rate of spread is - ``vv_coeff × normal wind``), plus ``Kcurv`` and ``beta``. Convenient for + ``vv_coeff × normal wind``). Convenient for idealized and teaching cases. * ``Rothermel``, ``BalbiNov2011``, ``Balbi2015`` and the other physical models — the full fuel description in ``fuels.csv``. See diff --git a/tests/README.md b/tests/README.md index 855fc5b..9ee7982 100644 --- a/tests/README.md +++ b/tests/README.md @@ -102,7 +102,8 @@ are demonstrations of the API rather than tests of the physics. compares ForeFire against a FARSITE case, and needs `flatland.lcp`, which is not in the repository — `python/README.md` has the download URL. -Three test scripts sit here too, and `run.bash` runs none of them: +Eight `test_*.py` scripts sit here too, and `run.bash` runs only +`test_validate.py`. `python/README.md` covers them all; the main ones: | File | What it checks | Where it runs | | --- | --- | --- | diff --git a/tests/python/README.md b/tests/python/README.md index 17ec1af..2b83c62 100644 --- a/tests/python/README.md +++ b/tests/python/README.md @@ -3,7 +3,8 @@ Everything here needs the `pyforefire` module: either a build configured with `-DFOREFIRE_BUILD_PYTHON=ON`, or `pip install forefire`. -`../run.bash` runs only the first two, through `$PYTHONEXE`. +`../run.bash` runs only the first two examples and `test_validate.py`, through +`$PYTHONEXE`. ## `percolation.py` @@ -35,8 +36,8 @@ The weather it uses, `flatland_3mph0deg7hr.raws`, *is* in this directory. ## The test scripts -These four are tests rather than examples, and `../run.bash` runs none of -them. They are plain scripts, not pytest modules. `TESTING.md` covers each in +The `test_*.py` scripts are tests rather than examples, and `../run.bash` +runs only `test_validate.py`. They are plain scripts, not pytest modules. `TESTING.md` covers each in detail, including how to build the module they import. ### `test_moisture_invariants.py`