Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
45e173b
Create Running_on_HPC.txt
Michelin25 Feb 4, 2026
62a8dd1
Fix package initialization for cell2fire
Michelin25 Feb 5, 2026
0b1c675
Merge pull request #1 from Michelin25/codex/fix-module-import-errors-…
Michelin25 Feb 5, 2026
837084d
Add Cell2Fire compatibility package alias
Michelin25 Feb 5, 2026
e8f1298
New Cell2Fire package setup
Michelin25 Feb 5, 2026
414b7e2
Auto-build C++ core when executable is missing
Michelin25 Feb 5, 2026
dbf3307
Merge branch 'main' into codex/fix-module-import-errors-in-cell2fire-…
Michelin25 Feb 5, 2026
ab38a4a
Merge pull request #3 from Michelin25/codex/fix-module-import-errors-…
Michelin25 Feb 5, 2026
bd5a408
Add inventory of Cell2Fire simulation parameters and inputs
Michelin25 Feb 18, 2026
c139350
Merge pull request #4 from Michelin25/codex/locate-cell2fire-simulati…
Michelin25 Feb 18, 2026
eda5ced
Add 100x100 power-line loss test script
Michelin25 Feb 27, 2026
d94b179
Merge pull request #5 from Michelin25/codex/create-grid-test-with-pow…
Michelin25 Feb 27, 2026
e3ed347
Make burn probability map vary across simulations
Michelin25 Mar 3, 2026
ff90918
Merge branch 'main' into codex/create-grid-test-with-power-line-simul…
Michelin25 Mar 3, 2026
0cdf566
Merge pull request #6 from Michelin25/codex/create-grid-test-with-pow…
Michelin25 Mar 3, 2026
2d87879
Clarify global weather assumption in powerline test script
Michelin25 Mar 3, 2026
4d568c5
Merge branch 'main' into codex/create-grid-test-with-power-line-simul…
Michelin25 Mar 3, 2026
9250f21
Merge pull request #7 from Michelin25/codex/create-grid-test-with-pow…
Michelin25 Mar 3, 2026
eb10b57
merging 'main' into 'main'
Michelin25 Mar 3, 2026
fd15a72
Revert ParseInputs.py documentation edits
Michelin25 Mar 3, 2026
5c30b3c
Merge pull request #8 from Michelin25/codex/comment-code-for-ignition…
Michelin25 Mar 3, 2026
2523089
Comment powerline test knobs for ROS-CV and ignition control
Michelin25 Mar 3, 2026
868538a
Merge pull request #9 from Michelin25/codex/comment-code-for-ignition…
Michelin25 Mar 3, 2026
573b52f
Expand powerline test comments for CVROS and ignition controls
Michelin25 Mar 3, 2026
e04abb3
Merge branch 'main' into codex/comment-code-for-ignition-position-var…
Michelin25 Mar 3, 2026
494b940
Merge pull request #10 from Michelin25/codex/comment-code-for-ignitio…
Michelin25 Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cell2Fire/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Compatibility package exposing the historical `Cell2Fire` import path."""

from importlib import import_module
import sys

_pkg = import_module("cell2fire")

# Re-export symbols and share package search path so submodules resolve:
# e.g. `from Cell2Fire.utils.ParseInputs import ParseInputs`.
globals().update(_pkg.__dict__)
__path__ = _pkg.__path__

# Ensure both names reference the same loaded package instance.
sys.modules[__name__] = _pkg
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@ For the full list of arguments and their explanation use:
$ python main.py -h
```

For ignition and ROS variability controls:
- `--ROS-CV`: controls stochastic spread-rate variability (`0.0` = deterministic ROS).
- `--ignitions`: reads fixed ignition locations from `Ignitions.csv` in the input folder.
- `--IgnitionRad`: if `--ignitions` is active, samples around each fixed ignition cell.
- `0` => exact CSV cell.
- `>0` => random cell inside the radius neighborhood.

`Ignitions.csv` is where you directly change ignition location per year (cell IDs):
```
year,cell
1,930
2,280
```


In addition, both the C++ core and Python scripts can be used separately:
## C ++
Only simulation and generate evolution grids (no stats or plots).
Expand Down
1 change: 1 addition & 0 deletions Running_on_HPC.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
How to run on HPC
15 changes: 9 additions & 6 deletions cell2fire/Cell2FireC/Cell2Fire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,10 @@ Cell2Fire::Cell2Fire(arguments _args) : CSVWeather(_args.InFolder + "Weather.csv
this->CSVWeather.parseWeatherDF(wdf_ptr, this->WeatherDF, WPeriods);
//DEBUGthis->CSVWeather.printData(this->WeatherDF);

/* Ignitions */
/* Ignitions
* - To force ignition location per year: enable --ignitions and edit <InFolder>/Ignitions.csv
* - To randomize ignition location per year: do not pass --ignitions
*/
int IgnitionYears;
std::vector<int> IgnitionPoints;

Expand All @@ -277,14 +280,14 @@ Cell2Fire::Cell2Fire(arguments _args) : CSVWeather(_args.InFolder + "Weather.csv
args.TotalYears = std::min(args.TotalYears, IgnitionYears);
//DEBUGstd::cout << "Setting TotalYears to " << args.TotalYears << " for consistency with Ignitions file" << std::endl;

// Ignition points
// Ignition points loaded from Ignitions.csv (year -> cell id)
this->IgnitionPoints = std::vector<int>(IgnitionYears, 0);
CSVIgnitions.parseIgnitionDF(this->IgnitionPoints, IgnitionsDF, IgnitionYears);
//this->IgnitionSets = std::vector<unordered_set<int>>(this->IgnitionPoints.size());
this->IgnitionSets = std::vector<std::vector<int>>(this->args.TotalYears);


// Ignition radius
// Ignition radius (IgnitionRad): expands each yearly ignition cell to a candidate neighborhood
if (this->args.IgnitionRadius > 0){
// Aux
int i, a, igVal;
Expand Down Expand Up @@ -577,7 +580,7 @@ bool Cell2Fire::RunIgnition(std::default_random_engine generator){
std::unordered_map<int, CellsFBP>::iterator it;
std::uniform_int_distribution<int> distribution(1, this->nCells);

// No Ignitions provided
// No Ignitions.csv mode: ignition cell is sampled uniformly at random each year.
if (this->args.Ignitions == 0) {
while (true) {
// Pick any cell (uniform distribution [a,b])
Expand Down Expand Up @@ -629,11 +632,11 @@ bool Cell2Fire::RunIgnition(std::default_random_engine generator){
}
}

// Ignitions with provided points from CSV
// Ignitions.csv mode: start from yearly fixed cell and optionally randomize within IgnitionRadius
else {
int temp = IgnitionPoints[this->year-1];

// If ignition Radius != 0, sample from the Radius set
// If IgnitionRadius > 0, sample a random candidate from the precomputed neighborhood set
if (this->args.IgnitionRadius > 0){
// Pick any at random and set temp with that cell
std::uniform_int_distribution<int> udistribution(0, this->IgnitionSets[this->year - 1].size()-1);
Expand Down
4 changes: 4 additions & 0 deletions cell2fire/Cell2FireC/CellsFBP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ std::vector<int> CellsFBP::manageFire(int period, std::unordered_set<int> & Avai
cartesianAngle += 360;
}

// ROSCV controls stochastic spread variation.
// ROSRV is a standard-normal random draw passed from the simulation loop.
double ROSRV = 0;
if (args->ROSCV > 0) {
//std::srand(args->seed);
Expand All @@ -401,6 +403,8 @@ std::vector<int> CellsFBP::manageFire(int period, std::unordered_set<int> & Avai
}

// If cell cannot send (thresholds), then it will be burned out in the main loop
// Key formula: scaled ROS = (1 + ROSCV * ROSRV) * deterministic FBP ROS.
// Increase --ROS-CV to increase variability around the deterministic ROS.
double HROS = (1 + args->ROSCV * ROSRV) * headstruct.ros * args->HFactor;

// Extra debug step for sanity checks
Expand Down
55 changes: 49 additions & 6 deletions cell2fire/Cell2FireC_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,42 @@
from cell2fire.utils.Stats import *
from cell2fire.utils.Heuristics import *
import cell2fire # for path finding
p = str(cell2fire.__path__)
l = p.find("'")
r = p.find("'", l+1)
cell2fire_path = p[l+1:r]
cell2fire_path = os.path.dirname(cell2fire.__file__)



def _core_binary_path():
return os.path.join(cell2fire_path, 'Cell2FireC', 'Cell2Fire')


def _ensure_core_binary_exists():
core_bin = _core_binary_path()
if os.path.isfile(core_bin):
return core_bin

build_dir = os.path.join(cell2fire_path, 'Cell2FireC')
if shutil.which('make') is None:
raise RuntimeError(
f"Cell2Fire core executable not found at {core_bin}. "
"Install make and build it manually with: "
f"cd {build_dir} && make"
)

try:
subprocess.check_call(['make'], cwd=build_dir)
except subprocess.CalledProcessError as exc:
raise RuntimeError(
"Failed to build the Cell2Fire C++ core automatically. "
f"Run manually: cd {build_dir} && make"
) from exc

if not os.path.isfile(core_bin):
raise RuntimeError(
f"Build completed but executable is still missing at {core_bin}. "
"Please inspect the Makefile/toolchain on this system."
)

return core_bin

class Cell2FireC:
# Constructor and initial run
Expand Down Expand Up @@ -55,9 +87,14 @@ def __init__(self, args):
def run(self):
# Parse args for calling C++ via subprocess
# old: execArray=[os.path.join(os.getcwd(),'Cell2FireC/Cell2Fire'),
execArray=[os.path.join(cell2fire_path,'Cell2FireC/Cell2Fire'),
core_bin = _ensure_core_binary_exists()
execArray=[core_bin,
'--input-instance-folder', self.args.InFolder,
'--output-folder', self.args.OutFolder if (self.args.OutFolder is not None) else '',
# IGNITION LOCATION CONTROL:
# --ignitions ON => read fixed yearly ignition locations from <InFolder>/Ignitions.csv
# (edit that file to choose the exact ignition cells per year)
# --ignitions OFF => C++ core samples ignition cell uniformly at random each year
'--ignitions' if (self.args.ignitions) else '',
'--sim-years', str(self.args.sim_years),
'--nsims', str(self.args.nsims),
Expand All @@ -66,7 +103,10 @@ def run(self):
'--output-messages' if (self.args.OutMessages) else '',
'--weather', self.args.WeatherOpt,
'--nweathers', str(self.args.nweathers),
# ROS VARIABILITY CONTROL: main stochastic spread knob (0.0 = deterministic ROS, >0 adds variability)
'--ROS-CV', str(self.args.ROS_CV),
# If --ignitions is enabled, expands each CSV ignition cell to a radius neighborhood
# and samples one cell from that neighborhood each simulation.
'--IgnitionRad', str(self.args.IgRadius),
'--seed', str(int(self.args.seed)),
'--ROS-Threshold', str(self.args.ROS_Threshold),
Expand Down Expand Up @@ -98,9 +138,11 @@ def run(self):
# Run C++ Sim with heuristic treatment
def run_Heur(self, OutFolder, HarvestPlanFile):
# Parse args for calling C++ via subprocess
execArray=[os.path.join(cell2fire_path,'Cell2FireC/Cell2Fire'),
core_bin = _ensure_core_binary_exists()
execArray=[core_bin,
'--input-instance-folder', self.args.InFolder,
'--output-folder', OutFolder if (OutFolder is not None) else '',
# Same ignition control as in run(): fixed CSV points when enabled, random ignition otherwise.
'--ignitions' if (self.args.ignitions) else '',
'--sim-years', str(self.args.sim_years),
'--nsims', str(self.args.nsims),
Expand All @@ -109,6 +151,7 @@ def run_Heur(self, OutFolder, HarvestPlanFile):
'--output-messages' if (self.args.OutMessages) else '',
'--weather', self.args.WeatherOpt,
'--nweathers', str(self.args.nweathers),
# Same ROS variability controls as in run().
'--ROS-CV', str(self.args.ROS_CV),
'--IgnitionRad', str(self.args.IgRadius),
'--seed', str(int(self.args.seed)),
Expand Down
14 changes: 14 additions & 0 deletions cell2fire/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Compatibility package exposing the historical `Cell2Fire` import path."""

from importlib import import_module
import sys

_pkg = import_module("cell2fire")

# Re-export symbols and share package search path so submodules resolve:
# e.g. `from Cell2Fire.utils.ParseInputs import ParseInputs`.
globals().update(_pkg.__dict__)
__path__ = _pkg.__path__

# Ensure both names reference the same loaded package instance.
sys.modules[__name__] = _pkg
132 changes: 132 additions & 0 deletions doc/simulation_parameters_inventory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Cell2Fire simulation inputs and tunable parameters

This note inventories what you can change when running Cell2Fire, based on the Python argument parser, the Python-to-C++ wrapper command construction, the C++ argument reader, and CSV/ASC readers.

## 1) Command-line parameters (Python entrypoint: `python cell2fire/main.py ...`)

Defined in `cell2fire/utils/ParseInputs.py`.

### Paths and run scope
- `--input-instance-folder` (`InFolder`, str, default `None`): folder with simulation inputs.
- `--output-folder` (`OutFolder`, str, default `None`): output folder.
- `--sim-years` (`sim_years`, int, default `1`): years per simulation.
- `--nsims` (`nsims`, int, default `1`): number of simulation replications.
- `--seed` (`seed`, int, default `123`): RNG seed.
- `--nweathers` (`nweathers`, int, default `1`): maximum weather index used in random-weather mode.
- `--nthreads` (`nthreads`, int, default `1`): Python-side argument (not currently forwarded by wrapper to C++ core).
- `--max-fire-periods` (`max_fire_periods`, int, default `1000`): hard cap on fire periods.
- `--IgnitionRad` (`IgRadius`, int, default `0`): neighborhood radius around ignition points.
- `--gridsStep` (`gridsStep`, int, default `60`): grid generation period step.
- `--gridsFreq` (`gridsFreq`, int, default `-1`): grid generation simulation frequency.

### Heuristic/treatment planning parameters
- `--heuristic` (`heuristic`, int, default `-1`): heuristic mode (`-1` disables heuristic flow).
- `--MessagesPath` (`messages_path`, str, default `None`): path to message files.
- `--GASelection` (`GASelection`, bool flag): use genetic algorithm selection.
- `--HarvestedCells` (`HCells`, str, default `None`): path to initial harvested cells CSV.
- `--msgheur` (`msgHeur`, str, default `""`): path to heuristic message files.
- `--applyPlan` (`planPath`, str, default `""`): path to treatment/harvesting plan.
- `--DFraction` (`TFraction`, float, default `1.0`): demand fraction.
- `--GPTree` (`GPTree`, bool flag): use global propagation tree.
- `--customValue` (`valueFile`, str, default `None`): custom objective/value file.
- `--noEvaluation` (`noEvaluation`, bool flag): generate plans without evaluation.

### Genetic algorithm hyperparameters
- `--ngen` (`ngen`, int, default `500`): generations.
- `--npop` (`npop`, int, default `100`): population size.
- `--tsize` (`tSize`, int, default `3`): tournament size.
- `--cxpb` (`cxpb`, float, default `0.8`): crossover probability.
- `--mutpb` (`mutpb`, float, default `0.2`): mutation probability.
- `--indpb` (`indpb`, float, default `0.5`): per-individual probability.

### Simulation behavior, outputs, and post-processing flags
- `--weather` (`WeatherOpt`, str, default `rows`): weather mode (`constant`, `random`, `rows`).
- `--spreadPlots`, `--finalGrid`, `--verbose`, `--ignitions`, `--grids`, `--simPlots`, `--allPlots`, `--combine`, `--no-output`, `--gen-data`, `--output-messages`, `--Prometheus-tuned`, `--trajectories`, `--stats`, `--correctedStats`, `--onlyProcessing`, `--bbo`, `--fdemand`, `--pdfOutputs`: boolean flags controlling simulation behavior and outputs.

### Core fire spread / intensity parameters
- `--Fire-Period-Length` (`input_PeriodLen`, float, default `60` min).
- `--Weather-Period-Length` (`weather_period_len`, float, default `60` min).
- `--ROS-Threshold` (`ROS_Threshold`, float, default `0.1` m/min).
- `--HFI-Threshold` (`HFI_Threshold`, float, default `0.1` kW/m in code help text typo says 10 default).
- `--ROS-CV` (`ROS_CV`, float, default `0.0`): stochastic ROS coefficient of variation.
- `--HFactor` (`HFactor`, float, default `1.0`): multiplier for head ROS.
- `--FFactor` (`FFactor`, float, default `1.0`): multiplier for flank ROS.
- `--BFactor` (`BFactor`, float, default `1.0`): multiplier for back ROS.
- `--EFactor` (`EFactor`, float, default `1.0`): ellipse adjustment factor.
- `--BurningLen` (`BurningLen`, float, default `-1.0`): burn duration in periods.

## 2) What actually reaches the C++ simulator from Python

The Python wrapper (`cell2fire/Cell2FireC_class.py`) forwards these options into the C++ binary call:

- `--input-instance-folder`, `--output-folder`
- `--ignitions`
- `--sim-years`, `--nsims`
- `--grids`, `--final-grid`
- `--Fire-Period-Length`
- `--output-messages`
- `--weather`, `--nweathers`
- `--ROS-CV`
- `--IgnitionRad`
- `--seed`
- `--ROS-Threshold`, `--HFI-Threshold`
- `--bbo`
- `--HarvestPlan` (populated from `--HarvestedCells` path)
- `--verbose`

Not currently forwarded in this wrapper despite being parsed in Python: `--HFactor`, `--FFactor`, `--BFactor`, `--EFactor`, `--Weather-Period-Length`, `--max-fire-periods`, `--nthreads`, many plotting/postprocessing flags (which are used in Python-side postprocess), and heuristic-only fields used by Python logic.

## 3) C++ CLI options accepted by the core binary

`cell2fire/Cell2FireC/ReadArgs.cpp` parses these options directly:

- Strings: `--input-instance-folder`, `--output-folder`, `--weather`, `--HarvestPlan`
- Boolean flags: `--output-messages`, `--trajectories`, `--no-output`, `--verbose`, `--ignitions`, `--grids`, `--final-grid`, `--PromTuned`, `--statistics`, `--bbo`
- Numeric: `--sim-years`, `--nsims`, `--Weather-Period-Length`, `--nweathers`, `--Fire-Period-Length`, `--IgnitionRad`, `--ROS-Threshold`, `--HFI-Threshold`, `--HFactor`, `--FFactor`, `--BFactor`, `--EFactor`, `--ROS-CV`, `--max-fire-periods`, `--seed`

## 4) Required/optional instance input files and their fields

The C++ constructor reads:

- `Forest.asc` (grid geometry and fuel raster)
- `Data.csv` (per-cell FBP inputs)
- `Weather.csv` (weather-by-period values)
- Optional `Ignitions.csv` (if `--ignitions`)
- Optional harvest plan CSV via `--HarvestPlan`
- Optional `BBOFuels.csv` (if `--bbo`)

### `Data.csv` fields (per cell)
Header expected (example in datasets):

`fueltype,mon,jd,M,jd_min,lat,lon,elev,ffmc,ws,waz,bui,ps,saz,pc,pdf,gfl,cur,time,pattern`

These are parsed into the FBP `inputs` struct values used by spread calculations.

### `Weather.csv` fields (per weather period)
Header expected:

`Scenario,datetime,APCP,TMP,RH,WS,WD,FFMC,DMC,DC,ISI,BUI,FWI`

This is where you control FFMC and other moisture/fire-weather drivers by period.

### `Ignitions.csv` fields
Typical header:

`Year,Ncell`

Each row fixes ignition cell per year (when `--ignitions` is enabled).

### `BBOFuels.csv` fields
Parsed as per-fuel factors (read when `--bbo` is active), used to tune spread/intensity behavior by fuel type.

## 5) Moisture-related parameters you can change

If you specifically want fuel-moisture controls:

- `ffmc` in `Data.csv` (cell baseline field, if used/populated).
- `FFMC`, `DMC`, `DC` columns in `Weather.csv` (time-varying moisture codes).
- `BUI` in both `Data.csv` and `Weather.csv` (build-up index).
- `RH`, `TMP`, and `APCP` in `Weather.csv` indirectly influence fire behavior and moisture context.
- `ROS-Threshold`, `HFI-Threshold`, `ROS-CV`, and ROS factor multipliers (`HFactor/FFactor/BFactor`) are direct simulation controls that modulate spread and continuation.

Note: foliar moisture content (FMC) is computed internally (`foliar_moisture(...)` in FBP code) rather than read as an explicit top-level CLI parameter.
Loading
Loading