diff --git a/CHANGELOG.md b/CHANGELOG.md
index 062a38d..f2389b4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@ history, so they summarise each release rather than list every change. The
### Added
+- The browser demo includes the `Farsite` propagation model in its model
+ selector.
- `tests/mnh_coupled.bash` goes from a bare Linux machine to a coupled
ForeFire + Meso-NH run: it downloads and builds Meso-NH 6.0.1, builds
ForeFire with MPI, links them and runs `tests/mnh_real_nested`. With
diff --git a/bindings/wasm/README.md b/bindings/wasm/README.md
index 7b98bb3..80c528e 100644
--- a/bindings/wasm/README.md
+++ b/bindings/wasm/README.md
@@ -94,10 +94,10 @@ map ForeFire writes natively, rebuilt from the perimeter of every frame.
nodes on a tight curve do not wash it out.
The models on offer are the ones that run on this fuel table with only slope
-and wind: Rothermel, BalbiNov2011Curv, BalbiUnsteady, TroisPourcent and Iso.
-Balbi2015, Balbi2020 and BalbiNov2011TMdMl also need moisture and temperature
-layers and abort without them; BalbiNov2011 places the front far from the
-ignition.
+and wind: Rothermel, Farsite, BalbiNov2011Curv, BalbiUnsteady, TroisPourcent
+and Iso. Balbi2015, Balbi2020 and BalbiNov2011TMdMl also need moisture and
+temperature layers and abort without them; BalbiNov2011 places the front far
+from the ignition.
### The landscape comes from map tiles
diff --git a/bindings/wasm/index.html b/bindings/wasm/index.html
index dccfee1..6c516f4 100644
--- a/bindings/wasm/index.html
+++ b/bindings/wasm/index.html
@@ -462,6 +462,7 @@
Run
// temperature layers abort here, and BalbiNov2011 misplaces the front.
const MODELS = [
["Rothermel", "Rothermel (1972)"],
+ ["Farsite", "FARSITE (Finney 1998)"],
["BalbiNov2011Curv", "Balbi 2011, curvature"],
["BalbiUnsteady", "Balbi, unsteady"],
["TroisPourcent", "3% rule"],
@@ -765,6 +766,8 @@ Run
liveMoisture: value.liveMoisture,
depth: { 5: value.depth5, 4: value.depth4 },
}),
+ deadMoisture: value.deadMoisture,
+ liveMoisture: value.liveMoisture,
defaultFuel: FUELS[0].index,
},
model: $("model").value,
diff --git a/bindings/wasm/landscape.mjs b/bindings/wasm/landscape.mjs
index 6915c84..4aaa4e3 100644
--- a/bindings/wasm/landscape.mjs
+++ b/bindings/wasm/landscape.mjs
@@ -20,15 +20,17 @@ const IMAGERY =
const TERRAIN = "https://s3.amazonaws.com/elevation-tiles-prod/terrarium";
/*! The three fuel classes, as rows of tests/runff/fuels.csv — the repository's
- * own Rothermel table, not invented numbers. Index 0 has a fuel bed depth of
- * zero, which is what makes it a barrier. */
+ * own Rothermel table — followed by the FARSITE columns from
+ * STDfarsiteFuelsTable (FM4 chaparral for shrub, FM1 short grass for grass,
+ * NB0 for bare ground). Index 0 has a fuel bed depth of zero, which is what
+ * makes it a barrier. */
const FUEL_ROWS = {
- 5: "5;626.0;600.0;0.1;1.0;4325.0;5844.0;0.6;1.393;0.201;8.3;1.0;300;70000;18802000.0;18802000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3",
- 4: "4;613.0;538.0;0.1;1.0;4357.0;6524.0;0.19;1.286;0.085;8.3;1.0;300;70000;18677000.0;18677000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3",
- 0: "0;563.0;522.0;0.1;1.0;6099.0;7273.0;0;0.764;0.352;8.3;1.0;300;70000;18169000.0;18167000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3",
+ 5: "5;626.0;600.0;0.1;1.0;4325.0;5844.0;0.6;1.393;0.201;8.3;1.0;300;70000;18802000.0;18802000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3;5.01;4.01;2.0;0.0;5.01;0;2000;1800;1500;6.0;0.2;8000.0;8000.0",
+ 4: "4;613.0;538.0;0.1;1.0;4357.0;6524.0;0.19;1.286;0.085;8.3;1.0;300;70000;18677000.0;18677000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3;0.74;0.0;0.0;0.0;0.0;0;3500;1800;1500;1.0;0.12;8000.0;8000.0",
+ 0: "0;563.0;522.0;0.1;1.0;6099.0;7273.0;0;0.764;0.352;8.3;1.0;300;70000;18169000.0;18167000.0;1800;1000;600;0.3;2.5e-05;4.0;0.3;0.0;0.0;0.0;0.0;0.0;0;0;0;0;0.0;0.0;0.0;0.0",
};
const FUEL_HEADER =
- "Index;Rhod;Rhol;Md;Ml;sd;sl;e;Sigmad;Sigmal;stoch;RhoA;Ta;Tau0;Deltah;DeltaH;Cp;Cpa;Ti;X0;r00;Blai;me";
+ "Index;Rhod;Rhol;Md;Ml;sd;sl;e;Sigmad;Sigmal;stoch;RhoA;Ta;Tau0;Deltah;DeltaH;Cp;Cpa;Ti;X0;r00;Blai;me;h1;h10;h100;lh;lw;dynamic;sav1;savlh;savlw;depth;xmext;heatd;heatl";
export const FUELS = [
{ index: 5, label: "shrub / maquis", note: "depth 0.6 m", rgb: [46, 125, 50] },
@@ -52,7 +54,12 @@ export function fuelsTable({ deadMoisture, liveMoisture, depth }) {
const cells = FUEL_ROWS[f.index].split(";");
cells[col("Md")] = String(deadMoisture);
cells[col("Ml")] = String(liveMoisture);
- if (depth[f.index] !== undefined) cells[col("e")] = String(depth[f.index]);
+ if (depth[f.index] !== undefined) {
+ cells[col("e")] = String(depth[f.index]);
+ cells[col("depth")] = String(
+ (+cells[col("depth")] * depth[f.index]) / FUEL_DEFAULTS.depth[f.index]
+ );
+ }
return cells.join(";");
});
return [FUEL_HEADER, ...rows].join("\n");
diff --git a/bindings/wasm/worker.mjs b/bindings/wasm/worker.mjs
index cf4cb4c..d8b7197 100644
--- a/bindings/wasm/worker.mjs
+++ b/bindings/wasm/worker.mjs
@@ -42,6 +42,17 @@ function build(land, model, solver) {
ff.setString("fuelsTable", land.fuelsTable);
ff.setDouble("defaultFuelType", land.defaultFuel);
for (const [key, value] of Object.entries(solver)) ff.setDouble(key, value);
+ if (solver.windReductionFactor !== undefined)
+ ff.setDouble("Farsite.adjustementWind", solver.windReductionFactor);
+ if (land.deadMoisture !== undefined) {
+ ff.setDouble("moistures.ones", land.deadMoisture);
+ ff.setDouble("moistures.tens", land.deadMoisture);
+ ff.setDouble("moistures.hundreds", land.deadMoisture);
+ }
+ if (land.liveMoisture !== undefined) {
+ ff.setDouble("moistures.liveh", land.liveMoisture);
+ ff.setDouble("moistures.livew", land.liveMoisture);
+ }
ff.setString("propagationModel", model);
ff.execute(`FireDomain[sw=(0,0,0);ne=(${side},${side},0);t=0]`);