示例#1
0
        //---------------------------------------------------------------------

        /// <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);
        }
示例#2
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);
        }
示例#3
0
        // ------------------------------------------------------------------------------------------------------
        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);
        }
示例#4
0
        // 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;
        }
示例#5
0
        //---------------------------------------------------------------------

        /// <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);
        }
示例#6
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);
        }
示例#7
0
        //---------------------------------------------------------------------

        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);
        }
示例#8
0
        // 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;
        }
示例#9
0
        //---------------------------------------------------------------------
        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.
                }
            }
        }
示例#10
0
        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];
     }
 }
示例#15
0
        //---------------------------------------------------------------------

        /// <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);
     }
 }
示例#17
0
        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
        }
示例#18
0
        //---------------------------------------------------------------------

        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);
        }
示例#20
0
        //---------------------------------------------------------------------

        /// <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);
        }
示例#21
0
        //---------------------------------------------------------------------

        public T this[IEcoregion ecoregion]
        {
            get {
                return(values[ecoregion.Index]);
            }

            set {
                values[ecoregion.Index] = value;
            }
        }
示例#22
0
        //---------------------------------------------------------------------------
        //... 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]);
        }
示例#24
0
        //---------------------------------------------------------------------------
        //... 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];
        }
示例#27
0
        //---------------------------------------------------------------------
        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 Hydrology(IEcoregion ecoregion)
        {
            this.ecoregion = ecoregion;

            snowpack = 0;
            water = WHC[ecoregion];
            infiltration = 0;
            runoff = 0;
            preciploss = 0;
            transpiration = 0;
            AnnualTranspiration = 0;
        }
示例#30
0
        //---------------------------------------------------------------------

        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;
            }
        }
示例#31
0
        //---------------------------------------------------------------------

        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);
        }
示例#33
0
        //---------------------------------------------------------------------

        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);
        }