public static int CalcFireSeverity(ActiveSite site, Event fireEvent, double severityCalibrate, int FMC) { //IFireRegion ecoregion = SiteVars.FireRegion[site]; int PH = SiteVars.PercentHardwood[site]; //Percent Hardwood int PDF = SiteVars.PercentDeadFir[site]; int PC = SiteVars.PercentConifer[site]; int fuelIndex = SiteVars.CFSFuelType[site]; int CBH = Event.FuelTypeParms[fuelIndex].CBH; //If M3 or M4 type (PDF >0) assign appropriate fuel index if (PDF > 0) { if (fireEvent.FireSeason.LeafStatus == LeafOnOff.LeafOff) { foreach (FuelType listFuel in Event.FuelTypeParms) { if (listFuel.SurfaceFuel == SurfaceFuelType.M3) fuelIndex = listFuel.FuelIndex; if (Event.FuelTypeParms[fuelIndex].CBH < CBH) CBH = Event.FuelTypeParms[fuelIndex].CBH; } } else { foreach (FuelType listFuel in Event.FuelTypeParms) { if (listFuel.SurfaceFuel == SurfaceFuelType.M4) fuelIndex = listFuel.FuelIndex; if (Event.FuelTypeParms[fuelIndex].CBH < CBH) CBH = Event.FuelTypeParms[fuelIndex].CBH; } } } //If mixed, use weighted average CBH if(PH > 0 && PC > 0 && PDF <= 0) { int decidIndex = SiteVars.DecidFuelType[site]; if (decidIndex > 0) { int decidCBH = Event.FuelTypeParms[decidIndex].CBH; CBH = ((CBH * PC) + (decidCBH * PH)) / 100; } } int FFMC = fireEvent.FFMC; int BUI = fireEvent.BuildUpIndex; double SFC = SurfaceFuelConsumption(fuelIndex, FFMC, BUI, PH, PDF); if (PH > 0 && PC > 0 && PDF <= 0) { int decidIndex = SiteVars.DecidFuelType[site]; double decidSFC = SurfaceFuelConsumption(decidIndex, FFMC, BUI, PH, PDF); SFC = ((SFC * PC) + (decidSFC * PH)) / 100; } int severity = 0; //-----Edited by BRM----- //double ROS = SiteVars.RateOfSpread[site]; //double ROS = SiteVars.AdjROS[site]; double ROS = (SiteVars.AdjROS[site] + (SiteVars.RateOfSpread[site] * severityCalibrate)) / (1 + severityCalibrate); //---------- double CSI = 0.001 * Math.Pow(CBH,1.5) * Math.Pow((460 + 25.9 * FMC),1.5); double RSO = CSI / (300 * SFC); double CFB = 1 - Math.Exp(-0.23 * (ROS - RSO)); // Finally, calculate SEVERITY: double lowThreshold = (RSO + 0.458)/2.0; // TEMPORARY? This seems to help adjust severities 1 and 2 so that there isn't so much of 1 and little of 2. lowThreshold *= severityCalibrate; if (CFB >= 0.9) severity = 5; if (CFB < 0.9 && CFB >= 0.495) severity = 4; if (CFB < 0.495 && CFB >= 0.1) severity = 3; if (CFB < 0.1 && ROS >= lowThreshold) severity = 2; if (CFB < 0.1 && ROS < lowThreshold) severity = 1; //UI.WriteLine(" Severity = {0}. CSI={1}, RSO={2}, ROS={3}, CFB={4}.", severity, CSI, RSO, ROS, CFB); return severity; }
//--------------------------------------------------------------------- public static Event Initiate(ActiveSite site, int currentTime, int timestep) { IEcoregion ecoregion = Model.SiteVars.Ecoregion[site]; IFireParameters eventParms = FireEventParms[ecoregion.Index]; double ignitionProb = eventParms.IgnitionProb * timestep; //The initial site must exceed the probability of initiation and //have a severity > 0 and exceed the ignition threshold: if ( Random.GenerateUniform() <= ignitionProb && Random.GenerateUniform() <= ComputeFireInitSpreadProb(site, currentTime) && calcSeverity(site, currentTime) > 0) { Event FireEvent = new Event(site); FireEvent.Spread(currentTime); return FireEvent; } else return null; }
//--------------------------------------------------------------------- private void LogEvent(int currentTime, Event FireEvent) { int totalSitesInEvent = 0; if (FireEvent.Severity > 0) { log.Write("{0},{1},{2},{3},{4},{5:0.0}", currentTime, FireEvent.StartLocation.Row, FireEvent.StartLocation.Column, FireEvent.NumSiteChecked, FireEvent.CohortsKilled, FireEvent.Severity); foreach (IFireRegion fireregion in FireRegions.Dataset) { log.Write(",{0}", FireEvent.SitesInEvent[fireregion.Index]); totalSitesInEvent += FireEvent.SitesInEvent[fireregion.Index]; summaryFireRegionEventCount[fireregion.Index] += FireEvent.SitesInEvent[fireregion.Index]; } summaryTotalSites += totalSitesInEvent; log.Write(", {0}", totalSitesInEvent); log.WriteLine(""); } }
public static int CalcFireSeverity(ActiveSite site, Event fireEvent) { IEcoregion ecoregion = SiteVars.Ecoregion[site]; IMoreEcoregionParameters fireParms = ecoregion.MoreEcoregionParameters; int PH = SiteVars.PercentHardwood[site]; //Percent Hardwood int PDF = SiteVars.PercentDeadFir[site]; int fuelIndex = SiteVars.CFSFuelType[site]; int CBH = fireEvent.FuelTypeParms[fuelIndex].CBH; int FFMC = fireEvent.FFMC; int BUI = fireEvent.BuildUpIndex; double SFC = SurfaceFuelConsumption(fuelIndex, FFMC, BUI, PH, PDF); int severity = 0; int FMC = 0; //Foliar Moisture Content if(fireEvent.FireSeason.NameOfSeason == SeasonName.Spring) { if (Util.Random.GenerateUniform() < fireParms.SpringFMCHiProp) FMC = fireParms.SpringFMCHi; else FMC = fireParms.SpringFMCLo; } if(fireEvent.FireSeason.NameOfSeason == SeasonName.Summer) { if (Util.Random.GenerateUniform() < fireParms.SummerFMCHiProp) FMC = fireParms.SummerFMCHi; else FMC = fireParms.SummerFMCLo; } if(fireEvent.FireSeason.NameOfSeason == SeasonName.Fall) { if (Util.Random.GenerateUniform() < fireParms.FallFMCHiProp) FMC = fireParms.FallFMCHi; else FMC = fireParms.FallFMCLo; } //-----Edited by BRM----- //double ROS = SiteVars.RateOfSpread[site]; double ROS = SiteVars.AdjROS[site]; //---------- double CSI = 0.001 * Math.Pow(CBH,1.5) * Math.Pow((460 + 25.9 * FMC),1.5); double RSO = CSI / 300 * SFC; double CFB = 1 - Math.Exp(-0.23 * (ROS - RSO)); // Finally, calculate SEVERITY: double lowThreshold = (RSO + 0.458)/2.0; if (CFB >= 0.9) severity = 5; if (CFB < 0.9 && CFB >= 0.495) severity = 4; if (CFB < 0.495 && CFB >= 0.1) severity = 3; if (CFB < 0.1 && ROS >= lowThreshold) severity = 2; if (CFB < 0.1 && ROS < lowThreshold) severity = 1; //UI.WriteLine(" Severity = {0}. CSI={1}, RSO={2}, ROS={3}, CFB={4}.", severity, CSI, RSO, ROS, CFB); return severity; }
//--------------------------------------------------------------------- private void LogEvent(int currentTime, Event FireEvent) { int totalSitesInEvent = 0; if (FireEvent.Severity > 0) { log.Write("{0},\"{1}\",{2},{3},{4:0.0}", currentTime, FireEvent.StartLocation, FireEvent.NumSiteChecked, FireEvent.CohortsKilled, FireEvent.Severity); foreach (IEcoregion ecoregion in Model.Core.Ecoregions) { if (ecoregion.Active) { log.Write(",{0}", FireEvent.SitesInEvent[ecoregion.Index]); totalSitesInEvent += FireEvent.SitesInEvent[ecoregion.Index]; summaryEcoregionEventCount[ecoregion.Index] += FireEvent.SitesInEvent[ecoregion.Index]; } } summaryTotalSites += totalSitesInEvent; log.Write(", {0}", totalSitesInEvent); log.WriteLine(""); } }
//--------------------------------------------------------------------- public static Event Initiate(ActiveSite site, int currentTime, int timestep) { IEcoregion ecoregion = SiteVars.Ecoregion[site]; IFireParameters eventParms = ecoregion.FireParameters; //Adjust ignition probability (measured on an annual basis) for the //user determined fire time step. double ignitionProb = eventParms.IgnitionProb * timestep; //The initial site must exceed the probability of initiation and //have a severity > 0 and exceed the ignition threshold: if (Random.GenerateUniform() <= ignitionProb && Random.GenerateUniform() <= ComputeFireInitSpreadProb(site, currentTime) && CalcSeverity(site, currentTime) > 0) { Event FireEvent = new Event(site); FireEvent.Spread(currentTime); return FireEvent; } else return null; }
//--------------------------------------------------------------------- private void LogEvent(int currentTime, Event fireEvent) { //HEADER: Time,Initiation Site,Sites Checked,Cohorts Killed,Mean Severity, int totalSitesInEvent = 0; if (fireEvent.EventSeverity > 0) { //-----Edited by BRM----- //-----to include MaxDuration log.Write("{0},\"{1}\",{2},{3},{4},{5:0.00},{6:0.00},{7},{8},{9},{10},{11},{12},{13},{14},{15:0.00}", currentTime, fireEvent.StartLocation, fireEvent.InitiationEcoregion, fireEvent.InitiationFuel, fireEvent.InitiationPercentConifer, fireEvent.MaxFireParameter, fireEvent.MaxDuration, fireEvent.FireSeason.NameOfSeason, fireEvent.WindSpeed, fireEvent.WindDirection, fireEvent.FFMC, fireEvent.BuildUpIndex, fireEvent.FireSeason.PercentCuring, fireEvent.NumSitesChecked, fireEvent.CohortsKilled, fireEvent.EventSeverity); //---------- foreach (IEcoregion ecoregion in Ecoregions.Dataset) { // if (ecoregion.Active) // { log.Write(",{0}", fireEvent.SitesInEvent[ecoregion.Index]); totalSitesInEvent += fireEvent.SitesInEvent[ecoregion.Index]; summaryEcoregionEventCount[ecoregion.Index] += fireEvent.SitesInEvent[ecoregion.Index]; // } } summaryTotalSites += totalSitesInEvent; log.Write(", {0}", totalSitesInEvent); log.WriteLine(""); } }
//--------------------------------------------------------------------- private void LogEvent(int currentTime, Event fireEvent) { //HEADER: Time,Initiation Site,Sites Checked,Cohorts Killed,Mean Severity, int totalSitesInEvent = 0; if (fireEvent.EventSeverity > 0) { log.Write("{0},\"{1}\",{2},{3},{4},{5:0.00},{6},{7:0.00},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17:0.00}", currentTime, fireEvent.StartLocation, fireEvent.InitiationFireRegion.Name, fireEvent.InitiationFuel, fireEvent.InitiationPercentConifer, fireEvent.MaxFireParameter, fireEvent.SizeBin, fireEvent.MaxDuration, fireEvent.FireSeason.NameOfSeason, fireEvent.WindSpeed, fireEvent.WindDirection, fireEvent.FFMC, fireEvent.BuildUpIndex, fireEvent.FireSeason.PercentCuring, fireEvent.ISI, fireEvent.NumSitesChecked, fireEvent.CohortsKilled, fireEvent.EventSeverity); //---------- foreach (IFireRegion fire_region in FireRegions.Dataset) { log.Write(",{0}", fireEvent.SitesInEvent[fire_region.Index]); totalSitesInEvent += fireEvent.SitesInEvent[fire_region.Index]; summaryFireRegionEventCount[fire_region.Index] += fireEvent.SitesInEvent[fire_region.Index]; } summaryTotalSites += totalSitesInEvent; log.Write(", {0}", totalSitesInEvent); log.WriteLine(""); } }
//--------------------------------------------------------------------- public static Event Initiate(ActiveSite site, int timestep, SizeType fireSizeType, bool bui, ISeasonParameters[] seasons, IWindDirectionParameters[] windDirs) { //Adjust ignition probability (measured on an annual basis) for the //user determined fire time step. int fuelIndex = SiteVars.CFSFuelType[site]; //-----Edited by BRM----- //double initProb = fuelTypeParms[fuelIndex].InitiationProbability * timestep; double initProb = fuelTypeParms[fuelIndex].InitiationProbability; //--------- //The initial site must exceed the probability of initiation and //have a severity > 0 and exceed the ignition threshold: if (Util.Random.GenerateUniform() <= initProb) { Event FireEvent = new Event(site, seasons, windDirs); if(!FireEvent.Spread(site, fireSizeType, bui)) return null; else return FireEvent; } return null; }
private static void MaximumFuelDistance(Event fireEvent) { UI.WriteLine(" Calculating maximum RSI..."); IFuelTypeParameters[] fuelTypeParms = fireEvent.FuelTypeParms; ISeasonParameters season = fireEvent.FireSeason; ushort tempSlope, maxSlope = 0; foreach (Site site in Model.Core.Landscape.AllSites) { if (site.IsActive) { tempSlope = SiteVars.GroundSlope[site]; if (tempSlope > maxSlope) maxSlope = tempSlope; } } double f_F = Weather.CalculateFuelMoistureEffect(fireEvent.FFMC); double SF = CalculateSF(maxSlope); double f_WZero = Weather.CalculateWindEffect(0); double ISZ = 0.208 * f_F * f_WZero; double ISI = 0; double f_backW = Weather.CalculateBackWindEffect(fireEvent.WindSpeed); double BISI = 0.208 * f_F * f_backW; double RSZ = 0; double RSF = 0; double WSE = 0; double WSV = 0; double f_W = 0; //M2 and M4 (leaf on) not included in maximum list because they will always be lower //than M1 and M3 (leaf off), respectively. double ROS = 0.0; double ROSmax = 0.0; double BROSmax = 0.0; double FROSmax = 0.0; int maxfuelIndex = -1; int fuelIndex = (int) FuelTypeCode.C1; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; maxfuelIndex = fuelIndex; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C2; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; maxfuelIndex = fuelIndex; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C3; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; maxfuelIndex = fuelIndex; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C4; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C5; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C6; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.C7; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 100, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.D1; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 0, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 100, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 100, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 100, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.S1; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 0, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.S2; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 0, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.S3; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 0, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 0, season); fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, fuelIndex); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 0, season); maxfuelIndex = fuelIndex; } /*fuelIndex = (int) FuelTypeCode.M1; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 100, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 100, 0, 0, season); FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 100, 0, 0, season); maxfuelIndex = fuelIndex; } fuelIndex = (int) FuelTypeCode.M3; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 100, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 100, season); FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 100, season); maxfuelIndex = fuelIndex; }*/ fuelIndex = (int) FuelTypeCode.O1a; RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, 0, 0, 0, season); RSF = RSZ * SF; WSE = CalculateWSE(fuelIndex, RSF, f_F, 100, season); WSV = WSE + fireEvent.WindSpeed; f_W = Weather.CalculateWindEffect(WSV); ISI = 0.208 * f_F * f_W; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 0, season); //Open fuel types have narrow LB, so to make sure max ellipse covers enough area we force it // to use the wider LB of the other types fireEvent.LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, (int) FuelTypeCode.D1); FROSmax = (ROSmax + BROSmax) / (fireEvent.LB * 2); //FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 0, season); maxfuelIndex = fuelIndex; } /* fuelIndex = (int) FuelTypeCode.O1b; ROS = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, 0, 0, 0, season) * fuelTypeParms[fuelIndex].MaxBE; if(ROS >= ROSmax) { ROSmax = ROS; BROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, 0, 0, 0, season); FROSmax = FuelEffects.InitialRateOfSpread(fuelIndex, RSZ, 0, 0, 0, season); maxfuelIndex = fuelIndex; }*/ if(maxfuelIndex == -1) UI.WriteLine(" Error: FFMC={0}, WSV={1}.", fireEvent.FFMC, fireEvent.WindSpeed); BROSmax *= fuelTypeParms[maxfuelIndex].MaxBE; // Use the Length to Breadth ratio to determine the FLANK rate of spread (FROS). //double LB = CalculateLengthBreadthRatio(fireEvent.WindSpeed, maxfuelIndex); //FROSmax = (ROSmax + BROSmax)/(LB * 2.0);// (FBP; 89) FROSmax *= fuelTypeParms[maxfuelIndex].MaxBE; fireEvent.LengthA = FROSmax; //fireEvent.LengthB = FROSmax * LB; //((ROSmax + BROSmax) / 2); fireEvent.LengthB = ((ROSmax + BROSmax) / 2); fireEvent.LengthD = BROSmax; //fireEvent.LB = fireEvent.LengthB / fireEvent.LengthA; UI.WriteLine(" ROSmax = {0:0.000}, FROSmax = {1:0.000}, BROSmax = {2:0.000}.", ROSmax, FROSmax, BROSmax); UI.WriteLine(" LBmax = {0:0.000}, WSV = {1}, maxfuelType = {2}", fireEvent.LB, fireEvent.WindSpeed, (FuelTypeCode) maxfuelIndex); UI.WriteLine(" LengthA = {0:0.000}, LengthB = {1:0.000}, LengthD = {2:0.000}.", fireEvent.LengthA, fireEvent.LengthB, fireEvent.LengthD); UI.WriteLine(" BISI = {0:0.000}, ISI = {1:0.000}, RSZ = {2:0.000}, f(F) = {3:0.000}, f(W) = {4:0.000}.", BISI, ISI, RSZ, f_F, f_W); return; }
//--------------------------------------------------------------------- //-----Edited by BRM----- //-----To pass fireSizeType public static List<Site> SizeFireCostSurface(Event fireEvent, SizeType fireSizeType) //---------- { Site initiationSite = Model.Core.Landscape.GetSite(fireEvent.StartLocation); MaximumFuelDistance(fireEvent); //Adjusted for SIZE or DURATION-----BRM----- if (fireSizeType == SizeType.size_based) { double ellipseAdjust = ((fireEvent.LengthB * 2) - fireEvent.LengthD) / fireEvent.LengthD; if (ellipseAdjust < 2) ellipseAdjust = 2; double ratioBD = fireEvent.LengthB/fireEvent.LengthD; double ellipseArea = fireEvent.MaxFireParameter * Model.Core.CellLength * Model.Core.CellLength * ellipseAdjust; fireEvent.LengthA = Math.Sqrt(ellipseArea / (Math.PI * fireEvent.LB)); fireEvent.LengthB = fireEvent.LengthA * fireEvent.LB; fireEvent.LengthD = fireEvent.LengthB/ratioBD; } else { //FBP 86; Area in ha double ellipseArea = (((Math.PI) / (4 * fireEvent.LB)) * Math.Pow(fireEvent.LengthB * 2 * fireEvent.MaxFireParameter, 2) / 10000); fireEvent.LengthD = fireEvent.LengthD * fireEvent.MaxFireParameter; fireEvent.LengthB = fireEvent.LengthB * fireEvent.MaxFireParameter; fireEvent.LengthA = fireEvent.LengthA * fireEvent.MaxFireParameter; } //double ellipseArea = fireEvent.LengthB * fireEvent.LengthA * Math.PI; //double ellipseAdjust = 2 * Math.Sqrt((double) fireEvent.MaxFireParameter / ellipseArea); //These are the parameters necessary for the calculating eliptical lengths: //double lengthD = fireEvent.LengthD * Model.Core.CellLength * ellipseAdjust; double lengthC = (fireEvent.LengthB - fireEvent.LengthD); //UI.WriteLine(" Max Distance = {0:0.0}. Calculating burn area...", maxDistance); UI.WriteLine(" Ellipse: LengthD = {0:0.0} (m). LengthC = {1:0.0} (m).", fireEvent.LengthD, lengthC); List<Site> newFireList = new List<Site>(); SiteVars.TravelTime[initiationSite] = 0.0; SiteVars.MinNeighborTravelTime[initiationSite] = 0.0; SiteVars.Event[initiationSite] = fireEvent; //Assign a ROS to the initiation site: double initiationTravelTime = CalculateTravelTime(initiationSite, initiationSite, fireEvent); SiteVars.TravelTime[initiationSite] = initiationTravelTime; //Create a queue of neighboring sites to which the fire will spread: Queue<Site> sitesToConsider = new Queue<Site>(); sitesToConsider.Enqueue(initiationSite); while (sitesToConsider.Count > 0) { //UI.WriteLine(" SiteToConsider = {0}.", sitesToConsider.Count); Site srcSite = sitesToConsider.Dequeue(); //Source site newFireList.Add(srcSite); //Next, add site's neighbors to the list of //sites to consider. The neighbors cannot be part of //any other Fire event in the current timestep, and //cannot already be on the list. List<Site> destinations = Get8Neighbors(srcSite); if (destinations.Count > 0) { foreach (Site destSite in destinations) { if (SiteVars.Event[destSite] != null) continue; if (sitesToConsider.Contains(destSite)) continue; if(ElipseDistanceBetweenSites(initiationSite, destSite, lengthC, fireEvent.LengthD, fireEvent.WindDirection)) { //Complex Cost Surface (Scheller's algorithm) SiteVars.CostTime[destSite] = CalculateTravelTime(destSite, srcSite, fireEvent); if (srcSite == initiationSite) { SiteVars.TravelTime[destSite] = (SiteVars.CostTime[destSite] / 2) * CellDistanceBetweenSites(destSite, srcSite) + SiteVars.TravelTime[srcSite]; } else { SiteVars.TravelTime[destSite] = (SiteVars.CostTime[destSite] / 2 + SiteVars.CostTime[srcSite] / 2) * CellDistanceBetweenSites(destSite, srcSite) + SiteVars.TravelTime[srcSite]; //SiteVars.TravelTime[destSite] = SiteVars.CostTime[destSite] * CellDistanceBetweenSites(destSite, srcSite) // + SiteVars.TravelTime[srcSite]; } SiteVars.MinNeighborTravelTime[destSite] = SiteVars.TravelTime[srcSite]; sitesToConsider.Enqueue(destSite); SiteVars.Event[destSite] = fireEvent; } } } } //Finally, check neighbor travel 10 times to optimize the shortest travel //distance. bool finished = false; int count = 1; while (!finished) { UI.WriteLine(" Re-Calculating optimal travel time: {0} times.", count++); finished = true; // Loop through list and check each for a new, shorter travel time. foreach (Site destSite in newFireList) //Fire destination { Site srcSite = CalculateMinNeighbor(destSite, fireEvent); // Where is the fire coming from? if(srcSite != null) { double oldTravelTime = SiteVars.TravelTime[destSite]; //double newTravelTime = (CalculateTravelTime(destSite, srcSite, fireEvent) // * CellDistanceBetweenSites(destSite, srcSite)) // + SiteVars.TravelTime[srcSite]; double newCostTime = CalculateTravelTime(destSite, srcSite, fireEvent); double newTravelTime = ((newCostTime / 2 + SiteVars.CostTime[srcSite] / 2) * CellDistanceBetweenSites(destSite, srcSite)) + SiteVars.TravelTime[srcSite]; if(newTravelTime < oldTravelTime) { SiteVars.CostTime[destSite] = newCostTime; SiteVars.TravelTime[destSite] = newTravelTime; //UI.WriteLine(" OldTT = {0:0.00}, NewTT = {1:0.00}, OldMinNeighborTT = {2:0.00}, MinNeighborTT = {3:0.00}.", //oldTravelTime, SiteVars.TravelTime[destSite], SiteVars.MinNeighborTravelTime[destSite]= SiteVars.TravelTime[srcSite]; if ((oldTravelTime - newTravelTime) > 0.5) finished = false; } } } if(count > 2000) finished = true; } return newFireList; }
private static double CalculateTravelTime(Site site, Site firesource, Event fireEvent) { //Calculate Fire regime size adjustment: IEcoregion ecoregion = SiteVars.Ecoregion[site]; IMoreEcoregionParameters eventParms = ecoregion.MoreEcoregionParameters; double FRUA = eventParms.MeanSize; ecoregion = SiteVars.Ecoregion[firesource]; eventParms = ecoregion.MoreEcoregionParameters; FRUA = FRUA / eventParms.MeanSize; int fuelIndex = SiteVars.CFSFuelType[site]; int percentConifer = SiteVars.PercentConifer[site]; int percentHardwood = SiteVars.PercentHardwood[site]; int percentDeadFir = SiteVars.PercentDeadFir[site]; List<int> siteWindList = new List<int>(); int siteWindSpeed, siteWindDirection; FuelTypeCode temp = (FuelTypeCode) fuelIndex; //UI.WriteLine(" Fuel Type Code = {0}.", temp.ToString()); IFuelTypeParameters[] fuelTypeParms = fireEvent.FuelTypeParms; ISeasonParameters season = fireEvent.FireSeason; double f_F = Weather.CalculateFuelMoistureEffect(fireEvent.FFMC); double ISZ = 0.208 * f_F; //No wind double RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, percentConifer, percentHardwood, percentDeadFir, season); siteWindList = CalculateSlopeEffect(fireEvent.WindSpeed, fireEvent.WindDirection, site, RSZ, f_F, season); if (siteWindList.Count > 0) { siteWindSpeed = siteWindList[0]; siteWindDirection = siteWindList[1]; } else { siteWindSpeed = fireEvent.WindSpeed; siteWindDirection = fireEvent.WindDirection; } double f_backW = Weather.CalculateBackWindEffect(siteWindSpeed); double f_W = Weather.CalculateWindEffect(siteWindSpeed); double ISI = 0.208 * f_F * f_W; double BISI = 0.208 * f_F * f_backW; double BROSi = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, percentConifer, percentHardwood, percentDeadFir, season); double ROSi = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, percentConifer, percentHardwood, percentDeadFir, season ); BROSi *= FRUA; ROSi *= FRUA; SiteVars.RateOfSpread[site] = ROSi; double LB = CalculateLengthBreadthRatio(siteWindSpeed, fuelIndex); double FROSi = (ROSi + BROSi)/(LB * 2.0);// (FBP; 89) double alpha = siteWindDirection; double A = FROSi; double beta = Beta(firesource, site, alpha); //Randomize around 8 neighbor directions //int wiggle = (int)((Util.Random.GenerateUniform() * 45.0) - 22.5); //beta = beta + wiggle; double B = A * LB; //fireEvent.LB; double C = B - BROSi; // Equations below for e, p, b, c, a utlize the polar equation // for an ellipse, given at: // http://www.du.edu/~jcalvert/math/ellipse.htm double e = C / B; double dist = CellDistanceBetweenSites(site, firesource) * Model.Core.CellLength; double r = ROSi; if (dist != 0) { double p = dist * (1 + e * Math.Cos(Math.PI - beta)); double b = p / (1 - e * e); double c = e * b; r = (dist / (b + c)) * ROSi; //double a = (1 / LB) * b; //Equations below for theta, r come from Finney 2002, eq [3], [5] //double cosSqBeta = CosSquared(beta); //double sinSqBeta = SinSquared(beta); //double termA = a * Math.Cos(beta) * Math.Pow(((a*a * cosSqBeta) + ((b*b)-(c*c)) * sinSqBeta),0.5); //double termB = b * c * sinSqBeta; //double termC = ((a*a) * cosSqBeta) + ((b*b) * sinSqBeta); //double theta = Math.Acos((termA - termB) / termC); //r = (a * ((c * Math.Cos(theta)) + b)) / // Math.Sqrt((a * a * CosSquared(theta)) + (b * b * SinSquared(theta))); } //-----Added by BRM----- SiteVars.AdjROS[site] = r; //---------- //UI.WriteLine(" FROSi = {0}, BROSi = {1}.", FROSi, BROSi); //UI.WriteLine(" beta = {0:0.00}, theta = {1:0.00}, alpha = {2:0.00}, Travel time = {3:0.000000}.", beta, theta, alpha, 1/r); //UI.WriteLine(" Travel time = {0:0.000000}. R = {1}.", 1/r, r); if (site == firesource) { double rate = 1.0 / r; //units = minutes / meter double cost = rate * Model.Core.CellLength / 2; //units = minutes return cost; } else { double rate = 1.0 / r; //units = minutes / meter double cost = rate * Model.Core.CellLength; //units = minutes return cost; } }
//------------------------------------------------------- private static Site CalculateMinNeighbor(Site site, Event fireEvent) { List<Site> neighborhood = Get8Neighbors(site); Site lowestNeighbor = null; double minNeighborTravelTime = SiteVars.MinNeighborTravelTime[site]; foreach (Site relneighbor in neighborhood) { if( //relneighbor != null && SiteVars.Event[relneighbor] == fireEvent && !Double.IsPositiveInfinity(SiteVars.TravelTime[relneighbor]) && SiteVars.TravelTime[relneighbor] < minNeighborTravelTime) { lowestNeighbor = relneighbor; SiteVars.MinNeighborTravelTime[site] = SiteVars.TravelTime[relneighbor]; //UI.WriteLine("Location = {0},{1}. MinTravelTime = {2}.", lowestNeighbor.Row, lowestNeighbor.Column, SiteVars.TravelTime[relneighbor]); } } return lowestNeighbor; }