Skip to content

aisystems-lab/wildfire-env

Repository files navigation

FirecastRL: Wildfire Suppression Environment

A Gymnasium-compatible wildfire simulation environment with physics-informed fire spread dynamics and helicopter-based firefighting. Designed for reinforcement learning research in wildfire management and suppression strategies.

The controllable agent is a helitack firefighting helicopter. Its job is to move over the terrain and drop fire suppressant/water on burning regions to slow or extinguish the fire. In RL terms, the agent should be trained to contain the wildfire as quickly as possible while minimizing total burned area and using suppressant actions effectively.

By default, the wildfire ignites near the center of the map and expands outward over time according to the terrain, landcover, and fire spread dynamics.

Python 3.11 Gymnasium License: MIT


Features

  • Physics-Informed Fire Dynamics: Realistic fire spread based on terrain, vegetation, wind, and elevation
  • Gymnasium API: Fully compatible with modern RL frameworks (Stable-Baselines3, RLlib, etc.)
  • Real-Time Visualization: Fast Pygame-based rendering at 60 FPS
  • Flexible Observation Space: Dict-based observations with customizable wrappers
  • Helitack Firefighting: Simulate aerial water/retardant drops
  • Custom Reward Functions: Easy-to-extend reward system via wrappers
  • Real Terrain Data: Includes landcover and elevation maps based on real geographic data

Environment Screenshots

Early Fire Spread

Early Fire Spread

Active Firefighting Operations

Active Firefighting

Legend:

  • Dark Blue = Water/non-burnable areas
  • Black = Unburned terrain
  • Pink/Purple gradient = Fire spread prediction (scheduled ignition times)
  • Orange = Currently burning
  • Dark Gray = Already burnt/extinguished
  • Yellow X = Helicopter position
  • Blue circles = Recent helitack drop locations (fade over time)

Installation

Prerequisites

  • Python 3.11.11 recommended
  • uv for Python environment and dependency management
  • pyenv optional, if you manage Python versions that way
  • Node.js only if you modify the 3D viewer in web/

From TestPyPI (for testing)

uv tool run --with pip pip install --index-url https://test.pypi.org/simple/ \
    --extra-index-url https://pypi.org/simple/ \
    firecastrl-env

From Source with uv

git clone https://github.com/aisystems-lab/wildfire-env.git
cd wildfire-env
uv venv --python 3.11.11
uv sync

If you use pyenv, set the project interpreter first:

pyenv local tactix-3.11.11
uv venv --python "$(pyenv which python)"
uv sync

This installs the package from source in the project virtual environment and includes all runtime dependencies declared in pyproject.toml.

Web Viewer Development

You do not need Node.js to use render_mode="3d" with the packaged viewer.

Only rebuild the web bundle if you change files under web/:

cd web
npm install
npm run build

Quick Start

Run the bundled examples with uv:

uv run python scripts/random_agent_human.py
uv run python scripts/random_agent_3d.py
import gymnasium as gym
import firecastrl_env  # Registers the environment

# Create environment
env = gym.make("firecastrl/Wildfire-env0", render_mode="human")

# Reset environment
obs, info = env.reset(seed=42)

# Run episode
done = False
truncated = False
total_reward = 0.0

while not (done or truncated):
    # Sample random action (or use your RL policy)
    action = env.action_space.sample()
    
    # Step environment
    obs, reward, done, truncated, info = env.step(action)
    total_reward += reward
    
    # Render (if render_mode="human")
    env.render()

env.close()
print(f"Episode reward: {total_reward:.2f}")

Environment Details

Observation Space

Dict with the following keys:

Key Type Shape Description
cells Box(float32) (160, 240) Ignition time for each cell (inf for unscheduled)
helicopter_coord Box(int32) (2,) Helicopter position [x, y]
quenched_cells Box(float32) (1,) Number of cells extinguished this step

Action Space

Discrete(5) - Five possible actions:

Action Value Description
Move Down 0 Move helicopter down
Move Up 1 Move helicopter up
Move Left 2 Move helicopter left
Move Right 3 Move helicopter right
Helitack 4 Drop water/retardant in radius around helicopter

Reward Function

The default reward encourages fire suppression:

  • +5.0 per cell extinguished by helitack
  • -0.05 per cell currently burning (continuous penalty)
  • -0.01 per time step (encourages faster containment)
  • -1.0 for performing helitack on non-burnable/burnt cells

Episode Termination

  • Terminated: All fires extinguished (cells_burning == 0)
  • Truncated: Maximum timesteps reached (default: 2000)

Info Dictionary

Each step() returns an info dict with:

  • cells_burning: Current count of burning cells
  • cells_burnt: Total cells that have burnt
  • simulation_time: Elapsed simulation time

Rendering Modes

Human Mode (Interactive Window)

env = gym.make("firecastrl/Wildfire-env0", render_mode="human")

Opens a Pygame window with real-time visualization at 60 FPS.

3D Browser Mode

env = gym.make("firecastrl/Wildfire-env0", render_mode="3d")
env.reset(seed=42)
env.render()

Launches the packaged standalone Tactics browser viewer and streams terrain and fire state directly from that exact WildfireEnv instance into the browser. The viewer is served from packaged static assets in firecastrl_env/web_dist.

Example 3D viewer outputs:

3D Simulation View 1

3D Simulation View 2

In the 3D viewer:

  • The wildfire starts near the center of the map and expands outward as the simulation progresses.
  • Grey regions represent concrete or city/urban areas.
  • Blue regions represent water bodies.
  • Other terrain colors are shades of green based on the MODIS land-cover legend, depicting different forest and vegetation types.

You can also override the viewer host and port when integrating into another app:

env = gym.make(
    "firecastrl/Wildfire-env0",
    render_mode="3d",
    viewer_host="127.0.0.1",
    viewer_port=8765,
    auto_open_3d_viewer=True,
)

RGB Array Mode (For Recording)

env = gym.make("firecastrl/Wildfire-env0", render_mode="rgb_array")
rgb_frame = env.render()  # Returns numpy array (H, W, 3)

Returns RGB arrays suitable for video recording or analysis.

Troubleshooting

  • If the 3D browser viewer does not open automatically, copy the local URL printed by the environment into your browser.
  • If port 8765 is already in use, pass a different viewer_port when creating the environment.
  • If you changed files in web/ and the viewer looks stale, rebuild with cd web && npm run build.
  • If human rendering fails with a pygame import error, rerun uv sync.

Custom Wrappers

FirecastRL provides powerful wrappers to customize observations and rewards:

1. CellObservationWrapper

Adds detailed cell-level features to observations, replacing the basic cells array with a multi-channel tensor.

Available Properties:

  • ignition_time - Time when cell will ignite
  • spread_rate - Fire spread rate
  • burn_time - Total burn duration
  • fire_state - Current fire state (Unburnt/Burning/Burnt)
  • is_river - Non-burnable water cells
  • is_unburnt_island - Isolated unburnt regions
  • helitack_drops - Number of times helitack performed on cell
  • elevation - Terrain elevation
  • zone - Vegetation/landcover zone
  • vegetation - Vegetation type
  • drought - Drought index
  • position - Normalized X,Y coordinates

Usage:

from firecastrl_env.wrappers import CellObservationWrapper

# Use default properties (most common features)
env = gym.make("firecastrl/Wildfire-env0")
env = CellObservationWrapper(env)

# Observation now includes 'detailed_cells' with shape (6, 160, 240)
# 6 channels: ignition_time, spread_rate, fire_state, is_river, helitack_drops, elevation

# Custom properties
env = CellObservationWrapper(
    env,
    properties=['ignition_time', 'fire_state', 'elevation', 'position'],
    remove_basic_cells=True  # Remove redundant 'cells' key
)

# All properties
env = CellObservationWrapper(env, properties='all')

Benefits:

  • Richer state representation for deep RL
  • CNN-friendly multi-channel format
  • Normalized values in [0, 1] range
  • Flexible feature selection

2. CustomRewardWrapper

Override the default reward function with your own logic.

Usage:

from firecastrl_env.wrappers import CustomRewardWrapper

def my_reward_function(env, prev_state, curr_state):
    """
    Custom reward based on state changes.
    
    Args:
        env: The environment instance
        prev_state: Dict with keys: cells_burning, cells_burnt, helicopter_coord, quenched_cells
        curr_state: Dict with same keys as prev_state
    
    Returns:
        float: Custom reward value
    """
    # Example: Heavily penalize fire spread, reward containment
    delta_burning = curr_state['cells_burning'] - prev_state['cells_burning']
    reward = -2.0 * delta_burning  # Penalty for new ignitions
    reward += 10.0 * curr_state['quenched_cells']  # Bonus for extinguishing
    return float(reward)

env = gym.make("firecastrl/Wildfire-env0")
env = CustomRewardWrapper(env, reward_fn=my_reward_function)

Default Reward Function: If no reward_fn is provided, uses a built-in default that balances:

  • Extinguishing fires (+)
  • Preventing spread (-)
  • Time efficiency (-)

3. Combining Wrappers

Wrappers can be stacked:

from firecastrl_env.wrappers import CellObservationWrapper, CustomRewardWrapper

env = gym.make("firecastrl/Wildfire-env0")

# Add detailed observations
env = CellObservationWrapper(
    env,
    properties=['ignition_time', 'fire_state', 'elevation', 'spread_rate']
)

# Add custom reward
env = CustomRewardWrapper(env, reward_fn=my_reward_function)

# Now ready for training!
obs, info = env.reset()

Training with Stable-Baselines3

stable-baselines3 is not installed by default with the base environment. Install it first if you want to run the example below:

uv add stable-baselines3
import gymnasium as gym
from stable_baselines3 import PPO
from stable_baselines3.common.env_checker import check_env
import firecastrl_env

# Create and verify environment
env = gym.make("firecastrl/Wildfire-env0")
check_env(env, warn=True)

# Train PPO agent
model = PPO(
    "MultiInputPolicy",  # For Dict observation spaces
    env,
    verbose=1,
    tensorboard_log="./firecast_tensorboard/"
)

model.learn(total_timesteps=100_000)
model.save("firecast_ppo_agent")

# Evaluate trained agent
obs, info = env.reset()
for _ in range(500):
    action, _states = model.predict(obs, deterministic=True)
    obs, reward, done, truncated, info = env.step(action)
    env.render()
    if done or truncated:
        break

env.close()

Configuration

Key parameters can be modified in firecastrl_env/envs/config.py:

Parameter Default Description
gridWidth 240 Grid width (cells)
gridHeight 160 Grid height (cells)
cellSize 500 Cell size (feet)
MAX_TIMESTEPS 2000 Episode truncation limit
HELICOPTER_SPEED 3 Cells moved per action
helitackDropRadius 2640 Effective helitack drop radius (feet)

Project Structure

firecastrl_env/
├── __init__.py                    # Environment registration
├── envs/
│   ├── __init__.py
│   ├── wildfire_env.py           # Main Gymnasium environment
│   ├── config.py                 # Configuration parameters
│   ├── environment/              # Core simulation components
│   │   ├── cell.py              # Grid cell representation
│   │   ├── enums.py             # Fire states, burn indices, etc.
│   │   ├── helper.py            # Utility functions
│   │   ├── vector.py            # 2D vector math
│   │   ├── wind.py              # Wind modeling
│   │   └── zone.py              # Vegetation zones
│   ├── fire_engine/             # Fire physics engine
│   │   ├── fire_engine.py      # Fire spread simulation
│   │   ├── fire_spread_rate.py # Spread rate calculations
│   │   └── utils.py            # Fire engine utilities
│   └── training_environments/   # Terrain data
│       ├── landcover_1.png     # Real landcover map
│       └── heightmap_1.png     # Real elevation data
├── viewer/
│   ├── __init__.py
│   └── server.py                # Static file and websocket server for 3D mode
├── web_dist/                    # Packaged 3D viewer assets
│   ├── index.html
│   └── assets/
└── wrappers/                    # Custom Gymnasium wrappers
    ├── __init__.py
    ├── full_cells_observation.py # Detailed cell features
    ├── custom_reward.py         # Custom reward functions
    └── clip_reward.py           # Reward clipping utility

scripts/
├── random_agent_human.py         # Random policy runner for Pygame mode
└── random_agent_3d.py            # Random policy runner for 3D browser mode

Citation

If you use FirecastRL in your research, please cite:

@software{firecastrl2025,
  title={Spatiotemporal Wildfire Prediction and Reinforcement Learning for Helitack Suppression},
  author={Shaurya Mathur, Shreyas Bellary Manjunath, Nitin Kulkarni, Alina Vereshchaka},
  year={2025},
  url={https://sites.google.com/view/firecastrl},
  doi={10.48550/arXiv.2601.14238}
}

Paper DOI: https://doi.org/10.48550/arXiv.2601.14238


Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.


Contact

Shaurya Mathur - shauryamathur2001@gmail.com Shreyas Bellary Manjunath - sbellary@buffalo.edu

Project Link: https://github.com/aisystems-lab/firecast-rl

About

A Gymnasium-compatible wildfire simulation environment with physics-informed fire spread dynamics and helicopter-based firefighting. Designed for reinforcement learning research in wildfire management and suppression strategies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors