From eab3bd5241358ed461f5d8ce7368129f66878423 Mon Sep 17 00:00:00 2001 From: RJ Sheperd Date: Thu, 15 Jan 2026 17:54:22 -0800 Subject: [PATCH 1/3] [BHP1-1375] Add Byram Flame Length to Fireline Intensity conversion --- src/behave/behaveUnits.cpp | 32 ++++++++++++++++++++++++++++++++ src/behave/spot.cpp | 25 +++++++++++++++++++++++++ src/behave/spot.h | 4 ++++ src/behave/spotInputs.cpp | 23 +++++++++++++++++++++++ src/behave/spotInputs.h | 24 ++++++++++++++---------- src/testBehave/testBehave.cpp | 13 +++++++++++++ 6 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/behave/behaveUnits.cpp b/src/behave/behaveUnits.cpp index 6ee550f..5d1ed72 100644 --- a/src/behave/behaveUnits.cpp +++ b/src/behave/behaveUnits.cpp @@ -30,6 +30,7 @@ double LengthUnits::toBaseUnits(double value, LengthUnits::LengthUnitsEnum units) { + if (value == 0.0) return 0.0; // Length to base units constants const double INCHES_TO_FEET = 0.08333333333333; const double METERS_TO_FEET = 3.2808398950131; @@ -91,6 +92,7 @@ double LengthUnits::toBaseUnits(double value, LengthUnits::LengthUnitsEnum units double LengthUnits::fromBaseUnits(double value, LengthUnits::LengthUnitsEnum units) { + if (value == 0.0) return 0.0; // Length from base units constants const double FEET_TO_INCHES = 12; const double FEET_TO_CENTIMETERS = 30.480; @@ -146,6 +148,7 @@ double LengthUnits::fromBaseUnits(double value, LengthUnits::LengthUnitsEnum uni double SpeedUnits::toBaseUnits(double value, SpeedUnits::SpeedUnitsEnum units) { + if (value == 0.0) return 0.0; // Velocity to base units constants const double METERS_PER_SECOND_TO_FEET_PER_MINUTE = 196.8503937; const double METERS_PER_MINUTE_TO_FEET_PER_MINUTE = 3.28084; @@ -201,6 +204,7 @@ double SpeedUnits::toBaseUnits(double value, SpeedUnits::SpeedUnitsEnum units) double SpeedUnits::fromBaseUnits(double value, SpeedUnits::SpeedUnitsEnum units) { + if (value == 0.0) return 0.0; // Velocity from base units constants const double FEET_PER_MINUTE_TO_METERS_PER_SECOND = 0.00508; const double FEET_PER_MINUTE_TO_METERS_PER_MINUTE = 0.3048; @@ -256,6 +260,7 @@ double SpeedUnits::fromBaseUnits(double value, SpeedUnits::SpeedUnitsEnum units) double FractionUnits::toBaseUnits(double value, FractionUnitsEnum units) { + if (value == 0.0) return 0.0; if (units == Percent) { value /= 100.0; @@ -265,6 +270,7 @@ double FractionUnits::toBaseUnits(double value, FractionUnitsEnum units) double FractionUnits::fromBaseUnits(double value, FractionUnitsEnum units) { + if (value == 0.0) return 0.0; if (units == Percent) { value *= 100.0; @@ -274,6 +280,7 @@ double FractionUnits::fromBaseUnits(double value, FractionUnitsEnum units) double SlopeUnits::toBaseUnits(double value, SlopeUnitsEnum units) { + if (value == 0.0) return 0.0; static const double PI = 3.141592653589793238463; if (units == Percent) @@ -285,6 +292,7 @@ double SlopeUnits::toBaseUnits(double value, SlopeUnitsEnum units) double SlopeUnits::fromBaseUnits(double value, SlopeUnitsEnum units) { + if (value == 0.0) return 0.0; static const double PI = 3.141592653589793238463; if (units == Percent) @@ -296,6 +304,7 @@ double SlopeUnits::fromBaseUnits(double value, SlopeUnitsEnum units) double DensityUnits::toBaseUnits(double value, DensityUnitsEnum units) { + if (value == 0.0) return 0.0; // Denisty to base units constants //static const double KG_PER_CUBIC_METER_TO_LBS_PER_CUBIC_FOOT = 0.06242796051; static const double KG_PER_CUBIC_METER_TO_LBS_PER_CUBIC_FOOT = 0.06242781786; @@ -309,6 +318,7 @@ double DensityUnits::toBaseUnits(double value, DensityUnitsEnum units) double DensityUnits::fromBaseUnits(double value, DensityUnitsEnum units) { + if (value == 0.0) return 0.0; // Denisty from base units constants //static const double LBS_PER_CUBIC_FOOT_TO_KG_PER_CUBIC_METER = 16.018463390932; static const double LBS_PER_CUBIC_FOOT_TO_KG_PER_CUBIC_METER = 16.0185; @@ -322,6 +332,7 @@ double DensityUnits::fromBaseUnits(double value, DensityUnitsEnum units) double LoadingUnits::toBaseUnits(double value, LoadingUnitsEnum units) { + if (value == 0.0) return 0.0; // Velocity to base units constants const double KILOGRAMS_PER_SQUARE_METER_TO_POUNDS_PER_SQUARE_FOOT = 0.2048161436225217; const double TONS_PER_ACRE_TO_POUNDS_PER_SQUARE_FOOT = 0.045913682277318638; @@ -359,6 +370,7 @@ double LoadingUnits::toBaseUnits(double value, LoadingUnitsEnum units) double LoadingUnits::fromBaseUnits(double value, LoadingUnitsEnum units) { + if (value == 0.0) return 0.0; // Velocity to base units constants const double POUNDS_PER_SQUARE_FOOT_TO_KILOGRAMS_PER_SQUARE_METER = 4.88242763638305; const double POUNDS_PER_SQUARE_FOOT_TO_TONS_PER_ACRE = 21.78; @@ -395,6 +407,7 @@ double LoadingUnits::fromBaseUnits(double value, LoadingUnitsEnum units) } double PressureUnits::toBaseUnits(double value, PressureUnitsEnum units) { + if (value == 0.0) return 0.0; // Pressure to base units constants const double HECTOPASCAL_TO_PASCAL = 1e2; const double KILOPASCAL_TO_PASCAL = 1e3; @@ -458,6 +471,7 @@ double PressureUnits::toBaseUnits(double value, PressureUnitsEnum units) { } double PressureUnits::fromBaseUnits(double value, PressureUnitsEnum units) { + if (value == 0.0) return 0.0; // Pressure to base units constants const double HECTOPASCAL_TO_PASCAL = 1e2; const double KILOPASCAL_TO_PASCAL = 1e3; @@ -521,6 +535,7 @@ double PressureUnits::fromBaseUnits(double value, PressureUnitsEnum units) { double SurfaceAreaToVolumeUnits::toBaseUnits(double value, SurfaceAreaToVolumeUnitsEnum units) { + if (value == 0.0) return 0.0; const double SQUARE_METERS_OVER_CUBIC_METERS_TO_SQUARE_FEET_OVER_CUBIC_FEET = 3.280839895013123; const double SQUARE_INCHES_OVER_CUBIC_INCHES_TO_SQUARE_FEET_OVER_CUBIC_FEET = 0.083333333333333; @@ -558,6 +573,7 @@ double SurfaceAreaToVolumeUnits::toBaseUnits(double value, SurfaceAreaToVolumeUn double SurfaceAreaToVolumeUnits::fromBaseUnits(double value, SurfaceAreaToVolumeUnitsEnum units) { + if (value == 0.0) return 0.0; const double SQUARE_FEET_OVER_CUBIC_FEET_TO_SQUARE_METERS_OVER_CUBIC_METERS = 0.3048; const double SQUARE_FEET_OVER_CUBIC_FEET_TO_SQUARE_INCHES_OVER_CUBIC_INCHES = 12; const double SQUARE_FEET_OVER_CUBIC_FEET_TO_SQUARE_CENTIMETERS_OVER_CUBIC_CENTIMERS = 30.48; @@ -648,6 +664,7 @@ double TemperatureUnits::fromBaseUnits(double value, TemperatureUnitsEnum units) double TimeUnits::toBaseUnits(double value, TimeUnitsEnum units) { + if (value == 0.0) return 0.0; switch (units) { case Minutes: @@ -685,6 +702,7 @@ double TimeUnits::toBaseUnits(double value, TimeUnitsEnum units) double TimeUnits::fromBaseUnits(double value, TimeUnitsEnum units) { + if (value == 0.0) return 0.0; switch (units) { case Minutes: @@ -722,6 +740,7 @@ double TimeUnits::fromBaseUnits(double value, TimeUnitsEnum units) double AreaUnits::toBaseUnits(double value, AreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double ACRES_TO_SQUARE_FEET = 43560.002160576107; const double HECTARES_TO_SQUARE_FEET = 107639.10416709723; const double SQUARE_METERS_TO_SQUARE_FEET = 10.76391041671; @@ -771,6 +790,7 @@ double AreaUnits::toBaseUnits(double value, AreaUnitsEnum units) double AreaUnits::fromBaseUnits(double value, AreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double SQUARE_FEET_TO_ACRES = 2.295684e-05; const double SQUARE_FEET_TO_HECTARES = 0.0000092903036; const double SQUARE_FEET_TO_SQUARE_KILOMETERS = 9.290304e-08; @@ -820,6 +840,7 @@ double AreaUnits::fromBaseUnits(double value, AreaUnitsEnum units) double BasalAreaUnits::toBaseUnits(double value, BasalAreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double SQUARE_FEET_PER_ACRE_TO_SQUARE_METERS_PER_HECTARE = 0.229568; switch(units) @@ -845,6 +866,7 @@ double BasalAreaUnits::toBaseUnits(double value, BasalAreaUnitsEnum units) double BasalAreaUnits::fromBaseUnits(double value, BasalAreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double SQUARE_METERS_PER_HECTARE_TO_SQUARE_FEET_PER_ACRE = 4.356; switch(units) { @@ -868,6 +890,7 @@ double BasalAreaUnits::fromBaseUnits(double value, BasalAreaUnitsEnum units) double HeatOfCombustionUnits::toBaseUnits(double value, HeatOfCombustionUnitsEnum units) { + if (value == 0.0) return 0.0; const double KILOJOULES_PER_KILOGRAM_TO_BTUS_PER_POUND = 0.429592; switch (units) @@ -893,6 +916,7 @@ double HeatOfCombustionUnits::toBaseUnits(double value, HeatOfCombustionUnitsEnu double HeatOfCombustionUnits::fromBaseUnits(double value, HeatOfCombustionUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_POUND_TO_KILOJOULES_PER_KILOGRAM = 2.32779; switch (units) @@ -918,6 +942,7 @@ double HeatOfCombustionUnits::fromBaseUnits(double value, HeatOfCombustionUnitsE double FirelineIntensityUnits::toBaseUnits(double value, FirelineIntensityUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_FOOT_PER_MINUTE_TO_BTUS_PER_FOOT_PER_SECOND = 0.01666666666666667; const double KILOJOULES_PER_METER_PER_MINUTE_TO_BTUS_PER_FOOT_PER_SECOND = 0.00481120819; const double KILOWATTS_PER_METER_TO_BTUS_PER_FOOT_PER_SECOND = 0.2886719; @@ -960,6 +985,7 @@ double FirelineIntensityUnits::toBaseUnits(double value, FirelineIntensityUnitsE double FirelineIntensityUnits::fromBaseUnits(double value, FirelineIntensityUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_FOOT_PER_SECOND_TO_BTUS_PER_FOOT_PER_MINUTE = 60; const double BTUS_PER_FOOT_PER_SECOND_TO_KILOJOULES_PER_METER_PER_MINUTE = 207.848; const double BTUS_PER_FOOT_PER_SECOND_TO_KILOWATTS_PER_METER = 3.464140419; @@ -1002,6 +1028,7 @@ double FirelineIntensityUnits::fromBaseUnits(double value, FirelineIntensityUnit double HeatPerUnitAreaUnits::toBaseUnits(double value, HeatPerUnitAreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double KILOJOULES_PER_SQUARE_METER_TO_BTUS_PER_SECOND = 0.0879872; const double KILOWATT_SECONDS_PER_SQUARE_METER_PER_TO_BTUS_PER_SQUARE_FOOT = 0.0879872; @@ -1034,6 +1061,7 @@ double HeatPerUnitAreaUnits::toBaseUnits(double value, HeatPerUnitAreaUnitsEnum double HeatPerUnitAreaUnits::fromBaseUnits(double value, HeatPerUnitAreaUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_SQUARE_FOOT_TO_KILOJOULES_PER_SQUARE_METER = 11.3653; const double BTUS_PER_SQUARE_FOOT_TO_KILOWATT_SECONDS_PER_SQUARE_METER = 11.3653; @@ -1066,6 +1094,7 @@ double HeatPerUnitAreaUnits::fromBaseUnits(double value, HeatPerUnitAreaUnitsEnu double HeatSourceAndReactionIntensityUnits::toBaseUnits(double value, HeatSourceAndReactionIntensityUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_SQUARE_FOOT_PER_SECOND_TO_BTUS_PER_SQUARE_FOOT_PER_MINUTE = 60; const double KILOJOULES_PER_SQUARE_METER_PER_MINUTE_TO_BTUS_PER_SQUARE_FOOT_PER_MINUTE = 0.0880549963329497; const double KILOWATTS_PER_SQUARE_METER_TO_BTUS_PER_SQUARE_FOOT_PER_MINUTE = 5.27921783108615; @@ -1108,6 +1137,7 @@ double HeatSourceAndReactionIntensityUnits::toBaseUnits(double value, HeatSource double HeatSourceAndReactionIntensityUnits::fromBaseUnits(double value, HeatSourceAndReactionIntensityUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_SQUARE_FOOT_PER_MINUTE_TO_BTUS_PER_SQUARE_FOOT_PER_SECOND = 0.01666666666666667; const double BTUS_PER_SQUARE_FOOT_PER_MINUTE_TO_KILOJOULES_PER_SQUARE_METER_PER_MINUTE = 11.356539; //const double BTUS_PER_SQUARE_FOOT_PER_MINUTE_TO_KILOWATTS_PER_SQUARE_METER = 0.18927565; @@ -1151,6 +1181,7 @@ double HeatSourceAndReactionIntensityUnits::fromBaseUnits(double value, HeatSour double HeatSinkUnits::toBaseUnits(double value, HeatSinkUnitsEnum units) { + if (value == 0.0) return 0.0; const double KILOJOULES_PER_CUBIC_METER_TO_BTUS_PER_CUBIC_FOOT = 0.02681849745789; switch (units) { @@ -1174,6 +1205,7 @@ double HeatSinkUnits::toBaseUnits(double value, HeatSinkUnitsEnum units) double HeatSinkUnits::fromBaseUnits(double value, HeatSinkUnitsEnum units) { + if (value == 0.0) return 0.0; const double BTUS_PER_CUBIC_FOOT_TO_KILOJOULES_PER_CUBIC_METER = 37.28769673134085; switch (units) { diff --git a/src/behave/spot.cpp b/src/behave/spot.cpp index 68e9fbf..a89c417 100644 --- a/src/behave/spot.cpp +++ b/src/behave/spot.cpp @@ -275,13 +275,29 @@ void Spot::calculateSpottingDistanceFromBurningPile() } } +// Byram (1959)'s fireline intensity (kW/m) is derived back from flame length (meters) +// \[ I_B = \left( \frac{L}{0.0775} \right)^{1/0.46} \] +double byramFirelineIntensity(double flameLength) { + constexpr double coeff = 0.0775; + constexpr double exponent = 1.0 / 0.46; + return std::pow(flameLength / coeff, exponent); +} + void Spot::calculateSpottingDistanceFromActiveCrown() { SpotFireLocation::SpotFireLocationEnum location = spotInputs_.getLocation(); double ridgeToValleyDistance = spotInputs_.getRidgeToValleyDistance(LengthUnits::Miles); double ridgeToValleyElevation = spotInputs_.getRidgeToValleyElevation(LengthUnits::Feet); double treeHeight = calculateTreeHeight(LengthUnits::Meters); + double firelineIntensity = spotInputs_.getCrownFirelineIntensity(FirelineIntensityUnits::KilowattsPerMeter); + double flameLength = spotInputs_.getSurfaceFlameLength(LengthUnits::Meters); + + // Use Byram (1959) FLI approximation if FLI is null + if ((std::abs(firelineIntensity) < 0.01) && (flameLength > 0.0)) { + firelineIntensity = byramFirelineIntensity(flameLength); + } + double windSpeed = spotInputs_.getWindSpeedAtTwentyFeet(SpeedUnits::KilometersPerHour);; double windHeight = 6.096; //20ft in meters double emberDiamMm = 1.0; @@ -517,6 +533,15 @@ void Spot::updateSpotInputsForTorchingTrees(SpotFireLocation::SpotFireLocationEn windSpeedAtTwentyFeet, windSpeedUnits); } +void Spot::updateSpotInputsForActiveCrownFire(SpotFireLocation::SpotFireLocationEnum location, double ridgeToValleyDistance, + LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits, double ridgeToValleyElevation, LengthUnits::LengthUnitsEnum elevationUnits, + double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode, double windSpeedAtTwentyFeet, + SpeedUnits::SpeedUnitsEnum windSpeedUnits, double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits) +{ + spotInputs_.updateSpotInputsForActiveCrownFire(location, ridgeToValleyDistance, ridgeToValleyDistanceUnits, ridgeToValleyElevation,elevationUnits, + treeHeight, treeHeightUnits, downwindCanopyMode, windSpeedAtTwentyFeet, windSpeedUnits, activeCrownFlameLength, flameLengthUnits); +} + double Spot::getBurningPileFlameHeight(LengthUnits::LengthUnitsEnum flameHeightUnits) const { return spotInputs_.getBurningPileFlameHeight(flameHeightUnits); diff --git a/src/behave/spot.h b/src/behave/spot.h index ad06f1a..d7953e0 100644 --- a/src/behave/spot.h +++ b/src/behave/spot.h @@ -80,6 +80,10 @@ class Spot double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode, int torchingTrees, double DBH, LengthUnits::LengthUnitsEnum DBHUnits, double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotTreeSpecies::SpotTreeSpeciesEnum treeSpecies, double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits); + void updateSpotInputsForActiveCrownFire(SpotFireLocation::SpotFireLocationEnum location, double ridgeToValleyDistance, + LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits, double ridgeToValleyElevation, LengthUnits::LengthUnitsEnum elevationUnits, + double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode, + double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits, double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); // Spot Inputs Getters double getBurningPileFlameHeight(LengthUnits::LengthUnitsEnum flameHeightUnits) const; diff --git a/src/behave/spotInputs.cpp b/src/behave/spotInputs.cpp index 2b3f80a..46806ad 100644 --- a/src/behave/spotInputs.cpp +++ b/src/behave/spotInputs.cpp @@ -101,6 +101,7 @@ void SpotInputs::updateSpotInputsForBurningPile(SpotFireLocation::SpotFireLocati double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downindCanopyMode, double buringPileFlameHeight, LengthUnits::LengthUnitsEnum flameHeightUnits, double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits) { + initializeMembers(); setLocation(location); setRidgeToValleyDistance(ridgeToValleyDistance, ridgeToValleyDistanceUnits); setRidgeToValleyElevation(ridgeToValleyElevation, elevationUnits); @@ -115,6 +116,7 @@ void SpotInputs::updateSpotInputsForSurfaceFire(SpotFireLocation::SpotFireLocati double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downindCanopyMode, double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits, double surfaceFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits) { + initializeMembers(); setLocation(location); setRidgeToValleyDistance(ridgeToValleyDistance, ridgeToValleyDistanceUnits); setRidgeToValleyElevation(ridgeToValleyElevation, elevationUnits); @@ -130,6 +132,7 @@ void SpotInputs::updateSpotInputsForTorchingTrees(SpotFireLocation::SpotFireLoca int torchingTrees, double DBH, LengthUnits::LengthUnitsEnum DBHUnits, double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotTreeSpecies::SpotTreeSpeciesEnum treeSpecies, double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits) { + initializeMembers(); setLocation(location); setRidgeToValleyDistance(ridgeToValleyDistance, ridgeToValleyDistanceUnits); setRidgeToValleyElevation(ridgeToValleyElevation, elevationUnits); @@ -142,6 +145,25 @@ void SpotInputs::updateSpotInputsForTorchingTrees(SpotFireLocation::SpotFireLoca setWindSpeedAtTwentyFeet(windSpeedAtTwentyFeet, windSpeedUnits); } +void SpotInputs::updateSpotInputsForActiveCrownFire( + SpotFireLocation::SpotFireLocationEnum location, double ridgeToValleyDistance, + LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits, double ridgeToValleyElevation, + LengthUnits::LengthUnitsEnum elevationUnits, double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, + SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downindCanopyMode, + double windSpeedAtTwentyFeet, + SpeedUnits::SpeedUnitsEnum windSpeedUnits, + double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits) +{ + initializeMembers(); + setLocation(location); + setSurfaceFlameLength(activeCrownFlameLength, flameLengthUnits); + setRidgeToValleyDistance(ridgeToValleyDistance, ridgeToValleyDistanceUnits); + setRidgeToValleyElevation(ridgeToValleyElevation, elevationUnits); + setTreeHeight(treeHeight, treeHeightUnits); + setDownwindCanopyMode(downindCanopyMode); + setWindSpeedAtTwentyFeet(windSpeedAtTwentyFeet, windSpeedUnits); +} + double SpotInputs::getBurningPileFlameHeight(LengthUnits::LengthUnitsEnum flameHeightUnits) const { return LengthUnits::fromBaseUnits(buringPileFlameHeight_, flameHeightUnits); @@ -211,6 +233,7 @@ void SpotInputs::initializeMembers() { downwindCoverHeight_ = 0.0; downwindCanopyMode_ = SpotDownWindCanopyMode::CLOSED; + crownFirelineIntensity_ = 0.0; location_ = SpotFireLocation::MIDSLOPE_WINDWARD; ridgeToValleyDistance_ = 0.0; ridgeToValleyElevation_ = 0.0; diff --git a/src/behave/spotInputs.h b/src/behave/spotInputs.h index 93d8b80..6335aca 100644 --- a/src/behave/spotInputs.h +++ b/src/behave/spotInputs.h @@ -104,6 +104,10 @@ class SpotInputs double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downindCanopyMode, int torchingTrees, double DBH, LengthUnits::LengthUnitsEnum DBHUnits, double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotTreeSpecies::SpotTreeSpeciesEnum treeSpecies, double windSpeedAtTwentyFeet, SpeedUnits::SpeedUnitsEnum windSpeedUnits); + void updateSpotInputsForActiveCrownFire(SpotFireLocation::SpotFireLocationEnum location, double ridgeToValleyDistance, + LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits, double ridgeToValleyElevation, LengthUnits::LengthUnitsEnum elevationUnits, + double treeHeight, LengthUnits::LengthUnitsEnum treeHeightUnits, SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downindCanopyMode, double windSpeedAtTwentyFeet, + SpeedUnits::SpeedUnitsEnum windSpeedUnits, double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); double getBurningPileFlameHeight(LengthUnits::LengthUnitsEnum flameHeightUnits) const; double getDBH(LengthUnits::LengthUnitsEnum DBHUnits) const; @@ -132,18 +136,18 @@ class SpotInputs protected: void initializeMembers(); - double DBH_; - double downwindCoverHeight_; + double DBH_ = 0.0; + double downwindCoverHeight_ = 0.0; SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode_; SpotFireLocation::SpotFireLocationEnum location_; - double ridgeToValleyDistance_; - double ridgeToValleyElevation_; - double windSpeedAtTwentyFeet_; - double buringPileFlameHeight_; - double surfaceFlameLength_; - double crownFirelineIntensity_; - int torchingTrees_; - double treeHeight_; + double ridgeToValleyDistance_ = 0.0; + double ridgeToValleyElevation_ = 0.0; + double windSpeedAtTwentyFeet_ = 0.0; + double buringPileFlameHeight_ = 0.0; + double surfaceFlameLength_ = 0.0; + double crownFirelineIntensity_ = 0.0; + int torchingTrees_ = 0.0; + double treeHeight_ = 0.0; SpotTreeSpecies::SpotTreeSpeciesEnum treeSpecies_; }; diff --git a/src/testBehave/testBehave.cpp b/src/testBehave/testBehave.cpp index 6dabdad..2fa6c9a 100644 --- a/src/testBehave/testBehave.cpp +++ b/src/testBehave/testBehave.cpp @@ -1415,6 +1415,19 @@ void testSpotModule(TestInfo& testInfo, BehaveRun& behaveRun) observedFlatSpottingDistance = roundToSixDecimalPlaces(behaveRun.spot.getMaxFlatTerrainSpottingDistanceFromTorchingTrees(spottingDistanceUnits)); reportTestResult(testInfo, testName, observedFlatSpottingDistance, expectedFlatSpottingDistance, error_tolerance); + /// Active Crown + testName = "Test mountain spotting distance from active crown fire, closed downwind canopy"; + double activeCrownFlameLength = 20.0; + + behaveRun.spot.updateSpotInputsForActiveCrownFire(location, ridgeToValleyDistance, ridgeToValleyDistanceUnits, + ridgeToValleyElevation, elevationUnits, treeHeight, treeHeightUnits, downWindCanopyMode, + windSpeedAtTwentyFeet, windSpeedUnits, activeCrownFlameLength, flameHeightUnits); + behaveRun.spot.calculateSpottingDistanceFromActiveCrown(); + + expectedMountainSpottingDistance = 0.384247; + observedMountainSpottingDistance = roundToSixDecimalPlaces(behaveRun.spot.getMaxMountainousTerrainSpottingDistanceFromActiveCrown(spottingDistanceUnits)); + reportTestResult(testInfo, testName, observedMountainSpottingDistance, expectedMountainSpottingDistance, error_tolerance); + std::cout << "Finished testing Spot module\n\n"; } From f3c3506c54312fa5fac0b7ac0f2ac2b217a3c2cf Mon Sep 17 00:00:00 2001 From: RJ Sheperd Date: Thu, 15 Jan 2026 23:07:43 -0800 Subject: [PATCH 2/3] Separate active crown flame length --- src/behave/spot.cpp | 12 +++++++++++- src/behave/spot.h | 2 ++ src/behave/spotInputs.cpp | 13 ++++++++++++- src/behave/spotInputs.h | 3 +++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/behave/spot.cpp b/src/behave/spot.cpp index a89c417..07005c1 100644 --- a/src/behave/spot.cpp +++ b/src/behave/spot.cpp @@ -291,7 +291,7 @@ void Spot::calculateSpottingDistanceFromActiveCrown() { double treeHeight = calculateTreeHeight(LengthUnits::Meters); double firelineIntensity = spotInputs_.getCrownFirelineIntensity(FirelineIntensityUnits::KilowattsPerMeter); - double flameLength = spotInputs_.getSurfaceFlameLength(LengthUnits::Meters); + double flameLength = spotInputs_.getActiveCrownFlameLength(LengthUnits::Meters); // Use Byram (1959) FLI approximation if FLI is null if ((std::abs(firelineIntensity) < 0.01) && (flameLength > 0.0)) { @@ -464,6 +464,11 @@ void Spot::setFlameLength(double flameLength, LengthUnits::LengthUnitsEnum flame spotInputs_.setSurfaceFlameLength(flameLength, flameLengthUnits); } +void Spot::setActiveCrownFlameLength(double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits) +{ + spotInputs_.setActiveCrownFlameLength(activeCrownFlameLength, flameLengthUnits); +} + void Spot::setFirelineIntensity(double firelineIntensity, FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) { spotInputs_.setCrownFirelineIntensity(firelineIntensity, firelineIntensityUnits); @@ -567,6 +572,11 @@ double Spot::getSurfaceFlameLength(LengthUnits::LengthUnitsEnum flameLengthUnits return spotInputs_.getSurfaceFlameLength(flameLengthUnits); } +double Spot::getActiveCrownFlameLength(LengthUnits::LengthUnitsEnum flameLengthUnits) const +{ + return spotInputs_.getActiveCrownFlameLength(flameLengthUnits); +} + double Spot::getCrownFirelineIntensity(FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) const { return spotInputs_.getCrownFirelineIntensity(firelineIntensityUnits); diff --git a/src/behave/spot.h b/src/behave/spot.h index d7953e0..b99e948 100644 --- a/src/behave/spot.h +++ b/src/behave/spot.h @@ -57,6 +57,7 @@ class Spot void setDownwindCoverHeight(double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits); void setDownwindCanopyMode(SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode); void setFlameLength(double flameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); + void setActiveCrownFlameLength(double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); void setFirelineIntensity(double firelineIntensity, FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits); void setLocation(SpotFireLocation::SpotFireLocationEnum location); void setRidgeToValleyDistance(double ridgeToValleyDistance, LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits); @@ -91,6 +92,7 @@ class Spot double getDownwindCoverHeight(LengthUnits::LengthUnitsEnum coverHeightUnits) const; SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum getDownwindCanopyMode() const; double getSurfaceFlameLength(LengthUnits::LengthUnitsEnum surfaceFlameLengthUnits) const; + double getActiveCrownFlameLength(LengthUnits::LengthUnitsEnum flameLengthUnits) const; double getCrownFirelineIntensity(FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) const; SpotFireLocation::SpotFireLocationEnum getLocation() const; double getRidgeToValleyDistance(LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits) const; diff --git a/src/behave/spotInputs.cpp b/src/behave/spotInputs.cpp index 46806ad..9ebc725 100644 --- a/src/behave/spotInputs.cpp +++ b/src/behave/spotInputs.cpp @@ -57,6 +57,11 @@ void SpotInputs::setSurfaceFlameLength(double surfaceFlameLength, LengthUnits::L surfaceFlameLength_ = LengthUnits::toBaseUnits(surfaceFlameLength, flameLengthUnits); } +void SpotInputs::setActiveCrownFlameLength(double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits) +{ + activeCrownFlameLength_ = LengthUnits::toBaseUnits(activeCrownFlameLength, flameLengthUnits); +} + void SpotInputs::setCrownFirelineIntensity(double crownFirelineIntensity, FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) { crownFirelineIntensity_ = FirelineIntensityUnits::toBaseUnits(crownFirelineIntensity, firelineIntensityUnits); } @@ -156,7 +161,7 @@ void SpotInputs::updateSpotInputsForActiveCrownFire( { initializeMembers(); setLocation(location); - setSurfaceFlameLength(activeCrownFlameLength, flameLengthUnits); + setActiveCrownFlameLength(activeCrownFlameLength, flameLengthUnits); setRidgeToValleyDistance(ridgeToValleyDistance, ridgeToValleyDistanceUnits); setRidgeToValleyElevation(ridgeToValleyElevation, elevationUnits); setTreeHeight(treeHeight, treeHeightUnits); @@ -189,6 +194,11 @@ double SpotInputs::getSurfaceFlameLength(LengthUnits::LengthUnitsEnum surfaceFla return LengthUnits::fromBaseUnits(surfaceFlameLength_, surfaceFlameLengthUnits); } +double SpotInputs::getActiveCrownFlameLength(LengthUnits::LengthUnitsEnum activeCrownFlameLengthUnits) const +{ + return LengthUnits::fromBaseUnits(activeCrownFlameLength_, activeCrownFlameLengthUnits); +} + double SpotInputs::getCrownFirelineIntensity(FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) const { return FirelineIntensityUnits::fromBaseUnits(crownFirelineIntensity_, firelineIntensityUnits); @@ -231,6 +241,7 @@ double SpotInputs::getWindSpeedAtTwentyFeet(SpeedUnits::SpeedUnitsEnum windSpeed void SpotInputs::initializeMembers() { + activeCrownFlameLength_ = 0.0; downwindCoverHeight_ = 0.0; downwindCanopyMode_ = SpotDownWindCanopyMode::CLOSED; crownFirelineIntensity_ = 0.0; diff --git a/src/behave/spotInputs.h b/src/behave/spotInputs.h index 6335aca..7059e6b 100644 --- a/src/behave/spotInputs.h +++ b/src/behave/spotInputs.h @@ -82,6 +82,7 @@ class SpotInputs void setDownwindCoverHeight(double downwindCoverHeight, LengthUnits::LengthUnitsEnum coverHeightUnits); void setDownwindCanopyMode(SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode); void setSurfaceFlameLength(double surfaceFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); + void setActiveCrownFlameLength(double activeCrownFlameLength, LengthUnits::LengthUnitsEnum flameLengthUnits); void setCrownFirelineIntensity(double crownFirelineIntensity, FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits); void setLocation(SpotFireLocation::SpotFireLocationEnum location); void setRidgeToValleyDistance(double ridgeToValleyDistance, LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits); @@ -114,6 +115,7 @@ class SpotInputs double getDownwindCoverHeight(LengthUnits::LengthUnitsEnum coverHeightUnits) const; SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum getDownWindCanopyMode() const; double getSurfaceFlameLength(LengthUnits::LengthUnitsEnum flameLengthUnits) const; + double getActiveCrownFlameLength(LengthUnits::LengthUnitsEnum activeCrownFlameLengthUnits) const; double getCrownFirelineIntensity(FirelineIntensityUnits::FirelineIntensityUnitsEnum firelineIntensityUnits) const; SpotFireLocation::SpotFireLocationEnum getLocation() const; double getRidgeToValleyDistance(LengthUnits::LengthUnitsEnum ridgeToValleyDistanceUnits) const; @@ -136,6 +138,7 @@ class SpotInputs protected: void initializeMembers(); + double activeCrownFlameLength_ = 0.0; double DBH_ = 0.0; double downwindCoverHeight_ = 0.0; SpotDownWindCanopyMode::SpotDownWindCanopyModeEnum downwindCanopyMode_; From 4b97bff01de6d5dd0ea03db82b668c3646903f29 Mon Sep 17 00:00:00 2001 From: RJ Sheperd Date: Fri, 16 Jan 2026 00:02:26 -0800 Subject: [PATCH 3/3] Increase min. CMake Version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0416f8f..27f1268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ # and links to the qtmain.lib library on Windows. # ***************************************************************************** -CMAKE_MINIMUM_REQUIRED(VERSION 3.2.3) +CMAKE_MINIMUM_REQUIRED(VERSION 3.5.0) # Make use of c++14 SET(CMAKE_CXX_STANDARD 14)