//--------------------------------------------------------------------- public static int CalculateDomAgeAgeOnly(Site site) { Dictionary<int, int> ageDictionary = new Dictionary<int, int>(); foreach (ISpeciesCohorts sppCohorts in SiteVars.AgeCohorts[site]) { foreach (ICohort cohort in sppCohorts) { int age = cohort.Age; if (ageDictionary.ContainsKey(age)) { ageDictionary[age] = ageDictionary[age] + 1; } else { ageDictionary[age] = 1; } } } int domAge = 0; int maxValue = 0; foreach (var i in ageDictionary) { if (i.Value > maxValue) { domAge = i.Key; maxValue = i.Value; } } return domAge; }
//--------------------------------------------------------------------- /// <summary> /// Computes fire effects on litter, coarse woody debris, mineral soil, and charcoal. /// No effects on soil organic matter (negligible according to Johnson et al. 2001). /// </summary> public static void ReduceLayers(byte severity, Site site) { //PlugIn.ModelCore.UI.WriteLine(" Calculating fire induced layer reductions..."); double litterLossMultiplier = ReductionsTable[severity].LitterReduction; // Structural litter first double carbonLoss = SiteVars.SurfaceStructural[site].Carbon * litterLossMultiplier; double nitrogenLoss = SiteVars.SurfaceStructural[site].Nitrogen * litterLossMultiplier; double summaryNLoss = nitrogenLoss; SiteVars.SurfaceStructural[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceStructural[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; // Metabolic litter carbonLoss = SiteVars.SurfaceMetabolic[site].Carbon * litterLossMultiplier; nitrogenLoss = SiteVars.SurfaceMetabolic[site].Nitrogen * litterLossMultiplier; summaryNLoss += nitrogenLoss; SiteVars.SurfaceMetabolic[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceMetabolic[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; // Surface dead wood double woodLossMultiplier = ReductionsTable[severity].WoodReduction; carbonLoss = SiteVars.SurfaceDeadWood[site].Carbon * woodLossMultiplier; nitrogenLoss = SiteVars.SurfaceDeadWood[site].Nitrogen * woodLossMultiplier; summaryNLoss += nitrogenLoss; SiteVars.SurfaceDeadWood[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceDeadWood[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; //SiteVars.MineralN[site] += summaryNLoss * 0.01; Need to substract N loss from Mineral N pool. -ML SiteVars.MineralN[site] -= summaryNLoss * 0.01; }
//New method for calculating N limits, called from Century.cs Run method before calling Grow //Iterates through cohorts, assigning each a N gathering efficiency based on fine root biomass //and N tolerance. public static void CalculateNLimits(Site site) { // Iterate through the first time, assigning each cohort un un-normalized N multiplier double NMultTotal=0.0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) foreach (ICohort cohort in speciesCohorts) { int Ntolerance = SpeciesData.NTolerance[cohort.Species]; //NMultiplier is a measure of how much N a cohort can gather relative to other cohorts double NMultiplier = CalculateNMultiplier(cohort.Biomass, Ntolerance); NMultTotal += NMultiplier; Dictionary<int,double> newEntry = new Dictionary<int,double>(); newEntry.Add(cohort.Age,NMultiplier); if (CohortNlimits.ContainsKey(cohort.Species.Index)) { CohortNlimits[cohort.Species.Index].Add(cohort.Age,NMultiplier); } else { CohortNlimits.Add(cohort.Species.Index,newEntry); } } double availableN = SiteVars.MineralN[site]; // g/m2 //Iterate through a second time now that we have total N multiplier //Divide through by total and multiply by total available N so each cohort has a max N value //and the sum of cohort max N values is the site available N double totalNUptake = 0.0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { double NMultiplier = CohortNlimits[cohort.Species.Index][cohort.Age]; double Nfrac = NMultiplier / NMultTotal; CohortNlimits[cohort.Species.Index][cohort.Age] = Nfrac * availableN; totalNUptake += Nfrac * availableN; } } if (totalNUptake > availableN) { totalNUptake = availableN; //PlugIn.ModelCore.Log.WriteLine(" ERROR: Total max N uptake = {0:0.000}, availableN = {1:0.000}.", totalNUptake, availableN); //throw new ApplicationException("Error: Max N uptake > availableN. See AvailableN.cs"); } return; }
//-------------------------------------------------------------------------- public static void Leach(Site site, double baseFlow, double stormFlow) { // double minlch, double frlech[3], double stream[8], double basef, double stormf) //Originally from leach.f of CENTURY model //...This routine computes the leaching of inorganic nitrogen (potential for use with phosphorus, and sulfur) //...Written 2/92 -rm. Revised on 12/11 by ML // ML left out leaching intensity factor. Cap on MAX leaching (MINLECH/OMLECH3) is poorly defined in CENTURY manual. Added a NO3frac factor to account //for the fact that only NO3 (not NH4) is leached from soils. //...Called From: SIMSOM //...amtlea: amount leached //...linten: leaching intensity //...strm: storm flow //...base: base flow //Outputs: //minerl and stream are recomputed IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; double waterMove = SiteVars.WaterMovement[site]; double amtNLeached = 0.0; //PlugIn.ModelCore.UI.WriteLine("WaterMove={0:0}, ", waterMove); //...waterMove > 0. indicates a saturated water flow out of layer lyr if (waterMove > 0.0 && SiteVars.MineralN[site] > 0.0) { double textureEffect = OtherData.MineralLeachIntercept + OtherData.MineralLeachSlope * EcoregionData.PercentSand[ecoregion]; //double leachIntensity = (1.0 - (OtherData.OMLeachWater - waterMove) / OtherData.OMLeachWater); //amtNLeached = textureEffect * SiteVars.MineralN[site] * OtherData.NfracLeachWater * OtherData.NO3frac; amtNLeached = textureEffect * SiteVars.MineralN[site] * OtherData.NO3frac; //PlugIn.ModelCore.UI.WriteLine("amtNLeach={0:0.0}, textureEffect={1:0.0}, waterMove={2:0.0}, MineralN={3:0.00}", amtNLeached, textureEffect, waterMove, SiteVars.MineralN[site]); } double totalNleached = (baseFlow * amtNLeached) + (stormFlow * amtNLeached); SiteVars.MineralN[site] -= totalNleached; //PlugIn.ModelCore.UI.WriteLine("AfterSoilWaterLeaching. totalNLeach={0:0.0}, MineralN={1:0.00}", totalNleached, SiteVars.MineralN[site]); SiteVars.Stream[site].Nitrogen += totalNleached; SiteVars.MonthlyStreamN[site][Century.Month] += totalNleached; //PlugIn.ModelCore.UI.WriteLine("AfterSoilWaterLeaching. totalNLeach={0:0.0}, MineralN={1:0.00}", totalNleached, SiteVars.MineralN[site]); return; }
//--------------------------------------------------------------------- public static double GetOrganicCarbon(Site site) { double totalC = SiteVars.SurfaceStructural[site].Carbon + SiteVars.SoilStructural[site].Carbon + SiteVars.SurfaceMetabolic[site].Carbon + SiteVars.SoilMetabolic[site].Carbon + SiteVars.SOM1surface[site].Carbon + SiteVars.SOM1soil[site].Carbon + SiteVars.SOM2[site].Carbon + SiteVars.SOM3[site].Carbon ; return totalC; }
//--------------------------------------------------------------------- // Number of age classes, an indicator of structural complexity. public static int GetAgeRichness(Site site) { int age_richness = 0; List<int> ages = new List<int>(); if (SiteVars.Cohorts[site] == null) return 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { if (!ages.Contains(cohort.Age)) { ages.Add(cohort.Age); age_richness++; } } } return age_richness; }
//--------------------------------------------------------------------- //Use E = Hprime / ln S where S apparently is # species) //where Hprime = -sum (pI * ln(pI)) where pI is proportion of individuals found in Ith species //from Magurran, A. 1988. Ecological diversity and its measurements. Princeton, NJ: Princeton University Press. Pp 35-37) //Return E * 100 to fit within uint range public static int GetAgeEvenness(Site site) { double E = 0; double Hprime = 0; double proportion=0; int evenness = 0; int total_count = 0; Dictionary<int, int> cohort_counts = new Dictionary<int, int>(); if (SiteVars.Cohorts[site] == null) return 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { total_count++; if (!cohort_counts.ContainsKey((int) cohort.Age)) { cohort_counts.Add((int) cohort.Age, 1); } else { cohort_counts[(int) cohort.Age]++; } } } foreach (KeyValuePair<int,int> cohortIter in cohort_counts) { proportion = (double)cohortIter.Value / (double)total_count; Hprime += proportion * System.Math.Log(proportion); } Hprime = - Hprime; E = Hprime / System.Math.Log(cohort_counts.Count); evenness = (int)(E * 100.0); return evenness; }
//--------------------------------------------------------------------- public static ushort GetSppMaxAge(Site site, ISpecies spp) { if (!site.IsActive) return 0; if (SiteVars.Cohorts[site] == null) { PlugIn.ModelCore.UI.WriteLine("Cohort are null."); return 0; } ushort max = 0; foreach (ISpeciesCohorts sppCohorts in SiteVars.Cohorts[site]) { if (sppCohorts.Species == spp) { //ModelCore.UI.WriteLine("cohort spp = {0}, compare species = {1}.", sppCohorts.Species.Name, spp.Name); foreach (ICohort cohort in sppCohorts) if (cohort.Age > max) max = cohort.Age; } } return max; }
//--------------------------------------------------------------------- public static int GetSppRichness(Site site) { //return total count of species int count = 0; if (SiteVars.Cohorts[site] == null) return 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { count++; } return count; }
//--------------------------------------------------------------------- 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 = modelCore.Ecoregion[(ActiveSite) site]; foreach(ISpecies species in modelCore.Species) { ISpeciesCohorts speciesCohorts = (Landis.Library.BiomassCohorts.ISpeciesCohorts) SiteVars.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; //modelCore.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) { // 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 && (modelCore.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 && (modelCore.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 && (modelCore.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; }
private static double GetTotalSoilNitrogen(Site site) { double totalsoilN = +SiteVars.MineralN[site] //+ SiteVars.SurfaceDeadWood[site].Nitrogen //+ SiteVars.SoilDeadWood[site].Nitrogen + SiteVars.SurfaceStructural[site].Nitrogen + SiteVars.SoilStructural[site].Nitrogen + SiteVars.SurfaceMetabolic[site].Nitrogen +SiteVars.SoilMetabolic[site].Nitrogen + SiteVars.SOM1surface[site].Nitrogen + SiteVars.SOM1soil[site].Nitrogen + SiteVars.SOM2[site].Nitrogen + SiteVars.SOM3[site].Nitrogen; ; return totalsoilN; }
//--------------------------------------------------------------------- public static int GetCohortCount(Site site) { //return total count of cohorts int count = 0; if (SiteVars.Cohorts[site] == null) return 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { count++; } } return count; }
//--------------------------------------------------------------------- public static int GetAvgAge(Site site) { if (SiteVars.Cohorts[site] == null) return 0; int avg = 0; int sum = 0; int count = 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { sum += cohort.Age; count++; } } if (count == 0) { return 0; } avg = (int)(sum / count); return avg; }
//--------------------------------------------------------------------- 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.Nvol[site] = 0.0; SiteVars.AnnualNEE[site] = 0.0; SiteVars.TotalNuptake[site] = 0.0; SiteVars.ResorbedN[site] = 0.0; SiteVars.FrassC[site] = 0.0; SiteVars.LAI[site] = 0.0; SiteVars.AgeMortality[site] = 0.0; //SiteVars.FireEfflux[site] = 0.0; }
// Calculates how much N a cohort gets, based on the amount of N available. public static void SetMineralNallocation(Site site) { AvailableN.CohortMineralNallocation = new Dictionary<int, Dictionary<int, double>>(); double availableN = SiteVars.MineralN[site]; // g/m2 Math.Max(availableN, 0.01); foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); if (Century.MonthCnt == 11) cohortAddYear--; //PlugIn.ModelCore.UI.WriteLine("SETMineralNallocation: year={0}, mo={1}, species={2}, cohortAge={3}, cohortAddYear={4}.", PlugIn.ModelCore.CurrentTime, Century.Month, cohort.Species.Name, cohort.Age, cohortAddYear); double Nfraction = 0.05; //even a new cohort gets a little love Dictionary<int, double> cohortDict = new Dictionary<int,double>(); if (AvailableN.CohortMineralNfraction.TryGetValue(cohort.Species.Index, out cohortDict)) cohortDict.TryGetValue(cohortAddYear, out Nfraction); double Nallocation = Nfraction * availableN; //PlugIn.ModelCore.UI.WriteLine(" NallocationlimitedbymineralN={0:0.00}, Nfraction={1:0.00}, availableN={2:0.00}.", Nallocation, Nfraction, availableN); if (Double.IsNaN(Nallocation) || Double.IsNaN(Nfraction) || Double.IsNaN(availableN)) { PlugIn.ModelCore.UI.WriteLine(" LIMIT N CALCULATION = NaN! "); PlugIn.ModelCore.UI.WriteLine(" Nallocation={0:0.00}, Nfraction={1:0.00}, availableN={2:0.00}.", Nallocation, Nfraction, availableN); } Dictionary<int, double> newEntry = new Dictionary<int, double>(); newEntry.Add(cohortAddYear, Nallocation); if (CohortMineralNallocation.ContainsKey(cohort.Species.Index)) { CohortMineralNallocation[cohort.Species.Index].Add(cohortAddYear, Nallocation); } else { CohortMineralNallocation.Add(cohort.Species.Index, newEntry); } } } /*if (totalNUptake > availableN) { totalNUptake = availableN; //PlugIn.ModelCore.UI.WriteLine(" ERROR: Total max N uptake = {0:0.000}, availableN = {1:0.000}.", totalNUptake, availableN); //throw new ApplicationException("Error: Max N uptake > availableN. See AvailableN.cs"); } SiteVars.TotalNuptake[site] = totalNUptake;*/ }
public static void Run(int year, int month, double liveBiomass, Site site) { //PlugIn.ModelCore.Log.WriteLine("year = {0}, month = {1}", year, month); //Originally from h2olos.f of CENTURY model //Water Submodel for Century - written by Bill Parton // Updated from Fortran 4 - rm 2/92 // Rewritten by Bill Pulliam - 9/94 //...Description of variables // // deadBiomass the average monthly standing dead biomass(gm/m..2) // soilDepth depth of the ith soil layer(cm) // fieldCapacity the field capacity of the ith soil layer(fraction) // litterBiomass the average monthly litter biomass(gm/m..2) // liveBiomass the average monthly live plant biomass(gm/m..2) // waterMovement the index for water movement(0-no flow,1-satruated flow) // soilWaterContent the soil water content of the ith soil layer(cm h2o) // asnow the snow pack water contint(cm-h2o) // avh2o (1) NA water available to plants for growth // avh2o (2) NA water available to plants for survival // (available water in the whole soil profile) // availableWater available water in current soil layer // wiltingPoint the wilting point of the ith soil layer(fraction) // transpLossFactor the weight factor for transpiration water loss // totalEvaporated the water evaporated from the soil and vegetation(cm/mon) // evaporatedSnow snow evaporated // inputs rain + irrigation // H2Oinputs inputs which are water (not converted to snow) // nlayer NA number of soil layers with water available for plant survival // nlaypg NA number of soil layers with water available for plant growth // remainingPET remaining pet, updated after each incremental h2o loss // potentialEvapTop the potential evaporation rate from the top soil layer (cm/day) // rain the total monthly rainfall (cm/month) // relativeWaterContent the relative water content of the ith soil layer(0-1) // liquidSnowpack the liquid water in the snow pack // tav average monthly air temperature (2m- //) // tran transpriation water loss(cm/mon) // transpirationLoss transpiration water loss //...Initialize Local Variables double addToSoil = 0.0; double bareSoilEvap = 0.0; double baseFlow = 0.0; double totalEvaporated = 0.0; double evaporativeLoss = 0.0; double potentialTrans = 0.0; double relativeWaterContent = 0.0; //double rwc1 = 0.0; double snow = 0.0; double liquidSnowpack = 0.0; double stormFlow = 0.0; //double tot = 0.0; //double tot2 = 0.0; //double totalAvailableWater = 0.0; double tran = 0.0; //double transpirationLoss = 0.0; double transpiration = 0.01; //...Calculate external inputs IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; double litterBiomass = (SiteVars.SurfaceStructural[site].Carbon + SiteVars.SurfaceMetabolic[site].Carbon) * 2.0; double deadBiomass = SiteVars.SurfaceDeadWood[site].Carbon * 2.0; double soilWaterContent = SiteVars.SoilWaterContent[site] ; double H2Oinputs = EcoregionData.AnnualWeather[ecoregion].MonthlyPrecip[month]; //rain + irract; double tave = EcoregionData.AnnualWeather[ecoregion].MonthlyTemp[month]; double tmax = EcoregionData.AnnualWeather[ecoregion].MonthlyMaxTemp[month]; double tmin = EcoregionData.AnnualWeather[ecoregion].MonthlyMinTemp[month]; double pet = EcoregionData.AnnualWeather[ecoregion].MonthlyPET[month]; //double soilTemp = tave; double wiltingPoint = EcoregionData.WiltingPoint[ecoregion]; double soilDepth = EcoregionData.SoilDepth[ecoregion]; double fieldCapacity = EcoregionData.FieldCapacity[ecoregion]; double stormFlowFraction= EcoregionData.StormFlowFraction[ecoregion]; double baseFlowFraction = EcoregionData.BaseFlowFraction[ecoregion]; double drain = EcoregionData.Drain[ecoregion]; deadBiomass = 0.0; //...Throughout, uses remainingPET as remaining energy for pet after // each melting and evaporation step. Initially calculated // pet is not modified. Pulliam 9/94 double remainingPET = pet; //...Determine the snow pack, melt snow, and evaporate from the snow pack //...When mean monthly air temperature is below freezing, // precipitation is in the form of snow. if (tave < 0.0) { snow = H2Oinputs; //snow + inputs; H2Oinputs = 0.0; } //...Melt snow if air temperature is above minimum (tmelt(1)) if (tave > OtherData.TMelt1) { //...Calculate the amount of snow to melt: double snowMelt = OtherData.TMelt2 * (tave - OtherData.TMelt1); if (snowMelt > snow) snowMelt = snow; snow = snow - snowMelt; //..Melted snow goes to snow pack and drains excess // addToSoil rain-on-snow and melted snow to snowpack liquid (liquidSnowpack): if (tave > 0.0 && snow > 0.0) liquidSnowpack = H2Oinputs; liquidSnowpack = liquidSnowpack + snowMelt; //...Drain snowpack to 5% liquid content (weight/weight), excess to soil: if (liquidSnowpack > (0.05 * snow)) { addToSoil = liquidSnowpack - 0.05 * snow; liquidSnowpack = liquidSnowpack - addToSoil; } } //...Evaporate water from the snow pack (rewritten Pulliam 9/94 to // evaporate from both snow aqnd liquidSnowpack in proportion) //...Coefficient 0.87 relates to heat of fusion for ice vs. liquid water // wasn't modified as snow pack is at least 95% ice. if (snow > 0) { //...Calculate cm of snow that remaining pet energy can evaporate: double evaporatedSnow = remainingPET * 0.87; //...Calculate total snowpack water, ice + liquid: double totalSnowpack = snow + liquidSnowpack; //...Don't evaporate more snow than actually exists: if (evaporatedSnow > totalSnowpack) evaporatedSnow = totalSnowpack; //...Take evaporatedSnow from snow and liquidSnowpack in proportion: snow = snow - evaporatedSnow * (snow / totalSnowpack); liquidSnowpack = liquidSnowpack - evaporatedSnow * (liquidSnowpack/totalSnowpack); //...addToSoil evaporated snow to evaporation accumulator (totalEvaporated): totalEvaporated = evaporatedSnow; //...Decrement remaining pet by energy used to evaporate snow: remainingPET = remainingPET - evaporatedSnow / 0.87; if (remainingPET < 0.0) remainingPET = 0.0; } //...Calculate bare soil water loss and interception // when air temperature is above freezing and no snow cover. //...Mofified 9/94 to allow interception when t < 0 but no snow // cover, Pulliam if (snow <= 0.0) { //...Calculate total canopy cover and litter, put cap on effects: double standingBiomass = liveBiomass + deadBiomass; if (standingBiomass > 800.0) standingBiomass = 800.0; if (litterBiomass > 400.0) litterBiomass = 400.0; //...canopy interception, fraction of precip (canopyIntercept): double canopyIntercept = ((0.0003 * litterBiomass) + (0.0006 * standingBiomass)) * OtherData.WaterLossFactor1; //...Bare soil evaporation, fraction of precip (bareSoilEvap): bareSoilEvap = 0.5 * System.Math.Exp((-0.002 * litterBiomass) - (0.004 * standingBiomass)) * OtherData.WaterLossFactor2; //PlugIn.ModelCore.Log.WriteLine("bareSoilEvap={0}, litterBiomass={1}, standingBiomass={2}.", bareSoilEvap, litterBiomass, standingBiomass); //...Calculate total surface evaporation losses, maximum // allowable is 0.4 * pet. -rm 6/94 evaporativeLoss = System.Math.Min(((bareSoilEvap + canopyIntercept) * H2Oinputs), (0.4 * remainingPET)); totalEvaporated = totalEvaporated + evaporativeLoss; //...Calculate remaining water to addToSoil to soil and potential // transpiration as remaining pet: addToSoil = H2Oinputs - evaporativeLoss; transpiration = remainingPET - evaporativeLoss; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, evaporativeLoss={2:0.0}, addToSoil={3:0.0}, remainingPET={4:0.0}", year, month, evaporativeLoss, addToSoil, remainingPET); } // ************************************************************************** //...Determine potential transpiration water loss (transpiration, cm/mon) as a // function of precipitation and live biomass. //...If temperature is less than 2C turn off transpiration. -rm 6/94 if (tave < 2.0) potentialTrans = 0.0; else potentialTrans = remainingPET * 0.65 * (1.0 - System.Math.Exp(-0.020 * liveBiomass)); if (potentialTrans < transpiration) transpiration = potentialTrans; if (transpiration < 0.0) transpiration = 0.01; // ************************************************************************** //...Calculate the potential evaporation rate from the top soil layer // (potentialEvapTop-cm/day). This is not actually taken out until after // transpiration losses double potentialEvapTop = remainingPET - transpiration - evaporativeLoss; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, PotentialEvapTop={2:0.0}, remainingPET={3:0.0}, transpiration={4:0.0}, evaporativeLoss={5:0.0}.", year, month, potentialEvapTop, remainingPET, transpiration, evaporativeLoss); if (potentialEvapTop < 0.0) potentialEvapTop = 0.0; // ************************************************************************** //...Transpire water from added water first, before passing water // on to soil. This is necessary for a monthly time step to // give plants in wet climates adequate access to water for // transpiration. -rm 6/94, Pulliam 9/94 tran = System.Math.Min((transpiration - 0.01), addToSoil); transpiration = transpiration - tran; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, tran={2:0.0}, transpiration={3:0.0}, addToSoil={4:0.00}.", year, month, tran, transpiration, addToSoil); addToSoil = addToSoil - tran; //...Add water to the soil //...Changed to add base flow and storm flow. -rm 2/92 //...addToSoil water to layer: soilWaterContent += addToSoil; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, soilWaterContent={2:0.0}, addToSoil={3:0.0}.", year, month, soilWaterContent,addToSoil); //...Calculate field capacity of soil, drain soil, pass excess // on to waterMovement: double waterFull = soilDepth * fieldCapacity; double waterMovement = 0.0; if (soilWaterContent > waterFull) { //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, soilWaterContent > waterFull", year, month); waterMovement = soilWaterContent - waterFull; soilWaterContent = waterFull; //...Compute storm flow. stormFlow = waterMovement * stormFlowFraction; } //...Compute base flow and stream flow for H2O. //...Put water draining out bottom that doesn't go to stormflow // into nlayer+1 holding tank: double drainedWater = addToSoil - stormFlow; //...Drain baseflow fraction from holding tank: baseFlow = drainedWater * baseFlowFraction; drainedWater = drainedWater - baseFlow; //...Streamflow = stormflow + baseflow: double streamFlow = stormFlow + baseFlow; //...Save soilWaterContent before transpiration for future use: double asimx = soilWaterContent; // ************************************************************************** //...Calculate transpiration water loss from each layer //...This section was completely rewritten by Pulliam, though it // should still do the same thing. 9/94 //...Calculate available water in layer, soilWaterContent minus wilting point: double availableWater = soilWaterContent - wiltingPoint * soilDepth; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, availableWater={2:0.0}, soilWaterContent={3:0.0}.", year, month, availableWater, soilWaterContent); if (availableWater < 0.0) availableWater = 0.0; //...Calculate available water weighted by transpiration loss depth // distribution factors: double availableWaterWeighted = availableWater * OtherData.TranspirationLossFactor; //...Calculate the actual transpiration water loss(tran-cm/mon) //...Also rewritten by Pulliam 9/94, should do the same thing //...Update potential transpiration to be no greater than available water: transpiration = System.Math.Min(availableWater, transpiration); //...Transpire water from layer: if(availableWaterWeighted > 0.0) { //...Calculate available water in layer j: //for( j = 0; j < nlayer; j++) availableWater = soilWaterContent - wiltingPoint * soilDepth ; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, availableWater={2:0.0}, SWC={3:0.0}", year, month, availableWater, soilWaterContent); if (availableWater < 0.0) availableWater = 0.0; //...Calculate transpiration loss from layer, using weighted // water availabilities: double transpirationLoss = (transpiration * availableWaterWeighted ) / availableWaterWeighted; if (transpirationLoss > availableWater) transpirationLoss = availableWater; soilWaterContent -= transpirationLoss; availableWater -= transpirationLoss; //tran = tran + transpirationLoss; // ???? relativeWaterContent = ((soilWaterContent /soilDepth) - wiltingPoint ) / (fieldCapacity-wiltingPoint); //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, TranspirationLoss={2:0.0}, availableWater={3:0.0}, soilwaterContent={4:0.00}, relativeWaterContent={5:0.00}.", year, month, transpirationLoss, availableWater, soilWaterContent, relativeWaterContent); //...Sum up water available to plants for GROWTH: //if (j <= nlaypg) // avh2o[1] = avh2o[1] + avinj; //...Sum up water available to plants for SURVIVAL: // avh2o[2] = avh2o[2] + avinj; //...Calculate parameter of H2O accumulation in top 2 soil layers: // if (j <= 2) //totalAvailableWater = totalAvailableWater + avinj; } // ************************************************************************** //...Evaporate water from the top layer //...Rewritten by Pulliam, should still do the same thing 9/94 //...Minimum relative water content for top layer to evaporate: double fwlos = 0.25; //...Fraction of water content between fwlos and field capacity: double evmt = (relativeWaterContent - fwlos) / (1.0 - fwlos); //PlugIn.ModelCore.Log.WriteLine("evmt={0:0.0}, relativeWaterContent={1:0.00}, fwlos={2}.", evmt,relativeWaterContent,fwlos); if (evmt <= 0.01) evmt = 0.01; //...Evaporation loss from layer 1: double evapLossTop = evmt * potentialEvapTop * bareSoilEvap * 0.10; double topWater = soilWaterContent - wiltingPoint * soilDepth; if (topWater < 0.0) topWater = 0.0; //topWater = max evaporative loss from surface if (evapLossTop > topWater) evapLossTop = topWater; //...Update available water pools minus evaporation from top layer availableWater -= evapLossTop; soilWaterContent -= evapLossTop; //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, evapLossTop={2:0.00}, SWC={3:0.00}", year, month, evapLossTop, soilWaterContent); //totalEvaporated += evapLossTop; //...Recalculate relative Water Content to estimate mid-month water content double avhsm = (soilWaterContent + relativeWaterContent * asimx) / (1.0 + relativeWaterContent); relativeWaterContent = ((avhsm / soilDepth) - wiltingPoint) / (fieldCapacity - wiltingPoint); //RMS: PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}, soilwaterContent={2:0.00}, relativeWaterContent={3:0.00}.", year, month,soilWaterContent, relativeWaterContent); // Compute the ratio of precipitation to PET double ratioPrecipPET = 0.0; if(pet > 0.0) ratioPrecipPET = (availableWater + H2Oinputs) / pet; //PlugIn.ModelCore.Log.WriteLine("ratioPrecipPET={0}, totalAvailableH20={1}, H2Oinputs={2}, pet={3}.", ratioPrecipPET, totalAvailableWater, H2Oinputs, pet); SiteVars.WaterMovement[site] = waterMovement; SiteVars.AvailableWater[site] = availableWater; //available to plants for growth SiteVars.SoilWaterContent[site] = soilWaterContent; SiteVars.SoilTemperature[site] = CalculateSoilTemp(tmin, tmax, liveBiomass, litterBiomass, month); SiteVars.DecayFactor[site] = CalculateDecayFactor((int) OtherData.WType, SiteVars.SoilTemperature[site], relativeWaterContent, ratioPrecipPET, month); SiteVars.AnaerobicEffect[site] = CalculateAnaerobicEffect(drain, ratioPrecipPET, pet, tave); //SiteVars.StormFlow[site] = stormFlow; //Leach(site, stormFlow, baseFlow); //PlugIn.ModelCore.Log.WriteLine("availH2O={0}, soilH2O={1}, wiltP={2}, soilCM={3}", availableWater, soilWaterContent, wiltingPoint, soilDepth); //PlugIn.ModelCore.Log.WriteLine(" yr={0}, mo={1}, DecayFactor={2:0.00}, Anaerobic={3:0.00}.", year, month, SiteVars.DecayFactor[site], SiteVars.AnaerobicEffect[site]); return; }
//--------------------------------------------------------------------- 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; ISpeciesDataset SpeciesDataset = modelCore.Species; foreach(ISpecies species in SpeciesDataset) { // 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 = SiteVars.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; double maxValue = 0.0; double maxDecidValue = 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 && (modelCore.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 && (modelCore.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 && (modelCore.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; }
public static int GetMaxAge(Site site) { if (SiteVars.Cohorts[site] == null) return 0; int max = 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { int maxSpeciesAge = GetMaxAge(speciesCohorts.Species, site); if (maxSpeciesAge > max) max = maxSpeciesAge; } return max; }
//--------------------------------------------------------------------- public static int GetMinAge(ISpecies species, Site site) { if (SiteVars.Cohorts[site] == null) { PlugIn.ModelCore.UI.WriteLine("Cohort are null."); return 0; } int min = 32767;//maxof uint foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { if (speciesCohorts.Species == species) foreach (ICohort cohort in speciesCohorts) { if (cohort.Age < min) min = (int) cohort.Age; } } return min; }
/*public static uint GetMaxAge(ISpecies species, ActiveSite site) //Cohorts speciesCohorts) { //if (speciesCohorts == null) // return 0; uint max = 0; foreach (ICohort cohort in speciesCohorts) { // First cohort is the oldest max = cohort.Age; break; } return max; }*/ //--------------------------------------------------------------------- public static int GetMinAge(Site site) { if (SiteVars.Cohorts[site] == null) return 0; int min = 32767;//maxof uint foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { int minSpeciesAge = GetMinAge(speciesCohorts.Species, site); //Cohorts); if (minSpeciesAge < min) min = minSpeciesAge; } return min; }
public static int GetMedianAge(ISpecies species, Site site) { if (SiteVars.Cohorts[site] == null) return 0; int median = 0; double dbl_median = 0.0; List<int> cohort_ages = new List<int>(); foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { if(speciesCohorts.Species == species) foreach (ICohort cohort in speciesCohorts) { cohort_ages.Add((int) cohort.Age); } } int count = cohort_ages.Count; if (count == 0) { return 0; } else if (count == 1) { return cohort_ages[0]; } cohort_ages.Sort();//sorts in ascending order if (count % 2 == 0) { dbl_median = (cohort_ages[count / 2] + cohort_ages[(count / 2) - 1]) / 2.0; median = (int)dbl_median; } else { median = cohort_ages[count / 2]; } return median; }
//--------------------------------------------------------------------- public static int GetMaxAge(ISpecies species, Site site) { if (SiteVars.Cohorts[site] == null) { PlugIn.ModelCore.UI.WriteLine("Cohort are null."); return 0; } int max = 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { if(speciesCohorts.Species == species) foreach (ICohort cohort in speciesCohorts) { if (cohort.Age > max) max = (int) cohort.Age; } } return max; }
//--------------------------------------------------------------------- private int CalcForestType(List<IForestType> forestTypes, Site site) { int forTypeCnt = 0; double[] forTypValue = new double[forestTypes.Count]; foreach(ISpecies species in modelCore.Species) { double sppValue = 0.0; if (SiteVars.Cohorts[site] == null) break; sppValue = Util.ComputeBiomass(SiteVars.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) { if(forTypValue[forTypeCnt]>maxValue) { maxValue = forTypValue[forTypeCnt]; finalForestType = forTypeCnt; } forTypeCnt++; } return finalForestType; }
public static void Run(int year, int month, double liveBiomass, Site site, out double baseFlow, out double stormFlow) { //Originally from h2olos.f of CENTURY model //Water Submodel for Century - written by Bill Parton // Updated from Fortran 4 - rm 2/92 // Rewritten by Bill Pulliam - 9/94 // Rewritten by Melissa Lucash- 11/2014 //PlugIn.ModelCore.UI.WriteLine("month={0}.", Century.Month); //...Initialize Local Variables double addToSoil = 0.0; double bareSoilEvap = 0.0; baseFlow = 0.0; double relativeWaterContent = 0.0; double snow = 0.0; stormFlow = 0.0; double actualET = 0.0; double remainingPET = 0.0; double availableWaterMax = 0.0; //amount of water available after precipitation and snowmelt (over-estimate of available water) double availableWaterMin = 0.0; //amount of water available after stormflow (runoff) evaporation and transpiration, but before baseflow/leaching (under-estimate of available water) double availableWater = 0.0; //amount of water deemed available to the trees, which will be the average between the max and min //...Calculate external inputs IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; double litterBiomass = (SiteVars.SurfaceStructural[site].Carbon + SiteVars.SurfaceMetabolic[site].Carbon) * 2.0; double deadBiomass = SiteVars.SurfaceDeadWood[site].Carbon / 0.47; double soilWaterContent = SiteVars.SoilWaterContent[site]; double liquidSnowpack = SiteVars.LiquidSnowPack[site]; H2Oinputs = EcoregionData.AnnualWeather[ecoregion].MonthlyPrecip[month]; //rain + irract in cm; //PlugIn.ModelCore.UI.WriteLine("SoilWater. WaterInputs={0:0.00}, .", H2Oinputs); tave = EcoregionData.AnnualWeather[ecoregion].MonthlyTemp[month]; //PlugIn.ModelCore.UI.WriteLine("SoilWater. AvgTemp={0:0.00}, .", tave); tmax = EcoregionData.AnnualWeather[ecoregion].MonthlyMaxTemp[month]; tmin = EcoregionData.AnnualWeather[ecoregion].MonthlyMinTemp[month]; pet = EcoregionData.AnnualWeather[ecoregion].MonthlyPET[month]; double wiltingPoint = EcoregionData.WiltingPoint[ecoregion]; double soilDepth = EcoregionData.SoilDepth[ecoregion]; double fieldCapacity = EcoregionData.FieldCapacity[ecoregion]; double stormFlowFraction = EcoregionData.StormFlowFraction[ecoregion]; double baseFlowFraction = EcoregionData.BaseFlowFraction[ecoregion]; double drain = EcoregionData.Drain[ecoregion]; //...Calculating snow pack first. Occurs when mean monthly air temperature is equal to or below freezing, // precipitation is in the form of snow. if (tmin <= 0.0) // Use tmin to dictate whether it snows or rains. { snow = H2Oinputs; H2Oinputs = 0.0; liquidSnowpack += snow; //only tracking liquidsnowpack (water equivalent) and not the actual amount of snow on the ground (i.e. not snowpack). //PlugIn.ModelCore.UI.WriteLine("Let it snow!! snow={0}, liquidsnowpack={1}.", snow, liquidSnowpack); } else { soilWaterContent += H2Oinputs; //PlugIn.ModelCore.UI.WriteLine("Let it rain and add it to soil! rain={0}, soilWaterContent={1}.", H2Oinputs, soilWaterContent); } //...Then melt snow if there is snow on the ground and air temperature (tmax) is above minimum. if (liquidSnowpack > 0.0 && tmax > 0.0) { //...Calculate the amount of snow to melt: double snowMeltFraction = Math.Max((tmax * 0.05) + 0.024, 0.0);//This equation assumes a linear increase in the fraction of snow that melts as a function of air temp. //This relationship ultimately derives from http://www.nps.gov/yose/planyourvisit/climate.htm which described the relationship between snow melting and air temp. //Documentation for the regression equation is in spreadsheet called WaterCalcs.xls by M. Lucash if (snowMeltFraction > 1.0) snowMeltFraction = 1.0; addToSoil = liquidSnowpack * snowMeltFraction; //Amount of liquidsnowpack that melts = liquidsnowpack multiplied by the fraction that melts. //Subtracted melted snow from snowpack and add it to the soil liquidSnowpack = liquidSnowpack - addToSoil; soilWaterContent += addToSoil; } //Calculate the max amout of water available to trees, an over-estimate of the water available to trees. It only reflects precip and melting of precip. availableWaterMax = soilWaterContent; //...Evaporate water from the snow pack (rewritten by Pulliam 9/94) //...Coefficient 0.87 relates to heat of fusion for ice vs. liquid water if (liquidSnowpack > 0.0) { //...Calculate cm of snow that remaining pet energy can evaporate: double evaporatedSnow = pet * 0.87; //...Don't evaporate more snow than actually exists: if (evaporatedSnow > liquidSnowpack) evaporatedSnow = liquidSnowpack; liquidSnowpack = liquidSnowpack - evaporatedSnow; //...Decrement remaining pet by energy used to evaporate snow: remainingPET = pet - evaporatedSnow; if (remainingPET < 0.0) remainingPET = 0.0; //Subtract evaporated snowfrom the soil water content soilWaterContent -= evaporatedSnow; } //Allow excess water to run off during storm events (stormflow) double waterFull = soilDepth * fieldCapacity; //units of cm double waterMovement = 0.0; if (soilWaterContent > waterFull) { waterMovement = Math.Max((soilWaterContent - waterFull), 0.0); // How much water should move during a storm event, which is based on how much water the soil can hold. soilWaterContent = waterFull; //...Compute storm flow. stormFlow = waterMovement * stormFlowFraction; //Subtract stormflow from soil water soilWaterContent -= stormFlow; //PlugIn.ModelCore.UI.WriteLine("Water Runs Off. stormflow={0}.", stormFlow); } //...Calculate bare soil water loss and interception when air temperature is above freezing and no snow cover. //...Mofified 9/94 to allow interception when t < 0 but no snow cover, Pulliam if (liquidSnowpack <= 0.0) { //...Calculate total canopy cover and litter, put cap on effects: double standingBiomass = liveBiomass + deadBiomass; if (standingBiomass > 800.0) standingBiomass = 800.0; if (litterBiomass > 400.0) litterBiomass = 400.0; //...canopy interception, fraction of precip (canopyIntercept): double canopyIntercept = ((0.0003 * litterBiomass) + (0.0006 * standingBiomass)) * OtherData.WaterLossFactor1; //...Bare soil evaporation, fraction of precip (bareSoilEvap): bareSoilEvap = 0.5 * System.Math.Exp((-0.002 * litterBiomass) - (0.004 * standingBiomass)) * OtherData.WaterLossFactor2; //...Calculate total surface evaporation losses, maximum allowable is 0.4 * pet. -rm 6/94 remainingPET = pet; double soilEvaporation = System.Math.Min(((bareSoilEvap + canopyIntercept) * H2Oinputs), (0.4 * remainingPET)); //Subtract soil evaporation from soil water content soilWaterContent -= soilEvaporation; } // Calculate actual evapotranspiration. This equation is derived from the stand equation for calculating AET from PET //http://www.civil.utah.edu/~mizukami/coursework/cveen7920/ETMeasurement.pdf double waterEmpty = wiltingPoint * soilDepth; if (soilWaterContent > waterFull) actualET = remainingPET; else { actualET = Math.Max(remainingPET * ((soilWaterContent - waterEmpty) / (waterFull - waterEmpty)), 0.0); } if (actualET < 0.0) actualET = 0.0; //Subtract transpiration from soil water content soilWaterContent -= actualET; //Leaching occurs. Drain baseflow fraction from holding tank. baseFlow = soilWaterContent * baseFlowFraction; //Subtract baseflow from soil water soilWaterContent -= baseFlow; //Calculate the amount of available water after all the evapotranspiration and leaching has taken place (minimum available water) availableWaterMin = Math.Max(soilWaterContent - waterEmpty, 0.0); //Calculate the final amount of available water to the trees, which is the average of the max and min availableWater = (availableWaterMax + availableWaterMin)/ 2.0; //// Compute the ratio of precipitation to PET double ratioPrecipPET = 0.0; //if (pet > 0.0) ratioPrecipPET = (availableWater + H2Oinputs) / pet; //old ratio used in previous versions of LANDIS-Century if (pet > 0.0) ratioPrecipPET = H2Oinputs / pet; //assumes that the ratio is the amount of incoming precip divided by PET. //SiteVars.NumberDryDays[site] = numberDryDays; //Calculated above using method below. SiteVars.LiquidSnowPack[site] = liquidSnowpack; SiteVars.WaterMovement[site] = waterMovement; SiteVars.AvailableWater[site] = availableWater; //available to plants for growth SiteVars.SoilWaterContent[site] = soilWaterContent; SiteVars.SoilTemperature[site] = CalculateSoilTemp(tmin, tmax, liveBiomass, litterBiomass, month); SiteVars.DecayFactor[site] = CalculateDecayFactor((int)OtherData.WType, SiteVars.SoilTemperature[site], relativeWaterContent, ratioPrecipPET, month); SiteVars.AnaerobicEffect[site] = CalculateAnaerobicEffect(drain, ratioPrecipPET, pet, tave); return; }
//--------------------------------------------------------------------- /// <summary> /// Computes fire effects on litter, coarse woody debris, mineral soil, and charcoal. /// No effects on soil organic matter (negligible according to Johnson et al. 2001). /// </summary> public static void ReduceLayers(string prescriptionName, Site site) { PlugIn.ModelCore.UI.WriteLine(" Calculating harvest induced layer reductions..."); double litterLossMultiplier = 0.0; double woodLossMultiplier = 0.0; bool found = false; foreach (HarvestReductions prescription in ReductionsTable) { if (SiteVars.HarvestPrescriptionName != null && SiteVars.HarvestPrescriptionName[site].Trim() == prescription.PrescriptionName.Trim()) { litterLossMultiplier = prescription.LitterReduction; woodLossMultiplier = prescription.WoodReduction; found = true; } } if (!found) return; // Structural litter first double carbonLoss = SiteVars.SurfaceStructural[site].Carbon * litterLossMultiplier; double nitrogenLoss = SiteVars.SurfaceStructural[site].Nitrogen * litterLossMultiplier; double summaryNLoss = nitrogenLoss; SiteVars.SurfaceStructural[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceStructural[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; // Metabolic litter carbonLoss = SiteVars.SurfaceMetabolic[site].Carbon * litterLossMultiplier; nitrogenLoss = SiteVars.SurfaceMetabolic[site].Nitrogen * litterLossMultiplier; summaryNLoss += nitrogenLoss; SiteVars.SurfaceMetabolic[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceMetabolic[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; // Surface dead wood //double woodLossMultiplier = ReductionsTable[severity].WoodReduction; carbonLoss = SiteVars.SurfaceDeadWood[site].Carbon * woodLossMultiplier; nitrogenLoss = SiteVars.SurfaceDeadWood[site].Nitrogen * woodLossMultiplier; summaryNLoss += nitrogenLoss; SiteVars.SurfaceDeadWood[site].Carbon -= carbonLoss; SiteVars.SourceSink[site].Carbon += carbonLoss; SiteVars.FireCEfflux[site] += carbonLoss; SiteVars.SurfaceDeadWood[site].Nitrogen -= nitrogenLoss; SiteVars.SourceSink[site].Nitrogen += nitrogenLoss; SiteVars.FireNEfflux[site] += nitrogenLoss; SiteVars.MineralN[site] += summaryNLoss * 0.01; }
public static uint GetVarAge(ISpecies species, Site site) { if (SiteVars.Cohorts[site] == null) return 0; int avg = GetAvgAge(species, site); //speciesCohorts); double sum = 0; int count = 0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { if(speciesCohorts.Species == species) foreach (ICohort cohort in speciesCohorts) { sum += System.Math.Pow(cohort.Age - avg, 2); count++; } } if (count <= 1) return 0; return (uint)System.Math.Round((sum / (count - 1))); }
//--------------------------------------------------------------------- public static int GetStdDevAge(Site site) { if (SiteVars.Cohorts[site] == null) return 0; int std_dev = (int)System.Math.Sqrt(GetVarAge(site)); return std_dev; }
//--------------------------------------------------------------------- // Method for calculating Mineral N allocation, called from Century.cs Run method before calling Grow // Iterates through cohorts, assigning each a portion of mineral N based on coarse root biomass. Uses an exponential function to "distribute" // the N more evenly between spp. so that the ones with the most woody biomass don't get all the N (L122). public static void CalculateMineralNfraction(Site site) { AvailableN.CohortMineralNfraction = new Dictionary<int, Dictionary<int, double>>(); double NAllocTotal = 0.0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); //PlugIn.ModelCore.UI.WriteLine("CALCMineralNfraction: year={0}, mo={1}, species={2}, cohortAge={3}, cohortAddYear={4}.", PlugIn.ModelCore.CurrentTime, Century.Month, cohort.Species.Name, cohort.Age, cohortAddYear); //Nallocation is a measure of how much N a cohort can gather relative to other cohorts //double Nallocation = Roots.CalculateFineRoot(cohort.LeafBiomass); double Nallocation = 1- Math.Exp((-Roots.CalculateCoarseRoot(cohort.WoodBiomass)*0.02)); if (Nallocation <= 0.0) //PlugIn.ModelCore.CurrentTime == 0) Nallocation = Math.Max(Nallocation, cohort.WoodBiomass * 0.01); //PlugIn.ModelCore.UI.WriteLine("Species = {0}, Age = {1}, Nallocation = {2}, WoodBiomass = {3}, LeafBioMass = {4}", cohort.Species.Name, cohort.Age, Nallocation, cohort.WoodBiomass, cohort.LeafBiomass); NAllocTotal += Nallocation; Dictionary<int, double> newEntry = new Dictionary<int, double>(); newEntry.Add(cohortAddYear, Nallocation); if (CohortMineralNfraction.ContainsKey(cohort.Species.Index)) { CohortMineralNfraction[cohort.Species.Index].Add(cohortAddYear, Nallocation); } else { CohortMineralNfraction.Add(cohort.Species.Index, newEntry); } } } // Next relativize foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { //PlugIn.ModelCore.UI.WriteLine(" SpeciesCohorts = {0}", speciesCohorts.Species.Name); foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); //PlugIn.ModelCore.UI.WriteLine("CALC2MineralNfraction: year={0}, mo={1}, species={2}, cohortAge={3}, cohortAddYear={4}.", PlugIn.ModelCore.CurrentTime, Century.Month, cohort.Species.Name, cohort.Age, cohortAddYear); double Nallocation = CohortMineralNfraction[cohort.Species.Index][cohortAddYear]; double relativeNallocation = Nallocation / NAllocTotal; CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = relativeNallocation; //PlugIn.ModelCore.UI.WriteLine(" Nallocation={0:0.00}, NAllocTotal={1:0.00}, relativeNallocation={2:0.00}.", Nallocation, NAllocTotal, relativeNallocation); if (Double.IsNaN(relativeNallocation) || Double.IsNaN(Nallocation) || Double.IsNaN(NAllocTotal)) { PlugIn.ModelCore.UI.WriteLine(" N ALLOCATION CALCULATION = NaN! "); PlugIn.ModelCore.UI.WriteLine(" Nallocation={0:0.00}, NAllocTotal={1:0.00}, relativeNallocation={2:0.00}.", Nallocation, NAllocTotal, relativeNallocation); PlugIn.ModelCore.UI.WriteLine(" Wood={0:0.00}, Leaf={1:0.00}.", cohort.WoodBiomass, cohort.LeafBiomass); } //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}. MineralNfraction={2:0.00}", PlugIn.ModelCore.CurrentTime, Century.Month, CohortMineralNfraction[cohort.Species.Index][cohortAddYear]); } } }
// --------------------------------------------------------------------- // This method calculates the initial rate of spread for a specific site. // See below for the method that estimates the initial rate of spread for a broad area. public static double InitialRateOfSpread(double ISI, ISeasonParameters season, Site site, bool secondRegionMap) { int fuelIndex = SiteVars.CFSFuelType[site]; if (secondRegionMap) fuelIndex = SiteVars.CFSFuelType2[site]; int PC = SiteVars.PercentConifer[site]; int PH = SiteVars.PercentHardwood[site]; int PDF = SiteVars.PercentDeadFir[site]; //PlugIn.ModelCore.Log.WriteLine("Fuel Type Code = {0}.", siteFuelType.ToString()); double RSI = 0.0; //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Conifer || //Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.ConiferPlantation) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C1 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C2 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C3 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C4 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C5 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C6 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.C7) { double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; double percentHard = (double) PH / 100.0; double percentConi = (double) PC / 100.0; RSI = CalculateRSI(a, b, c, ISI); if (PDF > 0) { if (PH > 0 && season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double) PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double) PDF); } else //M-3 { a = 170 * Math.Exp((-1) * 35 / (double) PDF); b = 0.082 * Math.Exp((-1) * 36 / (double)PDF); c = 1.698 - (0.00303 * PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } // These are the classic MIXED CONIFER + DECIDUOUS else if (PH > 0) { double RSIconifer = RSI; int dIndex = SiteVars.DecidFuelType[site]; //(int)FuelTypeCode.D1; double RSIdecid = CalculateRSI(Event.FuelTypeParms[dIndex].A, Event.FuelTypeParms[dIndex].B, Event.FuelTypeParms[dIndex].C, ISI); if (season.LeafStatus == LeafOnOff.LeafOn) //M-2 { RSI = ((1 - percentHard) * RSIconifer) + (0.2 * percentHard * RSIdecid); } else //M-1 { RSI = ((1 - percentHard) * RSIconifer) + (percentHard * RSIdecid); } //PlugIn.ModelCore.Log.WriteLine("Calculating ROSi for a MIXED type. PH={0}, PC={1}, LeafStatus={2}.", PH, PC, season.LeafStatus); //PlugIn.ModelCore.Log.WriteLine(" RSIcon={0:0.0}, RSIdecid={1:0.0}, RSImix={2:0.000}.", RSIconifer, RSIdecid, RSI); } } //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Open) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.O1a || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.O1b) //siteFuelType == FuelTypeCode.O1a) { double a, b, c; int percentCuring = season.PercentCuring; if(season.NameOfSeason == SeasonName.Spring) //O1a { a = 190; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].A; b = 0.0310; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].B; c = 1.4; //Event.FuelTypeParms[(int)FuelTypeCode.O1a].C; } else //O1b { a = 250; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].A; b = 0.0350; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].B; c = 1.7; //Event.FuelTypeParms[(int)FuelTypeCode.O1b].C; } double CF = (0.02 * percentCuring) - 1.0; RSI = CalculateRSI(a, b, c, ISI); if(percentCuring > 50) RSI *= CF; else RSI = 0; if (PDF > 0) { if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } } //if(Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.NoFuel || fuelIndex == 0) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.NoFuel || fuelIndex == 0) //siteFuelType == FuelTypeCode.NoFuel) { if (PDF > 0) { double a=0, b=0, c=0; if (season.LeafStatus == LeafOnOff.LeafOn) //M-4 { a = 140 * Math.Exp((-1) * 35.5 / (double)PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double)PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double)PDF)); b = 0.082 * (Math.Exp(((-1) * 36) / (double)PDF)); c = 1.698 - (0.00303 * (double)PDF); } RSI = CalculateRSI(a, b, c, ISI); } else { return 0; } } //if( Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Slash || //Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous) if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S1 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S2 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.S3 || Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1) { //PlugIn.ModelCore.Log.WriteLine("Calculating ROSi for a DECIDUOUS or SLASH type."); double a = Event.FuelTypeParms[fuelIndex].A; double b = Event.FuelTypeParms[fuelIndex].B; double c = Event.FuelTypeParms[fuelIndex].C; RSI = CalculateRSI(a, b, c, ISI); //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous if(Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1 && season.LeafStatus == LeafOnOff.LeafOn) //if(siteFuelType == FuelTypeCode.D1 && season.LeafStatus == LeafOnOff.LeafOn) RSI *= 0.2; if (PDF > 0) { //if (Event.FuelTypeParms[fuelIndex].BaseFuel == BaseFuelType.Deciduous if (Event.FuelTypeParms[fuelIndex].SurfaceFuel == SurfaceFuelType.D1 && season.LeafStatus == LeafOnOff.LeafOn) //M-4 //siteFuelType == FuelTypeCode.D1) { a = 140 * Math.Exp((-1) * 35.5 / (double) PDF); b = 0.0404; c = 3.02 * Math.Exp((-1) * 0.00714 * (double) PDF); } else //M-3 { a = 170 * (Math.Exp(((-1) * 35) / (double) PDF)); b = 0.082 * (Math.Exp(((-1) * 36 )/ (double) PDF)); c = 1.698 - (0.00303 * (double) PDF); } double MRSI = CalculateRSI(a, b, c, ISI); if (MRSI > RSI) RSI = MRSI; } } return RSI; }
public static int GetStdDevAge(ISpecies species, Site site) { if (SiteVars.Cohorts[site] == null) return 0; int std_dev = (int)System.Math.Round(System.Math.Sqrt(GetVarAge(species, site)),0); return std_dev; }