//--------------------------------------------------------------------- /// <summary> /// Determines if a species can establish on a site. /// This is a Delegate method to base succession. /// </summary> public bool PlantingEstablish(ISpecies species, ActiveSite site) { IEcoregion ecoregion = modelCore.Ecoregion[site]; double establishProbability = SpeciesData.EstablishProbability[species, ecoregion]; return(establishProbability > 0.0); }
//--------------------------------------------------------------------- /// <summary> /// Computes the initial biomass at a site. /// </summary> /// <param name="site"> /// The selected site. /// </param> /// <param name="initialCommunity"> /// The initial community of age cohorts at the site. /// </param> public static InitialBiomass Compute(ActiveSite site, ICommunity initialCommunity) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; uint key = ComputeKey(initialCommunity.MapCode, ecoregion.MapCode); InitialBiomass initialBiomass; if (initialSites.TryGetValue(key, out initialBiomass)) { return(initialBiomass); } // If we don't have a sorted list of age cohorts for the initial // community, make the list List <Landis.Library.AgeOnlyCohorts.ICohort> sortedAgeCohorts; if (!sortedCohorts.TryGetValue(initialCommunity.MapCode, out sortedAgeCohorts)) { sortedAgeCohorts = SortCohorts(initialCommunity.Cohorts); sortedCohorts[initialCommunity.MapCode] = sortedAgeCohorts; } SiteCohorts cohorts = MakeBiomassCohorts(sortedAgeCohorts, site); initialBiomass = new InitialBiomass(cohorts, SiteVars.WoodyDebris[site], SiteVars.Litter[site]); initialSites[key] = initialBiomass; return(initialBiomass); }
// ------------------------------------------------------------------------------------------------------ private void CalculateMonthlyData(IEcoregion ecoregion, ClimateRecord[] monthlyClimateRecords, int actualYear, double latitude) { this.Year = actualYear; this.TotalAnnualPrecip = 0.0; for (int mo = 0; mo < 12; mo++) { this.MonthlyMinTemp[mo] = monthlyClimateRecords[mo].AvgMinTemp; this.MonthlyMaxTemp[mo] = monthlyClimateRecords[mo].AvgMaxTemp; this.MonthlyVarTemp[mo] = monthlyClimateRecords[mo].AvgVarTemp; this.MonthlyVarPpt[mo] = monthlyClimateRecords[mo].AvgVarPpt; this.MonthlyPrecip[mo] = monthlyClimateRecords[mo].AvgPpt; this.MonthlyPAR[mo] = monthlyClimateRecords[mo].AvgPAR; this.MonthlyFWI[mo] = monthlyClimateRecords[mo].AvgFWI; this.MonthlyTemp[mo] = (this.MonthlyMinTemp[mo] + this.MonthlyMaxTemp[mo]) / 2.0; this.TotalAnnualPrecip += this.MonthlyPrecip[mo]; this.MonthlyWindDirection[mo] = monthlyClimateRecords[mo].AvgWindDirection; this.MonthlyWindSpeed[mo] = monthlyClimateRecords[mo].AvgWindSpeed; this.MonthlyNDeposition[mo] = monthlyClimateRecords[mo].AvgNDeposition; var hr = CalculateDayLength(mo, latitude); this.MonthlyDayLength[mo] = (3600.0 * hr); // seconds of daylight/day this.MonthlyNightLength[mo] = (3600.0 * (24.0 - hr)); // seconds of nighttime/day } this.MeanAnnualTemperature = CalculateMeanAnnualTemp(actualYear); }
// Constructor function public FireEvent(ActiveSite initiationSite, int day, IgnitionType ignitionType) { this.initiationSite = initiationSite; this.IgnitionDay = day; this.IgnitionType = ignitionType; IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[initiationSite]; int actualYear = (PlugIn.ModelCore.CurrentTime - 1) + Climate.Future_DailyData.First().Key; this.annualWeatherData = Climate.Future_DailyData[actualYear][ecoregion.Index]; SiteVars.Disturbed[initiationSite] = true; this.CohortsKilled = 0; this.AvailableCohorts = 0; this.TotalSitesSpread = 0; this.TotalSitesBurned = 0; this.InitiationFireWeatherIndex = annualWeatherData.DailyFireWeatherIndex[day]; this.NumberOfDays = 1; //this.MeanIntensity = 0.0; this.MeanPET = 0.0; this.MeanWD = 0.0; this.MeanClay = 0.0; this.MeanFineFuels = 0.0; this.MeanLadderFuels = 0.0; this.MeanWindDirection = 0.0; this.MeanWindSpeed = 0.0; this.MeanEffectiveWindSpeed = 0.0; this.MeanSpreadProbability = 0.0; this.MeanDNBR = 0.0; this.MeanSuppression = 0.0; this.MeanFWI = 0.0; this.TotalBiomassMortality = 0.0; this.currentSite = initiationSite; this.maxDay = day; }
//--------------------------------------------------------------------- /// <summary> /// Determines if a species can establish on a site. /// This is a Delegate method to base succession. /// </summary> public bool PlantingEstablish(ISpecies species, ActiveSite site) { IEcoregion ecoregion = modelCore.Ecoregion[site]; double establishProbability = Establishment.Calculate(species, site); return(establishProbability > 0.0); }
//--------------------------------------------------------------------- private IEcoregion GetEcoregion(InputValue <string> ecoregionName, Dictionary <string, int> lineNumbers) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregions[ecoregionName.Actual]; if (ecoregion == null) { throw new InputValueException(ecoregionName.String, "{0} is not an ecoregion name.", ecoregionName.String); } int lineNumber; if (lineNumbers.TryGetValue(ecoregion.Name, out lineNumber)) { throw new InputValueException(ecoregionName.String, "The ecoregion {0} was previously used on line {1}", ecoregionName.String, lineNumber); } else { lineNumbers[ecoregion.Name] = LineNumber; } return(ecoregion); }
//--------------------------------------------------------------------- public override byte ComputeShade(ActiveSite site) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; byte finalShade = 0; if (!ecoregion.Active) { return(0); } for (byte shade = 5; shade >= 1; shade--) { if (PlugIn.ShadeLAI[shade] <= 0) { string mesg = string.Format("Maximum LAI has not been defined for shade class {0}", shade); throw new System.ApplicationException(mesg); } if (SiteVars.LAI[site] >= PlugIn.ShadeLAI[shade]) { finalShade = shade; break; } } return(finalShade); }
// Constructor function public FireEvent(ActiveSite initiationSite, int day, Ignition ignitionType) { this.initiationSite = initiationSite; this.IgnitionDay = day; this.IgnitionType = ignitionType; IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[initiationSite]; int actualYear = (PlugIn.ModelCore.CurrentTime - 1) + Climate.Future_DailyData.First().Key; this.annualWeatherData = Climate.Future_DailyData[actualYear][ecoregion.Index]; SiteVars.Disturbed[initiationSite] = true; this.CohortsKilled = 0; this.TotalSitesDamaged = 1; // minimum 1 for the ignition cell this.InitiationFireWeatherIndex = annualWeatherData.DailyFireWeatherIndex[day]; this.NumberOfDays = 1; this.MeanSeverity = 0.0; this.MeanWindDirection = 0.0; this.MeanWindSpeed = 0.0; this.MeanEffectiveWindSpeed = 0.0; this.MeanSpreadProbability = 0.0; this.MeanSuppression = 0.0; this.MeanFWI = 0.0; this.TotalBiomassMortality = 0.0; this.NumberCellsSeverity1 = 0; this.NumberCellsSeverity2 = 0; this.NumberCellsSeverity3 = 0; this.currentSite = initiationSite; this.maxDay = day; }
//--------------------------------------------------------------------- public static void Initialize(IInputParameters parameters) { ActiveSiteCount = new Landis.Library.Parameters.Ecoregions.AuxParm <int>(PlugIn.ModelCore.Ecoregions); AnnualWeather = new Landis.Library.Parameters.Ecoregions.AuxParm <AnnualClimate_Monthly>(PlugIn.ModelCore.Ecoregions); MonthlyNDeposition = new Landis.Library.Parameters.Ecoregions.AuxParm <double[]>(PlugIn.ModelCore.Ecoregions); AnnualNDeposition = new Landis.Library.Parameters.Ecoregions.AuxParm <double>(PlugIn.ModelCore.Ecoregions); foreach (ActiveSite site in PlugIn.ModelCore.Landscape) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; ActiveSiteCount[ecoregion]++; } foreach (IEcoregion ecoregion in PlugIn.ModelCore.Ecoregions) { MonthlyNDeposition[ecoregion] = new double[12]; if (ecoregion.Active) { Climate.GenerateEcoregionClimateData(ecoregion, 0, 45); // PlugIn.Parameters.Latitude); RMS TESTING SetSingleAnnualClimate(ecoregion, 0, Climate.Phase.SpinUp_Climate); // Some placeholder data to get things started. } } }
static int GetWettestMonth(IEcoregion ecoregion, int year, int timespan) { // Get the wettest month from a timespan date - 0.5*timespan yr to date + 0.5 * timespan yr int HalfTimeSpan = (int)Math.Round(0.5 * timespan, 0); DateTime date = new DateTime(year, 1, 15); DateTime DateCounter = date.AddYears(-HalfTimeSpan); // Sum precipitation per month over the period timespan date - 0.5*timespan yr to date + 0.5 * timespan yr float[] P = new float[13]; while (DateCounter < date.AddYears(HalfTimeSpan)) { if (DateCounter.Year >= DateRange[0].Year && DateCounter.Year <= DateRange[1].Year) { P[DateCounter.Month] += prec[ecoregion, DateCounter]; } DateCounter = DateCounter.AddMonths(1); } int MonthMaxPrec = 0; float MaxPrec = float.MinValue; for (int Month = 1; Month < P.Count(); Month++) { if (P[Month] > MaxPrec) { MaxPrec = P[Month]; MonthMaxPrec = Month; } } return(MonthMaxPrec); }
//--------------------------------------------------------------------- /// <summary> /// Weathering of rock phosphorus (rate is user-defined), increasing /// mineral phosphorus and reducing rock phosphorus. /// </summary> public static void Weathering(IEcoregion ecoregion, Rock rock, MineralSoil mineralSoil) { rock.WeatheredMineralP = rock.ContentP * EcoregionData.WeatheringP[ecoregion]; rock.ContentP = Math.Max(rock.ContentP - rock.WeatheredMineralP, 0); mineralSoil.ContentP += rock.WeatheredMineralP; }
public void IndexerWithName() { for (int index = 0; index < ecoregionParms.Count; ++index) { IEcoregion ecoregion = dataset[ecoregionParms[index].Name]; CheckEcoregion(ecoregion, index); } }
//--------------------------------------------------------------------- /// <summary> /// Determines if a species can establish on a site. /// This is a Delegate method to base succession. /// </summary> public bool Establish(ISpecies species, ActiveSite site) { //double establishProbability = establishProbabilities[species][modelCore.Ecoregion[site]]; IEcoregion ecoregion = modelCore.Ecoregion[site]; double establishProbability = SpeciesData.EstablishProbability[species][ecoregion]; return(modelCore.GenerateUniform() < establishProbability); }
public ushort this[IEcoregion ecoregion, int water] { get { if (water >= table[ecoregion].Length) return 0; return table[ecoregion][water]; } }
//--------------------------------------------------------------------- /// <summary> /// Determines if a species can establish on a site. /// This is a Delegate method to base succession. /// </summary> public bool Establish(ISpecies species, ActiveSite site) { IEcoregion ecoregion = modelCore.Ecoregion[site]; double establishProbability = SpeciesData.EstablishProbability[species, ecoregion]; double modEstabProb = establishProbability * SpeciesData.EstablishModifier[species, ecoregion]; return(modelCore.GenerateUniform() < modEstabProb); }
public void Find() { for (int index = 0; index < ecoregionParms.Count; ++index) { IEcoregion ecoregion = dataset.Find(ecoregionParms[index].MapCode); CheckEcoregion(ecoregion, index); } }
public void IndexerWithTooBigInt() { // We expect the statement below to raise an exception, so disable // the CS0219 warning: // "The variable '...' is assigned but its value is never used'. #pragma warning disable 0219 IEcoregion ecoregion = dataset[dataset.Count]; #pragma warning restore 0219 }
//--------------------------------------------------------------------- protected override Dictionary <int, IDynamicEcoregionRecord[]> Parse() { ReadLandisDataVar(); Dictionary <int, IDynamicEcoregionRecord[]> ecoRegData = new Dictionary <int, IDynamicEcoregionRecord[]>(); //--------------------------------------------------------------------- //Read in growing space data: InputVar <int> year = new InputVar <int>("Time step for updating values"); InputVar <string> ecoregionName = new InputVar <string>("Ecoregion Name"); InputVar <double> gs_1 = new InputVar <double>("Growing Space Threshold 1"); InputVar <double> gs_2 = new InputVar <double>("Growing Space Threshold 2"); InputVar <double> gs_3 = new InputVar <double>("Growing Space Threshold 3"); InputVar <double> gs_4 = new InputVar <double>("Growing Space Threshold 4"); while (!AtEndOfInput) { StringReader currentLine = new StringReader(CurrentLine); ReadValue(year, currentLine); int yr = year.Value.Actual; if (!ecoRegData.ContainsKey(yr)) { IDynamicEcoregionRecord[] inputTable = new IDynamicEcoregionRecord[EcoregionData.ModelCore.Ecoregions.Count]; ecoRegData.Add(yr, inputTable); EcoregionData.ModelCore.UI.WriteLine(" Dynamic Ecoregion Parser: Add new year = {0}.", yr); } ReadValue(ecoregionName, currentLine); IEcoregion ecoregion = GetEcoregion(ecoregionName.Value); IDynamicEcoregionRecord dynamicEcoregionRecord = new DynamicEcoregionRecord(); ReadValue(gs_1, currentLine); dynamicEcoregionRecord.GSO1 = gs_1.Value; ReadValue(gs_2, currentLine); dynamicEcoregionRecord.GSO2 = gs_2.Value; ReadValue(gs_3, currentLine); dynamicEcoregionRecord.GSO3 = gs_3.Value; ReadValue(gs_4, currentLine); dynamicEcoregionRecord.GSO4 = gs_4.Value; ecoRegData[yr][ecoregion.Index] = dynamicEcoregionRecord; //CheckNoDataAfter("the " + pest.Name + " column", currentLine); GetNextLine(); } return(ecoRegData); }
//--------------------------------------------------------------------- protected override Dictionary <int, IDynamicInputRecord[, ]> Parse() { //InputVar<string> landisData = new InputVar<string>("LandisData"); //ReadVar(landisData); //if (landisData.Value.Actual != FileName) // throw new InputValueException(landisData.Value.String, "The value is not \"{0}\"", PlugIn.ExtensionName); ReadLandisDataVar(); Dictionary <int, IDynamicInputRecord[, ]> allData = new Dictionary <int, IDynamicInputRecord[, ]>(); //--------------------------------------------------------------------- //Read in establishment probability data: InputVar <int> year = new InputVar <int>("Time step for updating values"); InputVar <string> ecoregionName = new InputVar <string>("Ecoregion Name"); InputVar <string> speciesName = new InputVar <string>("Species Name"); InputVar <double> pest = new InputVar <double>("Probability of Establishment"); while (!AtEndOfInput) { StringReader currentLine = new StringReader(CurrentLine); ReadValue(year, currentLine); int yr = year.Value.Actual; if (!allData.ContainsKey(yr)) { IDynamicInputRecord[,] inputTable = new IDynamicInputRecord[EcoregionData.ModelCore.Species.Count, EcoregionData.ModelCore.Ecoregions.Count]; allData.Add(yr, inputTable); EcoregionData.ModelCore.UI.WriteLine(" Dynamic Input Parser: Add new year = {0}.", yr); } ReadValue(ecoregionName, currentLine); IEcoregion ecoregion = GetEcoregion(ecoregionName.Value); ReadValue(speciesName, currentLine); ISpecies species = GetSpecies(speciesName.Value); IDynamicInputRecord dynamicInputRecord = new DynamicInputRecord(); ReadValue(pest, currentLine); dynamicInputRecord.ProbEst = pest.Value; allData[yr][species.Index, ecoregion.Index] = dynamicInputRecord; CheckNoDataAfter("the " + pest.Name + " column", currentLine); GetNextLine(); } return(allData); }
//--------------------------------------------------------------------- /// <summary> /// Initializes a new instance with one young cohort (age = 1). /// </summary> public SpeciesCohorts(ISpecies species, ushort initialAge, int initialTrees, IEcoregion ecoregion) { this.species = species; this.cohortData = new List <CohortData>(); this.isMaturePresent = false; AddNewCohort(initialAge, initialTrees, ecoregion); }
//--------------------------------------------------------------------- public T this[IEcoregion ecoregion] { get { return(values[ecoregion.Index]); } set { values[ecoregion.Index] = value; } }
//--------------------------------------------------------------------------- //... Originally from pprdwc(wc,x,pprpts) of CENTURY //...This funtion returns a value for potential plant production // due to water content. Basically you have an equation of a // line with a moveable y-intercept depending on the soil type. // The value passed in for x is ((avh2o(1) + prcurr(month) + irract)/pet) // pprpts(1): The minimum ratio of available water to pet which // would completely limit production assuming wc=0. // pprpts(2): The effect of wc on the intercept, allows the // user to increase the value of the intercept and // thereby increase the slope of the line. // pprpts(3): The lowest ratio of available water to pet at which // there is no restriction on production. private static double calculateWater_Limit(ActiveSite site, IEcoregion ecoregion, ISpecies species) { // Ratio_AvailWaterToPET used to be pptprd and WaterLimit used to be pprdwc double Ratio_AvailWaterToPET = 0.0; double waterContent = SiteVars.SoilFieldCapacity[site] - SiteVars.SoilWiltingPoint[site]; double pet = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPET[Century.Month]; if (pet >= 0.01) { // Trees are allowed to access the whole soil profile -rm 2/97 Ratio_AvailWaterToPET = (SiteVars.AvailableWater[site] / pet); //Modified by ML so that we weren't double-counting precip as in above equation } else { Ratio_AvailWaterToPET = 0.01; } //...The equation for the y-intercept (intcpt) is A+B*WC. A and B // determine the effect of soil texture on plant production based // on moisture. //...Old way: // intcpt = 0.0 + 1.0 * wc // The second point in the equation is (.8,1.0) // slope = (1.0-0.0)/(.8-intcpt) // pprdwc = 1.0+slope*(x-.8) //PPRPTS naming convention is imported from orginal Century model. Now replaced with 'MoistureCurve' to be more intuitive //...New way (with updated naming convention): double moisturecurve1 = OtherData.MoistureCurve1; double moisturecurve2 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve2; double moisturecurve3 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve3; double intcpt = moisturecurve1 + (moisturecurve2 * waterContent); double slope = 1.0 / (moisturecurve3 - intcpt); double WaterLimit = 1.0 + slope * (Ratio_AvailWaterToPET - moisturecurve3); if (WaterLimit > 1.0) { WaterLimit = 1.0; } if (WaterLimit < 0.01) { WaterLimit = 0.01; } if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode) { Outputs.CalibrateLog.Write("{0:0.00},", SiteVars.AvailableWater[site]); } return(WaterLimit); }
//--------------------------------------------------------------------- /// <summary> /// Grows the cohorts during spin-up /// Makes the set of biomass cohorts at a site based on the age cohorts /// at the site, using a specified method for computing a cohort's /// initial biomass. /// </summary> /// <param name="ageCohorts"> /// A sorted list of age cohorts, from oldest to youngest. /// </param> /// <param name="site"> /// Site where cohorts are located. /// </param> /// <param name="initialBiomassMethod"> /// The method for computing the initial biomass for a new cohort. /// </param> public static ISiteCohorts MakeBiomassCohorts(List <Landis.Library.AgeOnlyCohorts.ICohort> ageCohorts, ActiveSite site, ComputeMethod initialBiomassMethod) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; //if (Climate.Spinup_AllData.Count >= ageCohorts[0].Age) //try //{ //PlugIn.ModelCore.UI.WriteLine("Making Biomass Cohorts using spin-up climate data"); SiteVars.Cohorts[site] = new Library.LeafBiomassCohorts.SiteCohorts(); if (ageCohorts.Count == 0) { return(SiteVars.Cohorts[site]); } int indexNextAgeCohort = 0; // The index in the list of sorted age cohorts of the next // cohort to be considered // Loop through time from -N to 0 where N is the oldest cohort. // So we're going from the time when the oldest cohort was "born" // to the present time (= 0). Because the age of any age cohort // is a multiple of the succession timestep, we go from -N to 0 // by that timestep. NOTE: the case where timestep = 1 requires // special treatment because if we start at time = -N with a // cohort with age = 1, then at time = 0, its age will N+1 not N. // Therefore, when timestep = 1, the ending time is -1. //int endTime = (successionTimestep == 1) ? -1 : -1; //PlugIn.ModelCore.UI.WriteLine(" Ageing initial cohorts. Oldest cohorts={0} yrs, succession timestep={1}, endTime={2}.", ageCohorts[0].Age, successionTimestep, endTime); for (int time = -(ageCohorts[0].Age); time <= -1; time += successionTimestep) { //PlugIn.ModelCore.UI.WriteLine(" Ageing initial cohorts. Oldest cohorts={0} yrs, succession timestep={1}.", ageCohorts[0].Age, successionTimestep); EcoregionData.SetSingleAnnualClimate(ecoregion, time + ageCohorts[0].Age, Climate.Phase.SpinUp_Climate); //the spinup climate array is sorted from oldest to newest years // Add those cohorts that were born at the current year while (indexNextAgeCohort < ageCohorts.Count && ageCohorts[indexNextAgeCohort].Age == -time) { ISpecies species = ageCohorts[indexNextAgeCohort].Species; float[] initialBiomass = initialBiomassMethod(species, SiteVars.Cohorts[site], site); SiteVars.Cohorts[site].AddNewCohort(ageCohorts[indexNextAgeCohort].Species, 1, initialBiomass[0], initialBiomass[1]); indexNextAgeCohort++; } Main.Run(site, successionTimestep, true); } return(SiteVars.Cohorts[site]); }
//--------------------------------------------------------------------------- //... Originally from pprdwc(wc,x,pprpts) of CENTURY //...This funtion returns a value for potential plant production // due to water content. Basically you have an equation of a // line with a moveable y-intercept depending on the soil type. // The value passed in for x is ((avh2o(1) + prcurr(month) + irract)/pet) // pprpts(1): The minimum ratio of available water to pet which // would completely limit production assuming wc=0. // pprpts(2): The effect of wc on the intercept, allows the // user to increase the value of the intercept and // thereby increase the slope of the line. // pprpts(3): The lowest ratio of available water to pet at which // there is no restriction on production. private static double calculateWater_Limit(ActiveSite site, IEcoregion ecoregion, ISpecies species) { double Ratio_AvailWaterToPET = 0.0; double waterContent = SiteVars.SoilFieldCapacity[site] - SiteVars.SoilWiltingPoint[site]; double tmin = ClimateRegionData.AnnualWeather[ecoregion].MonthlyMinTemp[Main.Month]; double H2Oinputs = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPrecip[Main.Month]; //rain + irract; double pet = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPET[Main.Month]; //PlugIn.ModelCore.UI.WriteLine("pet={0}, waterContent={1}, precip={2}.", pet, waterContent, H2Oinputs); if (pet >= 0.01) { // Trees are allowed to access the whole soil profile -rm 2/97 Ratio_AvailWaterToPET = (SiteVars.AvailableWater[site] / pet); //Modified by ML so that we weren't double-counting precip as in above equation //PlugIn.ModelCore.UI.WriteLine("RatioAvailWaterToPET={0}, AvailableWater={1}.", Ratio_AvailWaterToPET, SiteVars.AvailableWater[site]); } else { Ratio_AvailWaterToPET = 0.01; } //...The equation for the y-intercept (intcpt) is A+B*WC. A and B // determine the effect of soil texture on plant production based // on moisture. double moisturecurve1 = OtherData.MoistureCurve1; double moisturecurve2 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve2; double moisturecurve3 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve3; double intcpt = moisturecurve1 + (moisturecurve2 * waterContent); double slope = 1.0 / (moisturecurve3 - intcpt); double WaterLimit = 1.0 + slope * (Ratio_AvailWaterToPET - moisturecurve3); if (WaterLimit > 1.0) { WaterLimit = 1.0; } if (WaterLimit < 0.01) { WaterLimit = 0.01; } //PlugIn.ModelCore.UI.WriteLine("Intercept={0}, Slope={1}, WaterLimit={2}.", intcpt, slope, WaterLimit); if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode) { Outputs.CalibrateLog.Write("{0:0.00},", SiteVars.AvailableWater[site]); } return(WaterLimit); }
public PnETEcoregions(IEcoregion ecoregion, float AET, float LeakageFrac, float RunoffCapture, float PrecLossFrac, float RootingDepth, string SoilType, string ClimateFileName) { this.ecoregion = ecoregion; this.AET = AET; this.LeakageFrac = LeakageFrac; this.RunoffCapture = RunoffCapture; this.PrecLossFrac = PrecLossFrac; this.RootingDepth = RootingDepth; this.SoilType = SoilType; this.ClimateFileName = ClimateFileName; }
public MonthlyClimateRecord(IEcoregion ecoregion, DateTime date) { var month = date.Month - 1; // climate library month is zero-based, while DateTime.Month is one-based O3 = ClimateRegionData.AnnualWeather[ecoregion].MonthlyOzone[month]; CO2 = ClimateRegionData.AnnualWeather[ecoregion].MonthlyCO2[month]; PAR0 = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPAR[month]; Prec = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPrecip[month] * 10.0; // The climate library gives precipitation in cm, but PnET expects precipitation in mm, so multiply by 10. Tmax = ClimateRegionData.AnnualWeather[ecoregion].MonthlyMaxTemp[month]; Tmin = ClimateRegionData.AnnualWeather[ecoregion].MonthlyMinTemp[month]; }
//--------------------------------------------------------------------- public Hydrology(IEcoregion ecoregion) { this.ecoregion = ecoregion; snowpack = 0; water = WHC[ecoregion]; infiltration = 0; runoff = 0; preciploss = 0; transpiration = 0; AnnualTranspiration = 0; }
///<Summary> /// Gets a species and ecoregion specific value ///</Summary> public T this[ISpecies species, IEcoregion ecoregion] { get { return(values[species][ecoregion]); } set { values[species][ecoregion] = value; } }
//--------------------------------------------------------------------- public static void CalculateAnnualWeatherIndex(IAgent agent) { double monthTotal = 0; int monthCount = 0; double varValue = 0; string varName = "AnnualWeatherIndex"; int minMonth = agent.AnnualWeatherIndex.MinMonth; int maxMonth = agent.AnnualWeatherIndex.MaxMonth; var monthRange = Enumerable.Range(minMonth, (maxMonth - minMonth) + 1); Dictionary <IEcoregion, double> ecoClimateVars = new Dictionary <IEcoregion, double>(); foreach (IEcoregion ecoregion in PlugIn.ModelCore.Ecoregions) { double transformValue = 0; foreach (int monthIndex in monthRange) { //Select days that match month //for each day in month //varValue = WeatherIndex; monthTotal += varValue; monthCount++; } double avgValue = monthTotal / (double)monthCount; if (agent.AnnualWeatherIndex.Function.Equals("sum", StringComparison.OrdinalIgnoreCase)) { transformValue = monthTotal; } else if (agent.AnnualWeatherIndex.Function.Equals("mean", StringComparison.OrdinalIgnoreCase)) { transformValue = avgValue; } else { string mesg = string.Format("Annual Weather Index function is {1}; expected 'sum' or 'mean'.", agent.AnnualWeatherIndex.Function); throw new System.ApplicationException(mesg); } ecoClimateVars[ecoregion] = transformValue; } foreach (Site site in PlugIn.ModelCore.Landscape.AllSites) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; double climateValue = 0; if (ecoregion != null) { climateValue = ecoClimateVars[ecoregion]; } // Write Site Variable SiteVars.ClimateVars[site][varName] = (float)climateValue; } }
//--------------------------------------------------------------------- private void WriteLogFile() { double[,] allSppEcos = new double[ModelCore.Ecoregions.Count, ModelCore.Species.Count]; int[] activeSiteCount = new int[ModelCore.Ecoregions.Count]; //UI.WriteLine("Next, reset all values to zero."); foreach (IEcoregion ecoregion in ModelCore.Ecoregions) { foreach (ISpecies species in ModelCore.Species) { allSppEcos[ecoregion.Index, species.Index] = 0.0; } activeSiteCount[ecoregion.Index] = 0; } //UI.WriteLine("Next, accumulate data."); foreach (ActiveSite site in ModelCore.Landscape) { IEcoregion ecoregion = ModelCore.Ecoregion[site]; foreach (ISpecies species in ModelCore.Species) { allSppEcos[ecoregion.Index, species.Index] += ComputeSpeciesBiomass(SiteVars.Cohorts[site][species]); } activeSiteCount[ecoregion.Index]++; } foreach (IEcoregion ecoregion in ModelCore.Ecoregions) { summaryLog.Clear(); SummaryLog sl = new SummaryLog(); sl.Time = modelCore.CurrentTime; sl.EcoName = ecoregion.Name; sl.NumActiveSites = activeSiteCount[ecoregion.Index]; double[] aboveBiomass = new double[modelCore.Species.Count]; foreach (ISpecies species in ModelCore.Species) { aboveBiomass[species.Index] = allSppEcos[ecoregion.Index, species.Index] / (double)activeSiteCount[ecoregion.Index]; } sl.AboveGroundBiomass_ = aboveBiomass; summaryLog.AddObject(sl); summaryLog.WriteToFile(); } }
//--------------------------------------------------------------------- /// <summary> /// Computes the initial biomass at a site. /// </summary> /// <param name="site"> /// The selected site. /// </param> /// <param name="initialCommunity"> /// The initial community of age cohorts at the site. /// </param> public static InitialBiomass ComputeInitialBiomass(ActiveSite site, ICommunity initialCommunity) { InitialBiomass initialBiomass; IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; uint key = ComputeKey(initialCommunity.MapCode, ecoregion.MapCode); if (initialSites.TryGetValue(key, out initialBiomass) && HasSiteOutput[site] == false) { CanopyBiomass.CanopyLAImax[site] = initialBiomass.canopylaimax; CanopyBiomass.CanopyLAI[site] = initialBiomass.canopylai; Hydrology.Water[site] = initialBiomass.water; Hydrology.AnnualTranspiration[site] = initialBiomass.annualtrans; CanopyBiomass.SubCanopyPAR[site] = initialBiomass.subcanopypar; return(initialBiomass); } // If we don't have a sorted list of age cohorts for the initial // community, make the list List <Landis.Library.AgeOnlyCohorts.ICohort> sortedAgeCohorts; if (!sortedCohorts.TryGetValue(initialCommunity.MapCode, out sortedAgeCohorts)) { sortedAgeCohorts = PlugIn.RankCohortAgesOldToYoung(initialCommunity.Cohorts); sortedCohorts[initialCommunity.MapCode] = sortedAgeCohorts; } if (sortedAgeCohorts.Count == 0) { return(null); } ISiteCohorts cohorts = MakeBiomassCohorts(sortedAgeCohorts, site); initialBiomass = new InitialBiomass(cohorts, ForestFloor.WoodyDebris[site], ForestFloor.Litter[site], Hydrology.Water[site], Hydrology.AnnualTranspiration[site], CanopyBiomass.CanopyLAI[site], CanopyBiomass.CanopyLAImax[site], CanopyBiomass.SubCanopyPAR[site]); initialSites[key] = initialBiomass; return(initialBiomass); }
//--------------------------------------------------------------------- public override void Initialize() { Timestep = 1; // RMS: Initially we will force annual time step. parameters.Timestep; ///******************** DEBUGGER LAUNCH ********************* /// /* * if (Debugger.Launch()) * { * modelCore.UI.WriteLine("Debugger is attached"); * if (Debugger.IsLogging()) * { * modelCore.UI.WriteLine("Debugging is logging"); * } * Debugger.Break(); * } * else * { * modelCore.UI.WriteLine("Debugger not attached"); * } */ ///******************** DEBUGGER END ********************* // Initilize the FireRegions Maps modelCore.UI.WriteLine(" Initializing Fire..."); dynamicRxIgns = Parameters.DynamicRxIgnitionMaps; MapUtility.Initilize(Parameters.LighteningFireMap, Parameters.AccidentalFireMap, Parameters.RxFireMap, Parameters.LighteningSuppressionMap, Parameters.AccidentalSuppressionMap, Parameters.RxSuppressionMap); if (Parameters.RxZonesMap != null) { MapUtility.ReadMap(Parameters.RxZonesMap, SiteVars.RxZones); } MetadataHandler.InitializeMetadata(Parameters.Timestep, ModelCore); sitesPerEcoregions = new Dictionary <int, int>(); foreach (ActiveSite site in PlugIn.ModelCore.Landscape) { IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site]; if (!sitesPerEcoregions.ContainsKey(ecoregion.Index)) { sitesPerEcoregions.Add(ecoregion.Index, 1); } else { sitesPerEcoregions[ecoregion.Index]++; } } }
//--------------------------------------------------------------------- /// <summary> /// Computes the actual biomass at a site. The biomass is the total /// of all the site's cohorts except young ones. The total is limited /// to being no more than the site's maximum biomass less the previous /// year's mortality at the site. /// </summary> public static double ActualSiteBiomass(SiteCohorts siteCohorts, ActiveSite site, out IEcoregion ecoregion) { int youngBiomass; int totalBiomass = Cohorts.ComputeBiomass(siteCohorts, out youngBiomass); double B_ACT = totalBiomass - youngBiomass; int lastMortality = siteCohorts.PrevYearMortality; ecoregion = Model.Core.Ecoregion[site]; B_ACT = Math.Min( B_MAX[ecoregion] - lastMortality, B_ACT); return B_ACT; }
public EstablishmentProbability(ActiveSite site) { this.site = site; this.ecoregion = PlugIn.modelCore.Ecoregion[site]; pest = new Landis.Library.Biomass.Species.AuxParm<float>(PlugIn.ModelCore.Species); potestablishments = new Landis.Library.Biomass.Species.AuxParm<int>(PlugIn.ModelCore.Species); establishments = new Landis.Library.Biomass.Species.AuxParm<int>(PlugIn.ModelCore.Species); foreach (ISpecies spc in PlugIn.ModelCore.Species) { potestablishments[spc] = 0; establishments[spc] = 0; pest[spc] = 0; } }
//--------------------------------------------------------------------- // Generates new climate parameters for a SINGLE ECOREGION at an annual time step. public static void SetSingleAnnualClimate(IEcoregion ecoregion, int year, Climate.Phase spinupOrfuture) { int actualYear = PlugIn.ModelCore.CurrentTime + year; if (spinupOrfuture == Climate.Phase.Future_Climate) { actualYear += Climate.Future_MonthlyData.First().Key; //PlugIn.ModelCore.UI.WriteLine("Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); if (Climate.Future_MonthlyData.ContainsKey(actualYear)) { AnnualWeather[ecoregion] = Climate.Future_MonthlyData[actualYear][ecoregion.Index]; //AnnualWeather[ecoregion].WriteToLandisLogFile(); } //else // PlugIn.ModelCore.UI.WriteLine("Key is missing: Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); } else { if (LastYearUpdated[ecoregion] == year+1) return; actualYear += Climate.Spinup_MonthlyData.First().Key; //PlugIn.ModelCore.UI.WriteLine("Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); if (Climate.Spinup_MonthlyData.ContainsKey(actualYear)) { AnnualWeather[ecoregion] = Climate.Spinup_MonthlyData[actualYear][ecoregion.Index]; LastYearUpdated[ecoregion] = year+1; } } }
//--------------------------------------------------------------------- public static int GenerateFoliarMoistureContent(ISeasonParameters season, IEcoregion ecoregion) { double bui = 0.0; bui = GenerateRandomNum(season.BUIDist, season.BUIP1, season.BUIP2); if(bui < 0) bui = 0; if(bui > 200) bui = 200; return (int) bui; }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public int ComputeChange(ICohort cohort, ActiveSite site) { int siteBiomass = SiteVars.TotalBiomass[site]; ecoregion = PlugIn.ModelCore.Ecoregion[site]; // First, calculate age-related mortality. // Age-related mortality will include woody and standing leaf biomass (=0 for deciduous trees). double mortalityAge = ComputeAgeMortality(cohort); double actualANPP = ComputeActualANPP(cohort, site); // Age mortality is discounted from ANPP to prevent the over- // estimation of mortality. ANPP cannot be negative. actualANPP = Math.Max(1, actualANPP - mortalityAge); SiteVars.AGNPP[site] += actualANPP; // --------------------------------------------------------- // Growth-related mortality double mortalityGrowth = ComputeGrowthMortality(cohort, site); // Age-related mortality is discounted from growth-related // mortality to prevent the under-estimation of mortality. Cannot be negative. mortalityGrowth = Math.Max(0, mortalityGrowth - mortalityAge); // Also ensure that growth mortality does not exceed actualANPP. mortalityGrowth = Math.Min(mortalityGrowth, actualANPP); // Total mortality for the cohort double totalMortality = mortalityAge + mortalityGrowth; if (totalMortality > cohort.Biomass) throw new ApplicationException("Error: Mortality exceeds cohort biomass"); PlugIn.CurrentYearSiteMortality += totalMortality; // --------------------------------------------------------- // Defoliation ranges from 1.0 (total) to none (0.0). // Defoliation is calculated by an external function, typically an extension // with a defoliation calculator. The method CohortDefoliation.Compute is a delegate method // and lives within the defoliating extension. defoliation = Landis.Library.Biomass.CohortDefoliation.Compute(site, cohort.Species, cohort.Biomass, siteBiomass); double defoliationLoss = 0.0; if (defoliation > 0) { double standing_nonwood = ComputeFractionANPPleaf(cohort.Species) * actualANPP; defoliationLoss = standing_nonwood * defoliation; SiteVars.Defoliation[site] += defoliationLoss; } // --------------------------------------------------------- int deltaBiomass = (int)(actualANPP - totalMortality - defoliationLoss); double newBiomass = cohort.Biomass + (double)deltaBiomass; double totalLitter = UpdateDeadBiomass(cohort, actualANPP, totalMortality, site, newBiomass); double leafFraction = ComputeFractionANPPleaf(cohort.Species); // Mortality reduces the amount of new foliage int annualLeafANPP = (int)((actualANPP - totalMortality) * leafFraction); cohort.ChangeCurrentFoliage(annualLeafANPP); int newTotalFoliage = (int)(annualLeafANPP + cohort.TotalFoliage * (1 - (1 / SpeciesData.LeafLongevity[cohort.Species]))); cohort.ChangeTotalFoliage(newTotalFoliage); if (PlugIn.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0) { PlugIn.ModelCore.UI.WriteLine("Yr={0}. Calculate Delta Biomass...", (PlugIn.ModelCore.CurrentTime + SubYear)); PlugIn.ModelCore.UI.WriteLine("Yr={0}. Spp={1}, Age={2}.", (PlugIn.ModelCore.CurrentTime + SubYear), cohort.Species.Name, cohort.Age); PlugIn.ModelCore.UI.WriteLine("Yr={0}. ANPPact={1:0.0}, Mtotal={2:0.0}, litter={3:0.00}.", (PlugIn.ModelCore.CurrentTime + SubYear), actualANPP, totalMortality, totalLitter); PlugIn.ModelCore.UI.WriteLine("Yr={0}. DeltaB={1:0.0}, CohortB={2}, Bsite={3}", (PlugIn.ModelCore.CurrentTime + SubYear), deltaBiomass, cohort.Biomass, (int)siteBiomass); } return deltaBiomass; }
//--------------------------------------------------------------------- public void SetProbability(IEcoregion ecoregion, ISpecies species, double probability) { probabilities[ecoregion.Index, species.Index] = probability; }
public Hydrology(ActiveSite Site) { site = Site; ecoregion = PlugIn.ModelCore.Ecoregion[site]; soiltype = SoilType[ecoregion]; }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public float[] ComputeChange(ICohort cohort, ActiveSite site) { ecoregion = PlugIn.ModelCore.Ecoregion[site]; // First call to the Calibrate Log: if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode) Outputs.CalibrateLog.Write("{0}, {1}, {2}, {3}, {4}, {5:0.0}, {6:0.0}, ", PlugIn.ModelCore.CurrentTime, Century.Month + 1, ecoregion.Index, cohort.Species.Name, cohort.Age, cohort.WoodBiomass, cohort.LeafBiomass); double siteBiomass = Century.ComputeLivingBiomass(SiteVars.Cohorts[site]); if(siteBiomass < 0) throw new ApplicationException("Error: Site biomass < 0"); // ****** Mortality ******* // Age-related mortality includes woody and standing leaf biomass. double[] mortalityAge = ComputeAgeMortality(cohort, site); // Growth-related mortality double[] mortalityGrowth = ComputeGrowthMortality(cohort, site); double[] totalMortality = new double[2]{Math.Min(cohort.WoodBiomass, mortalityAge[0] + mortalityGrowth[0]), Math.Min(cohort.LeafBiomass, mortalityAge[1] + mortalityGrowth[1])}; double nonDisturbanceLeafFall = totalMortality[1]; // ****** Growth ******* double[] actualANPP = ComputeActualANPP(cohort, site, siteBiomass, mortalityAge); double scorch = 0.0; defoliatedLeafBiomass = 0.0; if (Century.Month == 6) //July = 6 { if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) scorch = FireEffects.CrownScorching(cohort, SiteVars.FireSeverity[site]); if (scorch > 0.0) // NEED TO DOUBLE CHECK WHAT CROWN SCORCHING RETURNS totalMortality[1] = Math.Min(cohort.LeafBiomass, scorch + totalMortality[1]); // Defoliation (index) ranges from 1.0 (total) to none (0.0). if (PlugIn.ModelCore.CurrentTime > 0) //Skip this during initialization { //defoliation = Landis.Library.LeafBiomassCohorts.CohortDefoliation.Compute(cohort, site, (int)siteBiomass); int cohortBiomass = (int)(cohort.LeafBiomass + cohort.WoodBiomass); defoliation = Landis.Library.Biomass.CohortDefoliation.Compute(site, cohort.Species, cohortBiomass, (int)siteBiomass); } if (defoliation > 1.0) defoliation = 1.0; if (defoliation > 0.0) { defoliatedLeafBiomass = (cohort.LeafBiomass) * defoliation; if (totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass > 0.001) defoliatedLeafBiomass = cohort.LeafBiomass - totalMortality[1]; //PlugIn.ModelCore.UI.WriteLine("Defoliation.Month={0:0.0}, LeafBiomass={1:0.00}, DefoliatedLeafBiomass={2:0.00}, TotalLeafMort={2:0.00}", Century.Month, cohort.LeafBiomass, defoliatedLeafBiomass , mortalityAge[1]); ForestFloor.AddFrassLitter(defoliatedLeafBiomass, cohort.Species, site); } } else { defoliation = 0.0; defoliatedLeafBiomass = 0.0; } //// Because Growth used some Nitrogen, it must be subtracted from the appropriate pools, either resorbed or mineral. //double totalNdemand = AvailableN.CalculateCohortNDemand(cohort.Species, site, actualANPP); //double adjNdemand = totalNdemand; //double resorbedNused = 0.0; //double mineralNused = 0.0; //// Treat Resorbed N first and only if it is spring time unless you are evergreen. //double leafLongevity = SpeciesData.LeafLongevity[cohort.Species]; //if ((leafLongevity <= 1.0 && Century.Month > 2 && Century.Month < 6) || leafLongevity > 1.0) //{ // double resorbedNallocation = Math.Max(0.0, AvailableN.GetResorbedNallocation(cohort)); // resorbedNused = resorbedNallocation - Math.Max(0.0, resorbedNallocation - totalNdemand); // AvailableN.SetResorbedNallocation(cohort, Math.Max(0.0, resorbedNallocation - totalNdemand)); // adjNdemand = Math.Max(0.0, totalNdemand - resorbedNallocation); //} //// Reduce available N after taking into account that some N may have been provided //// via resorption (above). //double Nuptake = 0.0; //if (SiteVars.MineralN[site] >= adjNdemand) //{ // SiteVars.MineralN[site] -= adjNdemand; // mineralNused = adjNdemand; // Nuptake = adjNdemand; //} //else //{ // double NdemandAdjusted = SiteVars.MineralN[site]; // mineralNused = SiteVars.MineralN[site]; // SiteVars.MineralN[site] = 0.0; // Nuptake = SiteVars.MineralN[site]; //} //SiteVars.TotalNuptake[site] += Nuptake; if (totalMortality[0] <= 0.0 || cohort.WoodBiomass <= 0.0) totalMortality[0] = 0.0; if (totalMortality[1] <= 0.0 || cohort.LeafBiomass <= 0.0) totalMortality[1] = 0.0; if ((totalMortality[0]) > cohort.WoodBiomass) { PlugIn.ModelCore.UI.WriteLine("Warning: WOOD Mortality exceeds cohort wood biomass. M={0:0.0}, B={1:0.0}", (totalMortality[0]), cohort.WoodBiomass); PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.0}, Mgrow={1:0.0},", mortalityAge[0], mortalityGrowth[0]); throw new ApplicationException("Error: WOOD Mortality exceeds cohort biomass"); } if ((totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass) > 0.01) { PlugIn.ModelCore.UI.WriteLine("Warning: LEAF Mortality exceeds cohort biomass. Mortality={0:0.000}, Leafbiomass={1:0.000}", (totalMortality[1] + defoliatedLeafBiomass), cohort.LeafBiomass); PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.00}, Mgrow={1:0.00}, Mdefo={2:0.000},", mortalityAge[1], mortalityGrowth[1], defoliatedLeafBiomass); throw new ApplicationException("Error: LEAF Mortality exceeds cohort biomass"); } float deltaWood = (float)(actualANPP[0] - totalMortality[0]); float deltaLeaf = (float)(actualANPP[1] - totalMortality[1] - defoliatedLeafBiomass); float[] deltas = new float[2] { deltaWood, deltaLeaf }; UpdateDeadBiomass(cohort, site, totalMortality); CalculateNPPcarbon(site, actualANPP); AvailableN.AdjustAvailableN(cohort, site, actualANPP); if (OtherData.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0) { Outputs.CalibrateLog.WriteLine("{0:0.00}, {1:0.00}, {2:0.00}, {3:0.00},", deltaWood, deltaLeaf, totalMortality[0], totalMortality[1]); } return deltas; }
//--------------------------------------------------------------------------- //... Originally from pprdwc(wc,x,pprpts) of CENTURY //...This funtion returns a value for potential plant production // due to water content. Basically you have an equation of a // line with a moveable y-intercept depending on the soil type. // The value passed in for x is ((avh2o(1) + prcurr(month) + irract)/pet) // pprpts(1): The minimum ratio of available water to pet which // would completely limit production assuming wc=0. // pprpts(2): The effect of wc on the intercept, allows the // user to increase the value of the intercept and // thereby increase the slope of the line. // pprpts(3): The lowest ratio of available water to pet at which // there is no restriction on production. private static double calculateWater_Limit(ActiveSite site, IEcoregion ecoregion, ISpecies species) { double pptprd = 0.0; double waterContent = EcoregionData.FieldCapacity[ecoregion] - EcoregionData.WiltingPoint[ecoregion]; double tmoist = EcoregionData.AnnualWeather[ecoregion].MonthlyPrecip[Century.Month]; //rain + irract; double pet = EcoregionData.AnnualWeather[ecoregion].MonthlyPET[Century.Month]; if (pet >= 0.01) { // Trees are allowed to access the whole soil profile -rm 2/97 // pptprd = (avh2o(1) + tmoist) / pet pptprd = (SiteVars.AvailableWater[site] + tmoist) / pet; //pptprd = SiteVars.AvailableWater[site] / pet; //PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}. AvailH20={2:0.0}, MonthPPT={3:0.0}, PET={4:0.0}.", PlugIn.ModelCore.CurrentTime, month, SiteVars.AvailableWater[site],tmoist,pet); } else pptprd = 0.01; //...The equation for the y-intercept (intcpt) is A+B*WC. A and B // determine the effect of soil texture on plant production based // on moisture. //...Old way: // intcpt = 0.0 + 1.0 * wc // The second point in the equation is (.8,1.0) // slope = (1.0-0.0)/(.8-intcpt) // pprdwc = 1.0+slope*(x-.8) //...New way: double pprpts1 = OtherData.PPRPTS1; double pprpts2 = FunctionalType.Table[SpeciesData.FuncType[species]].PPRPTS2; double pprpts3 = FunctionalType.Table[SpeciesData.FuncType[species]].PPRPTS3; double intcpt = pprpts1 + (pprpts2 * waterContent); double slope = 1.0 / (pprpts3 - intcpt); double pprdwc = 1.0 + slope * (pptprd - pprpts3); if (pprdwc > 1.0) pprdwc = 1.0; if (pprdwc < 0.01) pprdwc = 0.01; //PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}. AvailH20={2:0.0}, MonthlyPPT={3:0.0}, PET={4:0.0}, PPTPRD={5:0.0}, Limit={6:0.0}.", PlugIn.ModelCore.CurrentTime, month, SiteVars.AvailableWater[site],tmoist, pet,pptprd,pprdwc); return pprdwc; }
//--------------------------------------------------------------------- public void SetMinRelativeBiomass(byte shadeClass, IEcoregion ecoregion, InputValue<Percentage> newValue) { Debug.Assert(1 <= shadeClass && shadeClass <= 5); Debug.Assert(ecoregion != null); if (newValue != null) { if (newValue.Actual < 0.0 || newValue.Actual > 1.0) throw new InputValueException(newValue.String, "{0} is not between 0% and 100%", newValue.String); } minRelativeBiomass[shadeClass][ecoregion] = newValue; }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public float[] ComputeChange(ICohort cohort, ActiveSite site) { double siteBiomass = SiteVars.TotalWoodBiomass[site]; if(siteBiomass < 0) throw new ApplicationException("Error: Site biomass < 0"); ecoregion = Model.Core.Ecoregion[site]; // ****** Mortality ******* // Age-related mortality includes woody and standing leaf biomass. double[] mortalityAge = ComputeAgeMortality(cohort, site); // Growth-related mortality double[] mortalityGrowth = ComputeGrowthMortality(cohort); //, site, mortalityAge); double[] totalMortality = new double[2]{(mortalityAge[0] + mortalityGrowth[0]), (mortalityAge[1] + mortalityGrowth[1])}; if(totalMortality[0] <= 0.0 || cohort.WoodBiomass <= 0.0) totalMortality[0] = 0.0; if(totalMortality[1] <= 0.0 || cohort.LeafBiomass <= 0.0) totalMortality[1] = 0.0; if((totalMortality[0] + totalMortality[1]) > (cohort.WoodBiomass + cohort.LeafBiomass)) { UI.WriteLine("Warning: Mortality exceeds cohort biomass. M={0:0.0}, B={1:0.0}", (totalMortality[0] + totalMortality[1]), (cohort.WoodBiomass + cohort.LeafBiomass)); throw new ApplicationException("Error: Mortality exceeds cohort biomass"); } // ****** Growth ******* double[] actualANPP = ComputeActualANPP(cohort, site, siteBiomass, mortalityAge); double defoliatedLeafBiomass = 0.0; if(month == 6) //July = 6 { // Defoliation ranges from 1.0 (total) to none (0.0). double defoliation = CohortDefoliation.Compute(cohort, site, (int) siteBiomass); if(SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) defoliation += FireEffects.CrownScorching(cohort, SiteVars.FireSeverity[site]); if(defoliation > 1.0) defoliation = 1.0; defoliatedLeafBiomass = cohort.LeafBiomass * defoliation; if (defoliation > 0) totalMortality[1] = Math.Min(cohort.LeafBiomass, defoliatedLeafBiomass + totalMortality[1]); } //Ensure all translocated N is used and reduce available N double Nreduction = AvailableN.CohortUptakeAvailableN(cohort.Species, site, actualANPP); SiteVars.MineralN[site] -= Nreduction; float deltaWood = (float) (actualANPP[0] - totalMortality[0]); float deltaLeaf = (float) (actualANPP[1] - totalMortality[1]); float[] deltas = new float[2]{deltaWood, deltaLeaf}; CalculateNPPcarbon(site, actualANPP); UpdateDeadBiomass(cohort.Species, site, totalMortality); if(OtherData.CalibrateMode && Model.Core.CurrentTime > 0) { UI.WriteLine("Yr={0},Mo={1}. Spp={2}, Age={3}.", Model.Core.CurrentTime, month+1, cohort.Species.Name, cohort.Age); UI.WriteLine("Yr={0},Mo={1}. ANPPact={2:0.0}, M={3:0.0}.", Model.Core.CurrentTime, month + 1, (actualANPP[0] + actualANPP[1]), (totalMortality[0] + totalMortality[1])); } return deltas; }
private IClimateRecord[,] AnnualClimate_AvgDaily(IEcoregion ecoregion, int year, double latitude) { IClimateRecord[,] timestepData = new IClimateRecord[Climate.ModelCore.Ecoregions.Count, 366]; IClimateRecord[,] avgEcoClimate = new IClimateRecord[Climate.ModelCore.Ecoregions.Count, MaxDayInYear]; IClimateRecord[,] ecoClimateT = new IClimateRecord[Climate.ModelCore.Ecoregions.Count, MaxDayInYear]; for (int i = 0; i < MaxDayInYear; i++) { this.DailyMinTemp[i] = 0.0; this.DailyMaxTemp[i] = 0.0; this.DailyVarTemp[i] = 0.0; this.DailyPptVarTemp[i] = 0.0; this.DailyPrecip[i] = 0.0; this.DailyPAR[i] = 0.0; } int allDataCount = 0; if (this.climatePhase == Climate.Phase.Future_Climate) allDataCount = Climate.Future_AllData.Count; else if (this.climatePhase == Climate.Phase.SpinUp_Climate) allDataCount = Climate.Spinup_AllData.Count; for (int day = 0; day < MaxDayInYear; day++) { for (int stp = 0; stp < allDataCount; stp++) { if (this.climatePhase == Climate.Phase.Future_Climate) timestepData = Climate.Future_AllData.ElementAt(stp).Value; else if (this.climatePhase == Climate.Phase.SpinUp_Climate) timestepData = Climate.Spinup_AllData.ElementAt(stp).Value; ecoClimateT[ecoregion.Index, day] = timestepData[ecoregion.Index, day]; //Climate.TimestepData[ecoregion.Index, day]; if (ecoClimateT[ecoregion.Index, day] != null) { this.DailyMinTemp[day] += ecoClimateT[ecoregion.Index, day].AvgMinTemp; this.DailyMaxTemp[day] += ecoClimateT[ecoregion.Index, day].AvgMaxTemp; this.DailyVarTemp[day] += ecoClimateT[ecoregion.Index, day].AvgVarTemp; this.DailyPptVarTemp[day] += ecoClimateT[ecoregion.Index, day].AvgPptVarTemp; this.DailyPrecip[day] += ecoClimateT[ecoregion.Index, day].AvgPpt; this.DailyPAR[day] += ecoClimateT[ecoregion.Index, day].PAR; } } this.DailyMinTemp[day] = this.DailyMinTemp[day] / allDataCount; this.DailyMaxTemp[day] = this.DailyMaxTemp[day] / allDataCount; this.DailyVarTemp[day] = this.DailyVarTemp[day] / allDataCount; this.DailyPptVarTemp[day] = this.DailyPptVarTemp[day] / allDataCount; this.DailyPrecip[day] = this.DailyPrecip[day] / allDataCount; //This DailyPrecip avg is the historic average so the average should be taken as opposed to summing that up. this.DailyPAR[day] = this.DailyPAR[day] / allDataCount; avgEcoClimate[ecoregion.Index, day] = new ClimateRecord(); avgEcoClimate[ecoregion.Index, day].AvgMinTemp = this.DailyMinTemp[day]; avgEcoClimate[ecoregion.Index, day].AvgMaxTemp = this.DailyMaxTemp[day]; avgEcoClimate[ecoregion.Index, day].AvgVarTemp = this.DailyVarTemp[day]; avgEcoClimate[ecoregion.Index, day].StdDevTemp = Math.Sqrt(DailyVarTemp[day]); avgEcoClimate[ecoregion.Index, day].AvgPptVarTemp = this.DailyPptVarTemp[day]; avgEcoClimate[ecoregion.Index, day].AvgPpt = this.DailyPrecip[day]; avgEcoClimate[ecoregion.Index, day].StdDevPpt = Math.Sqrt(this.DailyPrecip[day]); avgEcoClimate[ecoregion.Index, day].PAR = this.DailyPAR[day]; } return avgEcoClimate; }
//--------------------------------------------------------------------- /// <summary> /// Decomposition of soil organic matter and mineralization of N/P. /// C:N ratio should be rough average of C:Ns at limit value transfers. /// </summary> public static void Decompose(IEcoregion ecoregion, ActiveSite site) { double k = DecayRateSOM[ecoregion]; SiteVars.SoilOrganicMatter[site].Mass = SiteVars.SoilOrganicMatter[site].Mass * Math.Exp(-1 * k); SiteVars.SoilOrganicMatter[site].ContentC = SiteVars.SoilOrganicMatter[site].ContentC * Math.Exp(-1 * k); SiteVars.SoilOrganicMatter[site].MineralizedN = SiteVars.SoilOrganicMatter[site].ContentN - (SiteVars.SoilOrganicMatter[site].ContentN * Math.Exp(-1 * k)); SiteVars.SoilOrganicMatter[site].ContentN = Math.Max(SiteVars.SoilOrganicMatter[site].ContentN - SiteVars.SoilOrganicMatter[site].MineralizedN, 0); SiteVars.MineralSoil[site].ContentN += SiteVars.SoilOrganicMatter[site].MineralizedN; SiteVars.SoilOrganicMatter[site].MineralizedP = SiteVars.SoilOrganicMatter[site].ContentP - (SiteVars.SoilOrganicMatter[site].ContentP * Math.Exp(-1 * k)); SiteVars.SoilOrganicMatter[site].ContentP = Math.Max(SiteVars.SoilOrganicMatter[site].ContentP - SiteVars.SoilOrganicMatter[site].MineralizedP, 0); SiteVars.MineralSoil[site].ContentP += SiteVars.SoilOrganicMatter[site].MineralizedP; }
//For Sequenced and Random timeStep arg should be passed public AnnualClimate_Daily(IEcoregion ecoregion, int actualYear, double latitude, Climate.Phase spinupOrfuture = Climate.Phase.Future_Climate, int timeStep = Int32.MinValue) { this.climatePhase = spinupOrfuture; IClimateRecord[,] timestepData = new IClimateRecord[Climate.ModelCore.Ecoregions.Count, 366]; string climateOption = Climate.ConfigParameters.ClimateTimeSeries; if (this.climatePhase == Climate.Phase.SpinUp_Climate) climateOption = Climate.ConfigParameters.SpinUpClimateTimeSeries; //Climate.ModelCore.UI.WriteLine(" Calculating daily data ... Ecoregion = {0}, Year = {1}, timestep = {2}.", ecoregion.Name, actualYear, timeStep); switch (climateOption) { case "Daily_RandomYear": { TimeStep = timeStep; if (this.climatePhase == Climate.Phase.Future_Climate) timestepData = Climate.Future_AllData[Climate.RandSelectedTimeSteps_future[TimeStep]]; else if (this.climatePhase == Climate.Phase.SpinUp_Climate) timestepData = Climate.Spinup_AllData[Climate.RandSelectedTimeSteps_future[TimeStep]]; break; } case "Daily_AverageAllYears": { if (this.climatePhase == Climate.Phase.Future_Climate) timestepData = AnnualClimate_AvgDaily(ecoregion, actualYear, latitude); else if (this.climatePhase == Climate.Phase.SpinUp_Climate) timestepData = AnnualClimate_AvgDaily(ecoregion, actualYear, latitude); break; } case "Daily_SequencedYears": { TimeStep = timeStep; try { timestepData = Climate.Future_AllData[TimeStep]; } catch (System.Collections.Generic.KeyNotFoundException ex) { throw new ClimateDataOutOfRangeException("Exception: The requested Time-step or ecoregion is out of range of the provided " + this.climatePhase.ToString() + " input file. This may be because the number of input climate data is not devisable to the number of specified time-steps or there is not enough historic climate data to run the model for the specified duration.", ex); } break; } default: throw new ApplicationException(String.Format("Unknown Climate Time Series: {}", climateOption)); } IClimateRecord[] ecoClimate = new IClimateRecord[MaxDayInYear]; this.Year = actualYear; this.AnnualPrecip = 0.0; for (int day = 0; day < MaxDayInYear; day++) { ecoClimate[day] = timestepData[ecoregion.Index, day]; if (ecoClimate[day] != null) { double DailyAvgTemp = (ecoClimate[day].AvgMinTemp + ecoClimate[day].AvgMaxTemp) / 2.0; //Climate.ModelCore.UI.WriteLine("Timestep Data. PPt={0}, T={1}.", ecoClimate[day].AvgPpt, DailyAvgTemp); this.DailyTemp[day] = DailyAvgTemp; this.DailyMinTemp[day] = ecoClimate[day].AvgMinTemp; this.DailyMaxTemp[day] = ecoClimate[day].AvgMaxTemp; this.DailyPrecip[day] = Math.Max(0.0, ecoClimate[day].AvgPpt); this.DailyPAR[day] = ecoClimate[day].PAR; this.AnnualPrecip += this.DailyPrecip[day]; if (this.DailyPrecip[day] < 0) this.DailyPrecip[day] = 0; double hr = CalculateDayNightLength(day, latitude); this.DailyDayLength[day] = (60.0 * 60.0 * hr); // seconds of daylight/day this.DailyNightLength[day] = (60.0 * 60.0 * (24 - hr)); // seconds of nighttime/day //this.DOY[day] = DayOfYear(day); } else { Climate.ModelCore.UI.WriteLine("Daily data = null."); } } this.beginGrowing = CalculateBeginGrowingDay_Daily(); //ecoClimate); this.endGrowing = CalculateEndGrowingDay_Daily(ecoClimate); this.growingDegreeDays = GrowSeasonDegreeDays(actualYear); //if (Climate.TimestepData.GetLength(1) > 365) if (timestepData.GetLength(1) > 365) this.isLeapYear = true; }
//--------------------------------------------------------------------- // Generates new climate parameters for a SINGLE ECOREGION at an annual time step. public static void SetSingleAnnualClimate(IEcoregion ecoregion, int year, Climate.Phase spinupOrfuture) { int actualYear = Climate.Future_MonthlyData.Keys.Min() + year; if (spinupOrfuture == Climate.Phase.Future_Climate) { //PlugIn.ModelCore.UI.WriteLine("Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); if (Climate.Future_MonthlyData.ContainsKey(actualYear)) { AnnualWeather[ecoregion] = Climate.Future_MonthlyData[actualYear][ecoregion.Index]; } //else // PlugIn.ModelCore.UI.WriteLine("Key is missing: Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); } else { //PlugIn.ModelCore.UI.WriteLine("Retrieving {0} for year {1}.", spinupOrfuture.ToString(), actualYear); if (Climate.Spinup_MonthlyData.ContainsKey(actualYear)) { AnnualWeather[ecoregion] = Climate.Spinup_MonthlyData[actualYear][ecoregion.Index]; } } }
//--------------------------------------------------------------------- /// <summary> /// Add nitrogen and phosphorus deposition to the mineral pools. /// </summary> public static void Deposition(IEcoregion ecoregion, MineralSoil mineralSoil) { mineralSoil.ContentN += EcoregionData.DepositionN[ecoregion]; mineralSoil.ContentP += EcoregionData.DepositionP[ecoregion]; }
public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude, double fieldCapacity, double wiltingPoint) { // JM: these next three lines are not currently used, but may need to be modified if used: //int numberOftimeSteps = Climate.ModelCore.EndTime - Climate.ModelCore.StartTime; //annualPDSI = new double[Climate.ModelCore.Ecoregions.Count, future_allData.Count]; //landscapeAnnualPDSI = new double[future_allData.Count]; double[] temperature_normals = new double[12]; double[] precip_normals = new double[12]; double availableWaterCapacity = fieldCapacity - wiltingPoint; Climate.TextLog.WriteLine("Core.StartTime = {0}, Core.EndTime = {1}.", ModelCore.StartTime, ModelCore.EndTime); //Climate.TextLog.WriteLine(" Climate.LandscapeAnnualPDSI.Length = {0}.", Climate.LandscapeAnnualPDSI.Length); //First Calculate Climate Normals from Spin-up data int timeStepIndex = 0; foreach (KeyValuePair<int, AnnualClimate_Monthly[]> timeStep in Spinup_MonthlyData) { //Climate.TextLog.WriteLine(" Calculating Weather for SPINUP: timeStep = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.SpinUp_Climate, timeStep.Key, timeStepIndex); Spinup_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] += annualClimateMonthly.MonthlyTemp[mo]; precip_normals[mo] += annualClimateMonthly.MonthlyPrecip[mo]; } timeStepIndex++; } // Calculate AVERAGE T normal. for (int mo = 0; mo < 12; mo++) { temperature_normals[mo] /= (double)Spinup_MonthlyData.Count; precip_normals[mo] /= (double)Spinup_MonthlyData.Count; //Climate.TextLog.WriteLine("Month = {0}, Original Monthly T normal = {1}", mo, month_Temp_normal[mo]); } timeStepIndex = 0; //PDSI_Calculator.InitializeEcoregion_PDSI(temperature_normals, precip_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); foreach (KeyValuePair<int, AnnualClimate_Monthly[]> timeStep in Future_MonthlyData) { //Climate.TextLog.WriteLine(" Completed calculations for Future_Climate: TimeStepYear = {0}, actualYear = {1}", timeStep.Key, startYear + timeStep.Key); AnnualClimate_Monthly annualClimateMonthly = new AnnualClimate_Monthly(ecoregion, latitude, Climate.Phase.Future_Climate, timeStep.Key, timeStepIndex); Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index] = annualClimateMonthly; // Next calculate PSDI for the future data //Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculateEcoregion_PDSI(annualClimateMonthly, temperature_normals, precip_normals, availableWaterCapacity, latitude, UnitSystem.metrics, ecoregion); //Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI = PDSI_Calculator.CalculateEcoregion_PDSI(annualClimateMonthly, temperature_normals, precip_normals, latitude, UnitSystem.metrics, ecoregion); // Climate.LandscapeAnnualPDSI[timeStepIndex] += (Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI / Climate.ModelCore.Ecoregions.Count); //Climate.TextLog.WriteLine("Calculated PDSI for Ecoregion {0}, timestep {1}, PDSI Year {2}; PDSI={3:0.00}.", ecoregion.Name, timeStepIndex, timeStep.Key, Future_MonthlyData[startYear + timeStep.Key][ecoregion.Index].PDSI); timeStepIndex++; WriteAnnualLog(ecoregion, startYear + timeStep.Key, annualClimateMonthly); } }
public static int PressureHead(IEcoregion ecoregion, ushort Water) { return Pressureheadtable[ecoregion, Water]; }
//--------------------------------------------------------------------- private static void WriteAnnualLog(IEcoregion ecoregion, int year, AnnualClimate_Monthly annualClimateMonthly) { AnnualLog.Clear(); AnnualLog al = new AnnualLog(); //al.SimulationPeriod = TBD al.Time = year; al.EcoregionName = ecoregion.Name; al.EcoregionIndex = ecoregion.Index; al.BeginGrow = annualClimateMonthly.BeginGrowing; al.EndGrow = annualClimateMonthly.EndGrowing; al.TAP = annualClimateMonthly.TotalAnnualPrecip; al.MAT = annualClimateMonthly.MeanAnnualTemperature; al.PDSI = Future_MonthlyData[year][ecoregion.Index].PDSI; AnnualLog.AddObject(al); AnnualLog.WriteToFile(); }
//--------------------------------------------------------------------- public void SetAET(IEcoregion ecoregion, InputValue<int> newValue) { Debug.Assert(ecoregion != null); aet[ecoregion] = Util.CheckBiomassParm(newValue, 0, 10000); //FIXME: FIND GOOD MAXIMUM }
//--------------------------------------------------------------------- /// <summary> /// Computes the Annual Net Primary Productivity (ANPP) for a cohort, /// adjusted for age-related mortality (M_AGE). /// </summary> private void ComputeAdjustedANPP(ICohort cohort, ActiveSite site, int siteBiomass, int prevYearSiteMortality) { this.site = site; ecoregion = Model.Core.Ecoregion[site]; B_ij = cohort.Biomass; species = cohort.Species; B_MAX_Spp = LivingBiomass.B_MAX_i[species][ecoregion]; ANPP_MAX_i = LivingBiomass.ANPP_MAX_i[species][ecoregion]; ComputeActualANPP(siteBiomass, prevYearSiteMortality); // M_AGE_ij: Age related mortality: wood only ComputeAgeMortality(cohort.Age); // Age mortality is discounted from ANPP to prevent the over- // estimation of mortality. ANPP_ACT_ij -= M_AGE_ij; // Ensure that ANPP is not negative. ANPP_ACT_ij = Math.Max(0, ANPP_ACT_ij); }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public float[] ComputeChange(ICohort cohort, ActiveSite site) { ecoregion = PlugIn.ModelCore.Ecoregion[site]; // First call to the Calibrate Log: if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode) Outputs.CalibrateLog.Write("{0}, {1}, {2}, {3}, {4}, {5:0.0}, {6:0.0}, ", PlugIn.ModelCore.CurrentTime, Century.Month + 1, ecoregion.Index, cohort.Species.Name, cohort.Age, cohort.WoodBiomass, cohort.LeafBiomass); double siteBiomass = Century.ComputeLivingBiomass(SiteVars.Cohorts[site]); if(siteBiomass < 0) throw new ApplicationException("Error: Site biomass < 0"); // ****** Mortality ******* // Age-related mortality includes woody and standing leaf biomass. double[] mortalityAge = ComputeAgeMortality(cohort, site); // Growth-related mortality double[] mortalityGrowth = ComputeGrowthMortality(cohort, site); double[] totalMortality = new double[2]{(mortalityAge[0] + mortalityGrowth[0]), (mortalityAge[1] + mortalityGrowth[1])}; if(totalMortality[0] <= 0.0 || cohort.WoodBiomass <= 0.0) totalMortality[0] = 0.0; if(totalMortality[1] <= 0.0 || cohort.LeafBiomass <= 0.0) totalMortality[1] = 0.0; if((totalMortality[0] + totalMortality[1]) > (cohort.WoodBiomass + cohort.LeafBiomass)) { PlugIn.ModelCore.Log.WriteLine("Warning: Mortality exceeds cohort biomass. M={0:0.0}, B={1:0.0}", (totalMortality[0] + totalMortality[1]), (cohort.WoodBiomass + cohort.LeafBiomass)); PlugIn.ModelCore.Log.WriteLine("Warning: If M>B, then list mortality. Mage0={0:0.0}, Mgrow0={1:0.0}, Mage1={2:0.0}, Mgrow1={3:0.0},", mortalityAge[0], mortalityGrowth[0], mortalityAge[1] + mortalityGrowth[1]); throw new ApplicationException("Error: Mortality exceeds cohort biomass"); } // ****** Growth ******* double[] actualANPP = ComputeActualANPP(cohort, site, siteBiomass, mortalityAge); double defoliatedLeafBiomass = 0.0; double scorch = 0.0; if(Century.Month == 6) //July = 6 { // Defoliation ranges from 1.0 (total) to none (0.0). defoliation = CohortDefoliation.Compute(cohort, site, (int) siteBiomass); if(defoliation > 1.0) defoliation = 1.0; defoliatedLeafBiomass = cohort.LeafBiomass * defoliation; ForestFloor.AddFrassLitter(defoliatedLeafBiomass, cohort.Species, site); if (defoliation > 0) totalMortality[1] = Math.Min(cohort.LeafBiomass, defoliatedLeafBiomass + totalMortality[1]); if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0) scorch = FireEffects.CrownScorching(cohort, SiteVars.FireSeverity[site]); if (scorch > 0.0) // NEED TO DOUBLE CHECK WHAT CROWN SCORCHING RETURNS totalMortality[1] = Math.Min(cohort.LeafBiomass, scorch + totalMortality[1]); } double totalNdemand = AvailableN.CalculateCohortNDemand(cohort.Species, site, actualANPP); double adjNdemand = totalNdemand; double resorbedNused = 0.0; double mineralNused = 0.0; // Treat Resorbed N first and only if it is spring time. if (Century.Month > 2 && Century.Month < 6) { double resorbedNallocation = Math.Max(0.0, AvailableN.GetResorbedNallocation(cohort)); resorbedNused = resorbedNallocation - Math.Max(0.0, resorbedNallocation - totalNdemand); AvailableN.SetResorbedNallocation(cohort, Math.Max(0.0, resorbedNallocation - totalNdemand)); adjNdemand = Math.Max(0.0, totalNdemand - resorbedNallocation); } // Reduce available N after taking into account that some N may have been provided // via resorption (above). double Nuptake = 0.0; if (SiteVars.MineralN[site] >= adjNdemand) { SiteVars.MineralN[site] -= adjNdemand; mineralNused = adjNdemand; Nuptake = adjNdemand; } else { double NdemandAdjusted = SiteVars.MineralN[site]; mineralNused = SiteVars.MineralN[site]; SiteVars.MineralN[site] = 0.0; //actualANPP[0] = NdemandAdjusted / adjNdemand; //actualANPP[1] = NdemandAdjusted / adjNdemand; Nuptake = SiteVars.MineralN[site]; // *NdemandAdjusted / adjNdemand; //PlugIn.ModelCore.Log.WriteLine("Yr={0},Mo={1}. Adjusted ANPP: ANPPleaf={2:0.0}, ANPPwood={3:0.0}.", PlugIn.ModelCore.CurrentTime, month + 1, actualANPP[1], actualANPP[0]); } SiteVars.TotalNuptake[site] += Nuptake; float deltaWood = (float) (actualANPP[0] - totalMortality[0]); float deltaLeaf = (float)(actualANPP[1] - totalMortality[1]); float[] deltas = new float[2]{deltaWood, deltaLeaf}; UpdateDeadBiomass(cohort.Species, site, totalMortality); CalculateNPPcarbon(site, actualANPP); if (OtherData.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0) { Outputs.CalibrateLog.Write("{0:0.00}, {1:0.00}, {2:0.00}, {3:0.00},", deltaWood, deltaLeaf, totalMortality[0], totalMortality[1]); Outputs.CalibrateLog.WriteLine("{0:0.00}, {1:0.00}, {2:0.00}", resorbedNused, mineralNused, totalNdemand); } return deltas; }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public int ComputeChange(ICohort cohort, ActiveSite site, int siteBiomass, int prevYearSiteMortality) { ecoregion = Model.Core.Ecoregion[site]; // First, calculate age-related mortality. // Age-related mortality will include woody and standing leaf biomass (=0 for deciduous trees). double mortalityAge = ComputeAgeMortality(cohort); double actualANPP = ComputeActualANPP(cohort, site, siteBiomass, prevYearSiteMortality); // Age mortality is discounted from ANPP to prevent the over- // estimation of mortality. ANPP cannot be negative. actualANPP = Math.Max(0, actualANPP - mortalityAge); // Growth-related mortality double mortalityGrowth = ComputeGrowthMortality(cohort, site); // Age-related mortality is discounted from growth-related // mortality to prevent the under-estimation of mortality. Cannot be negative. mortalityGrowth = Math.Max(0, mortalityGrowth - mortalityAge); // Also ensure that growth mortality does not exceed actualANPP. mortalityGrowth = Math.Min(mortalityGrowth, actualANPP); // Total mortality for the cohort double totalMortality = mortalityAge + mortalityGrowth; if(totalMortality > cohort.Biomass) throw new ApplicationException("Error: Mortality exceeds cohort biomass"); int deltaBiomass = (int) (actualANPP - totalMortality); double newBiomass = cohort.Biomass + (double) deltaBiomass; double totalLitter = UpdateDeadBiomass(cohort, actualANPP, totalMortality, site, newBiomass); //UI.WriteLine("Age={0}, ANPPact={1:0.0}, M={2:0.0}, litter={3:0.00}.", cohort.Age, actualANPP, totalMortality, totalLitter); return deltaBiomass; }
//--------------------------------------------------------------------- // Generates new climate parameters at an annual time step. // Note: During the spin-up phase of growth, the same annual climates will // be used repeatedly in order. public static void SetAnnualClimate(IEcoregion ecoregion, int year) { int actualYear = PlugIn.ModelCore.CurrentTime + year; if(actualYear == 0 || actualYear != AnnualWeather[ecoregion].Year) { //PlugIn.ModelCore.Log.WriteLine(" SETTING ANNAUL CLIMATE: Yr={0}, SimYr={1}, Eco={2}.", year, actualYear, ecoregion.Name); AnnualWeather[ecoregion] = AnnualClimateArray[ecoregion][year]; AnnualWeather[ecoregion].SetAnnualN(EcoregionData.AtmosNslope[ecoregion], EcoregionData.AtmosNintercept[ecoregion]); string weatherWrite = AnnualWeather[ecoregion].Write(); //PlugIn.ModelCore.Log.WriteLine("{0}", weatherWrite); } }
// Overload method without field capacity and wilting point. RMS added 9/7/2016 // If using this method, CANNOT calculate AET or PDSI. Note: PDSI not working regardless. public static void GenerateEcoregionClimateData(IEcoregion ecoregion, int startYear, double latitude) { GenerateEcoregionClimateData(ecoregion, startYear, latitude, 20.0, 10.0); }
//--------------------------------------------------------------------- /// <summary> /// Computes the change in a cohort's biomass due to Annual Net Primary /// Productivity (ANPP), age-related mortality (M_AGE), and development- /// related mortality (M_BIO). /// </summary> public int ComputeChange(ICohort cohort, ActiveSite site, int siteBiomass, int prevYearSiteMortality) { ecoregion = PlugIn.ModelCore.Ecoregion[site]; // First, calculate age-related mortality. // Age-related mortality will include woody and standing leaf biomass (=0 for deciduous trees). double mortalityAge = ComputeAgeMortality(cohort); double actualANPP = ComputeActualANPP(cohort, site, siteBiomass, prevYearSiteMortality); // Age mortality is discounted from ANPP to prevent the over- // estimation of mortality. ANPP cannot be negative. actualANPP = Math.Max(1, actualANPP - mortalityAge); SiteVars.AGNPP[site] += actualANPP; // Growth-related mortality double mortalityGrowth = ComputeGrowthMortality(cohort, site, siteBiomass); // Age-related mortality is discounted from growth-related // mortality to prevent the under-estimation of mortality. Cannot be negative. mortalityGrowth = Math.Max(0, mortalityGrowth - mortalityAge); // Also ensure that growth mortality does not exceed actualANPP. mortalityGrowth = Math.Min(mortalityGrowth, actualANPP); // Total mortality for the cohort double totalMortality = mortalityAge + mortalityGrowth; if (totalMortality > cohort.Biomass) throw new ApplicationException("Error: Mortality exceeds cohort biomass"); // Defoliation ranges from 1.0 (total) to none (0.0). defoliation = CohortDefoliation.Compute(cohort, site, siteBiomass); double defoliationLoss = 0.0; if (defoliation > 0) { double standing_nonwood = ComputeFractionANPPleaf(cohort.Species) * actualANPP; defoliationLoss = standing_nonwood * defoliation; } int deltaBiomass = (int)(actualANPP - totalMortality - defoliationLoss); double newBiomass = cohort.Biomass + (double)deltaBiomass; double totalLitter = UpdateDeadBiomass(cohort, actualANPP, totalMortality, site, newBiomass); //CalculateCohortLAI(cohort, actualANPP, newBiomass, site); CalculateCohortLight(cohort, actualANPP, newBiomass, site); if (PlugIn.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0) { PlugIn.ModelCore.Log.WriteLine("Yr={0}. Calculate Delta Biomass...", (PlugIn.ModelCore.CurrentTime+SubYear)); PlugIn.ModelCore.Log.WriteLine("Yr={0}. Spp={1}, Age={2}.", (PlugIn.ModelCore.CurrentTime+SubYear), cohort.Species.Name, cohort.Age); PlugIn.ModelCore.Log.WriteLine("Yr={0}. ANPPact={1:0.0}, Mtotal={2:0.0}, litter={3:0.00}.", (PlugIn.ModelCore.CurrentTime+SubYear), actualANPP, totalMortality, totalLitter); PlugIn.ModelCore.Log.WriteLine("Yr={0}. DeltaB={1:0.0}, CohortB={2}, Bsite={3}", (PlugIn.ModelCore.CurrentTime+SubYear), deltaBiomass, cohort.Biomass, (int) siteBiomass); } return deltaBiomass; }
private void CalculateMonthlyData_NoVariance(IEcoregion ecoregion, ClimateRecord[][] timestepData, int actualYear, double latitude) { ClimateRecord[] ecoClimate = new ClimateRecord[12]; this.Year = actualYear; this.TotalAnnualPrecip = 0.0; for (int mo = 0; mo < 12; mo++) { //Climate.ModelCore.UI.WriteLine(" Calculating Monthly Climate (No Variance): Yr={0}, month={1}, Eco={2}, Phase={3}.", actualYear, mo, ecoregion.Name, this.climatePhase); ecoClimate[mo] = timestepData[ecoregion.Index][mo]; double MonthlyAvgTemp = (ecoClimate[mo].AvgMinTemp + ecoClimate[mo].AvgMaxTemp) / 2.0; this.MonthlyTemp[mo] = MonthlyAvgTemp; this.MonthlyMinTemp[mo] = ecoClimate[mo].AvgMinTemp; this.MonthlyMaxTemp[mo] = ecoClimate[mo].AvgMaxTemp; this.MonthlyPrecip[mo] = Math.Max(0.0, ecoClimate[mo].AvgPpt); this.MonthlyPAR[mo] = ecoClimate[mo].AvgPAR; this.MonthlyWindDirection[mo] = ecoClimate[mo].AvgWindDirection; this.MonthlyWindSpeed[mo] = ecoClimate[mo].AvgWindSpeed; this.MonthlyNDeposition[mo] = ecoClimate[mo].AvgNDeposition; this.TotalAnnualPrecip += this.MonthlyPrecip[mo]; if (this.MonthlyPrecip[mo] < 0) this.MonthlyPrecip[mo] = 0; double hr = CalculateDayLength(mo, latitude); this.MonthlyDayLength[mo] = (60.0 * 60.0 * hr); // seconds of daylight/day this.MonthlyNightLength[mo] = (60.0 * 60.0 * (24 - hr)); // seconds of nighttime/day } this.MeanAnnualTemperature = CalculateMeanAnnualTemp(actualYear); }