//--------------------------------------------------------------------- public static DataRow GenerateSeasonWindData(ISeasonParameters season) { int weatherRandomizer = PlugIn.WeatherRandomizer; //string seasonName = season.NameOfSeason.ToString(); //string ecoName = fire_region.Name; //int weatherBin = 0; int seasonStart = season.StartDay; int seasonEnd = season.EndDay; string selectString = "Day >= " + seasonStart + " AND Day <= " + seasonEnd; DataRow[] rows = PlugIn.WindDataTable.Select(selectString); if (rows.Length > 0) { int newRandNum = (int)(Math.Round(PlugIn.ModelCore.GenerateUniform() * (rows.Length - 1))); DataRow weatherRow = rows[newRandNum]; return(weatherRow); } else { return(null); } }
//--------------------------------------------------------------------- public static int GenerateWindSpeed(ISeasonParameters season) { double windSpeed = 0.0; windSpeed = GenerateRandomNum(season.WSVDist, season.WSVP1, season.WSVP2); if(windSpeed < 0) windSpeed = 0; return (int) windSpeed; }
//--------------------------------------------------------------------- public static int GenerateFineFuelMoistureCode(ISeasonParameters season) { double ffmc = 0.0; ffmc = GenerateRandomNum(season.FFMCDist, season.FFMCP1, season.FFMCP2); if(ffmc < 0) ffmc = 0; if(ffmc > 100) ffmc = 100; return (int) ffmc; }
//--------------------------------------------------------------------- public static ISeasonParameters GenerateSeason(ISeasonParameters[] seasons) { double randNum = PlugIn.ModelCore.GenerateUniform(); double bottom = 0.0; double top = 0.0; foreach (ISeasonParameters season in seasons) { top += season.FireProbability; if(randNum >= bottom && randNum <= top) return season; bottom += season.FireProbability; } return null; }
//--------------------------------------------------------------------- public static ISeasonParameters GetSeason(ISeasonParameters[] seasons, int day) { ISeasonParameters theSeason = seasons[0]; foreach (ISeasonParameters season in seasons) { if (season.NameOfSeason == SeasonName.Spring && day < season.StartDay) { string mesg = string.Format("Error: The fire day {0} is before the beginning of spring", day); throw new System.ApplicationException(mesg); } if (day < season.EndDay) theSeason = season; } return theSeason; }
//--------------------------------------------------------------------- private Event(ActiveSite initiationSite, ISeasonParameters fireSeason, SizeType fireSizeType) { this.initiationSite = initiationSite; this.sitesInEvent = new int[FireRegions.Dataset.Count]; //PlugIn.ModelCore.UI.WriteLine(" initialzing siteInEvent ..."); foreach (IFireRegion fire_region in FireRegions.Dataset) { this.sitesInEvent[fire_region.Index] = 0; } this.cohortsKilled = 0; this.eventSeverity = 0; this.totalSitesDamaged = 0; this.lengthB = 0.0; this.lengthA = 0.0; this.lengthD = 0.0; IFireRegion eco = SiteVars.FireRegion[initiationSite]; this.initiationFireRegion = eco; this.maxFireParameter = ComputeSize(eco.MeanSize, eco.StandardDeviation, eco.MaxSize); //fireSizeType); this.sizeBin = ComputeSizeBin(eco.MeanSize, eco.StandardDeviation, this.maxFireParameter); this.fireSeason = fireSeason; //Weather.GenerateSeason(seasons); System.Data.DataRow weatherRow = Weather.GenerateDataRow(this.fireSeason, eco, this.sizeBin); this.windSpeed = Weather.GenerateWindSpeed(weatherRow); this.fineFuelMoistureCode = Weather.GenerateFineFuelMoistureCode(weatherRow); this.buildUpIndex = Weather.GenerateBuildUpIndex(weatherRow); this.windDirection = Weather.GenerateWindDirection(weatherRow); this.foliarMC = Weather.GenerateFMC(this.fireSeason, eco); //PlugIn.ModelCore.UI.WriteLine(); /*PlugIn.ModelCore.UI.WriteLine(" New Fire Event Data: WSV={0}, FFMC={1}, BUI={2}, foliarMC={3}, windDirection={4}, Season={5}, FireRegion={6}, SizeBin = {7}.", * this.windSpeed, * this.fineFuelMoistureCode, * this.buildUpIndex, * this.foliarMC, * this.windDirection, * this.fireSeason.NameOfSeason, * this.initiationFireRegion.Name, * this.sizeBin * );*/ }
//--------------------------------------------------------------------- public static ISeasonParameters GetSeason(ISeasonParameters[] seasons, int day) { ISeasonParameters theSeason = seasons[0]; foreach (ISeasonParameters season in seasons) { if (season.NameOfSeason == SeasonName.Spring && day < season.StartDay) { string mesg = string.Format("Error: The fire day {0} is before the beginning of spring", day); throw new System.ApplicationException(mesg); } if (day < season.EndDay) { theSeason = season; } } return(theSeason); }
//--------------------------------------------------------------------- public static int GenerateFMC(ISeasonParameters season, IFireRegion fire_region) { int FMC = 0; if (season.NameOfSeason == SeasonName.Spring) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.SpringFMCHiProp) { FMC = fire_region.SpringFMCHi; } else { FMC = fire_region.SpringFMCLo; } } if (season.NameOfSeason == SeasonName.Summer) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.SummerFMCHiProp) { FMC = fire_region.SummerFMCHi; } else { FMC = fire_region.SummerFMCLo; } } if (season.NameOfSeason == SeasonName.Fall) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.FallFMCHiProp) { FMC = fire_region.FallFMCHi; } else { FMC = fire_region.FallFMCLo; } } return(FMC); }
//--------------------------------------------------------------------- public static DataTable ReadWeatherFile(string path, IDynamicInputRecord[] regionRecords, ISeasonParameters[] seasonParms) { PlugIn.ModelCore.UI.WriteLine(" Loading Weather Data..."); CSVParser weatherParser = new CSVParser(); DataTable weatherTable = weatherParser.ParseToDataTable(path); int recordCount = 0; for (int i = 0; i <= 2; i++) { string seasName = seasonParms[i].NameOfSeason.ToString(); foreach (IDynamicInputRecord fire_region in regionRecords) { string ecoName = fire_region.Name; //PlugIn.ModelCore.Log.WriteLine("Read Weather File: Season={0}, FireRegion={1}.", seasName, ecoName); string selectText = ("FireRegion = '" + ecoName + "' AND Season = '" + seasName + "'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); DataRow[] foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("FireRegion = 'All' AND Season = '" + seasName + "'"); foundRows = weatherTable.Select(selectText); } if ((foundRows.Length == 0) && (seasonParms[i].FireProbability > 0) && (fire_region.EcoIgnitionNum > 0)) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 430): FireRegion " + ecoName + ", Season " + seasName + " has fire probability > 0, but 0 weather records. Using alternate season."); if (seasName == "Spring") { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Summer'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Fall'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); } if (foundRows.Length == 0) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 445): FireRegion " + ecoName + " has fire probability > 0, but 0 weather records. No fires will occur in this fire region."); } } if (seasName == "Fall") { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Summer'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Spring'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); } if (foundRows.Length == 0) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 464): FireRegion " + ecoName + " has fire probability > 0, but 0 weather records. No fires will occur in this fire region."); } } if (seasName == "Summer") { if (PlugIn.ModelCore.GenerateUniform() >= 0.5) { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Spring'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Fall'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); } if (foundRows.Length == 0) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 485): FireRegion " + ecoName + " has fire probability > 0, but 0 weather records. No fires will occur in this fire region."); } } else { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Fall'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("FireRegion = '" + ecoName + "' AND Season = 'Spring'"); //PlugIn.ModelCore.Log.WriteLine("Read Weather File SelectText = {0}.", selectText); foundRows = weatherTable.Select(selectText); } if (foundRows.Length == 0) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 503): FireRegion " + ecoName + " has fire probability > 0, but 0 weather records. No fires will occur in this fire region."); } } } } if(foundRows.Length > 0) { //Input validation double WSV, FFMC, BUI; int WINDDIR, FWIBIN; for(int j = 0; j < foundRows.Length; j ++) //weatherDataSet.Tables["Table"].Rows) { DataRow myDataRow = foundRows[j]; //WSV = (double)myDataRow["WSV"]; WSV = Convert.ToDouble(myDataRow["WSV"]); //Console.WriteLine("WSV: {0}", WSV); if (WSV < 0.0) { throw new System.ApplicationException("Error: Wind Speed < 0: FireRegion = " + ecoName + "; Season = " + seasName); } FFMC = Convert.ToDouble(myDataRow["FFMC"]); //Console.WriteLine("FFMC: {0}", FFMC); if (FFMC < 0.0) { throw new System.ApplicationException("Error: FFMC < 0: FireRegion = " + ecoName + "; Season = " + seasName); } else if (FFMC > 100.0) { throw new System.ApplicationException("Error: FFMC > 100: FireRegion = " + ecoName + "; Season = " + seasName); } BUI = Convert.ToDouble(myDataRow["BUI"]); //Console.WriteLine("BUI: {0}", BUI); if (BUI < 0.0) { throw new System.ApplicationException("Error: BUI < 0: FireRegion = " + ecoName + "; Season = " + seasName); } WINDDIR = (int) myDataRow["WindDir"]; //Console.WriteLine("WindDir: {0}", WINDDIR); if (WINDDIR < 0) { throw new System.ApplicationException("Error: WINDDIR < 0: FireRegion = " + ecoName + "; Season = " + seasName); } else if (WINDDIR > 360) { throw new System.ApplicationException("Error: WINDDIR > 360: FireRegion = " + ecoName + "; Season = " + seasName); } FWIBIN = (int) myDataRow["FWIBin"]; //Console.WriteLine("FWIBIN: {0}", FWIBIN); if (FWIBIN < 1) { throw new System.ApplicationException("Error: FWIBIN < 1: FireRegion = " + ecoName + "; Season = " + seasName); } else if (FWIBIN > 5) { throw new System.ApplicationException("Error: FWIBIN > 5: FireRegion = " + ecoName + "; Season = " + seasName); } } } if(seasName == "Fall") { fire_region.FallRecords = recordCount; } else if (seasName == "Spring") { fire_region.SpringRecords = recordCount; } else if (seasName == "Summer") { fire_region.SummerRecords = recordCount; } } } return weatherTable; }
//--------------------------------------------------------------------- public static int GenerateBuildUpIndex(ISeasonParameters season) { double bui = 0.0; bui = GenerateRandomNum(season.BUIDist, season.BUIP1, season.BUIP2); if(bui < 0) bui = 0; if(bui > 200) bui = 200; return (int) bui; }
public static double InitialRateOfSpread(int fuelIndex, double ISI, int PC, int PH, int PDF, ISeasonParameters season) { FuelTypeCode siteFuelType = (FuelTypeCode) fuelIndex; //UI.WriteLine("Fuel Type Code = {0}.", siteFuelType.ToString()); double RSI = 0.0; if (siteFuelType == FuelTypeCode.C1 || siteFuelType == FuelTypeCode.C2 || siteFuelType == FuelTypeCode.C3 || siteFuelType == FuelTypeCode.C4 || siteFuelType == FuelTypeCode.C5 || siteFuelType == FuelTypeCode.C6 || siteFuelType == FuelTypeCode.C7) { double a = Event.fuelTypeParms[fuelIndex].A; double b = Event.fuelTypeParms[fuelIndex].B; double c = Event.fuelTypeParms[fuelIndex].C; double percentHard = (double) PH / 100.0; double percentConi = (double) PC / 100.0; RSI = CalculateRSI(a, b, c, ISI); if(PH > 0) { double RSIconifer = RSI; int dIndex = (int) FuelTypeCode.D1; double RSIdecid = CalculateRSI(Event.fuelTypeParms[dIndex].A, Event.fuelTypeParms[dIndex].B, Event.fuelTypeParms[dIndex].C, ISI); if(season.LeafStatus == LeafOnOff.LeafOn) RSI = (percentHard * RSIconifer) + (0.2 * percentHard * RSIdecid); else RSI = (percentConi * RSIconifer) + (percentHard * RSIdecid); //UI.WriteLine("Calculating ROSi for a MIXED type. PH={0}, PC={1}, LeafStatus={2}.", PH, PC, season.LeafStatus); //UI.WriteLine(" RSIcon={0:0.0}, RSIdecid={1:0.0}, RSImix={2:0.000}.", RSIconifer, RSIdecid, RSI); } } if( siteFuelType == FuelTypeCode.D1 || siteFuelType == FuelTypeCode.S1 || siteFuelType == FuelTypeCode.S2 || siteFuelType == FuelTypeCode.S3) { //UI.WriteLine("Calculating ROSi for a DECIDUOUS or SLASH type."); double a = Event.fuelTypeParms[fuelIndex].A; double b = Event.fuelTypeParms[fuelIndex].B; double c = Event.fuelTypeParms[fuelIndex].C; RSI = CalculateRSI(a, b, c, ISI); if(siteFuelType == FuelTypeCode.D1 && season.LeafStatus == LeafOnOff.LeafOn) RSI *= 0.2; } /* if(siteFuelType == FuelTypeCode.M2) { int cIndex = (int) FuelTypeCode.C2; int dIndex = (int) FuelTypeCode.D1; double RSI_c2 = CalculateRSI(Event.fuelTypeParms[cIndex].A, Event.fuelTypeParms[cIndex].B, Event.fuelTypeParms[cIndex].C, ISI); double RSI_d1 = CalculateRSI(Event.fuelTypeParms[dIndex].A, Event.fuelTypeParms[dIndex].B, Event.fuelTypeParms[dIndex].C, ISI); RSI = ((PC/100 * RSI_c2) + (0.2 * PH/100 * RSI_d1)); } */ if(PH > 0 && PDF > 0) { double a, b, c; if(season.LeafStatus == LeafOnOff.LeafOff) { a = 170 * System.Math.Exp(-35 / PDF); b = 0.082 * System.Math.Exp(-36 / PDF); c = 1.698 - 0.00303 * PDF; } else { a = 170 * System.Math.Exp(-35 / PDF); b = 0.0404; c = 3.02 * System.Math.Exp(-0.00714 * PDF); } RSI = CalculateRSI(a, b, c, ISI); } /* if(siteFuelType == FuelTypeCode.M4) { double a = 170 * System.Math.Exp(-35 / PDF); double b = 0.0404; double c = 3.02 * System.Math.Exp(-0.00714 * PDF); RSI = CalculateRSI(a, b, c, ISI); } if(siteFuelType == FuelTypeCode.O1a || siteFuelType == FuelTypeCode.O1b) { double a = Event.fuelTypeParms[fuelIndex].A; double b = Event.fuelTypeParms[fuelIndex].B; double c = Event.fuelTypeParms[fuelIndex].C; double CF = (0.02 * percentCuring) - 1.0; RSI = CalculateRSI(a, b, c, ISI) * CF; }*/ if(siteFuelType == FuelTypeCode.O1a) { double a, b, c; int percentCuring = season.PercentCuring; if(season.NameOfSeason == SeasonName.Spring) { a = Event.fuelTypeParms[(int) FuelTypeCode.O1a].A; b = Event.fuelTypeParms[(int) FuelTypeCode.O1a].B; c = Event.fuelTypeParms[(int) FuelTypeCode.O1a].C; } else { a = Event.fuelTypeParms[(int) FuelTypeCode.O1b].A; b = Event.fuelTypeParms[(int) FuelTypeCode.O1b].B; c = Event.fuelTypeParms[(int) FuelTypeCode.O1b].C; } double CF = (0.02 * percentCuring) - 1.0; RSI = CalculateRSI(a, b, c, ISI); if(percentCuring > 50) RSI *= CF; else RSI = 0; } if(siteFuelType == FuelTypeCode.NoFuel) { return 0; } return RSI; }
//--------------------------------------------------------------------- public static DataRow GenerateDataRow(ISeasonParameters season, IFireRegion fire_region, int sizeBin) { int weatherRandomizer = PlugIn.WeatherRandomizer; string seasonName = season.NameOfSeason.ToString(); string ecoName = fire_region.Name; int weatherBin = 0; if (weatherRandomizer == 0) { weatherBin = sizeBin; } else { // First, tally the available bins and assign a probability based on their size // (number of records). // Bins can only be 1 - 5. int minBin = (int)System.Math.Max(1, sizeBin - weatherRandomizer); int maxBin = (int)System.Math.Min(5, sizeBin + weatherRandomizer); double[] binProbability = new double[maxBin - minBin + 1]; int[] binCount = new int[maxBin - minBin + 1]; int binSum = 0; for (int bin = minBin; bin <= maxBin; bin++) { string selectString = "FWIBin = '" + bin + "' AND Season = '" + seasonName + "' AND Ecoregion = '" + ecoName + "'"; DataRow[] rows = PlugIn.WeatherDataTable.Select(selectString); if (rows.Length == 0) { selectString = "FWIBin = '" + bin + "' AND Season = '" + seasonName + "' AND Ecoregion = 'All'"; rows = PlugIn.WeatherDataTable.Select(selectString); } int numRecs = rows.Length; binCount[bin - minBin] = numRecs; binSum += numRecs; } for (int bin = minBin; bin <= maxBin; bin++) { binProbability[bin - minBin] = (double)binCount[bin - minBin] / (double)binSum; } // Now randomly select from the available bins: double randomBinNum = PlugIn.ModelCore.GenerateUniform(); double minProb = 0.0; double maxProb = 0.0; for (int bin = minBin; bin <= maxBin; bin++) { maxProb += binProbability[bin - minBin]; if (randomBinNum >= minProb && randomBinNum < maxProb) { weatherBin = bin; break; } else { minProb = binProbability[bin - minBin]; } } } if (weatherBin == 0) { weatherBin = sizeBin; } //throw new System.ApplicationException("No Weather Bin randomly selected. FireRegion = "+ecoName+", Season = "+seasonName+", sizeBin = "+sizeBin); int rowCount = 0; int loopCount = 0; int firstDir = 0; DataRow[] foundRows = null; if (PlugIn.ModelCore.GenerateUniform() >= 0.5) { firstDir = 1; // Direction (+ or -) to check first if target bin is not available (+1 or -1) } else { firstDir = -1; } while (rowCount == 0) { string selectString = "FWIBin = '" + weatherBin + "' AND Season = '" + seasonName + "' AND Ecoregion = '" + ecoName + "'"; foundRows = PlugIn.WeatherDataTable.Select(selectString); rowCount = foundRows.Length; if (rowCount == 0) { selectString = "FWIBin = '" + weatherBin + "' AND Season = '" + seasonName + "' AND Ecoregion = 'All'"; foundRows = PlugIn.WeatherDataTable.Select(selectString); rowCount = foundRows.Length; } if (rowCount == 0) { //PlugIn.ModelCore.UI.WriteLine(" weatherBin "+weatherBin+" Not Found. Using alternate weatherBin."); if (sizeBin == 5) { weatherBin = weatherBin - 1; } else if (sizeBin == 1) { weatherBin = weatherBin + 1; } else { if (loopCount == 0) { weatherBin = sizeBin + firstDir; } else if (loopCount == 1) { weatherBin = sizeBin - firstDir; } else if (loopCount == 2) { weatherBin = sizeBin + (firstDir * 2); } else if (loopCount == 3) { weatherBin = sizeBin - (firstDir * 2); } else if (loopCount == 4) { weatherBin = sizeBin + (firstDir * 3); } else if (loopCount == 5) { weatherBin = sizeBin - (firstDir * 3); } else if (loopCount == 6) { weatherBin = sizeBin + (firstDir * 4); } else { weatherBin = sizeBin - (firstDir * 4); } } loopCount++; if (loopCount > 100) { PlugIn.ModelCore.UI.WriteLine(" No Weather Rows Selected"); throw new System.ApplicationException("No Weather Row could be selected. Ecoregion = " + ecoName + ", Season = " + seasonName + ", sizeBin = " + sizeBin); } } } int newRandNum = (int)(Math.Round(PlugIn.ModelCore.GenerateUniform() * (rowCount - 1))); DataRow weatherRow = foundRows[newRandNum]; return(weatherRow); }
private static double CalculateWSE(int fuelIndex, double RSF, double f_F, int PC, ISeasonParameters season) { FuelTypeCode siteFuelType = (FuelTypeCode) fuelIndex; double ISF, WSE; double a = Event.fuelTypeParms[fuelIndex].A; double b = Event.fuelTypeParms[fuelIndex].B; double c = Event.fuelTypeParms[fuelIndex].C; if (siteFuelType == FuelTypeCode.O1a) { double CF = (0.02 * season.PercentCuring) - 1; ISF = Math.Log(1 - Math.Pow((RSF/(CF * a)),(1/c)))/(-1 * b); } else { ISF = Math.Log(1 - Math.Pow((RSF / ( a)), (1 / c))) / (-1 * b); } WSE = Math.Log(ISF / (0.208 * f_F)) / 0.05039; return WSE; }
//--------------------------------------------------------------------- public Parameters(int timestep, SizeType fireSizeType, bool buildUpIndex, ISeasonParameters[] seasonParameters, IWindDirectionParameters[] windDirectionParameters, IFuelTypeParameters[] fuelTypeParameters, IDamageTable[] damages, string mapNameTemplate, string logFileName, string summaryLogFileName) { this.timestep = timestep; this.fireSizeType = fireSizeType; this.buildUpIndex = buildUpIndex; this.seasonParameters = seasonParameters; this.windDirectionParameters = windDirectionParameters; this.fuelTypeParameters = fuelTypeParameters; this.damages = damages; this.mapNamesTemplate = mapNameTemplate; this.logFileName = logFileName; this.summaryLogFileName = summaryLogFileName; }
//--------------------------------------------------------------------- public static int GenerateFoliarMoistureContent(ISeasonParameters season, IEcoregion ecoregion) { double bui = 0.0; bui = GenerateRandomNum(season.BUIDist, season.BUIP1, season.BUIP2); if(bui < 0) bui = 0; if(bui > 200) bui = 200; return (int) bui; }
//--------------------------------------------------------------------- public static DataRow GenerateDataRow(ISeasonParameters season, IDynamicInputRecord fire_region, int sizeBin) { int weatherRandomizer = PlugIn.WeatherRandomizer; string seasonName = season.NameOfSeason.ToString(); string ecoName = fire_region.Name; int weatherBin = 0; if(weatherRandomizer == 0) weatherBin = sizeBin; else { if (weatherRandomizer == 4) { weatherBin = -1; } else { // First, tally the available bins and assign a probability based on their size // (number of records). // Bins can only be 1 - 5. int minBin = (int)System.Math.Max(1, sizeBin - weatherRandomizer); int maxBin = (int)System.Math.Min(5, sizeBin + weatherRandomizer); double[] binProbability = new double[maxBin - minBin + 1]; int[] binCount = new int[maxBin - minBin + 1]; int binSum = 0; for (int bin = minBin; bin <= maxBin; bin++) { string selectString = "FWIBin = '" + bin + "' AND Season = '" + seasonName + "' AND FireRegion = '" + ecoName + "'"; DataRow[] rows = PlugIn.WeatherDataTable.Select(selectString); if (rows.Length == 0) { selectString = "FWIBin = '" + bin + "' AND Season = '" + seasonName + "' AND FireRegion = 'All'"; rows = PlugIn.WeatherDataTable.Select(selectString); } int numRecs = rows.Length; binCount[bin - minBin] = numRecs; binSum += numRecs; } for (int bin = minBin; bin <= maxBin; bin++) binProbability[bin - minBin] = (double)binCount[bin - minBin] / (double)binSum; // Now randomly select from the available bins: double randomBinNum = PlugIn.ModelCore.GenerateUniform(); double minProb = 0.0; double maxProb = 0.0; for (int bin = minBin; bin <= maxBin; bin++) { maxProb += binProbability[bin - minBin]; if (randomBinNum >= minProb && randomBinNum < maxProb) { weatherBin = bin; break; } else { minProb = binProbability[bin - minBin]; } } } } if(weatherBin == 0) weatherBin = sizeBin; //throw new System.ApplicationException("No Weather Bin randomly selected. FireRegion = "+ecoName+", Season = "+seasonName+", sizeBin = "+sizeBin); int rowCount = 0; int loopCount = 0; int firstDir = 0; DataRow[] foundRows = null; string seasonOrig = seasonName; if (PlugIn.ModelCore.GenerateUniform() >= 0.5) firstDir = 1; // Direction (+ or -) to check first if target bin is not available (+1 or -1) else firstDir = -1; while (rowCount == 0) { string selectString = "FWIBin = '" + weatherBin + "' AND Season = '" + seasonName + "' AND FireRegion = '" + ecoName + "'"; if (weatherBin == -1) { selectString = "Season = '" + seasonName + "' AND FireRegion = '" + ecoName + "'"; } foundRows = PlugIn.WeatherDataTable.Select(selectString); rowCount = foundRows.Length; if (rowCount == 0) { selectString = "FWIBin = '" + weatherBin + "' AND Season = '" + seasonName + "' AND FireRegion = 'All'"; { selectString = "Season = '" + seasonName + "' AND FireRegion = 'All'"; } foundRows = PlugIn.WeatherDataTable.Select(selectString); rowCount = foundRows.Length; } if (rowCount == 0) { //PlugIn.ModelCore.Log.WriteLine(" weatherBin "+weatherBin+" Not Found. Using alternate weatherBin."); if (sizeBin == 5) weatherBin = weatherBin - 1; else if (sizeBin == 1) weatherBin = weatherBin + 1; else { if (loopCount == 0) weatherBin = sizeBin + firstDir; else if (loopCount == 1) weatherBin = sizeBin - firstDir; else if (loopCount == 2) weatherBin = sizeBin + (firstDir * 2); else if (loopCount == 3) weatherBin = sizeBin - (firstDir * 2); else if (loopCount == 4) weatherBin = sizeBin + (firstDir * 3); else if (loopCount == 5) weatherBin = sizeBin - (firstDir * 3); else if (loopCount == 6) weatherBin = sizeBin + (firstDir * 4); else weatherBin = sizeBin - (firstDir * 4); } loopCount ++; if (loopCount > 100) { PlugIn.ModelCore.UI.WriteLine(" No Weather Rows Selected. Using alternate season."); if (seasonOrig == "Spring" || seasonOrig == "Fall") seasonName = "Summer"; else // Summer { if (firstDir == 1) { seasonName = "Spring"; } else { seasonName = "Fall"; } } } if (loopCount > 200) { PlugIn.ModelCore.UI.WriteLine(" No Weather Rows Selected. Using alternate season 2."); if (seasonOrig == "Spring") seasonName = "Fall"; else if (seasonOrig == "Fall") seasonName = "Spring"; else // Summer { if (firstDir == 1) { seasonName = "Fall"; } else { seasonName = "Spring"; } } } if (loopCount > 300) { PlugIn.ModelCore.UI.WriteLine("WARNING (Ln 350): FireRegion " + ecoName + " has fire probability > 0, but 0 weather records. No fires will occur in this fire region."); break; } } } if (rowCount > 0) { int newRandNum = (int)(Math.Round(PlugIn.ModelCore.GenerateUniform() * (rowCount - 1))); DataRow weatherRow = foundRows[newRandNum]; return weatherRow; } else { return null; } }
//--------------------------------------------------------------------- private Event(ActiveSite initiationSite, ISeasonParameters[] seasons, IWindDirectionParameters[] windDirs) { this.initiationSite = initiationSite; this.sitesInEvent = new int[Ecoregions.Dataset.Count]; foreach(IEcoregion ecoregion in Ecoregions.Dataset) this.sitesInEvent[ecoregion.Index] = 0; this.cohortsKilled = 0; this.eventSeverity = 0; this.totalSitesDamaged = 0; this.lengthB = 0.0; this.lengthA = 0.0; this.lengthD = 0.0; this.fireSeason = Weather.GenerateSeason(seasons); this.windSpeed = Weather.GenerateWindSpeed(this.fireSeason); this.fineFuelMoistureCode = Weather.GenerateFineFuelMoistureCode(this.fireSeason); this.buildUpIndex = Weather.GenerateBuildUpIndex(this.fireSeason); IWindDirectionParameters windDir = windDirs[(int) this.fireSeason.NameOfSeason]; this.windDirection = Weather.GenerateWindDirection(windDir); }
//--------------------------------------------------------------------- public static void Initialize(ISeasonParameters[] seasons, IFuelTypeParameters[] fuelTypeParameters, IDamageTable[] damages) { double totalSeasonFireProb = 0.0; foreach(ISeasonParameters season in seasons) totalSeasonFireProb += season.FireProbability; if (totalSeasonFireProb != 1.0) throw new System.ApplicationException("Error: Season Probabilities don't add to 1.0"); Event.fuelTypeParms = fuelTypeParameters; Event.damages = damages; cohorts = Model.Core.SuccessionCohorts as ILandscapeCohorts; if (cohorts == null) throw new System.ApplicationException("Error: Cohorts don't support age-cohort interface"); }
//--------------------------------------------------------------------- public static Event Initiate(ActiveSite site, int timestep, SizeType fireSizeType, bool bui, ISeasonParameters[] seasons, double severityCalibrate) { //Adjust ignition probability (measured on an annual basis) for the //user determined fire time step. int fuelIndex = SiteVars.CFSFuelType[site]; double initProb = FuelTypeParms[fuelIndex].InitiationProbability; //If mixed type, need to use weighted average initProb if (FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Conifer && SiteVars.PercentHardwood[site] > 0) //Mixed type { double decidInitProb; int decidFuelIndex = SiteVars.DecidFuelType[site]; if (decidFuelIndex > 0) { decidInitProb = FuelTypeParms[decidFuelIndex].InitiationProbability; initProb = (initProb * SiteVars.PercentConifer[site] + decidInitProb * SiteVars.PercentHardwood[site]) / 100; } } //The initial site must exceed the probability of initiation and //have a severity > 0 and exceed the ignition threshold: double randomNum = PlugIn.ModelCore.GenerateUniform(); ISeasonParameters fireSeason = Weather.GenerateSeason(seasons); if (SiteVars.PercentDeadFir[site] > 0) // If M3 or M4 type, use initProb if greater { if (SiteVars.PercentConifer[site] == 100 || fireSeason.LeafStatus == LeafOnOff.LeafOff) { //find the fuelindex with surfacefuel M3 foreach (FuelType listFuel in FuelTypeParms) { if (listFuel.SurfaceFuel == SurfaceFuelType.M3) { if (listFuel.InitiationProbability > initProb) //Only use M3 initprob if > c-type { initProb = listFuel.InitiationProbability; } } } } else { //find the fuel index with surfacefuel M4 foreach (FuelType listFuel in FuelTypeParms) { if (listFuel.SurfaceFuel == SurfaceFuelType.M4) { if (listFuel.InitiationProbability > initProb) //Only use M4 initprob if > c-type { initProb = listFuel.InitiationProbability; } } } } } if (randomNum <= initProb) { if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Generating a new fire event..."); } Event fireEvent = new Event(site, fireSeason, fireSizeType); //Must create event to determine season // Test that adequate weather data was retrieved: if (fireEvent.windSpeed == 0 && fireEvent.fineFuelMoistureCode == 0 && fireEvent.buildUpIndex == 0) { PlugIn.ModelCore.UI.WriteLine(" No weather data available: {0}; fire_region = {1}.", fireEvent.fireSeason.NameOfSeason, fireEvent.initiationFireRegion.Name); return(null); } if (fireEvent.FireSeason.PercentCuring == 0 && FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) { return(null); } if (!fireEvent.Spread(site, fireSizeType, bui, severityCalibrate)) { return(null); } else { return(fireEvent); } } else { if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Fire Event failed to initiate due to fuel type initiation probability"); } //return null; } return(null); }
private static double CalculateWSE(int fuelIndex, double RSF, double f_F, /*int PC,*/ ISeasonParameters season) { //FuelTypeCode siteFuelType = (FuelTypeCode) fuelIndex; double ISF, WSE; double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) //siteFuelType == FuelTypeCode.O1a) { double CF = (0.02 * season.PercentCuring) - 1; ISF = Math.Log(1 - Math.Pow((RSF / (CF * a)), (1 / c))) / (-1 * b); } else { ISF = Math.Log(1 - Math.Pow((RSF / (a)), (1 / c))) / (-1 * b); } WSE = Math.Log(ISF / (0.208 * f_F)) / 0.05039; return(WSE); }
private static List <int> CalculateSlopeEffect(int windSpeed, int windDirection, Site site, double RSZ, double f_F, ISeasonParameters season) { List <int> siteWindList = new List <int>(); if ((SiteVars.GroundSlope[site] == 0) || (RSZ == 0)) { siteWindSpeed = windSpeed; siteWindDirection = windDirection; //nothing is changed } else { //FuelTypeCode siteFuelType = (FuelTypeCode)SiteVars.CFSFuelType[site]; ; //Walk through the equations from FBP: double SF = 0; if (SiteVars.GroundSlope[site] > 60) { SF = CalculateSF(60); //FBP 39 has a max slope of 60% } else { SF = CalculateSF(SiteVars.GroundSlope[site]); //FBP 39 } double RSF = RSZ * SF; //FBP 40 double ISF = 0.0; double a, b, c; int fuelIndex = SiteVars.CFSFuelType[site]; if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) //(siteFuelType == FuelTypeCode.O1a) { int percentCuring = season.PercentCuring; double CF = (0.02 * percentCuring) - 1.0; if (season.NameOfSeason == SeasonName.Spring) { a = 190; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].A; b = 0.0310; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].B; c = 1.4; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].C; } else { a = 250; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].A; b = 0.0350; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].B; c = 1.7; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].C; } ISF = Math.Log((1 - Math.Pow((RSF / (CF * a)), (1 / c)))) / (-1 * b); //FBP 43 } else { a = Event.FuelTypeParms[fuelIndex].A; b = Event.FuelTypeParms[fuelIndex].B; c = Event.FuelTypeParms[fuelIndex].C; if (SiteVars.PercentDeadFir[site] > 0) { int PDF = SiteVars.PercentDeadFir[site]; if ((SiteVars.PercentHardwood[site] > 0) && (season.LeafStatus == LeafOnOff.LeafOn)) //M-4 { a = 140 * System.Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * System.Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * System.Math.Exp((-1) * 35 / (double)PDF); b = 0.082 * System.Math.Exp((-1) * 36 / (double)PDF); c = 1.698 - (0.00303 * (double)PDF); } ISF = Math.Log((1 - Math.Pow((RSF / a), (1 / c)))) / (-1 * b); //FBP 41 } else if ((SiteVars.PercentHardwood[site] > 0) && (SiteVars.PercentConifer[site] > 0)) { int PC = SiteVars.PercentConifer[site]; ISF = Math.Log((1 - Math.Pow(((100 - RSF) / (PC * a)), (1 / c)))) / (-1 * b); //FBP 42 } else { ISF = Math.Log((1 - Math.Pow((RSF / a), (1 / c)))) / (-1 * b); //FBP 41 } } double WSE = (Math.Log((ISF) / (.208 * f_F))) / (0.05039); //FBP 43: The effect the % slope would have on ROS if it were a wind speed double WAZ = (double)windDirection * Math.PI / 180; //wind direction/azimuth in radians double SAZ = (double)SiteVars.UphillSlopeAzimuth[site] * Math.PI / 180; //uphill slope azimuth in radians double WSX = ((double)windSpeed * Math.Sin(WAZ)) + (WSE * Math.Sin(SAZ)); //FBP 47 double WSY = ((double)windSpeed * Math.Cos(WAZ)) + (WSE * Math.Cos(SAZ)); //FBP 48 double WSV = Math.Sqrt(Math.Pow(WSX, 2) + Math.Pow(WSY, 2)); //FBP 49 siteWindSpeed = (int)WSV; double RAZ = Math.Acos(WSY / WSV); //FBP 50 RAZ = RAZ * 180 / Math.PI; // net wind direction radians to degrees if (WSX < 0) { RAZ = 360 - RAZ; } siteWindDirection = (int)RAZ; if (siteWindSpeed < 0 || siteWindDirection < 0) { } } siteWindList.Add(siteWindSpeed); siteWindList.Add(siteWindDirection); SiteVars.SiteWindSpeed[site] = (ushort)siteWindSpeed; SiteVars.SiteWindDirection[site] = (ushort)siteWindDirection; return(siteWindList); }
private static double CalculateTravelTime(Site site, Site firesource, Event fireEvent, bool buildUp) { if (!site.IsActive || !firesource.IsActive) { throw new ApplicationException("Either site or fire source are not active."); } //Calculate Fire regime size adjustment: IFireRegion fire_region = SiteVars.FireRegion[site]; double FRUA = fire_region.MeanSize; fire_region = SiteVars.FireRegion[firesource]; FRUA = FRUA / fire_region.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; //PlugIn.ModelCore.UI.WriteLine(" Fuel Type Code = {0}.", temp.ToString()); ISeasonParameters season = fireEvent.FireSeason; double f_F = Weather.CalculateFuelMoistureEffect(fireEvent.FFMC); double ISZ = 0.208 * f_F; //No wind double RSZ = FuelEffects.InitialRateOfSpread(ISZ, season, site); if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.ConiferPlantation)//SurfaceFuel == SurfaceFuelType.C6) { double FME = (Math.Pow((1.5 - (0.00275 * fireEvent.FMC)), 4) / (460 + (25.9 * fireEvent.FMC))) * 1000; double RSC = FuelEffects.CalculateRSI(60, 0.0497, 1, ISZ) * (FME / 0.778); double CSI = 0.001 * Math.Pow(7, 1.5) * Math.Pow((460 + 25.9 * fireEvent.FMC), 1.5); double SFC = FireSeverity.SurfaceFuelConsumption(fuelIndex, fireEvent.FFMC, fireEvent.BuildUpIndex, percentHardwood, percentDeadFir); double RSO = CSI / (300 * SFC); double CFB = 0; if (RSZ > RSO) { CFB = 1 - Math.Exp(-0.23 * (RSZ - RSO)); } RSZ = RSZ + (CFB * (RSC - RSZ)); } double BE = 0; 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; SiteVars.ISI[site] = ISI; double BISI = 0.208 * f_F * f_backW; double BROSi = FuelEffects.InitialRateOfSpread(BISI, season, site); double ROSi = FuelEffects.InitialRateOfSpread(ISI, season, site); if (ROSi == 0) { SiteVars.RateOfSpread[site] = 0; SiteVars.AdjROS[site] = 0; return(Double.PositiveInfinity); } else { BROSi *= FRUA; ROSi *= FRUA; if (buildUp) { if (SiteVars.PercentDeadFir[site] > 0) //either criteria indicates a DEAD FIR type { BE = Math.Exp(50 * Math.Log(0.80) * ((1 / (double)fireEvent.BuildUpIndex) - (1 / (double)50))); } else { BE = Math.Exp(50.0 * Math.Log(Event.FuelTypeParms[fuelIndex].Q) * ((1.0 / (double)fireEvent.BuildUpIndex) - (1 / (double)Event.FuelTypeParms[fuelIndex].BUI))); } } else { BE = 1; } ROSi *= BE; BROSi *= BE; SiteVars.RateOfSpread[site] = ROSi; double LB = CalculateLengthBreadthRatio(siteWindSpeed, fuelIndex); double FROSi = (ROSi + BROSi) / (LB * 2.0);// (FBP; 89) double alpha = siteWindDirection * (-1); double A = FROSi; 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 // Note that a and b are switched from those defined in these equations // so that they will fit in Finney's equation below double e = Math.Sqrt((double)1 - (Math.Pow(((double)1 / LB), 2))); //e = Eccentricity double dist = CellDistanceBetweenSites(site, firesource) * PlugIn.ModelCore.CellLength; //dist = r in Calvert's equation double r = ROSi; double time = 0; double index = 1; if (dist != 0) { double beta = BetaRand(firesource, site, alpha); // Beta = angle between wind direction, site double p = dist * (1 + e * Math.Cos(Math.PI - beta)); // p = semi-latus rectum = dist from focus to ellipse perimeter perpendicular to major axis double b = p / (1 - (e * e)); // b = half major axis (a in Calvert's equations) double a = b * Math.Sqrt(1 - (e * e)); // a = half minor axis (b in Calvert's equations) double c = e * b; // c = dist between focus and center // New (10/22/2007) equations to get r // a, b, c, and dist are real distances in m time = (b + c) / ROSi; // Calculate the time it would take to travel the distance of b+c if ROSi was the rate r = dist / time; // Calculate the ROS given the distance to the cell and the time //++++++++++ // This is a better way to make adjustments to account for randomization of angles // These equations were derived in MathCad (Beta_Adjust.xmcd) // See rationale for adjustments in Randomization Summary.doc index = 1; if (beta < 0) { beta = (Math.PI * 2) + beta; } double L2 = LB * LB; double partA = L2 * Math.Pow(((L2 - 1) / L2), 0.5); double partB = (-2) * (Math.Atan(Math.Tan(((0.5) * beta) + ((0.0625) * (Math.PI))) * Math.Pow((2 * L2 + 2 * L2 * Math.Pow(((LB - 1) * ((LB + 1) / L2)), (0.5)) - 1), (0.5)))); double partC = (((-1) * (L2)) + (partA * Math.Cos(beta)) - (partA) + (Math.Cos(beta) * L2) - (Math.Cos(beta))) / (Math.Pow(((2 * L2) + (2 * partA) - 1), (0.5))); double partD = (2) * (Math.Atan(((double)1 / (Math.Tan(((0.5) * beta) + ((0.4375) * (Math.PI))))) * Math.Pow((2 * L2 + 2 * L2 * Math.Pow(((LB - 1) * ((LB + 1) / L2)), (0.5)) - 1), (0.5)))); if ((((beta + 0.125 * Math.PI) >= Math.PI) && ((beta - 0.125 * Math.PI) >= Math.PI)) || (((beta + 0.125 * Math.PI) <= Math.PI) && ((beta - 0.125 * Math.PI) <= Math.PI))) { index = 4 * (partB * partC - partD * partC) / Math.PI; //Console.WriteLine("Beta = {0}; LB = {1}; partA = {2}; partB = {3}, partC = {4}, partD = {5}; Index = {6}", Beta, LB, partA, partB, partC, partD, index); } else { double indexA = ((-1) * Math.PI * partC - partD * partC) / (Math.PI * ((double)9 / (double)8) - beta); double indexB = (partB * partC - Math.PI * partC) / (beta - Math.PI * ((double)7 / (double)8)); double weightA = (Math.PI - (beta - 0.125 * Math.PI)) / (0.25 * Math.PI); double weightB = ((beta + 0.125 * Math.PI) - Math.PI) / (0.25 * Math.PI); index = indexA * weightA + indexB * weightB; //Console.WriteLine("Beta = {0}; IndexA = {1}; weightA = {2}; IndexB = {3}; weightB = {4}; Index = {5}", Beta, indexA, weightA, indexB, weightB, index); } r = r * (1 / index); //++++++++++ } if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.ConiferPlantation) //(int)FuelTypeCode.C6) { double FME = (Math.Pow((1.5 - (0.00275 * fireEvent.FMC)), 4) / (460 + (25.9 * fireEvent.FMC))) * 1000; double RSC = FuelEffects.CalculateRSI(60, 0.0497, 1, ISI) * (FME / 0.778); double CSI = 0.001 * Math.Pow(7, 1.5) * Math.Pow((460 + 25.9 * fireEvent.FMC), 1.5); double SFC = FireSeverity.SurfaceFuelConsumption(fuelIndex, fireEvent.FFMC, fireEvent.BuildUpIndex, percentHardwood, percentDeadFir); double RSO = CSI / (300 * SFC); double CFB = 0; if (r > RSO) { CFB = 1 - Math.Exp(-0.23 * (r - RSO)); } r = r + (CFB * (RSC - r)); } //-----Added by BRM----- SiteVars.AdjROS[site] = r; //---------- //PlugIn.ModelCore.UI.WriteLine(" FROSi = {0}, BROSi = {1}.", FROSi, BROSi); //PlugIn.ModelCore.UI.WriteLine(" beta = {0:0.00}, theta = {1:0.00}, alpha = {2:0.00}, Travel time = {3:0.000000}.", beta, theta, alpha, 1/r); //PlugIn.ModelCore.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 * PlugIn.ModelCore.CellLength / 2.0; //units = minutes return(cost); } else { double rate = 1.0 / r; //units = minutes / meter double cost = rate * PlugIn.ModelCore.CellLength; //units = minutes //if (cost < 1) // PlugIn.ModelCore.UI.WriteLine("Travel time < 1 min"); return(cost); } } }
// --------------------------------------------------------------------- // This method calculates the initial rate of spread for a specific site. // See below for the method that estimates the initial rate of spread for a broad area. public static double InitialRateOfSpread(double ISI, ISeasonParameters season, Site site) { int fuelIndex = SiteVars.CFSFuelType[site]; int PC = SiteVars.PercentConifer[site]; int PH = SiteVars.PercentHardwood[site]; int PDF = SiteVars.PercentDeadFir[site]; //PlugIn.ModelCore.UI.WriteLine("Fuel Type Code = {0}.", siteFuelType.ToString()); double RSI = 0.0; if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Conifer || Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.ConiferPlantation) { double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; double percentHard = (double)PH / 100.0; double percentConi = (double)PC / 100.0; RSI = CalculateRSI(a, b, c, ISI); if (PDF > 0) { if (PH > 0 && season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * Math.Exp((-1) * 35 / (double)PDF); b = 0.082 * Math.Exp((-1) * 36 / (double)PDF); c = 1.698 - (0.00303 * PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) { RSI = MRSI; } } // These are the classic MIXED CONIFER + DECIDUOUS else if (PH > 0) { double RSIconifer = RSI; int dIndex = SiteVars.DecidFuelType[site]; //(int)FuelTypeCode.D1; double RSIdecid = CalculateRSI(Event.FuelTypeParms[dIndex].A, Event.FuelTypeParms[dIndex].B, Event.FuelTypeParms[dIndex].C, ISI); if (season.LeafStatus == LeafOnOff.LeafOn) //M-2 { RSI = ((1 - percentHard) * RSIconifer) + (0.2 * percentHard * RSIdecid); } else //M-1 { RSI = ((1 - percentHard) * RSIconifer) + (percentHard * RSIdecid); } //PlugIn.ModelCore.UI.WriteLine("Calculating ROSi for a MIXED type. PH={0}, PC={1}, LeafStatus={2}.", PH, PC, season.LeafStatus); //PlugIn.ModelCore.UI.WriteLine(" RSIcon={0:0.0}, RSIdecid={1:0.0}, RSImix={2:0.000}.", RSIconifer, RSIdecid, RSI); } } if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) //siteFuelType == FuelTypeCode.O1a) { double a, b, c; int percentCuring = season.PercentCuring; if (season.NameOfSeason == SeasonName.Spring) //O1a { a = 190; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].A; b = 0.0310; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].B; c = 1.4; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].C; } else //O1b { a = 250; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].A; b = 0.0350; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].B; c = 1.7; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].C; } double CF = (0.02 * percentCuring) - 1.0; RSI = CalculateRSI(a, b, c, ISI); if (percentCuring > 50) { RSI *= CF; } else { RSI = 0; } if (PDF > 0) { if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) { RSI = MRSI; } } } if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.NoFuel || fuelIndex == 0) //siteFuelType == FuelTypeCode.NoFuel) { if (PDF > 0) { double a = 0, b = 0, c = 0; if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } RSI = CalculateRSI(a, b, c, ISI); } else { return(0); } } if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Slash || Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous) { //PlugIn.ModelCore.UI.WriteLine("Calculating ROSi for a DECIDUOUS or SLASH type."); double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; RSI = CalculateRSI(a, b, c, ISI); if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous && season.LeafStatus == LeafOnOff.LeafOn) { //if(siteFuelType == FuelTypeCode.D1 && season.LeafStatus == LeafOnOff.LeafOn) RSI *= 0.2; } if (PDF > 0) { if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous && season.LeafStatus == LeafOnOff.LeafOn) //M-4 //siteFuelType == FuelTypeCode.D1) { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) { RSI = MRSI; } } } return(RSI); }
//--------------------------------------------------------------------- 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 List<int> CalculateSlopeEffect(int windSpeed, int windDirection, Site site, double RSZ, double f_F, ISeasonParameters season) { List<int> siteWindList = new List<int>(); if (SiteVars.GroundSlope[site] == 0) { siteWindSpeed = windSpeed; siteWindDirection = windDirection; //nothing is changed } else { FuelTypeCode siteFuelType = (FuelTypeCode)SiteVars.CFSFuelType[site]; ; //Walk through the equations from FBP: double SF = CalculateSF(SiteVars.GroundSlope[site]); //FBP 39 double RSF = RSZ * SF; //FBP 40 double ISF = 0.0; double a, b, c; int fuelIndex = SiteVars.CFSFuelType[site]; if (siteFuelType == FuelTypeCode.O1a) { int percentCuring = season.PercentCuring; double CF = (0.02 * percentCuring) - 1.0; if (season.NameOfSeason == SeasonName.Spring) { a = Event.fuelTypeParms[(int)FuelTypeCode.O1a].A; b = Event.fuelTypeParms[(int)FuelTypeCode.O1a].B; c = Event.fuelTypeParms[(int)FuelTypeCode.O1a].C; } else { a = Event.fuelTypeParms[(int)FuelTypeCode.O1b].A; b = Event.fuelTypeParms[(int)FuelTypeCode.O1b].B; c = Event.fuelTypeParms[(int)FuelTypeCode.O1b].C; } ISF = Math.Log((1 - Math.Pow((RSF / (CF * a)), (1 / c)))) / (-1 * b); //FBP 43 } else { a = Event.fuelTypeParms[fuelIndex].A; b = Event.fuelTypeParms[fuelIndex].B; c = Event.fuelTypeParms[fuelIndex].C; if (SiteVars.PercentHardwood[site] > 0) { int PC = SiteVars.PercentConifer[site]; ISF = Math.Log((1 - Math.Pow(((100 - RSF) / (PC * a)), (1 / c)))) / (-1 * b); //FBP 42 } else { ISF = Math.Log((1 - Math.Pow(((RSF) / (a)), (1 / c)))) / (-1 * b); //FBP 41 } } double WSE = (Math.Log((ISF) / (.208 * f_F))) / (0.05039); //FBP 43: The effect the % slope would have on ROS if it were a wind speed double WAZ = windDirection * Math.PI / 180; //wind direction/azimuth in radians double SAZ = SiteVars.UphillSlopeAzimuth[site] * Math.PI / 180; //uphill slope azimuth in radians double WSX = (windSpeed * Math.Sin(WAZ)) + (WSE * Math.Sin(SAZ)); //FBP 47 double WSY = (windSpeed * Math.Cos(WAZ)) + (WSE * Math.Cos(SAZ)); //FBP 48 double WSV = Math.Sqrt(Math.Pow(WSX, 2) + Math.Pow(WSY, 2)); //FBP 49 siteWindSpeed = (int)WSV; double RAZ = Math.Acos(WSY / WSV); //FBP 50 if (WSX < 0) RAZ = 360 - RAZ; siteWindDirection = (int)RAZ; } siteWindList.Add(siteWindSpeed); siteWindList.Add(siteWindDirection); SiteVars.SiteWindSpeed[site] = (ushort)siteWindSpeed; SiteVars.SiteWindDirection[site] = (ushort)siteWindDirection; return siteWindList; }
//--------------------------------------------------------------------- public static DataRow GenerateSeasonWindData(ISeasonParameters season) { int weatherRandomizer = PlugIn.WeatherRandomizer; //string seasonName = season.NameOfSeason.ToString(); //string ecoName = fire_region.Name; //int weatherBin = 0; int seasonStart = season.StartDay; int seasonEnd = season.EndDay; string selectString = "Day >= " + seasonStart + " AND Day <= " + seasonEnd; DataRow[] rows = PlugIn.WindDataTable.Select(selectString); if (rows.Length > 0) { int newRandNum = (int)(Math.Round(PlugIn.ModelCore.GenerateUniform() * (rows.Length - 1))); DataRow weatherRow = rows[newRandNum]; return weatherRow; } else { return null; } }
//--------------------------------------------------------------------- public static int GenerateFMC(ISeasonParameters season, IDynamicInputRecord fire_region) { int FMC = 0; if (season.NameOfSeason == SeasonName.Spring) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.SpringFMCHiProp) FMC = fire_region.SpringFMCHi; else FMC = fire_region.SpringFMCLo; } if (season.NameOfSeason == SeasonName.Summer) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.SummerFMCHiProp) FMC = fire_region.SummerFMCHi; else FMC = fire_region.SummerFMCLo; } if (season.NameOfSeason == SeasonName.Fall) { if (PlugIn.ModelCore.GenerateUniform() < fire_region.FallFMCHiProp) FMC = fire_region.FallFMCHi; else FMC = fire_region.FallFMCLo; } return FMC; }
//--------------------------------------------------------------------- public static DataTable ReadWeatherFile(string path, List<IFireRegion> ecoDataSet, ISeasonParameters[] seasonParms) { UI.WriteLine(" Dynamic Fire: Loading Weather Data..."); CSVParser weatherParser = new CSVParser(); DataTable weatherTable = weatherParser.ParseToDataTable(path); int recordCount = 0; for (int i = 0; i <= 2; i++) { string seasName = seasonParms[i].NameOfSeason.ToString(); foreach (IFireRegion fire_region in ecoDataSet) { string ecoName = fire_region.Name; //UI.WriteLine("Read Weather File: Season={0}, FireRegion={1}.", seasName, ecoName); string selectText = ("Ecoregion = '" + ecoName + "' AND Season = '" + seasName + "'"); //UI.WriteLine("Read Weather File SelectText = {0}.", selectText); DataRow[] foundRows = weatherTable.Select(selectText); if (foundRows.Length == 0) { selectText = ("Ecoregion = 'All' AND Season = '" + seasName + "'"); foundRows = weatherTable.Select(selectText); } if(foundRows.Length > 0) { //Input validation double WSV, FFMC, BUI; int WINDDIR, FWIBIN; for(int j = 0; j < foundRows.Length; j ++) //weatherDataSet.Tables["Table"].Rows) { DataRow myDataRow = foundRows[j]; WSV = (double) myDataRow["WSV"]; //Console.WriteLine("WSV: {0}", WSV); if (WSV < 0.0) { throw new System.ApplicationException("Error: Wind Speed < 0: FireRegion = " + ecoName + "; Season = " + seasName); } FFMC = (double) myDataRow["FFMC"]; //Console.WriteLine("FFMC: {0}", FFMC); if (FFMC < 0.0) { throw new System.ApplicationException("Error: FFMC < 0: FireRegion = " + ecoName + "; Season = " + seasName); } else if (FFMC > 100.0) { throw new System.ApplicationException("Error: FFMC > 100: FireRegion = " + ecoName + "; Season = " + seasName); } BUI = (double) myDataRow["BUI"]; //Console.WriteLine("BUI: {0}", BUI); if (BUI < 0.0) { throw new System.ApplicationException("Error: BUI < 0: FireRegion = " + ecoName + "; Season = " + seasName); } WINDDIR = (int) myDataRow["WindDir"]; //Console.WriteLine("WindDir: {0}", WINDDIR); if (WINDDIR < 0) { throw new System.ApplicationException("Error: WINDDIR < 0: FireRegion = " + ecoName + "; Season = " + seasName); } else if (WINDDIR > 360) { throw new System.ApplicationException("Error: WINDDIR > 360: FireRegion = " + ecoName + "; Season = " + seasName); } FWIBIN = (int) myDataRow["FWIBin"]; //Console.WriteLine("FWIBIN: {0}", FWIBIN); if (FWIBIN < 1) { throw new System.ApplicationException("Error: FWIBIN < 1: FireRegion = " + ecoName + "; Season = " + seasName); } else if (FWIBIN > 5) { throw new System.ApplicationException("Error: FWIBIN > 5: FireRegion = " + ecoName + "; Season = " + seasName); } } } if ((foundRows.Length == 0) && (seasonParms[i].FireProbability > 0) && (fire_region.EcoIgnitionNum > 0)) { throw new System.ApplicationException("Error: Ecoregion " + ecoName + ", Season " + seasName + " has fire probability > 0, but 0 weather records"); } if(seasName == "Fall") { fire_region.FallRecords = recordCount; } else if (seasName == "Spring") { fire_region.SpringRecords = recordCount; } else if (seasName == "Summer") { fire_region.SummerRecords = recordCount; } } } return weatherTable; }
// --------------------------------------------------------------------- // This method calculates the initial rate of spread for a specific site. // See below for the method that estimates the initial rate of spread for a broad area. public static double InitialRateOfSpread(double ISI, ISeasonParameters season, Site site, bool secondRegionMap) { int fuelIndex = SiteVars.CFSFuelType[site]; if (secondRegionMap) fuelIndex = SiteVars.CFSFuelType2[site]; int PC = SiteVars.PercentConifer[site]; int PH = SiteVars.PercentHardwood[site]; int PDF = SiteVars.PercentDeadFir[site]; //PlugIn.ModelCore.Log.WriteLine("Fuel Type Code = {0}.", siteFuelType.ToString()); double RSI = 0.0; //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Conifer || //Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.ConiferPlantation) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C1 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C2 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C3 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C4 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C5 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C6 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C7) { double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; double percentHard = (double) PH / 100.0; double percentConi = (double) PC / 100.0; RSI = CalculateRSI(a, b, c, ISI); if (PDF > 0) { if (PH > 0 && season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double) PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double) PDF); } else //M-3 { a = 170 * Math.Exp((-1) * 35 / (double) PDF); b = 0.082 * Math.Exp((-1) * 36 / (double)PDF); c = 1.698 - (0.00303 * PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } // These are the classic MIXED CONIFER + DECIDUOUS else if (PH > 0) { double RSIconifer = RSI; int dIndex = SiteVars.DecidFuelType[site]; //(int)FuelTypeCode.D1; double RSIdecid = CalculateRSI(Event.FuelTypeParms[dIndex].A, Event.FuelTypeParms[dIndex].B, Event.FuelTypeParms[dIndex].C, ISI); if (season.LeafStatus == LeafOnOff.LeafOn) //M-2 { RSI = ((1 - percentHard) * RSIconifer) + (0.2 * percentHard * RSIdecid); } else //M-1 { RSI = ((1 - percentHard) * RSIconifer) + (percentHard * RSIdecid); } //PlugIn.ModelCore.Log.WriteLine("Calculating ROSi for a MIXED type. PH={0}, PC={1}, LeafStatus={2}.", PH, PC, season.LeafStatus); //PlugIn.ModelCore.Log.WriteLine(" RSIcon={0:0.0}, RSIdecid={1:0.0}, RSImix={2:0.000}.", RSIconifer, RSIdecid, RSI); } } //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.O1a || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.O1b) //siteFuelType == FuelTypeCode.O1a) { double a, b, c; int percentCuring = season.PercentCuring; if(season.NameOfSeason == SeasonName.Spring) //O1a { a = 190; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].A; b = 0.0310; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].B; c = 1.4; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].C; } else //O1b { a = 250; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].A; b = 0.0350; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].B; c = 1.7; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].C; } double CF = (0.02 * percentCuring) - 1.0; RSI = CalculateRSI(a, b, c, ISI); if(percentCuring > 50) RSI *= CF; else RSI = 0; if (PDF > 0) { if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } } //if(Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.NoFuel || fuelIndex == 0) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.NoFuel || fuelIndex == 0) //siteFuelType == FuelTypeCode.NoFuel) { if (PDF > 0) { double a=0, b=0, c=0; if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } RSI = CalculateRSI(a, b, c, ISI); } else { return 0; } } //if( Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Slash || //Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S1 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S2 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S3 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1) { //PlugIn.ModelCore.Log.WriteLine("Calculating ROSi for a DECIDUOUS or SLASH type."); double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; RSI = CalculateRSI(a, b, c, ISI); //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous if(Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1 && season.LeafStatus == LeafOnOff.LeafOn) //if(siteFuelType == FuelTypeCode.D1 && season.LeafStatus == LeafOnOff.LeafOn) RSI *= 0.2; if (PDF > 0) { //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1 && season.LeafStatus == LeafOnOff.LeafOn) //M-4 //siteFuelType == FuelTypeCode.D1) { a = 140 * Math.Exp((-1) * 35.5 / (double) PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double) PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double) PDF)); b = 0.082 * (Math.Exp(((-1) * 36 )/ (double) PDF)); c = 1.698 - (0.00303 * (double) PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } } return RSI; }
//--------------------------------------------------------------------- public static int GenerateFMC(ISeasonParameters season, IFireRegion fire_region) { int FMC = 0; if (season.NameOfSeason == SeasonName.Spring) { if (Util.Random.GenerateUniform() < fire_region.SpringFMCHiProp) FMC = fire_region.SpringFMCHi; else FMC = fire_region.SpringFMCLo; } if (season.NameOfSeason == SeasonName.Summer) { if (Util.Random.GenerateUniform() < fire_region.SummerFMCHiProp) FMC = fire_region.SummerFMCHi; else FMC = fire_region.SummerFMCLo; } if (season.NameOfSeason == SeasonName.Fall) { if (Util.Random.GenerateUniform() < fire_region.FallFMCHiProp) FMC = fire_region.FallFMCHi; else FMC = fire_region.FallFMCLo; } return FMC; }