//--------------------------------------------------------------------- public static Event Initiate(ActiveSite site, int currentTime, int timestep) { IFireRegion ecoregion = SiteVars.FireRegion[site]; //Adjust ignition probability (measured on an annual basis) for the //user determined fire time step. double ignitionProb = ecoregion.IgnitionProbability * timestep; //The initial site must exceed the probability of initiation and //have a severity > 0 and exceed the ignition threshold: if (PlugIn.ModelCore.GenerateUniform() <= ignitionProb && PlugIn.ModelCore.GenerateUniform() <= ComputeFireInitSpreadProb(site, currentTime) && CalcSeverity(site, currentTime) > 0) { Event FireEvent = new Event(site); FireEvent.Spread(currentTime); return(FireEvent); } else { return(null); } }
//--------------------------------------------------------------------- public static int ComputeSize(IFireRegion ecoregion) { if (ecoregion.MeanSize <= 0) { return(0); } PlugIn.ModelCore.ExponentialDistribution.Lambda = 1.0 / ecoregion.MeanSize; double sizeGenerated = PlugIn.ModelCore.ExponentialDistribution.NextDouble(); int finalSize; if (sizeGenerated < ecoregion.MinSize) { finalSize = (int)(ecoregion.MinSize / PlugIn.ModelCore.CellArea); } else if (sizeGenerated > ecoregion.MaxSize) { finalSize = (int)(ecoregion.MaxSize / PlugIn.ModelCore.CellArea); } else { finalSize = (int)(sizeGenerated / PlugIn.ModelCore.CellArea); } return(finalSize); }
//--------------------------------------------------------------------- private IFireRegion GetFireRegion(InputValue <string> ecoregionName, Dictionary <string, int> lineNumbers) { //IFireRegion ecoregion = FireRegions.Dataset[ecoregionName.Actual]; IFireRegion ecoregion = FireRegions.FindName(ecoregionName.Actual); if (ecoregion == null) { throw new InputValueException(ecoregionName.String, "{0} is not an ecoregion name.", ecoregionName.String); } int lineNumber; if (lineNumbers.TryGetValue(ecoregion.Name, out lineNumber)) { throw new InputValueException(ecoregionName.String, "The ecoregion {0} was previously used on line {1}", ecoregionName.String, lineNumber); } else { lineNumbers[ecoregion.Name] = LineNumber; } return(ecoregion); }
//--------------------------------------------------------------------- // The probability of fire initiation (different from ignition) // and spread. Formula from Jian Yang, University of Missouri-Columbia, // personal communication. public static double ComputeFireInitSpreadProb(ActiveSite site, int currentTime) { IFireRegion ecoregion = SiteVars.FireRegion[site]; int timeSinceLastFire = currentTime - SiteVars.TimeOfLastFire[site]; double fireInitSpreadProb = 1.0 - System.Math.Exp(timeSinceLastFire * (-1.0 / (double)ecoregion.FireSpreadAge)); return(fireInitSpreadProb); }
//--------------------------------------------------------------------- public static void ReadMap(string path) { IInputRaster <IntPixel> map; try { map = PlugIn.ModelCore.OpenRaster <IntPixel>(path); } catch (FileNotFoundException) { string mesg = string.Format("Error: The file {0} does not exist", path); throw new System.ApplicationException(mesg); } if (map.Dimensions != PlugIn.ModelCore.Landscape.Dimensions) { string mesg = string.Format("Error: The input map {0} does not have the same dimension (row, column) as the ecoregions map", path); throw new System.ApplicationException(mesg); } using (map) { IntPixel pixel = map.BufferPixel; foreach (Site site in PlugIn.ModelCore.Landscape.AllSites) { map.ReadBufferPixel(); int mapCode = pixel.MapCode.Value; if (site.IsActive) { if (Dataset == null) { PlugIn.ModelCore.UI.WriteLine("FireRegion.Dataset not set correctly."); } IFireRegion fire_region = Find(mapCode); if (fire_region == null) { string mesg = string.Format("Unknown map code = {0}, Row/Column = {1}/{2}", mapCode, site.Location.Row, site.Location.Column); throw new System.ApplicationException(mesg); } SiteVars.FireRegion[site] = fire_region; fire_region.FireRegionSites.Add(site.Location); } } } }
//--------------------------------------------------------------------- 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 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); }
//--------------------------------------------------------------------- private bool Spread(ActiveSite initiationSite, SizeType fireSizeType, bool BUI, double severityCalibrate) { //First, check for fire overlap: if (SiteVars.Event[initiationSite] != null) { return(false); } if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Spreading fire event started at {0} ...", initiationSite.Location); } IFireRegion fire_region = SiteVars.FireRegion[initiationSite]; int totalSiteSeverities = 0; int siteCohortsKilled = 0; int totalISI = 0; totalSitesDamaged = 1; this.initiationFuel = SiteVars.CFSFuelType[initiationSite]; this.initiationPercentConifer = SiteVars.PercentConifer[initiationSite]; //PlugIn.ModelCore.UI.WriteLine(" Calculated max fire size or duration = {0:0.0}", maxFireParameter); //PlugIn.ModelCore.UI.WriteLine(" Fuel Type = {0}", activeFT.ToString()); //Next, calculate the fire area: List <Site> FireLocations = new List <Site>(); if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Calling SizeFireCostSurface ..."); } FireLocations = EventRegion.SizeFireCostSurface(this, fireSizeType, BUI); if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" FireLocations.Count = {0}", FireLocations.Count); } if (FireLocations.Count == 0) { return(false); } //Attach travel time weights here if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Computing SizeFireCostSurface ..."); } List <WeightedSite> FireCostSurface = new List <WeightedSite>(0); foreach (Site site in FireLocations) { double myWeight = SiteVars.TravelTime[site]; if ((Double.IsNaN(myWeight)) || (Double.IsInfinity(myWeight))) { } else { FireCostSurface.Add(new WeightedSite(site, myWeight)); } } WeightComparer weightComp = new WeightComparer(); FireCostSurface.Sort(weightComp); FireLocations = new List <Site>(); double cellArea = (PlugIn.ModelCore.CellLength * PlugIn.ModelCore.CellLength) / 10000; //convert to ha double totalArea = 0.0; int cellCnt = 0; double durMax = 0; if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Determining cells burned ..."); } if (fireSizeType == SizeType.size_based) { foreach (WeightedSite weighted in FireCostSurface) { //weightCnt++; cellCnt++; if (totalArea > this.maxFireParameter) { SiteVars.Event[weighted.Site] = null; } else { totalArea += cellArea; FireLocations.Add(weighted.Site); if (SiteVars.TravelTime[weighted.Site] > durMax) { durMax = SiteVars.TravelTime[weighted.Site]; } } } this.maxDuration = durMax; //PlugIn.ModelCore.UI.WriteLine(" Fire Summary: Cells Checked={0}, BurnedArea={1:0.0} (ha), Target Area={2:0.0} (ha).", cellCnt, totalArea, this.maxFireParameter); //if(totalArea < this.maxFireParameter) // PlugIn.ModelCore.UI.WriteLine(" NOTE: Partial fire burn; fire may have spread to the edge of the active area."); } else if (fireSizeType == SizeType.duration_based) { double durationAdj = this.maxFireParameter; if (durationAdj >= 1440) { durationAdj = durationAdj * this.FireSeason.DayLengthProp; } foreach (WeightedSite weighted in FireCostSurface) { cellCnt++; if (weighted.Site == this.initiationSite) { totalArea += cellArea; FireLocations.Add(weighted.Site); if (SiteVars.TravelTime[weighted.Site] > durMax) { durMax = SiteVars.TravelTime[weighted.Site]; } } else { if (weighted.Weight > durationAdj) { SiteVars.Event[weighted.Site] = null; } else { totalArea += cellArea; FireLocations.Add(weighted.Site); //-----Added by BRM----- if (SiteVars.TravelTime[weighted.Site] > durMax) { durMax = SiteVars.TravelTime[weighted.Site]; } //---------- } } } this.maxDuration = durMax; //PlugIn.ModelCore.UI.WriteLine(" Fire Summary: Cells Checked={0}, BurnedArea={1:0.0} (ha), Target Duration={2:0.0}, Adjusted Duration = {3:0.0}.", cellCnt, totalArea, this.maxFireParameter, durationAdj); //if(durationAdj - durMax > 5.0) // PlugIn.ModelCore.UI.WriteLine(" NOTE: Partial fire burn; fire may have spread to the edge of the active area."); } if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" FireLocations.Count = {0}", FireLocations.Count); } int FMC = this.FMC; //Foliar Moisture Content if (FireLocations.Count == 0) { return(false); } if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Damaging cohorts at burned sites ..."); } foreach (Site site in FireLocations) { currentSite = (ActiveSite)site; if (site.IsActive) { this.numSitesChecked++; this.siteSeverity = FireSeverity.CalcFireSeverity(currentSite, this, severityCalibrate, FMC); SiteVars.Severity[currentSite] = (byte)siteSeverity; siteCohortsKilled = Damage(currentSite); this.totalSitesDamaged++; totalSiteSeverities += this.siteSeverity; totalISI += (int)SiteVars.ISI[site]; IFireRegion siteFireRegion = SiteVars.FireRegion[site]; sitesInEvent[siteFireRegion.Index]++; SiteVars.Disturbed[currentSite] = true; if (siteSeverity > 0) { SiteVars.LastSeverity[currentSite] = (byte)siteSeverity; } } } if (this.totalSitesDamaged == 0) { this.eventSeverity = 0; } else { this.eventSeverity = ((double)totalSiteSeverities) / (double)this.totalSitesDamaged; } this.isi = (int)((double)totalISI / (double)this.totalSitesDamaged); if (isDebugEnabled) { PlugIn.ModelCore.UI.WriteLine(" Done spreading"); } return(true); }
//--------------------------------------------------------------------- public static int ComputeSize(IFireRegion ecoregion) { if (ecoregion.MeanSize <= 0) return 0; PlugIn.ModelCore.ExponentialDistribution.Lambda = 1.0 / ecoregion.MeanSize; double sizeGenerated = PlugIn.ModelCore.ExponentialDistribution.NextDouble(); int finalSize; if (sizeGenerated < ecoregion.MinSize) finalSize = (int)(ecoregion.MinSize / PlugIn.ModelCore.CellArea); else if (sizeGenerated > ecoregion.MaxSize) { finalSize = (int)(ecoregion.MaxSize / PlugIn.ModelCore.CellArea); } else finalSize = (int)(sizeGenerated / PlugIn.ModelCore.CellArea); return finalSize; }
//--------------------------------------------------------------------- public static byte CalcSeverity(ActiveSite site, int currentTime) { IFireRegion ecoregion = SiteVars.FireRegion[site]; IFuelCurve fuelCurve = ecoregion.FuelCurve; IWindCurve windCurve = ecoregion.WindCurve; int severity = 0; int timeSinceLastFire = currentTime - SiteVars.TimeOfLastFire[site]; if (fuelCurve.Severity1 != -1 && timeSinceLastFire >= fuelCurve.Severity1) { severity = 1; } if (fuelCurve.Severity2 != -1 && timeSinceLastFire >= fuelCurve.Severity2) { severity = 2; } if (fuelCurve.Severity3 != -1 && timeSinceLastFire >= fuelCurve.Severity3) { severity = 3; } if (fuelCurve.Severity4 != -1 && timeSinceLastFire >= fuelCurve.Severity4) { severity = 4; } if (fuelCurve.Severity5 != -1 && timeSinceLastFire >= fuelCurve.Severity5) { severity = 5; } int windSeverity = 0; int timeSinceLastWind = 0; if (SiteVars.TimeOfLastWind != null) { timeSinceLastWind = currentTime - SiteVars.TimeOfLastWind[site]; if (windCurve.Severity1 != -1 && timeSinceLastWind <= windCurve.Severity1) { windSeverity = 1; } if (windCurve.Severity2 != -1 && timeSinceLastWind <= windCurve.Severity2) { windSeverity = 2; } if (windCurve.Severity3 != -1 && timeSinceLastWind <= windCurve.Severity3) { windSeverity = 3; } if (windCurve.Severity4 != -1 && timeSinceLastWind <= windCurve.Severity4) { windSeverity = 4; } if (windCurve.Severity5 != -1 && timeSinceLastWind <= windCurve.Severity5) { windSeverity = 5; } } if (windSeverity > severity) { severity = windSeverity; } return((byte)severity); }
//--------------------------------------------------------------------- private void Spread(int currentTime) { int windDirection = (int)(PlugIn.ModelCore.GenerateUniform() * 8); double windSpeed = PlugIn.ModelCore.GenerateUniform(); int[] size = new int[FireRegions.Dataset.Count]; // in # of sites int totalSitesInEvent = 0; long totalSiteSeverities = 0; int maxFireRegionSize = 0; int siteCohortsKilled = 0; IFireRegion ecoregion = SiteVars.FireRegion[initiationSite]; int ecoIndex = ecoregion.Index; size[ecoIndex] = ComputeSize(ecoregion); if (size[ecoIndex] > maxFireRegionSize) { maxFireRegionSize = size[ecoIndex]; } //Create a queue of neighboring sites to which the fire will spread: Queue <Site> sitesToConsider = new Queue <Site>(); sitesToConsider.Enqueue(initiationSite); //Fire size cannot be larger than the size calculated for each ecoregion. //Fire size cannot be larger than the largest size for any ecoregion. while (sitesToConsider.Count > 0 && this.sitesInEvent[ecoIndex] < size[ecoIndex] && totalSitesInEvent < maxFireRegionSize) { this.numSiteChecked++; Site site = sitesToConsider.Dequeue(); currentSite = (ActiveSite)site; //site as ActiveSite; ecoregion = SiteVars.FireRegion[site]; if (ecoregion.Index != ecoIndex) { ecoIndex = ecoregion.Index; if (size[ecoIndex] < 1) { size[ecoIndex] = ComputeSize(ecoregion); if (size[ecoIndex] > maxFireRegionSize) { maxFireRegionSize = size[ecoIndex]; } } } SiteVars.Event[site] = this; if (currentSite != null) { siteSeverity = CalcSeverity(currentSite, currentTime); } else { siteSeverity = 0; } if (siteSeverity > 0) { this.sitesInEvent[ecoIndex]++; totalSitesInEvent++; SiteVars.Severity[currentSite] = siteSeverity; SiteVars.TimeOfLastFire[currentSite] = currentTime; totalSiteSeverities += siteSeverity; SiteVars.Disturbed[currentSite] = true; siteCohortsKilled = KillSiteCohorts(currentSite); if (siteCohortsKilled > 0) { totalSitesDamaged++; } //Next, add site's neighbors in random order 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. //Fire can burn into neighbors only if the //spread probability is exceeded. List <Site> neighbors = GetNeighbors(site, windDirection, windSpeed); if (neighbors.Count > 0) { neighbors = PlugIn.ModelCore.shuffle(neighbors); foreach (Site neighbor in neighbors) { if (!neighbor.IsActive) { continue; } if (SiteVars.Event[neighbor] != null) { continue; } if (sitesToConsider.Contains(neighbor)) { continue; } if (PlugIn.ModelCore.GenerateUniform() <= ComputeFireInitSpreadProb((ActiveSite)neighbor, currentTime)) //(neighbor as ActiveSite, currentTime)) { sitesToConsider.Enqueue(neighbor); } } } } } if (this.totalSitesDamaged == 0) { this.severity = 0; } else { this.severity = ((double)totalSiteSeverities) / totalSitesInEvent; } }
//--------------------------------------------------------------------- public static int ComputeSize(IFireRegion ecoregion) { if (ecoregion.MeanSize <= 0) return 0; double sizeGenerated = Random.GenerateExponential(ecoregion.MeanSize); //UI.WriteLine("Max={0}, Min={1}, Mean={2}, Eco={3}.", ecoregion.MaxSize, ecoregion.MinSize, ecoregion.MeanSize, ecoregion.Name); //double sizeGenerated = Random.GenerateLogNormal(ecoregion.MeanSize); if (sizeGenerated < ecoregion.MinSize) return (int) (ecoregion.MinSize/Model.Core.CellArea); else if (sizeGenerated > ecoregion.MaxSize) { return (int) (ecoregion.MaxSize / Model.Core.CellArea); } else return (int) (sizeGenerated/Model.Core.CellArea); }
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); } } }
//--------------------------------------------------------------------- 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 = Util.Random.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 (Util.Random.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) { //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) { 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(Util.Random.GenerateUniform() * (rowCount - 1))); DataRow weatherRow = foundRows[newRandNum]; return weatherRow; }
//--------------------------------------------------------------------- ///<summary> /// Run the plug-in at a particular timestep. ///</summary> public override void Run() { SiteVars.InitializeFuelType(); modelCore.UI.WriteLine(" Processing landscape for Fire events ..."); if (FireRegions.Dataset.Count == 0) { throw new ApplicationException("Fire region data set is empty."); } SiteVars.Event.SiteValues = null; SiteVars.Severity.ActiveSiteValues = 0; SiteVars.Disturbed.ActiveSiteValues = false; SiteVars.TravelTime.ActiveSiteValues = Double.PositiveInfinity; SiteVars.MinNeighborTravelTime.ActiveSiteValues = Double.PositiveInfinity; SiteVars.RateOfSpread.ActiveSiteValues = 0.0; foreach (IFireRegion fire_region in FireRegions.Dataset) { summaryFireRegionEventCount[fire_region.Index] = 0; } summaryTotalSites = 0; summaryEventCount = 0; // Update the FireRegions Map as necessary: //modelCore.UI.WriteLine(" Dynamic Fire: Loading Dynamic Fire Regions..."); foreach (IDynamicFireRegion dyneco in dynamicEcos) { if (dyneco.Year == modelCore.CurrentTime) { modelCore.UI.WriteLine(" Reading in new Fire FireRegions Map {0}.", dyneco.MapName); foreach (IFireRegion fire_region in FireRegions.Dataset) { fire_region.FireRegionSites.Clear(); // = new List<Location>(); } FireRegions.ReadMap(dyneco.MapName); //Sites added to their respective fire_region lists } } //Update the weather table as necessary: foreach (IDynamicWeather dynweather in dynamicWeather) { if (dynweather.Year == modelCore.CurrentTime) { modelCore.UI.WriteLine(" Reading in new Weather Table {0}", dynweather.FileName); WeatherDataTable = Weather.ReadWeatherFile(dynweather.FileName, FireRegions.Dataset, seasonParameters); } } // Fill in open types as needed: modelCore.UI.WriteLine(" Dynamic Fire: Filling open types as needed ..."); foreach (ActiveSite site in modelCore.Landscape) { IFireRegion fire_region = SiteVars.FireRegion[site]; if (fire_region == null) { throw new System.ApplicationException("Error: SiteVars.FireRegion is empty."); } //if(SiteVars.CFSFuelType[site] == 0) // throw new System.ApplicationException("Error: SiteVars.CFSFuelType is empty."); if (Event.FuelTypeParms[SiteVars.CFSFuelType[site]] == null) { modelCore.UI.WriteLine("Error: SiteVars.CFSFuelType[site]={0}.", SiteVars.CFSFuelType[site]); throw new System.ApplicationException("Error: Event BaseFuel Empty."); } if (Event.FuelTypeParms[SiteVars.CFSFuelType[site]].BaseFuel == BaseFuelType.NoFuel) { if (SiteVars.PercentDeadFir[site] == 0) { SiteVars.CFSFuelType[site] = fire_region.OpenFuelType; } } } if (isDebugEnabled) { modelCore.UI.WriteLine("Done filling open types"); } modelCore.UI.WriteLine(" Dynamic Fire: Igniting Fires ..."); foreach (IFireRegion fire_region in FireRegions.Dataset) { if (isDebugEnabled) { modelCore.UI.WriteLine(" There are {0} site locations in fire region {1}", fire_region.FireRegionSites.Count, fire_region.Name); } if (fire_region.EcoIgnitionNum > 0) { //PoissonDistribution randVar = new PoissonDistribution(RandomNumberGenerator.Singleton); double doubleLambda; int ignGenerated = 0; if (isDebugEnabled) { modelCore.UI.WriteLine("{0}: EcoIgnitionNum = {1}, computing ignGenerated ...", fire_region.Name, fire_region.EcoIgnitionNum); } if (fire_region.EcoIgnitionNum < 1) { // Adjust ignition probability for multiple years // (The inverse of the probability of NOT having any ignition for the time period.) // P = 1 - (1-Pignition)^timestep //doubleLambda = 1 - System.Math.Pow(1.0 - fire_region.EcoIgnitionNum, Timestep); for (int i = 1; i <= Timestep; i++) { int annualFires = 0; if (modelCore.GenerateUniform() <= fire_region.EcoIgnitionNum) { annualFires = 1; } ignGenerated += annualFires; } } else { doubleLambda = fire_region.EcoIgnitionNum; bool boolLarge = false; // 745 is the upper limit for valid Poisson lambdas. If greater than // 745, divide by 10 and readjust back up below. if (doubleLambda > 745) { doubleLambda = doubleLambda / 10; boolLarge = true; } PlugIn.ModelCore.PoissonDistribution.Lambda = doubleLambda; //randVar.Lambda = doubleLambda; for (int i = 1; i <= Timestep; i++) { int annualFires = PlugIn.ModelCore.PoissonDistribution.Next(); if (boolLarge) { annualFires = annualFires * 10; //readjust if necessary. } ignGenerated += annualFires; } } if (isDebugEnabled) { modelCore.UI.WriteLine(" Ignitions generated = {0}; Shuffling {0} cells ...", ignGenerated, fire_region.FireRegionSites.Count); } List <Location> cellsPerFireRegion = new List <Location>(0); foreach (Location location in fire_region.FireRegionSites) { cellsPerFireRegion.Add(location); } cellsPerFireRegion = Shuffle(cellsPerFireRegion); int fireCount = 0; //Try to create poissonNumber of fires in each fire_region. //Fires should only initiate if a fire event has not previously occurred //at that site. foreach (Location siteLocation in cellsPerFireRegion) { Site site = modelCore.Landscape.GetSite(siteLocation); ActiveSite asite = (ActiveSite)site; if (fireCount >= ignGenerated) { continue; //exit loop if the required number of fires has occurred. } if (SiteVars.Event[asite] == null) { fireCount++; if (isDebugEnabled) { modelCore.UI.WriteLine(" fireCount = {0}", fireCount); } Event FireEvent = Event.Initiate(asite, Timestep, fireSizeType, bui, seasonParameters, severityCalibrate); if (isDebugEnabled) { modelCore.UI.WriteLine(" fire event {0} started at {1}", FireEvent == null ? "not ": "", asite.Location); } if (FireEvent != null) { LogEvent(modelCore.CurrentTime, FireEvent); summaryEventCount++; //fireCount++; //RMS test } } } } } // Track the time of last fire; registered in SiteVars.cs for other extensions to access. if (isDebugEnabled) { modelCore.UI.WriteLine("Assigning TimeOfLastFire site var ..."); } foreach (Site site in modelCore.Landscape.AllSites) { if (SiteVars.Disturbed[site]) { SiteVars.TimeOfLastFire[site] = modelCore.CurrentTime; } } // Write Fire severity map string path = MapNames.ReplaceTemplateVars(mapNameTemplate, modelCore.CurrentTime); modelCore.UI.WriteLine(" Writing Fire severity map to {0} ...", path); using (IOutputRaster <BytePixel> outputRaster = modelCore.CreateRaster <BytePixel>(path, modelCore.Landscape.Dimensions)) { BytePixel pixel = outputRaster.BufferPixel; foreach (Site site in modelCore.Landscape.AllSites) { if (site.IsActive) { if (SiteVars.Disturbed[site]) { pixel.MapCode.Value = (byte)(SiteVars.Severity[site] + 2); } else { pixel.MapCode.Value = 1; } } else { // Inactive site pixel.MapCode.Value = 0; } outputRaster.WriteBufferPixel(); } } path = MapNames.ReplaceTemplateVars("./DFFS-output/TimeOfLastFire-{timestep}.img", modelCore.CurrentTime); modelCore.UI.WriteLine(" Writing Travel Time output map to {0} ...", path); using (IOutputRaster <ShortPixel> outputRaster = modelCore.CreateRaster <ShortPixel>(path, modelCore.Landscape.Dimensions)) { ShortPixel pixel = outputRaster.BufferPixel; foreach (Site site in modelCore.Landscape.AllSites) { if (site.IsActive) { pixel.MapCode.Value = (short)(SiteVars.TimeOfLastFire[site]); } else { pixel.MapCode.Value = 0; } outputRaster.WriteBufferPixel(); } } WriteSummaryLog(modelCore.CurrentTime); if (isDebugEnabled) { modelCore.UI.WriteLine("Done running extension"); } }
//--------------------------------------------------------------------- protected override IInputParameters Parse() { InputVar <string> landisData = new InputVar <string>("LandisData"); ReadVar(landisData); if (landisData.Value.Actual != PlugIn.ExtensionName) { throw new InputValueException(landisData.Value.String, "The value is not \"{0}\"", PlugIn.ExtensionName); } InputParameters parameters = new InputParameters(); InputVar <int> timestep = new InputVar <int>("Timestep"); ReadVar(timestep); parameters.Timestep = timestep.Value; //---------------------------------------------------------- // First, read table of additional parameters for ecoregions PlugIn.ModelCore.UI.WriteLine(" Loading FireRegion data..."); //IEditableFireRegionDataset dataset = new EditableFireRegionDataset(); List <IFireRegion> dataset = new List <IFireRegion>(0); Dictionary <string, int> nameLineNumbers = new Dictionary <string, int>(); Dictionary <ushort, int> mapCodeLineNumbers = new Dictionary <ushort, int>(); InputVar <string> name = new InputVar <string>("Fire Region Name"); InputVar <ushort> mapCode = new InputVar <ushort>("Map Code"); InputVar <double> meanSize = new InputVar <double>("Mean Fire Size"); InputVar <double> maxSize = new InputVar <double>("Maximum Fire Size"); InputVar <double> minSize = new InputVar <double>("Minimum Fire Size"); InputVar <double> ignitionProb = new InputVar <double>("Ignition Probability"); InputVar <int> fireSpreadAge = new InputVar <int>("Fire Spread Age"); Dictionary <string, int> lineNumbers = new Dictionary <string, int>(); const string DynamicFireRegionTable = "DynamicFireRegionTable"; const string InitialFireFireRegionsMap = "InitialFireRegionsMap"; int fireRegionIndex = 0; while (!AtEndOfInput && CurrentName != InitialFireFireRegionsMap) { //IEditableFireRegionParameters ecoparameters = new EditableFireRegionParameters(); IFireRegion ecoparameters = new FireRegion(fireRegionIndex); dataset.Add(ecoparameters); StringReader currentLine = new StringReader(CurrentLine); int lineNumber; ReadValue(name, currentLine); if (nameLineNumbers.TryGetValue(name.Value.Actual, out lineNumber)) { throw new InputValueException(name.Value.String, "The name \"{0}\" was previously used on line {1}", name.Value.Actual, lineNumber); } else { nameLineNumbers[name.Value.Actual] = LineNumber; } ecoparameters.Name = name.Value; ReadValue(mapCode, currentLine); if (mapCodeLineNumbers.TryGetValue(mapCode.Value.Actual, out lineNumber)) { throw new InputValueException(mapCode.Value.String, "The map code {0} was previously used on line {1}", mapCode.Value.Actual, lineNumber); } else { mapCodeLineNumbers[mapCode.Value.Actual] = LineNumber; } ecoparameters.MapCode = mapCode.Value; ReadValue(meanSize, currentLine); ecoparameters.MeanSize = meanSize.Value; ReadValue(minSize, currentLine); ecoparameters.MinSize = minSize.Value; ReadValue(maxSize, currentLine); ecoparameters.MaxSize = maxSize.Value; ReadValue(ignitionProb, currentLine); ecoparameters.IgnitionProbability = ignitionProb.Value; ReadValue(fireSpreadAge, currentLine); ecoparameters.FireSpreadAge = fireSpreadAge.Value; //UI.WriteLine("Max={0}, Min={1}, Mean={2}, Eco={3}.", ecoparameters.MaxSize, ecoparameters.MinSize, ecoparameters.MeanSize, ecoparameters.Name); fireRegionIndex++; CheckNoDataAfter("the " + fireSpreadAge.Name + " column", currentLine); GetNextLine(); } FireRegions.Dataset = dataset; //---------------------------------------------------------- // Read in the initial fire ecoregions map: InputVar <string> ecoregionsMap = new InputVar <string>("InitialFireRegionsMap"); ReadVar(ecoregionsMap); FireRegions.ReadMap(ecoregionsMap.Value); //---------------------------------------------------------- // Read in the table of dynamic ecoregions: const string FuelCurves = "FuelCurveTable"; if (ReadOptionalName(DynamicFireRegionTable)) { //ReadName(DynamicFireRegionTable); InputVar <string> mapName = new InputVar <string>("Dynamic Map Name"); InputVar <int> year = new InputVar <int>("Year to read in new FireRegion Map"); double previousYear = 0; while (!AtEndOfInput && CurrentName != FuelCurves) { StringReader currentLine = new StringReader(CurrentLine); IDynamicFireRegion dynEco = new DynamicFireRegion(); parameters.DynamicFireRegions.Add(dynEco); ReadValue(year, currentLine); dynEco.Year = year.Value; if (year.Value.Actual <= previousYear) { throw new InputValueException(year.Value.String, "Year must > the year ({0}) of the preceeding ecoregion map", previousYear); } previousYear = year.Value.Actual; ReadValue(mapName, currentLine); dynEco.MapName = mapName.Value; CheckNoDataAfter("the " + mapName.Name + " column", currentLine); GetNextLine(); } } //------------------------------------------------------------- // Second, read table of Fire curve parameters for ecoregions ReadName(FuelCurves); InputVar <string> fireRegionName = new InputVar <string>("Fire Region Name"); InputVar <int> severity1 = new InputVar <int>("Fire Severity1 Age"); InputVar <int> severity2 = new InputVar <int>("Fire Severity2 Age"); InputVar <int> severity3 = new InputVar <int>("Fire Severity3 Age"); InputVar <int> severity4 = new InputVar <int>("Fire Severity4 Age"); InputVar <int> severity5 = new InputVar <int>("Fire Severity5 Age"); lineNumbers.Clear(); const string WindCurves = "WindCurveTable"; while (!AtEndOfInput && CurrentName != WindCurves) { StringReader currentLine = new StringReader(CurrentLine); ReadValue(fireRegionName, currentLine); IFireRegion ecoregion = GetFireRegion(fireRegionName.Value, lineNumbers); IFuelCurve fuelCurve = new FuelCurve(); ReadValue(severity1, currentLine); fuelCurve.Severity1 = severity1.Value; ReadValue(severity2, currentLine); fuelCurve.Severity2 = severity2.Value; ReadValue(severity3, currentLine); fuelCurve.Severity3 = severity3.Value; ReadValue(severity4, currentLine); fuelCurve.Severity4 = severity4.Value; ReadValue(severity5, currentLine); fuelCurve.Severity5 = severity5.Value; ecoregion.FuelCurve = fuelCurve; //.GetComplete(); CheckNoDataAfter("the " + severity1.Name + " column", currentLine); GetNextLine(); } //---------------------------------------------------------- // Third, read table of wind curve parameters for ecoregions ReadName(WindCurves); InputVar <int> wseverity1 = new InputVar <int>("Wind Severity1 Age"); InputVar <int> wseverity2 = new InputVar <int>("Wind Severity2 Age"); InputVar <int> wseverity3 = new InputVar <int>("Wind Severity3 Age"); InputVar <int> wseverity4 = new InputVar <int>("Wind Severity4 Age"); InputVar <int> wseverity5 = new InputVar <int>("Wind Severity5 Age"); lineNumbers.Clear(); const string FireDamage = "FireDamageTable"; while (!AtEndOfInput && CurrentName != FireDamage) { StringReader currentLine = new StringReader(CurrentLine); ReadValue(fireRegionName, currentLine); IFireRegion ecoregion = GetFireRegion(fireRegionName.Value, lineNumbers); IWindCurve windCurve = new WindCurve(); ReadValue(wseverity5, currentLine); windCurve.Severity5 = wseverity5.Value; ReadValue(wseverity4, currentLine); windCurve.Severity4 = wseverity4.Value; ReadValue(wseverity3, currentLine); windCurve.Severity3 = wseverity3.Value; ReadValue(wseverity2, currentLine); windCurve.Severity2 = wseverity2.Value; ReadValue(wseverity1, currentLine); windCurve.Severity1 = wseverity1.Value; ecoregion.WindCurve = windCurve; //.GetComplete(); CheckNoDataAfter("the " + wseverity1.Name + " column", currentLine); GetNextLine(); } //------------------------------------------------------------------- // Read table of Fire Damage classes. // Damages are in increasing order. ReadName(FireDamage); InputVar <Percentage> maxAge = new InputVar <Percentage>("Max Survival Age"); InputVar <int> severTolerDifference = new InputVar <int>("Severity Tolerance Diff"); const string MapNames = "MapNames"; int previousNumber = -4; double previousMaxAge = 0.0; while (!AtEndOfInput && CurrentName != MapNames && previousNumber != 4) { StringReader currentLine = new StringReader(CurrentLine); IDamageTable damage = new DamageTable(); parameters.FireDamages.Add(damage); ReadValue(maxAge, currentLine); damage.MaxAge = maxAge.Value; if (maxAge.Value.Actual <= 0) { // Maximum age for damage must be > 0% throw new InputValueException(maxAge.Value.String, "Must be > 0% for the all damage classes"); } if (maxAge.Value.Actual > 1) { // Maximum age for damage must be <= 100% throw new InputValueException(maxAge.Value.String, "Must be <= 100% for the all damage classes"); } // Maximum age for every damage must be > // maximum age of previous damage. if (maxAge.Value.Actual <= previousMaxAge) { throw new InputValueException(maxAge.Value.String, "MaxAge must > the maximum age ({0}) of the preceeding damage class", previousMaxAge); } previousMaxAge = (double)maxAge.Value.Actual; ReadValue(severTolerDifference, currentLine); damage.SeverTolerDifference = severTolerDifference.Value; //Check that the current damage number is > than //the previous number (numbers are must be in increasing //order). if (severTolerDifference.Value.Actual <= previousNumber) { throw new InputValueException(severTolerDifference.Value.String, "Expected the damage number {0} to be greater than previous {1}", damage.SeverTolerDifference, previousNumber); } if (severTolerDifference.Value.Actual > 4) { throw new InputValueException(severTolerDifference.Value.String, "Expected the damage number {0} to be less than 5", damage.SeverTolerDifference); } previousNumber = severTolerDifference.Value.Actual; CheckNoDataAfter("the " + severTolerDifference.Name + " column", currentLine); GetNextLine(); } if (parameters.FireDamages.Count == 0) { throw NewParseException("No damage classes defined."); } InputVar <string> mapNames = new InputVar <string>(MapNames); ReadVar(mapNames); parameters.MapNamesTemplate = mapNames.Value; InputVar <string> logFile = new InputVar <string>("LogFile"); ReadVar(logFile); parameters.LogFileName = logFile.Value; InputVar <string> summaryLogFile = new InputVar <string>("SummaryLogFile"); ReadVar(summaryLogFile); parameters.SummaryLogFileName = summaryLogFile.Value; CheckNoDataAfter(string.Format("the {0} parameter", summaryLogFile.Name)); return(parameters); //.GetComplete(); }
//--------------------------------------------------------------------- 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; }
//--------------------------------------------------------------------- public override void Initialize() { Timestep = parameters.Timestep; fireSizeType = parameters.FireSizeType; bui = parameters.BUI; mapNameTemplate = parameters.MapNamesTemplate; dynamicWeather = parameters.DynamicWeather; severityCalibrate = parameters.SeverityCalibrate; modelCore.UI.WriteLine(" Initializing Fire Events..."); Event.Initialize(parameters.SeasonParameters, parameters.FuelTypeParameters, parameters.FireDamages); seasonParameters = parameters.SeasonParameters; dynamicEcos = parameters.DynamicFireRegions; summaryFireRegionEventCount = new int[FireRegions.Dataset.Count]; ecoregionSitesCount = new int[FireRegions.Dataset.Count]; //foreach (IFireRegion fire_region in FireRegions.Dataset) //modelCore.UI.WriteLine(" FireSize={0}, SD={1}", fire_region.MeanSize, fire_region.StandardDeviation); // Count the number of sites per fire_region: foreach (Site site in modelCore.Landscape) { if (site.IsActive) { IFireRegion fire_region = SiteVars.FireRegion[site]; ecoregionSitesCount[fire_region.Index]++; } } modelCore.UI.WriteLine(" Opening and Initializing Fire log files \"{0}\" and \"{1}\"...", parameters.LogFileName, parameters.SummaryLogFileName); List <string> colnames = new List <string>(); foreach (IFireRegion fire_region in FireRegions.Dataset) { colnames.Add(fire_region.MapCode.ToString()); } ExtensionMetadata.ColumnNames = colnames; MetadataHandler.InitializeMetadata(mapNameTemplate, parameters.LogFileName, parameters.SummaryLogFileName); summaryLog.Clear(); SummaryLog sl = new SummaryLog(); sl.Time = 0; sl.TotalSitesBurned = 0; sl.NumberFires = 0; sl.EcoMaps_ = new double[FireRegions.Dataset.Count]; int i = 0; foreach (IFireRegion fire_region in FireRegions.Dataset) { sl.EcoMaps_[i] = ecoregionSitesCount[fire_region.Index]; i = i + 1; } summaryLog.AddObject(sl); summaryLog.WriteToFile(); if (isDebugEnabled) { modelCore.UI.WriteLine("Initialization done"); } }
//--------------------------------------------------------------------- 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); }