//--------------------------------------------------------------------- private void CheckNeighbor(Site neighbor, Location expectedLocation) { Assert.IsNotNull(neighbor); Assert.AreEqual(expectedLocation, neighbor.Location); Assert.AreEqual(activeSites[expectedLocation.Row - 1, expectedLocation.Column - 1], neighbor.IsActive); }
//------------------------------------------------------- ///<summary> ///Calculate the distance between two Sites ///</summary> public static double DistanceBetweenSites(Site a, Site b) { int Col = (int) a.Location.Column - (int) b.Location.Column; int Row = (int) a.Location.Row - (int) b.Location.Row; double aSq = System.Math.Pow(Col,2); double bSq = System.Math.Pow(Row,2); //UI.WriteLine("Col={0}, Row={1}.", Col, Row); //UI.WriteLine("aSq={0}, bSq={1}.", aSq, bSq); //UI.WriteLine("Distance in Grid Units = {0}.", System.Math.Sqrt(aSq + bSq)); return (System.Math.Sqrt(aSq + bSq) * (double) Model.Core.CellLength); }
//--------------------------------------------------------------------- TypeIndependent.ISiteCohorts TypeIndependent.ILandscapeCohorts.this[Site site] { get { return cohorts[site]; } }
//--------------------------------------------------------------------- public ISiteCohorts this[Site site] { get { return cohorts[site]; } }
// --------------------------------------------------------------------- // 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]; //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); } //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 (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) { //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; }
//--------------------------------------------------------------------- private List<Site> GetNeighbors(Site site, int windDirection, double windSpeed) { if(windDirection > 7) windDirection = 7; double[] windProbs = { (((4.0 - windSpeed)/8.0) * (1+windSpeed)), //Primary direction (((4.0 - windSpeed)/8.0) * (1+windSpeed)), (((4.0 - windSpeed)/8.0)), (((4.0 - windSpeed)/8.0) * (1-windSpeed)), (((4.0 - windSpeed)/8.0) * (1-windSpeed)), //Opposite of primary direction (((4.0 - windSpeed)/8.0) * (1-windSpeed)), (((4.0 - windSpeed)/8.0)), (((4.0 - windSpeed)/8.0) * (1+windSpeed)), }; double windProb = 0.0; int index = 0; int success = 0; List<Site> neighbors = new List<Site>(9); foreach (RelativeLocation relativeLoc in neighborhood) { Site neighbor = site.GetNeighbor(relativeLoc); if(index + windDirection > 7) windProb = windProbs[index + windDirection - 8]; else windProb = windProbs[index + windDirection]; //System.Console.WriteLine("WindProb={0:0.00}, windSpeed={1:0.00}, neighbor={2}.", windProb, windSpeed, index+1); if (neighbor != null && Random.GenerateUniform() < windProb) { neighbors.Add(neighbor); success++; } index++; } logger.Debug(string.Format("Successfully added {0} neighbors.", success)); //Next, add the 9th neighbor, a neighbor one cell beyond the //8 nearest neighbors. //array index 0 = north; 1 = northeast, 2 = east,...,8 = northwest int[] vertical ={2,2,0,-2,-2,-2,0,2}; int[] horizontal={0,2,2,2,0,-2,-2,-2}; RelativeLocation relativeLoc9 = new RelativeLocation(vertical[windDirection], horizontal[windDirection]); Site neighbor9 = site.GetNeighbor(relativeLoc9); if (neighbor9 != null && Random.GenerateUniform() < windSpeed) neighbors.Add(neighbor9); return neighbors; }
//--------------------------------------------------------------------- /// <summary> /// Determines if a species has at least one mature cohort at a site. /// </summary> public static bool MaturePresent(ISpecies species, Site site) { return cohorts[site].IsMaturePresent(species); }
//--------------------------------------------------------------------- public static void ResetAnnualValues(Site site) { // Reset these accumulators to zero: SiteVars.AGNPP[site] = 0.0; }
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; }
private static List<Site> Get8Neighbors(Site site) { List<Site> neighbors = new List<Site>(); RelativeLocation[] neighborhood = new RelativeLocation[] { new RelativeLocation(-1, 0), // north new RelativeLocation(-1, 1), // northeast new RelativeLocation( 0, 1), // east new RelativeLocation( 1, 1), // southeast new RelativeLocation( 1, 0), // south new RelativeLocation( 1, -1), // southwest new RelativeLocation( 0, -1), // west new RelativeLocation(-1, -1), // northwest }; foreach (RelativeLocation relativeLoc in neighborhood) { Site neighbor = site.GetNeighbor(relativeLoc); if(neighbor != null && neighbor.IsActive) neighbors.Add(neighbor); } Landis.Util.Random.Shuffle(neighbors); return neighbors; }
//------------------------------------------------------- //Calculate the distance (in units of cells) from a location to a center //point (row and column = 0). private static double CellDistanceBetweenSites(Site asite, Site bsite) { double row = ((double) asite.Location.Row - (double) bsite.Location.Row); double column = ((double) asite.Location.Column - (double) bsite.Location.Column); double cSq = column * column; double rSq = row * row; return Math.Sqrt(cSq + rSq); }
private static bool ElipseDistanceBetweenSites(Site igSite, Site burnSite, double C, double D, double fireDirection) { bool lessThan = false; //In the landscape, 'higher' rows have lower numbers, the inverse of what you //would expect if the ignition site is located at (0,0). double dYburn = ((double) igSite.Location.Row - (double) burnSite.Location.Row); double dXburn = ((double) burnSite.Location.Column - (double) igSite.Location.Column); C = C / Model.Core.CellLength; D = D / Model.Core.CellLength; //Assume that ignition site (F0) is at location 0,0. double LengthA = Math.Sqrt((dXburn*dXburn) + (dYburn*dYburn)); //Where is second focal site? double dYf1 = C * 2 * Math.Sin((90 + fireDirection) * Math.PI / 180); double dXf1 = C * 2 * Math.Cos((90 + fireDirection) * Math.PI / 180); double dXburn_f1 = dXburn - dXf1; double dYburn_f1 = dYburn - dYf1; double LengthB = Math.Sqrt((dXburn_f1 * dXburn_f1) + (dYburn_f1 * dYburn_f1)); if(LengthA + LengthB <= ((C + D) * 2.0) ) lessThan = true; //UI.WriteLine("LengthA={0:0.0}, LengthB={1:0.0}, C={2:0.0}, D={3:0.0}.", LengthA, LengthB, C,D); //UI.WriteLine("dXf1={0:0.0}, dYf1={1:0.0}, dXburn={2:0.0}, dYburn={3:0.0}.", dXf1, dYf1,dXburn,dYburn); //return true; return lessThan; }
//------------------------------------------------------- private static double Beta(Site sourcesite, Site site, double windDirection) { double row = (double) sourcesite.Location.Row - (double) site.Location.Row; double column = (double) sourcesite.Location.Column - (double) site.Location.Column; double atan = 0.0; if (row == 0) { if (column == 0) { return atan; } row = 0.0000001; } atan = Math.Atan(column / row) * 180 / Math.PI;// Convert to degrees if(Math.Sign(row) == -1) atan -= 180; double beta = atan - windDirection; //Randomize around 8 neighbor directions double wiggle = (Util.Random.GenerateUniform() * 45.0) - 22.5; beta = beta + wiggle; // beta = beta * Math.PI / 180; //Convert to radians return beta; //atan = atan * Math.PI / 180; //Back to radians //UI.WriteLine("Column = {0}, Row = {1}, Atan = {2}.", column, row, atan); //return atan - (windDirection * Math.PI / 180); }
private static double CalculateTravelTime(Site site, Site firesource, Event fireEvent) { //Calculate Fire regime size adjustment: IEcoregion ecoregion = SiteVars.Ecoregion[site]; IMoreEcoregionParameters eventParms = ecoregion.MoreEcoregionParameters; double FRUA = eventParms.MeanSize; ecoregion = SiteVars.Ecoregion[firesource]; eventParms = ecoregion.MoreEcoregionParameters; FRUA = FRUA / eventParms.MeanSize; int fuelIndex = SiteVars.CFSFuelType[site]; int percentConifer = SiteVars.PercentConifer[site]; int percentHardwood = SiteVars.PercentHardwood[site]; int percentDeadFir = SiteVars.PercentDeadFir[site]; List<int> siteWindList = new List<int>(); int siteWindSpeed, siteWindDirection; FuelTypeCode temp = (FuelTypeCode) fuelIndex; //UI.WriteLine(" Fuel Type Code = {0}.", temp.ToString()); IFuelTypeParameters[] fuelTypeParms = fireEvent.FuelTypeParms; ISeasonParameters season = fireEvent.FireSeason; double f_F = Weather.CalculateFuelMoistureEffect(fireEvent.FFMC); double ISZ = 0.208 * f_F; //No wind double RSZ = FuelEffects.InitialRateOfSpread(fuelIndex, ISZ, percentConifer, percentHardwood, percentDeadFir, season); siteWindList = CalculateSlopeEffect(fireEvent.WindSpeed, fireEvent.WindDirection, site, RSZ, f_F, season); if (siteWindList.Count > 0) { siteWindSpeed = siteWindList[0]; siteWindDirection = siteWindList[1]; } else { siteWindSpeed = fireEvent.WindSpeed; siteWindDirection = fireEvent.WindDirection; } double f_backW = Weather.CalculateBackWindEffect(siteWindSpeed); double f_W = Weather.CalculateWindEffect(siteWindSpeed); double ISI = 0.208 * f_F * f_W; double BISI = 0.208 * f_F * f_backW; double BROSi = FuelEffects.InitialRateOfSpread(fuelIndex, BISI, percentConifer, percentHardwood, percentDeadFir, season); double ROSi = FuelEffects.InitialRateOfSpread(fuelIndex, ISI, percentConifer, percentHardwood, percentDeadFir, season ); BROSi *= FRUA; ROSi *= FRUA; SiteVars.RateOfSpread[site] = ROSi; double LB = CalculateLengthBreadthRatio(siteWindSpeed, fuelIndex); double FROSi = (ROSi + BROSi)/(LB * 2.0);// (FBP; 89) double alpha = siteWindDirection; double A = FROSi; double beta = Beta(firesource, site, alpha); //Randomize around 8 neighbor directions //int wiggle = (int)((Util.Random.GenerateUniform() * 45.0) - 22.5); //beta = beta + wiggle; double B = A * LB; //fireEvent.LB; double C = B - BROSi; // Equations below for e, p, b, c, a utlize the polar equation // for an ellipse, given at: // http://www.du.edu/~jcalvert/math/ellipse.htm double e = C / B; double dist = CellDistanceBetweenSites(site, firesource) * Model.Core.CellLength; double r = ROSi; if (dist != 0) { double p = dist * (1 + e * Math.Cos(Math.PI - beta)); double b = p / (1 - e * e); double c = e * b; r = (dist / (b + c)) * ROSi; //double a = (1 / LB) * b; //Equations below for theta, r come from Finney 2002, eq [3], [5] //double cosSqBeta = CosSquared(beta); //double sinSqBeta = SinSquared(beta); //double termA = a * Math.Cos(beta) * Math.Pow(((a*a * cosSqBeta) + ((b*b)-(c*c)) * sinSqBeta),0.5); //double termB = b * c * sinSqBeta; //double termC = ((a*a) * cosSqBeta) + ((b*b) * sinSqBeta); //double theta = Math.Acos((termA - termB) / termC); //r = (a * ((c * Math.Cos(theta)) + b)) / // Math.Sqrt((a * a * CosSquared(theta)) + (b * b * SinSquared(theta))); } //-----Added by BRM----- SiteVars.AdjROS[site] = r; //---------- //UI.WriteLine(" FROSi = {0}, BROSi = {1}.", FROSi, BROSi); //UI.WriteLine(" beta = {0:0.00}, theta = {1:0.00}, alpha = {2:0.00}, Travel time = {3:0.000000}.", beta, theta, alpha, 1/r); //UI.WriteLine(" Travel time = {0:0.000000}. R = {1}.", 1/r, r); if (site == firesource) { double rate = 1.0 / r; //units = minutes / meter double cost = rate * Model.Core.CellLength / 2; //units = minutes return cost; } else { double rate = 1.0 / r; //units = minutes / meter double cost = rate * Model.Core.CellLength; //units = minutes return cost; } }
//------------------------------------------------------- private static Site CalculateMinNeighbor(Site site, Event fireEvent) { List<Site> neighborhood = Get8Neighbors(site); Site lowestNeighbor = null; double minNeighborTravelTime = SiteVars.MinNeighborTravelTime[site]; foreach (Site relneighbor in neighborhood) { if( //relneighbor != null && SiteVars.Event[relneighbor] == fireEvent && !Double.IsPositiveInfinity(SiteVars.TravelTime[relneighbor]) && SiteVars.TravelTime[relneighbor] < minNeighborTravelTime) { lowestNeighbor = relneighbor; SiteVars.MinNeighborTravelTime[site] = SiteVars.TravelTime[relneighbor]; //UI.WriteLine("Location = {0},{1}. MinTravelTime = {2}.", lowestNeighbor.Row, lowestNeighbor.Column, SiteVars.TravelTime[relneighbor]); } } return lowestNeighbor; }
public WeightedSites (Site site, double weight) { this.site = site; this.weight = weight; }
//--------------------------------------------------------------------- private int CalcFuelType(Site site, IEnumerable<IFuelType> FuelTypes, IEnumerable<ISlashType> SlashTypes) { double[] forTypValue = new double[100]; //Maximum of 50 fuel types double sumConifer = 0.0; double sumDecid = 0.0; //double totalSppValue = 0.0; //UI.WriteLine(" Calculating species values..."); Species.IDataset SpeciesDataset = Model.Core.Species; foreach(ISpecies species in SpeciesDataset) { /* ushort maxSpeciesAge = 0; double sppValue = 0.0; maxSpeciesAge = AgeCohort.Util.GetMaxAge(cohorts[site][species]); if(maxSpeciesAge > 0) { sppValue = (double) maxSpeciesAge / (double) species.Longevity * fuelCoefs[species.Index]; //if(coniferIndex[species.Index]) // sumConifer += sppValue; //if(decidIndex[species.Index]) // sumDecid += sppValue; //UI.WriteLine(" accumulating species values..."); foreach(IFuelType ftype in FuelTypes) { if(maxSpeciesAge >= ftype.MinAge && maxSpeciesAge <= ftype.MaxAge && sppValue > 0) { if(ftype[species.Index] != 0) { if(ftype[species.Index] == -1) forTypValue[ftype.FuelIndex] -= sppValue; if(ftype[species.Index] == 1) forTypValue[ftype.FuelIndex] += sppValue; } } } }*/ ISpeciesCohorts speciesCohorts = cohorts[site][species]; if(speciesCohorts == null) continue; foreach(IFuelType ftype in FuelTypes) { if(ftype[species.Index] != 0) { double sppValue = 0.0; foreach(ICohort cohort in speciesCohorts) { double cohortValue =0.0; if(cohort.Age >= ftype.MinAge && cohort.Age <= ftype.MaxAge) { // Adjust max range age to the spp longevity double maxAge = System.Math.Min(ftype.MaxAge, (double) species.Longevity); // The fuel type range must be at least 5 years: double ftypeRange = System.Math.Max(1.0, maxAge - (double) ftype.MinAge); // The cohort age relative to the fuel type range: double relativeCohortAge = System.Math.Max(1.0, (double) cohort.Age - ftype.MinAge); cohortValue = relativeCohortAge / ftypeRange * fuelCoefs[species.Index]; // Add a weight, dependent upon the size of the range. Smaller ranges = smaller // weight because cohorts will more quickly advance to the end of small ranges. //cohortValue *= ftypeRange / 100.0; sppValue += System.Math.Max(sppValue, cohortValue); } } if(ftype[species.Index] == -1) forTypValue[ftype.FuelIndex] -= sppValue; if(ftype[species.Index] == 1) forTypValue[ftype.FuelIndex] += sppValue; } } } //UI.WriteLine(" Determining CFS fuel type..."); int finalFuelType = 0; int decidFuelType = 0; int coniferFuelType = 0; int openFuelType = 0; int slashFuelType = 0; double maxValue = 0.0; double maxDecidValue = 0.0; double maxConiferValue = 0.0; double maxConPlantValue = 0.0; double maxOpenValue = 0.0; double maxSlashValue = 0.0; //Set the PERCENT CONIFER DOMINANCE: int coniferDominance = 0; int hardwoodDominance = 0; //First assign the CONIFER and DECIDUOUS types: foreach(IFuelType ftype in FuelTypes) { if(ftype != null) { if ((ftype.BaseFuel == BaseFuelType.Conifer || ftype.BaseFuel == BaseFuelType.ConiferPlantation) && forTypValue[ftype.FuelIndex] > 0) { sumConifer += forTypValue[ftype.FuelIndex]; //maxOtherValue = forTypValue[ftype.FuelIndex]; //otherFuelType = ftype.FuelIndex; } //This is calculated for the mixed types: if ((ftype.BaseFuel == BaseFuelType.Deciduous) && forTypValue[ftype.FuelIndex] > 0) { sumDecid += forTypValue[ftype.FuelIndex]; //maxDecidValue = forTypValue[ftype.FuelIndex]; //decidFuelType = ftype.FuelIndex; } // CONIFER if(forTypValue[ftype.FuelIndex] > maxConiferValue && ftype.BaseFuel == BaseFuelType.Conifer) { maxConiferValue = forTypValue[ftype.FuelIndex]; if(maxConiferValue > maxConPlantValue) coniferFuelType = ftype.FuelIndex; } // CONIFER PLANTATION if (forTypValue[ftype.FuelIndex] > maxConPlantValue && ftype.BaseFuel == BaseFuelType.ConiferPlantation) { maxConPlantValue = forTypValue[ftype.FuelIndex]; if(maxConPlantValue > maxConiferValue) coniferFuelType = ftype.FuelIndex; } // OPEN if (forTypValue[ftype.FuelIndex] > maxOpenValue && ftype.BaseFuel == BaseFuelType.Open) { maxOpenValue = forTypValue[ftype.FuelIndex]; openFuelType = ftype.FuelIndex; } // SLASH if (forTypValue[ftype.FuelIndex] > maxSlashValue && ftype.BaseFuel == BaseFuelType.Slash) { maxSlashValue = forTypValue[ftype.FuelIndex]; slashFuelType = ftype.FuelIndex; } // DECIDUOUS if(forTypValue[ftype.FuelIndex] > maxDecidValue && ftype.BaseFuel == BaseFuelType.Deciduous) { maxDecidValue = forTypValue[ftype.FuelIndex]; decidFuelType = ftype.FuelIndex; } } } if (maxConiferValue >= maxConPlantValue && maxConiferValue >= maxDecidValue && maxConiferValue >= maxOpenValue && maxConiferValue >= maxSlashValue) { maxValue = maxConiferValue; } else if (maxDecidValue >= maxConiferValue && maxDecidValue >= maxConPlantValue && maxDecidValue >= maxOpenValue && maxDecidValue >= maxSlashValue) { maxValue = maxDecidValue; } else if (maxConPlantValue >= maxConiferValue && maxConPlantValue >= maxDecidValue && maxConPlantValue >= maxOpenValue && maxConPlantValue >= maxSlashValue) { maxValue = maxConPlantValue; finalFuelType = coniferFuelType; decidFuelType = 0; sumConifer = 100; sumDecid = 0; } else if (maxSlashValue >= maxConiferValue && maxSlashValue >= maxConPlantValue && maxSlashValue >= maxDecidValue && maxSlashValue >= maxOpenValue) { maxValue = maxSlashValue; finalFuelType = slashFuelType; decidFuelType = 0; sumConifer = 0; sumDecid = 0; } else if (maxOpenValue >= maxConiferValue && maxOpenValue >= maxConPlantValue && maxOpenValue >= maxDecidValue && maxOpenValue >= maxSlashValue) { maxValue = maxOpenValue; finalFuelType = openFuelType; decidFuelType = 0; sumConifer = 0; sumDecid = 0; } //Set the PERCENT DOMINANCE values: if (sumConifer > 0 || sumDecid > 0) { coniferDominance = (int)((sumConifer / (sumConifer + sumDecid) * 100) + 0.5); hardwoodDominance = (int)((sumDecid / (sumConifer + sumDecid) * 100) + 0.5); if (hardwoodDominance < hardwoodMax) { coniferDominance = 100; hardwoodDominance = 0; finalFuelType = coniferFuelType; decidFuelType = 0; } if (coniferDominance < hardwoodMax) { coniferDominance = 0; hardwoodDominance = 100; finalFuelType = decidFuelType; decidFuelType = 0; } if (hardwoodDominance > hardwoodMax && coniferDominance > hardwoodMax) finalFuelType = coniferFuelType; } //--------------------------------------------------------------------- // Next check the disturbance types. This will override any other existing fuel type. foreach(SlashType slash in SlashTypes) { if (SiteVars.HarvestCohortsKilled != null && SiteVars.HarvestCohortsKilled[site] > 0) { if (SiteVars.TimeOfLastHarvest != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastHarvest[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (SiteVars.HarvestPrescriptionName != null && SiteVars.HarvestPrescriptionName[site].Trim() == pName.Trim()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } //Check for fire severity effects of fuel type if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) { if (SiteVars.TimeOfLastFire != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastFire[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("FireSeverity")) { if((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.FireSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } //Check for wind severity effects of fuel type if (SiteVars.WindSeverity != null && SiteVars.WindSeverity[site] > 0) { if (SiteVars.TimeOfLastWind != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastWind[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("WindSeverity")) { if ((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.WindSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } } /* //If NEITHER conifer nor deciduous, then set those dominances values to zero: foreach(IFuelType ftype in FuelTypes) if (ftype.FuelIndex == finalFuelType && ftype.BaseFuel != BaseFuelType.Conifer && ftype.BaseFuel != BaseFuelType.ConiferPlantation && ftype.BaseFuel != BaseFuelType.Deciduous) { coniferDominance = 0; hardwoodDominance = 0; } */ //if(decidFuelType == 0) hardwoodDominance = 0; //Assign Percent Conifer: SiteVars.PercentConifer[site] = coniferDominance; SiteVars.PercentHardwood[site] = hardwoodDominance; SiteVars.CFSFuelType[site] = finalFuelType; SiteVars.DecidFuelType[site] = decidFuelType; return finalFuelType; }
AgeCohort.ISiteCohorts Cohorts.ILandscapeCohorts<AgeCohort.ISiteCohorts>.this[Site site] { get { return null; } }
//--------------------------------------------------------------------- private int CalcFuelType(Site site, IEnumerable<IFuelType> FuelTypes, IEnumerable<IDisturbanceType> DisturbanceTypes) { double[] forTypValue = new double[100]; //Maximum of 100 fuel types double sumConifer = 0.0; double sumDecid = 0.0; //UI.WriteLine(" Calculating species values..."); Species.IDataset SpeciesDataset = Model.Core.Species; foreach(ISpecies species in SpeciesDataset) { /*ushort maxSpeciesAge = 0; double sppValue = 0.0; maxSpeciesAge = AgeCohort.Util.GetMaxAge(cohorts[site][species]); if(maxSpeciesAge > 0) { sppValue = (double) maxSpeciesAge / (double) species.Longevity * (double) fuelCoefs[species.Index]; //if(coniferIndex[species.Index]) // sumConifer += sppValue; //if(decidIndex[species.Index]) // sumDecid += sppValue; //UI.WriteLine(" accumulating species values..."); foreach(IFuelType ftype in FuelTypes) { if(maxSpeciesAge >= ftype.MinAge && maxSpeciesAge <= ftype.MaxAge && sppValue > 0) { if(ftype[species.Index] != 0) { if(ftype[species.Index] == -1) forTypValue[ftype.FuelIndex] -= sppValue; if(ftype[species.Index] == 1) forTypValue[ftype.FuelIndex] += sppValue; } } } } */ // This is the new algorithm, based on where a cohort is within it's age range. // This algorithm is less biased towards older cohorts. ISpeciesCohorts speciesCohorts = cohorts[site][species]; if(speciesCohorts == null) continue; foreach(IFuelType ftype in FuelTypes) { if(ftype[species.Index] != 0) { double sppValue = 0.0; foreach(ICohort cohort in speciesCohorts) { double cohortValue =0.0; if(cohort.Age >= ftype.MinAge && cohort.Age <= ftype.MaxAge) { // Adjust max range age to the spp longevity double maxAge = System.Math.Min(ftype.MaxAge, (double) species.Longevity); // The fuel type range must be at least 5 years: double ftypeRange = System.Math.Max(1.0, maxAge - (double) ftype.MinAge); // The cohort age relative to the fuel type range: double relativeCohortAge = System.Math.Max(1.0, (double) cohort.Age - ftype.MinAge); cohortValue = relativeCohortAge / ftypeRange * fuelCoefs[species.Index]; // Use the one cohort with the largest value: //sppValue += System.Math.Max(sppValue, cohortValue); // A BUG, should be... sppValue = System.Math.Max(sppValue, cohortValue); } } if(ftype[species.Index] == -1) forTypValue[ftype.FuelIndex] -= sppValue; if(ftype[species.Index] == 1) forTypValue[ftype.FuelIndex] += sppValue; } } } int finalFuelType = 0; int decidFuelType = 0; //int coniferFuelType = 0; //int openFuelType = 0; //int slashFuelType = 0; double maxValue = 0.0; double maxDecidValue = 0.0; //double maxConiferValue = 0.0; //double maxConPlantValue = 0.0; //double maxOpenValue = 0.0; //double maxSlashValue = 0.0; //Set the PERCENT CONIFER DOMINANCE: int coniferDominance = 0; int hardwoodDominance = 0; //First accumulate data for the BASE fuel types: foreach(IFuelType ftype in FuelTypes) { if(ftype != null) { if ((ftype.BaseFuel == BaseFuelType.Conifer || ftype.BaseFuel == BaseFuelType.ConiferPlantation) && forTypValue[ftype.FuelIndex] > 0) { sumConifer += forTypValue[ftype.FuelIndex]; } //This is calculated for the mixed types: if ((ftype.BaseFuel == BaseFuelType.Deciduous) && forTypValue[ftype.FuelIndex] > 0) { sumDecid += forTypValue[ftype.FuelIndex]; } if(forTypValue[ftype.FuelIndex] > maxValue) { maxValue = forTypValue[ftype.FuelIndex]; finalFuelType = ftype.FuelIndex; } if(ftype.BaseFuel == BaseFuelType.Deciduous && forTypValue[ftype.FuelIndex] > maxDecidValue) { maxDecidValue = forTypValue[ftype.FuelIndex]; decidFuelType = ftype.FuelIndex; } } } // Next, use rules to modify the conifer and deciduous dominance: foreach(IFuelType ftype in FuelTypes) { if(ftype != null) { if(ftype.FuelIndex == finalFuelType && ftype.BaseFuel == BaseFuelType.ConiferPlantation) { decidFuelType = 0; sumConifer = 100; sumDecid = 0; } // a SLASH type else if(ftype.FuelIndex == finalFuelType && ftype.BaseFuel == BaseFuelType.Slash) { //maxValue = maxSlashValue; //finalFuelType = slashFuelType; //decidFuelType = 0; sumConifer = 0; sumDecid = 0; } // an OPEN type else if(ftype.FuelIndex == finalFuelType && ftype.BaseFuel == BaseFuelType.Open) { //maxValue = maxOpenValue; //finalFuelType = openFuelType; //decidFuelType = 0; sumConifer = 0; sumDecid = 0; } } } //Set the PERCENT DOMINANCE values: if (sumConifer > 0 || sumDecid > 0) { coniferDominance = (int)((sumConifer / (sumConifer + sumDecid) * 100) + 0.5); hardwoodDominance = (int)((sumDecid / (sumConifer + sumDecid) * 100) + 0.5); if (hardwoodDominance < hardwoodMax) { coniferDominance = 100; hardwoodDominance = 0; } if (coniferDominance < hardwoodMax) { coniferDominance = 0; hardwoodDominance = 100; finalFuelType = decidFuelType; } } //--------------------------------------------------------------------- // Next check the disturbance types. This will override any other existing fuel type. foreach(DisturbanceType slash in DisturbanceTypes) { if (SiteVars.HarvestCohortsKilled != null && SiteVars.HarvestCohortsKilled[site] > 0) { if (SiteVars.TimeOfLastHarvest != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastHarvest[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (SiteVars.HarvestPrescriptionName != null && SiteVars.HarvestPrescriptionName[site].Trim() == pName.Trim()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } //Check for fire severity effects of fuel type if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) { if (SiteVars.TimeOfLastFire != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastFire[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("FireSeverity")) { if((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.FireSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } //Check for wind severity effects of fuel type if (SiteVars.WindSeverity != null && SiteVars.WindSeverity[site] > 0) { if (SiteVars.TimeOfLastWind != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastWind[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("WindSeverity")) { if ((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.WindSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } } //Assign Percent Conifer: SiteVars.PercentConifer[site] = coniferDominance; SiteVars.PercentHardwood[site] = hardwoodDominance; SiteVars.FuelType[site] = finalFuelType; SiteVars.DecidFuelType[site] = decidFuelType; return finalFuelType; }
//--------------------------------------------------------------------- private List<Site> GetNeighbors(Site site) { List<Site> neighbors = new List<Site>(4); foreach (RelativeLocation relativeLoc in neighborhood) { Site neighbor = site.GetNeighbor(relativeLoc); if (neighbor != null) neighbors.Add(neighbor); } return neighbors; }
//--------------------------------------------------------------------- // This method replaces the delegate method. It is called every year when // ACT_ANPP is calculated, for each cohort. Therefore, this method is operating at // an ANNUAL time step and separate from the normal extension time step. public static double DefoliateCohort(Biomass.ICohort cohort, Site site, int siteBiomass) { //UI.WriteLine(" Calculating insect defoliation..."); int sppIndex = cohort.Species.Index; double totalDefoliation = 0.0; foreach(IInsect insect in manyInsect) { if(!insect.ActiveOutbreak) continue; double defoliation = 0.0; double weightedDefoliation = 0.0; int suscIndex = insect.SppTable[sppIndex].Susceptibility - 1; if (suscIndex < 0) suscIndex = 0; // Get the Neighborhood GrowthReduction Density double meanNeighborhoodDefoliation = 0.0; int neighborCnt = 0; // If it is the first year, the neighborhood growth reduction // will have been initialized in Outbreak.InitializeDefoliationPatches if(insect.NeighborhoodDefoliation[site] > 0) { //UI.WriteLine(" First Year of Defoliation: Using initial patch defo={0:0.00}.", SiteVars.NeighborhoodDefoliation[site]); meanNeighborhoodDefoliation = insect.NeighborhoodDefoliation[site]; } // If not the first year, calculate mean neighborhood defoliation based on the // previous year. else { double sumNeighborhoodDefoliation = 0.0; //UI.WriteLine("Look at the Neighbors... "); foreach (RelativeLocation relativeLoc in insect.Neighbors) { Site neighbor = site.GetNeighbor(relativeLoc); if (neighbor != null && neighbor.IsActive) { neighborCnt++; // The previous year... //if(SiteVars.DefoliationByYear[neighbor].ContainsKey(Model.Core.CurrentTime - 1)) // sumNeighborhoodDefoliation += SiteVars.DefoliationByYear[neighbor][Model.Core.CurrentTime - 1]; sumNeighborhoodDefoliation += insect.LastYearDefoliation[neighbor]; } } if(neighborCnt > 0.0) meanNeighborhoodDefoliation = sumNeighborhoodDefoliation / (double) neighborCnt; } //endif if(meanNeighborhoodDefoliation > 1.0 || meanNeighborhoodDefoliation < 0) { UI.WriteLine("MeanNeighborhoodDefoliation={0}; NeighborCnt={1}.", meanNeighborhoodDefoliation, neighborCnt); throw new ApplicationException("Error: Mean Neighborhood GrowthReduction is not between 1.0 and 0.0"); } // First assume that there are no neighbors whatsoever: DistributionType dist = insect.SusceptibleTable[suscIndex].Distribution_0.Name; double value1 = insect.SusceptibleTable[suscIndex].Distribution_0.Value1; double value2 = insect.SusceptibleTable[suscIndex].Distribution_0.Value2; if(meanNeighborhoodDefoliation <= 1.0 && meanNeighborhoodDefoliation >= 0.8) { dist = insect.SusceptibleTable[suscIndex].Distribution_80.Name; value1 = insect.SusceptibleTable[suscIndex].Distribution_80.Value1; value2 = insect.SusceptibleTable[suscIndex].Distribution_80.Value2; } else if(meanNeighborhoodDefoliation < 0.8 && meanNeighborhoodDefoliation >= 0.6) { dist = insect.SusceptibleTable[suscIndex].Distribution_60.Name; value1 = insect.SusceptibleTable[suscIndex].Distribution_60.Value1; value2 = insect.SusceptibleTable[suscIndex].Distribution_60.Value2; } else if(meanNeighborhoodDefoliation < 0.6 && meanNeighborhoodDefoliation >= 0.4) { dist = insect.SusceptibleTable[suscIndex].Distribution_40.Name; value1 = insect.SusceptibleTable[suscIndex].Distribution_40.Value1; value2 = insect.SusceptibleTable[suscIndex].Distribution_40.Value2; } else if(meanNeighborhoodDefoliation < 0.4 && meanNeighborhoodDefoliation >= 0.2) { dist = insect.SusceptibleTable[suscIndex].Distribution_20.Name; value1 = insect.SusceptibleTable[suscIndex].Distribution_20.Value1; value2 = insect.SusceptibleTable[suscIndex].Distribution_20.Value2; } else if(meanNeighborhoodDefoliation < 0.2 && meanNeighborhoodDefoliation >= 0.0) { dist = insect.SusceptibleTable[suscIndex].Distribution_0.Name; value1 = insect.SusceptibleTable[suscIndex].Distribution_0.Value1; value2 = insect.SusceptibleTable[suscIndex].Distribution_0.Value2; } // Next, ensure that all cohorts of the same susceptibility class // receive the same level of defoliation. if(insect.HostDefoliationByYear[site].ContainsKey(Model.Core.CurrentTime)) { if(insect.HostDefoliationByYear[site][Model.Core.CurrentTime][suscIndex] <= 0.00000000) { defoliation = Distribution.GenerateRandomNum(dist, value1, value2); insect.HostDefoliationByYear[site][Model.Core.CurrentTime][suscIndex] = defoliation; } else defoliation = insect.HostDefoliationByYear[site][Model.Core.CurrentTime][suscIndex]; } else { insect.HostDefoliationByYear[site].Add(Model.Core.CurrentTime, new Double[3]{0.0, 0.0, 0.0}); defoliation = Distribution.GenerateRandomNum(dist, value1, value2); insect.HostDefoliationByYear[site][Model.Core.CurrentTime][suscIndex] = defoliation; } // Alternatively, allow defoliation to vary even among cohorts and species with // the same susceptibility. //defoliation = Distribution.GenerateRandomNum(dist, value1, value2); if(defoliation > 1.0 || defoliation < 0) { UI.WriteLine("DEFOLIATION TOO BIG or SMALL: {0}, {1}, {2}, {3}.", dist, value1, value2, defoliation); throw new ApplicationException("Error: New defoliation is not between 1.0 and 0.0"); } //UI.WriteLine("Cohort age={0}, species={1}, suscIndex={2}, defoliation={3}.", cohort.Age, cohort.Species.Name, (suscIndex -1), defoliation); // For first insect in a given year, actual defoliation equals the potential defoliation drawn from insect distributions. if (totalDefoliation == 0.0) { weightedDefoliation = (defoliation * ((double)cohort.Biomass / (double)siteBiomass)); //UI.WriteLine("Cohort age={0}, species={1}, suscIndex={2}, cohortDefoliation={3}.", cohort.Age, cohort.Species.Name, (suscIndex+1), cohortDefoliation); } // For second insect in a given year, actual defoliation can only be as high as the amount of canopy foliage left by first insect. // This change makes sure next year's neighborhoodDefoliation will reflect actual defoliation, rather than "potential" defoliation. // It should also ensure that the sum of defoliation maps for all insects adds up to 1 for a given year. else { weightedDefoliation = (Math.Min((1 - totalDefoliation), defoliation) * ((double)cohort.Biomass / (double)siteBiomass)); } insect.ThisYearDefoliation[site] += weightedDefoliation; if (insect.ThisYearDefoliation[site] > 1.0) // Weighted defoliation cannot exceed 100% of site biomass. insect.ThisYearDefoliation[site] = 1.0; //Put in error statement to see if sum of weighted defoliation is ever over 1. if (insect.ThisYearDefoliation[site] > 1.0 || insect.ThisYearDefoliation[site] < 0) { UI.WriteLine("Site Weighted Defoliation = {0:0.000000}. Site R/C={1}/{2}. Last Weighted Defoliation = {3}.", insect.ThisYearDefoliation[site], site.Location.Row, site.Location.Column, weightedDefoliation); throw new ApplicationException("Error: Site Weighted Defoliation is not between 1.0 and 0.0"); } totalDefoliation += defoliation; // Is totalDefoliation getting used anywhere else? Or an orphan? } if(totalDefoliation > 1.0) // Cannot exceed 100% defoliation, comment out to see if it ever does. totalDefoliation = 1.0; if(totalDefoliation > 1.0 || totalDefoliation < 0) { UI.WriteLine("Cohort Total Defoliation = {0:0.00}. Site R/C={1}/{2}.", totalDefoliation, site.Location.Row, site.Location.Column); throw new ApplicationException("Error: Total Defoliation is not between 1.0 and 0.0"); } return totalDefoliation; }
//--------------------------------------------------------------------- private List<Site> GetNeighbors(Site site, int windDirection) { if(windDirection > 7) windDirection = 7; double[] windProbs = { (((4.0 - this.intensity)/8.0) * (1+this.intensity)), //Primary direction (((4.0 - this.intensity)/8.0) * (1+this.intensity)), (((4.0 - this.intensity)/8.0)), (((4.0 - this.intensity)/8.0) * (1-this.intensity)), (((4.0 - this.intensity)/8.0) * (1-this.intensity)), //Opposite of primary direction (((4.0 - this.intensity)/8.0) * (1-this.intensity)), (((4.0 - this.intensity)/8.0)), (((4.0 - this.intensity)/8.0) * (1+this.intensity)), }; double windProb = 0.0; int index = 0; List<Site> neighbors = new List<Site>(9); foreach (RelativeLocation relativeLoc in neighborhood) { Site neighbor = site.GetNeighbor(relativeLoc); if(index + windDirection > 7) windProb = windProbs[index + windDirection - 8]; else windProb = windProbs[index + windDirection]; if (neighbor != null && Random.GenerateUniform() < windProb) neighbors.Add(neighbor); index++; } //Next, add the 9th neighbor, a neighbor one cell beyond the //8 nearest neighbors. //array index 0 = north; 1 = northeast, 2 = east,...,8 = northwest int[] vertical ={2,2,0,-2,-2,-2,0,2}; int[] horizontal={0,2,2,2,0,-2,-2,-2}; RelativeLocation relativeLoc9 = new RelativeLocation(vertical[windDirection], horizontal[windDirection]); Site neighbor9 = site.GetNeighbor(relativeLoc9); if (neighbor9 != null && Random.GenerateUniform() < this.intensity) neighbors.Add(neighbor9); return neighbors; }
//--------------------------------------------------------------------- private byte CalcForestType(IForestType[] forestTypes, Site site) { int forTypeCnt = 0; double[] forTypValue = new double[forestTypes.Length]; Species.IDataset SpeciesDataset = modelCore.Species; foreach(ISpecies species in SpeciesDataset) { double sppValue = 0.0; //Biomass.ICohort cohort = cohorts[site][species]; //sppValue = cohort.Biomass;//Util.ComputeBiomass(cohorts[site][species]); sppValue = Util.ComputeBiomass(cohorts[site][species]); forTypeCnt = 0; foreach(IForestType ftype in forestTypes) { if(ftype[species.Index] != 0) { if(ftype[species.Index] == -1) forTypValue[forTypeCnt] -= sppValue; if(ftype[species.Index] == 1) forTypValue[forTypeCnt] += sppValue; } forTypeCnt++; } } int finalForestType = 0; double maxValue = 0.0; forTypeCnt = 0; foreach(IForestType ftype in forestTypes) { //System.Console.WriteLine("ForestTypeNum={0}, Value={1}.",forTypeCnt,forTypValue[forTypeCnt]); if(forTypValue[forTypeCnt]>maxValue) { maxValue = forTypValue[forTypeCnt]; finalForestType = forTypeCnt+1; } forTypeCnt++; } return (byte) finalForestType; }
//--------------------------------------------------------------------- // This method replaces the delegate method. It is called every year when // ACT_ANPP is calculated, for each cohort. Therefore, this method is operating at // an ANNUAL time step and separate from the normal extension time step. public static double ReduceCohortGrowth(Biomass.ICohort cohort, Site site, int siteBiomass) { //UI.WriteLine(" Calculating cohort growth reduction due to insect defoliation..."); double summaryGrowthReduction = 0.0; int sppIndex = cohort.Species.Index; foreach(IInsect insect in PlugIn.ManyInsect) { if(!insect.ActiveOutbreak) continue; int suscIndex = insect.SppTable[sppIndex].Susceptibility - 1; //if (suscIndex < 0) suscIndex = 0; int yearBack = 0; double annualDefoliation = 0.0; if(insect.HostDefoliationByYear[site].ContainsKey(Model.Core.CurrentTime - yearBack)) { //UI.WriteLine("Host Defoliation By Year: Time={0}, suscIndex={1}, spp={2}.", (Model.Core.CurrentTime - yearBack), suscIndex+1, cohort.Species.Name); annualDefoliation += insect.HostDefoliationByYear[site][Model.Core.CurrentTime - yearBack][suscIndex]; } double cumulativeDefoliation = annualDefoliation; while(annualDefoliation > 0) { yearBack++; annualDefoliation = 0.0; if(insect.HostDefoliationByYear[site].ContainsKey(Model.Core.CurrentTime - yearBack)) { //UI.WriteLine("Host Defoliation By Year: Time={0}, suscIndex={1}, spp={2}.", (Model.Core.CurrentTime - yearBack), suscIndex+1, cohort.Species.Name); annualDefoliation = insect.HostDefoliationByYear[site][Model.Core.CurrentTime - yearBack][suscIndex]; cumulativeDefoliation += annualDefoliation; } } double slope = insect.SppTable[sppIndex].GrowthReduceSlope; double intercept = insect.SppTable[sppIndex].GrowthReduceIntercept; double growthReduction = 1.0 - (cumulativeDefoliation * slope + intercept); double weightedGD = (growthReduction * ((double) cohort.Biomass / (double) siteBiomass)); //Below looks like it should be multiplied by weightedGD above, but it isn't?? CHECK! summaryGrowthReduction += growthReduction; //UI.WriteLine("Time={0}, Spp={1}, SummaryGrowthReduction={2:0.00}.", Model.Core.CurrentTime,cohort.Species.Name, summaryGrowthReduction); } if (summaryGrowthReduction > 1.0) // Cannot exceed 100% summaryGrowthReduction = 1.0; if(summaryGrowthReduction > 1.0 || summaryGrowthReduction < 0) { UI.WriteLine("Cohort Total Growth Reduction = {0:0.00}. Site R/C={1}/{2}.", summaryGrowthReduction, site.Location.Row, site.Location.Column); throw new ApplicationException("Error: Total Growth Reduction is not between 1.0 and 0.0"); } return summaryGrowthReduction; }
//--------------------------------------------------------------------- private int CalcFuelType(Site site, IEnumerable<IFuelType> FuelTypes, IEnumerable<IDisturbanceType> DisturbanceTypes) { double[] forTypValue = new double[100]; //Maximum of 100 fuel types double sumConifer = 0.0; double sumDecid = 0.0; IEcoregion ecoregion = Model.Core.Ecoregion[(ActiveSite) site]; foreach(ISpecies species in Model.Core.Species) { ISpeciesCohorts speciesCohorts = cohorts[site][species]; if(speciesCohorts == null) continue; foreach(IFuelType ftype in FuelTypes) { if(ftype.Ecoregions[ecoregion.Index]) { if(ftype[species.Index] != 0) { int sppValue = 0; foreach(ICohort cohort in speciesCohorts) if(cohort.Age >= ftype.MinAge && cohort.Age <= ftype.MaxAge) sppValue += cohort.Biomass; //UI.WriteLine("sppVaue={0}, spp={1}, cohortB={2}.", sppValue, cohort.Species.Name, cohort.Biomass); if(ftype[species.Index] == -1) forTypValue[ftype.Index] -= sppValue; if(ftype[species.Index] == 1) forTypValue[ftype.Index] += sppValue; } } } } int finalFuelType = 0; int decidFuelType = 0; int coniferFuelType = 0; int openFuelType = 0; int slashFuelType = 0; double maxValue = 0.0; double maxDecidValue = 0.0; double maxConiferValue = 0.0; double maxConPlantValue = 0.0; double maxOpenValue = 0.0; double maxSlashValue = 0.0; //Set the PERCENT CONIFER DOMINANCE: int coniferDominance = 0; int hardwoodDominance = 0; //First accumulate data for the various Base Fuel Types: foreach(IFuelType ftype in FuelTypes) { if(ftype != null) { //UI.WriteLine(" FuelType: Index={0}.", ftype.Index); // Sum for the Conifer and Deciduous dominance if ((ftype.BaseFuel == BaseFuelType.Conifer || ftype.BaseFuel == BaseFuelType.ConiferPlantation) && forTypValue[ftype.Index] > 0) { sumConifer += forTypValue[ftype.Index]; } //This is calculated for the mixed types: if ((ftype.BaseFuel == BaseFuelType.Deciduous) && forTypValue[ftype.Index] > 0) { sumDecid += forTypValue[ftype.Index]; } // CONIFER if(forTypValue[ftype.Index] > maxConiferValue && ftype.BaseFuel == BaseFuelType.Conifer) { maxConiferValue = forTypValue[ftype.Index]; if(maxConiferValue > maxConPlantValue) coniferFuelType = ftype.Index; } // CONIFER PLANTATION if (forTypValue[ftype.Index] > maxConPlantValue && ftype.BaseFuel == BaseFuelType.ConiferPlantation) { maxConPlantValue = forTypValue[ftype.Index]; if(maxConPlantValue > maxConiferValue) coniferFuelType = ftype.Index; } // OPEN if (forTypValue[ftype.Index] > maxOpenValue && ftype.BaseFuel == BaseFuelType.Open) { maxOpenValue = forTypValue[ftype.Index]; openFuelType = ftype.Index; } // SLASH if (forTypValue[ftype.Index] > maxSlashValue && ftype.BaseFuel == BaseFuelType.Slash) { maxSlashValue = forTypValue[ftype.Index]; slashFuelType = ftype.Index; } // DECIDUOUS if(forTypValue[ftype.Index] > maxDecidValue && ftype.BaseFuel == BaseFuelType.Deciduous) { maxDecidValue = forTypValue[ftype.Index]; decidFuelType = ftype.Index; } } } // Rules indicating a CONIFER cell if (maxConiferValue >= maxConPlantValue && maxConiferValue >= maxDecidValue && maxConiferValue >= maxOpenValue && maxConiferValue >= maxSlashValue) { maxValue = maxConiferValue; } // Rules indicating a DECIDUOUS cell else if (maxDecidValue >= maxConiferValue && maxDecidValue >= maxConPlantValue && maxDecidValue >= maxOpenValue && maxDecidValue >= maxSlashValue) { maxValue = maxDecidValue; } // Rules indicating a CONIFER PLANTATION cell else if (maxConPlantValue >= maxConiferValue && maxConPlantValue >= maxDecidValue && maxConPlantValue >= maxOpenValue && maxConPlantValue >= maxSlashValue) { maxValue = maxConPlantValue; finalFuelType = coniferFuelType; decidFuelType = 0; sumConifer = 100; sumDecid = 0; } // Rules indicating a SLASH cell else if (maxSlashValue >= maxConiferValue && maxSlashValue >= maxConPlantValue && maxSlashValue >= maxDecidValue && maxSlashValue >= maxOpenValue) { maxValue = maxSlashValue; finalFuelType = slashFuelType; decidFuelType = 0; sumConifer = 0; sumDecid = 0; } // Rules indicating an OPEN (typically grass) cell else if (maxOpenValue >= maxConiferValue && maxOpenValue >= maxConPlantValue && maxOpenValue >= maxDecidValue && maxOpenValue >= maxSlashValue) { maxValue = maxOpenValue; finalFuelType = openFuelType; decidFuelType = 0; sumConifer = 0; sumDecid = 0; } //Set the PERCENT DOMINANCE values: if (sumConifer > 0 || sumDecid > 0) { coniferDominance = (int)((sumConifer / (sumConifer + sumDecid) * 100) + 0.5); hardwoodDominance = (int)((sumDecid / (sumConifer + sumDecid) * 100) + 0.5); if (hardwoodDominance < hardwoodMax) { coniferDominance = 100; hardwoodDominance = 0; finalFuelType = coniferFuelType; decidFuelType = 0; } if (coniferDominance < hardwoodMax) { coniferDominance = 0; hardwoodDominance = 100; finalFuelType = decidFuelType; decidFuelType = 0; } if (hardwoodDominance > hardwoodMax && coniferDominance > hardwoodMax) finalFuelType = coniferFuelType; } //--------------------------------------------------------------------- // Next check the disturbance types. This will override any other existing fuel type. foreach(DisturbanceType slash in DisturbanceTypes) { //if (SiteVars.HarvestCohortsKilled != null && SiteVars.HarvestCohortsKilled[site] > 0) //{ if (SiteVars.TimeOfLastHarvest != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastHarvest[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (SiteVars.HarvestPrescriptionName != null && SiteVars.HarvestPrescriptionName[site].Trim() == pName.Trim()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } //} //Check for fire severity effects of fuel type if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) { if (SiteVars.TimeOfLastFire != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastFire[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("FireSeverity")) { if((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.FireSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } //Check for wind severity effects of fuel type if (SiteVars.WindSeverity != null && SiteVars.WindSeverity[site] > 0) { if (SiteVars.TimeOfLastWind != null && (Model.Core.CurrentTime - SiteVars.TimeOfLastWind[site] <= slash.MaxAge)) { foreach (string pName in slash.PrescriptionNames) { if (pName.StartsWith("WindSeverity")) { if ((pName.Substring((pName.Length - 1), 1)).ToString() == SiteVars.WindSeverity[site].ToString()) { finalFuelType = slash.FuelIndex; //Name; decidFuelType = 0; coniferDominance = 0; hardwoodDominance = 0; } } } } } } SiteVars.PercentConifer[site] = coniferDominance; SiteVars.PercentHardwood[site] = hardwoodDominance; SiteVars.FuelType[site] = finalFuelType; SiteVars.DecidFuelType[site] = decidFuelType; return finalFuelType; }
//--------------------------------------------------------------------- public static void ResetAnnualValues(Site site) { // Reset these accumulators to zero: SiteVars.CohortLeafN[site] = 0.0; SiteVars.CohortLeafC[site] = 0.0; SiteVars.CohortWoodN[site] = 0.0; SiteVars.CohortWoodC[site] = 0.0; SiteVars.GrossMineralization[site] = 0.0; SiteVars.AGNPPcarbon[site] = 0.0; SiteVars.BGNPPcarbon[site] = 0.0; SiteVars.LitterfallC[site] = 0.0; SiteVars.Stream[site] = new Layer(LayerName.Other, LayerType.Other); SiteVars.SourceSink[site] = new Layer(LayerName.Other, LayerType.Other); SiteVars.SurfaceDeadWood[site].NetMineralization = 0.0; SiteVars.SurfaceStructural[site].NetMineralization = 0.0; SiteVars.SurfaceMetabolic[site].NetMineralization = 0.0; SiteVars.SoilDeadWood[site].NetMineralization = 0.0; SiteVars.SoilStructural[site].NetMineralization = 0.0; SiteVars.SoilMetabolic[site].NetMineralization = 0.0; SiteVars.SOM1surface[site].NetMineralization = 0.0; SiteVars.SOM1soil[site].NetMineralization = 0.0; SiteVars.SOM2[site].NetMineralization = 0.0; SiteVars.SOM3[site].NetMineralization = 0.0; SiteVars.AnnualNEE[site] = 0.0; //SiteVars.FireEfflux[site] = 0.0; //SiteVars.AgeMortality[site] = 0.0; }
//--------------------------------------------------------------------- AgeCohort.ISiteCohorts ILandscapeCohorts<AgeCohort.ISiteCohorts>.this[Site site] { get { return cohorts[site]; } }
//--------------------------------------------------------------------- private byte CalcForestType(Site site, IForestType[] forestTypes) { int forTypeCnt = 0; double[] forTypValue = new double[forestTypes.Length]; Species.IDataset SpeciesDataset = modelCore.Species; foreach(ISpecies species in SpeciesDataset) { ushort maxSpeciesAge = 0; double sppValue = 0.0; //ISpeciesCohorts speciesCohorts = cohorts[species]; maxSpeciesAge = AgeCohort.Util.GetMaxAge(cohorts[site][species]); //MaxAge(speciesCohorts); if(maxSpeciesAge > 0) { sppValue = (double) maxSpeciesAge / (double) species.Longevity * (double) reclassCoefs[species.Index]; forTypeCnt = 0; foreach(IForestType ftype in forestTypes) { if(ftype[species.Index] != 0) { if(ftype[species.Index] == -1) forTypValue[forTypeCnt] -= sppValue; if(ftype[species.Index] == 1) forTypValue[forTypeCnt] += sppValue; } forTypeCnt++; } } } int finalForestType = 0; double maxValue = 0.0; forTypeCnt = 0; foreach(IForestType ftype in forestTypes) { //System.Console.WriteLine("ForestTypeNum={0}, Value={1}.",forTypeCnt,forTypValue[forTypeCnt]); if(forTypValue[forTypeCnt]>maxValue) { maxValue = forTypValue[forTypeCnt]; finalForestType = forTypeCnt+1; } forTypeCnt++; } return (byte) finalForestType; }
//--------------------------------------------------------------------- private List<Site> GetNeighbors(Site site, int windDirection) { List<Site> neighbors = new List<Site>(5); foreach (RelativeLocation relativeLoc in neighborhood) { Site neighbor = site.GetNeighbor(relativeLoc); if (neighbor != null) neighbors.Add(neighbor); } int vertical=0; int horizontal=0; if(windDirection==1) { //wind is from south vertical = -2; horizontal = 0; } if(windDirection==2) { //wind is from north vertical = 2; horizontal = 0; } if(windDirection==3) { //wind is from east vertical = 0; horizontal = -2; } if(windDirection==4) { //wind is from west vertical = 0; horizontal = 2; } RelativeLocation relativeLoc5 = new RelativeLocation(vertical, horizontal); Site neighbor5 = site.GetNeighbor(relativeLoc5); if (neighbor5 != null) neighbors.Add(neighbor5); return neighbors; }
//--------------------------------------------------------------------- /// <summary> /// Validates that a site refers to the same landscape as the site /// variable was created for. /// </summary> protected void Validate(Site site) { Trace.Assert(site != null); Trace.Assert(site.Landscape == landscape); }