Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build, Test, and Push Docker Image
name: Docker

on:
push:
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@


---
<!-- Identity & Citation -->
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![DOI](https://img.shields.io/badge/DOI-10.14195/978--989--26--0884--6_29-blue)](https://www.researchgate.net/publication/278769168_ForeFire_open-source_code_for_wildland_fire_spread_models) <!-- Or use Zenodo DOI if available -->
<!-- Project Health & Status -->
[![linuxCI](https://github.com/forefireAPI/forefire/actions/workflows/main.yml/badge.svg)](https://github.com/forefireAPI/forefire/actions/workflows/main.yml)
[![macOSCI](https://github.com/forefireAPI/forefire/actions/workflows/macos.yml/badge.svg)](https://github.com/forefireAPI/forefire/actions/workflows/macos.yml)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Docker CI/CD](https://github.com/forefireAPI/forefire/actions/workflows/docker.yml/badge.svg)](https://github.com/forefireAPI/forefire/actions/workflows/docker.yml)
[![Documentation Status](https://readthedocs.org/projects/forefire/badge/?version=latest)](https://forefire.readthedocs.io/en/latest/?badge=latest)
<!-- Distribution and Technical Stack -->
[![Docker Package](https://img.shields.io/badge/Docker-Package-blue?logo=docker&logoColor=white)](https://github.com/forefireAPI/forefire/pkgs/container/forefire)
![Language](https://img.shields.io/badge/C++-00599C?logo=c%2B%2B&logoColor=white)
![Language](https://img.shields.io/badge/Python-3776AB?logo=python&logoColor=white)
[![Documentation Status](https://readthedocs.org/projects/forefire/badge/?version=latest)](https://forefire.readthedocs.io/en/latest/?badge=latest)
[![DOI](https://img.shields.io/badge/DOI-10.14195/978--989--26--0884--6_29-blue)](https://www.researchgate.net/publication/278769168_ForeFire_open-source_code_for_wildland_fire_spread_models) <!-- Or use Zenodo DOI if available -->


**ForeFire** is an open-source **wildfire simulation engine** written in C++. Developed by CNRS at the [Université de Corse Pascal Paoli](https://www.univ-corse.fr/), it is used for research and operational forecasting. The engine implements various fire behavior models and enables high-fidelity coupled fire-atmosphere simulations, aiming to improve wildfire prediction and understanding for complex environments.
Expand Down Expand Up @@ -80,9 +85,11 @@ The easiest way to get started is often using Docker and the interactive console
This server provides a graphical user interface that you can access on your browser at http://localhost:8000/

6. Run your first simulation
- Run the command `include[real_case.ff]`
- Then press Refresh Map


In ForeFire, running a simulation and viewing the result are separate commands. The UI guides you through this process.
- **Step 1: Run the simulation script.** In the command input box, type `include[real_case.ff]` and click the **`Send`** button. The simulation will run on the server.
- **Step 2: View the result.** After the command finishes, click the **`Refresh Map`** button to load the simulation results onto the map.

You should see a simulation running in the Aullène region of Corsica. **This confirms your Docker setup is working!** Check the full documentation for more details on this example

## Build from source
Expand Down
Binary file modified docs/source/_static/images/gui_real_case_ff.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions docs/source/getting_started/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ Steps

8. **Run a Simulation:**

* In the web console's command input box, type: `include[real_case.ff]` and press Enter or click Send.
* Click the "Refresh Map" button.
In ForeFire, running a simulation and viewing the result are separate commands. The UI guides you through this.

* **Step 1: Run the simulation script.** In the command input box, type `include[real_case.ff]` and click the **`Send`** button. The simulation will run on the server.
* **Step 2: View the result.** After the command finishes, click the **`Refresh Map`** button to load the simulation results onto the map.

You should see a simulation running in the Aullène region of Corsica.

.. image:: /_static/images/gui_real_case_ff.jpg
Expand Down
6 changes: 4 additions & 2 deletions src/HttpCommandServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,14 @@ namespace http_command {
return buildResponse("200 OK", "text/html; charset=UTF-8", body);
} else {
if (!fileExists(path)) {
cout << "File not found: " << path << std::endl;
if (const char* ffHome = std::getenv("FOREFIREHOME")) {

std::string altPath = std::string(ffHome) +"/tools/htdocs/"+ path;
if (fileExists(altPath))
if (fileExists(altPath)){
path = altPath;
}
} else {
cout << "FOREFIREHOME not set. File not found: " << path << std::endl;
}
}
if (fileExists(path)) {
Expand Down
194 changes: 9 additions & 185 deletions tools/htdocs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,165 +7,17 @@
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
<!-- leaflet-velocity CSS -->
<link rel="stylesheet" href="js/leaflet-velocity.css" />
<style>
/* Global Styles */
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: monospace;
background-color: #111;
color: #eee;
}
/* Main container as a flex row: sidebar + main area */
#container {
display: flex;
height: 100vh;
}
/* Sidebar: left bar with layers list */
#sidebar {
width: 200px;
background-color: #222;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
/* Logo container */
#logo {
text-align: center;
margin-bottom: 10px;
}

<link rel="stylesheet" href="style.css" />

/* Logo image sizing */
#logo img {
max-width: 100%;
height: auto;
display: block;
}
<!-- External JS Libraries -->
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js" defer></script>
<script src="https://unpkg.com/togeojson@0.16.0/togeojson.js" defer></script>
<script src="js/leaflet-velocity.js" defer></script>
<script src="js/rosacewind.js" defer></script>
<!-- Our GUI JS -->
<script src="js/forefireGUI.js" defer></script>

#layerList {
list-style: none;
padding: 0;
margin: 0;
flex-grow: 1;
overflow-y: auto;
}
#layerList li {
margin: 5px 0;
padding: 5px;
cursor: pointer;
background-color: #333;
}
#layerList li:hover {
background-color: #444;
}
#updateLayers {
background-color: #444;
border: none;
color: #eee;
padding: 5px;
cursor: pointer;
margin-top: 10px;
}
/* Right side: main area */
#mainArea {
flex-grow: 1;
display: flex;
flex-direction: column;
}
/* Header: big orange date with toggle checkbox */
#dateHeader {
background: #111;
text-align: center;
font-size: 2em;
color: orange;
padding: 10px;
}
#dateHeader label {
font-size: 0.5em;
color: #ccc;
margin-left: 10px;
cursor: pointer;
}
/* Response Console: server responses */
#responseConsole {
background: #222;
padding: 10px;
height: 200px;
overflow-y: auto;
}
/* Command History: sent commands in green */
#commandHistory {
background: #222;
padding: 10px;
height: 100px;
overflow-y: auto;
margin: 5px;
color: lightgreen;
}
.commandText {
margin: 2px 0;
}
/* Input Area: command input and buttons */
#inputArea {
display: flex;
align-items: center;
height: 40px;
padding: 5px;
background-color: #111;
}
#inputArea input {
flex: 1;
padding: 5px;
font-size: 1em;
background-color: #333;
color: #eee;
border: 1px solid #444;
}
#inputArea button {
padding: 5px 10px;
background-color: #444;
color: #eee;
border: none;
cursor: pointer;
margin-left: 5px;
}
/* Predefined Command Buttons */
#commandButtons {
margin: 5px;
}
#commandButtons button {
padding: 5px 10px;
margin: 2px;
background-color: #444;
color: #eee;
border: none;
cursor: pointer;
font-size: 0.9em;
}
#commandButtons button:hover {
background-color: #555;
}
/* Map container: fixed height to avoid layout issues with big images */
#map {
height: 500px;
width: calc(100% - 10px);
margin: 5px;
}
/* Bounding box handle style */
.bbox-handle {
background: red;
border-radius: 50%;
width: 8px;
height: 8px;
border: 1px solid #fff;
}
/* Container for the wind canvas */
#windContainer {
margin: 5px;
}
</style>
</head>
<body>
<div id="container">
Expand Down Expand Up @@ -213,33 +65,5 @@
</div>
</div>

<!-- External JS Libraries -->
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script src="https://unpkg.com/togeojson@0.16.0/togeojson.js"></script>
<script src="js/leaflet-velocity.js"></script>
<script src="js/rosacewind.js"></script>
<!-- Our GUI JS -->
<script src="js/forefireGUI.js"></script>

<!-- Script to toggle logs -->
<script>
const toggleLogs = document.getElementById('toggleLogs');
const responseConsole = document.getElementById('responseConsole');
const commandHistory = document.getElementById('commandHistory');

toggleLogs.addEventListener('change', function() {
const displayStyle = this.checked ? 'block' : 'none';
responseConsole.style.display = displayStyle;
commandHistory.style.display = displayStyle;

// Optional: Adjust map height if needed when logs are hidden
// For example, increase the map height when logs are hidden
if (!this.checked) {
document.getElementById('map').style.height = '700px';
} else {
document.getElementById('map').style.height = '500px';
}
});
</script>
</body>
</html>
43 changes: 25 additions & 18 deletions tools/htdocs/js/forefireGUI.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Updated list of commands.
const commands = {
"include": "include[real_case.ff]",
"FireDomain": "FireDomain[sw=(0.0,0.0,0.0);ne=(100.0,100.0,0.0);t=0.0]",
"FireNode": "FireNode[loc=(0.0,0.0,0.0);vel=(0.0,0.0,0.0);t=0.]",
"FireFront": "FireFront[]",
Expand All @@ -15,7 +16,6 @@ const commands = {
"setParameter": "setParameter[param=value]",
"setParameters": "setParameters[param1=val1;param2=val2]",
"getParameter": "getParameter[paramNames]",
"include": "include[run.ff]",
"loadData": "loadData[data.nc;2024-12-13T15:41:33Z]",
"clear": "clear[]",
"systemExec": "systemExec[ls]",
Expand Down Expand Up @@ -256,19 +256,6 @@ function updateMapWithGeoJSON(geojson, refit = true) {
}
}

document.getElementById('refreshMap').addEventListener('click', async () => {
await sendCommand("setParameter[dumpMode=geojson]");
const geojsonText = await sendCommand("print[]");
if (geojsonText) {
try {
const geojson = JSON.parse(geojsonText);
updateMapWithGeoJSON(geojson);
} catch (e) {
console.error("Failed to parse GeoJSON:", e);
}
}
});

document.getElementById('sendCommand').addEventListener('click', () => {
const command = document.getElementById('commandInput').value.trim();
if (command !== "") {
Expand Down Expand Up @@ -453,14 +440,14 @@ function updateMapWithGeoJSON(geojson, refit = true) {
let autoRefreshInterval = null;

// 1) Factor out the refresh logic into a separate function:
async function refreshMap() {
async function refreshMap(refit = true) {
// The same logic you had in the 'refreshMap' button’s click handler
await sendCommand("setParameter[dumpMode=geojson]");
const geojsonText = await sendCommand("print[]");
if (geojsonText) {
try {
const geojson = JSON.parse(geojsonText);
updateMapWithGeoJSON(geojson, false);
updateMapWithGeoJSON(geojson, refit);
} catch (e) {
console.error("Failed to parse GeoJSON:", e);
}
Expand Down Expand Up @@ -510,8 +497,10 @@ document.getElementById('refreshMap').addEventListener('click', refreshMap);
// 3) Handle the auto-refresh checkbox changes:
document.getElementById('autoRefreshCheckbox').addEventListener('change', (e) => {
if (e.target.checked) {
// Start auto-refresh every 10 seconds (adjust as needed)
autoRefreshInterval = setInterval(refreshMap, 500);
// Start auto-refresh (adjust as needed)
autoRefreshInterval = setInterval(() => {
refreshMap(false);
}, 500);
} else {
// Stop auto-refresh
clearInterval(autoRefreshInterval);
Expand All @@ -521,4 +510,22 @@ document.getElementById('autoRefreshCheckbox').addEventListener('change', (e) =>

document.getElementById('WindOrParts').addEventListener('change', (e) => {
setWindMapUseVector(e.target.checked)
});

const toggleLogs = document.getElementById('toggleLogs');
const responseConsole = document.getElementById('responseConsole');
const commandHistory = document.getElementById('commandHistory');

toggleLogs.addEventListener('change', function() {
const displayStyle = this.checked ? 'block' : 'none';
responseConsole.style.display = displayStyle;
commandHistory.style.display = displayStyle;

// Optional: Adjust map height if needed when logs are hidden
// For example, increase the map height when logs are hidden
if (!this.checked) {
document.getElementById('map').style.height = '700px';
} else {
document.getElementById('map').style.height = '500px';
}
});
Loading
Loading