From e715b046cb5469557bf15a7d8bc2cca4d9319fc6 Mon Sep 17 00:00:00 2001 From: Antonio Leblanc Date: Wed, 11 Nov 2026 10:37:51 -0300 Subject: [PATCH 1/3] Make three ignored settings take effect without changing results setParameter strips triple quotes from a multiline value, Balbi2020.Cpa replaces the hard-coded 1150 (now its default), and FDCellsOutputs is read under its documented name. --- CHANGELOG.md | 7 +++++++ src/Command.cpp | 6 ++++++ src/FireDomain.cpp | 2 +- src/propagation/Balbi2020.cpp | 3 +-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2389b40..f48e6a43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,13 @@ history, so they summarise each release rather than list every change. The ### Fixed +- `setParameter[key="""..."""]` stores the value without the triple quotes, so + an inline multiline `fuelsTable` in a `.ff` script is read correctly. +- `Balbi2020.Cpa` now sets the air heat capacity; the model used a fixed + 1150 J/kg/K whatever the parameter said. The default is now 1150, so results + do not change. +- `FDCellsOutputs`, the documented name, turns on the atmospheric cell debug + output; the code read `FDCellOutputs`. - The Farsite model now matches the FARSITE reference (mbedward/farsite) at the flanks and back of the fire, not only at the head. On slopes it is an approximation. This changes Farsite results. ([#270]) diff --git a/src/Command.cpp b/src/Command.cpp index f6783ed8..e48f301a 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -2045,6 +2045,12 @@ namespace libforefire return error; } + // A value wrapped in triple quotes (a multiline literal) is stored without them. + string &value = tmpArgs[1]; + if (value.size() >= 6 && value.compare(0, 3, "\"\"\"") == 0 + && value.compare(value.size() - 3, 3, "\"\"\"") == 0) + value = value.substr(3, value.size() - 6); + // Check if the parameter value begins with '!' if (!tmpArgs[1].empty() && tmpArgs[1][0] == '!') { diff --git a/src/FireDomain.cpp b/src/FireDomain.cpp index eb8d0e5c..bbb8c17a 100644 --- a/src/FireDomain.cpp +++ b/src/FireDomain.cpp @@ -2526,7 +2526,7 @@ if ( params->getInt("FireDomainOutputs") != 0 ) outputs = true; if ( params->getInt("FireFrontOutputs") != 0 ) FireFront::outputs = true; if ( params->getInt("FireNodeOutputs") != 0 ) FireNode::outputs = true; - if ( params->getInt("FDCellOutputs") != 0 ) FDCell::outputs = true; + if ( params->getInt("FDCellsOutputs") != 0 ) FDCell::outputs = true; } // std::cout<<"ID"<getParameter("SOUTH")<<" WEST:"<getParameter("WEST")<<" NORTH:"<getParameter("NORTH")<<" EAST:"<getParameter("EAST")<isValued("Balbi2020.cooling") ) cooling = params->getDouble("Balbi2020.cooling"); - Cpa = 1004.; + Cpa = 1150.; if ( params->isValued("Balbi2020.Cpa") ) Cpa = params->getDouble("Balbi2020.Cpa"); } @@ -176,7 +176,6 @@ double Balbi2020::getSpeed(double* valueOf){ double lg = 9.81; double B = 5.6e-8; // nomenclature - double Cpa = 1150 ;// nomenclature double Tvap = 373; // nomenclature double K1 = 130 ;// nomenclature new parameter double st = 17 ;// nomenclature new parameter From 320ef05162c6716b4b10d444172cd6a639e0ea4f Mon Sep 17 00:00:00 2001 From: Antonio Leblanc Date: Wed, 11 Nov 2026 11:32:27 -0300 Subject: [PATCH 2/3] setParameter: split on the first '=', strip quotes after '!', trim, check the argument One helper strips triple quotes for setParameter and startFire[geojson=]. Script lines lose a trailing CR, so CRLF multiline literals parse. The duplicate store at the end of setParameter is gone. Docs give the Balbi2020.Cpa default as 1150. --- CHANGELOG.md | 6 ++- docs/source/user_guide/models.rst | 2 +- src/Command.cpp | 77 +++++++++++++++---------------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f48e6a43..2584a8a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,12 +52,14 @@ history, so they summarise each release rather than list every change. The ### Fixed - `setParameter[key="""..."""]` stores the value without the triple quotes, so - an inline multiline `fuelsTable` in a `.ff` script is read correctly. + an inline multiline `fuelsTable` in a `.ff` script is read correctly. The + value may also contain `=`. - `Balbi2020.Cpa` now sets the air heat capacity; the model used a fixed 1150 J/kg/K whatever the parameter said. The default is now 1150, so results do not change. - `FDCellsOutputs`, the documented name, turns on the atmospheric cell debug - output; the code read `FDCellOutputs`. + output when `watchedProc` selects the process, like the other `*Outputs` + flags; the code read `FDCellOutputs`. - The Farsite model now matches the FARSITE reference (mbedward/farsite) at the flanks and back of the fire, not only at the head. On slopes it is an approximation. This changes Farsite results. ([#270]) diff --git a/docs/source/user_guide/models.rst b/docs/source/user_guide/models.rst index 599d6f2a..3210aa3d 100644 --- a/docs/source/user_guide/models.rst +++ b/docs/source/user_guide/models.rst @@ -84,7 +84,7 @@ Balbi2020 :ref:`The Standard Rothermel / Balbi Fuel Table ` (from ``fuel.Rhod`` to ``fuel.Blai``). Optional parameters: ``Balbi2020.cooling`` (default ``0``) and ``Balbi2020.Cpa`` (default - ``1004``). + ``1150``). BalbiNov2011, BalbiNov2011Curv and BalbiNov2011TMdMl ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/Command.cpp b/src/Command.cpp index e48f301a..e4408694 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -18,6 +18,25 @@ using namespace std; +namespace +{ + // If `in`, once trimmed of surrounding whitespace, is wrapped in triple + // quotes, puts the text between them in `out` and returns true. + bool stripTripleQuotes(const std::string &in, std::string &out) + { + const std::string ws = " \t\r\n"; + const std::size_t first = in.find_first_not_of(ws); + if (first == std::string::npos) + return false; + const std::string trimmed = in.substr(first, in.find_last_not_of(ws) - first + 1); + if (trimmed.size() < 6 || trimmed.compare(0, 3, "\"\"\"") != 0 + || trimmed.compare(trimmed.size() - 3, 3, "\"\"\"") != 0) + return false; + out = trimmed.substr(3, trimmed.size() - 6); + return true; + } +} + namespace libforefire { @@ -308,16 +327,7 @@ namespace libforefire trimmed.erase(0, trimmed.find_first_not_of(" \t\r\n")); trimmed.erase(trimmed.find_last_not_of(" \t\r\n") + 1); - /* Triple‑quoted inline string? e.g. \"\"\"{ ... }\"\"\" */ - bool tripleQuoted = trimmed.size() >= 6 && - trimmed.substr(0, 3) == "\"\"\"" && - trimmed.substr(trimmed.size() - 3) == "\"\"\""; - - if (tripleQuoted) - { - geojsonText = trimmed.substr(3, trimmed.size() - 6); // strip outer quotes - } - else + if (!stripTripleQuotes(trimmed, geojsonText)) { /* Try to open it as a file path. */ std::ifstream jf(trimmed.c_str()); @@ -2034,40 +2044,25 @@ namespace libforefire } int Command::setParameter(const string &arg, size_t &/*numTabs*/) { - // Getting all the arguments, using the 'tokenize' function - // Returns strings of the form 'arg=...' - vector tmpArgs; - string delimiter = "="; - tokenize(arg, tmpArgs, delimiter); - if (tmpArgs.size() > 2) + // key=value, split on the first '=' so the value may contain '='. + // A leading '!' protects the key; a value wrapped in triple quotes + // (a multiline literal) is stored without them. + const size_t eq = arg.find('='); + if (eq == string::npos || eq == 0) { cout << "problem in the number of arguments when setting " << arg << endl; return error; } + const string key = arg.substr(0, eq); + string value = arg.substr(eq + 1); + const bool protect = !value.empty() && value[0] == '!'; + if (protect) + value = value.substr(1); + stripTripleQuotes(value, value); - // A value wrapped in triple quotes (a multiline literal) is stored without them. - string &value = tmpArgs[1]; - if (value.size() >= 6 && value.compare(0, 3, "\"\"\"") == 0 - && value.compare(value.size() - 3, 3, "\"\"\"") == 0) - value = value.substr(3, value.size() - 6); - - // Check if the parameter value begins with '!' - if (!tmpArgs[1].empty() && tmpArgs[1][0] == '!') - { - // Remove the leading '!' to get the actual value. - std::string value = tmpArgs[1].substr(1); - // Set the parameter with a protection flag (true). - currentSession.params->setParameter(tmpArgs[0], value, true); - std::cout << "Parameter " << tmpArgs[0] - << " set to fixed protected value " << value << std::endl; - } - else - { - // Set the parameter normally (without protection). - currentSession.params->setParameter(tmpArgs[0], tmpArgs[1], false); - } - - currentSession.params->setParameter(tmpArgs[0], tmpArgs[1]); + currentSession.params->setParameter(key, value, protect); + if (protect) + cout << "Parameter " << key << " set to fixed protected value " << value << endl; return normal; } @@ -2441,6 +2436,10 @@ namespace libforefire while (std::getline(*inputStream, line)) { + // Scripts saved with CRLF line endings. + if (!line.empty() && line.back() == '\r') + line.pop_back(); + // A `quit[]` earlier in the script stops the file here rather than // ending the process, so the caller still gets to return normally. if (quitAsked) From 477988bcb39cc8b70b15a0e0cb592ce534e03ecc Mon Sep 17 00:00:00 2001 From: Antonio Leblanc Date: Wed, 11 Nov 2026 11:50:20 -0300 Subject: [PATCH 3/3] CHANGELOG: FDCellsOutputs=0 is what changes --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2584a8a4..ed4a9d1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,9 +57,9 @@ history, so they summarise each release rather than list every change. The - `Balbi2020.Cpa` now sets the air heat capacity; the model used a fixed 1150 J/kg/K whatever the parameter said. The default is now 1150, so results do not change. -- `FDCellsOutputs`, the documented name, turns on the atmospheric cell debug - output when `watchedProc` selects the process, like the other `*Outputs` - flags; the code read `FDCellOutputs`. +- `FDCellsOutputs=0` turns off the atmospheric cell debug output. The code + read `FDCellOutputs`, so the output was always on when `watchedProc` + selected the process. - The Farsite model now matches the FARSITE reference (mbedward/farsite) at the flanks and back of the fire, not only at the head. On slopes it is an approximation. This changes Farsite results. ([#270])