Example #1
0
        //---------------------------------------------------------------------------
        private static double MinJanuaryTempModifier(AnnualClimate_Monthly weather, ISpecies species)
        // Is the January mean temperature greater than the species specified minimum?
        {
            int speciesMinimum = SpeciesData.MinJanTemp[species];

            if (weather.MonthlyTemp[0] < speciesMinimum)
            {
                return(0.0);
            }
            else
            {
                return(1.0);
            }
        }
Example #2
0
        public static double Calculate(ISpecies species, ActiveSite site)//, int years)
        {
            IEcoregion climateRegion = PlugIn.ModelCore.Ecoregion[site];
            int        swhc          = (int)((SiteVars.SoilFieldCapacity[site] - SiteVars.SoilWiltingPoint[site]) * SiteVars.SoilDepth[site]);
            int        swhc_index    = PlugIn.SWHC_List.BinarySearch(swhc);

            double tempMultiplier       = 0.0;
            double soilMultiplier       = 0.0;
            double minJanTempMultiplier = 0.0;
            //if (!ecoregion.Active || ClimateRegionData.ActiveSiteCount[ecoregion] < 1)
            //    continue;

            double establishProbability = 0.0;

            AnnualClimate_Monthly ecoClimate = ClimateRegionData.AnnualWeather[climateRegion];

            if (ecoClimate == null)
            {
                throw new System.ApplicationException("Error in Establishment: CLIMATE NULL.");
            }

            double ecoDryDays = SiteVars.DryDays[site]; // CalculateSoilMoisture(ecoClimate, climateRegion, ecoClimate.Year);

            soilMultiplier       = SoilMoistureMultiplier(ecoClimate, species, ecoDryDays);
            tempMultiplier       = BotkinDegreeDayMultiplier(ecoClimate, species);
            minJanTempMultiplier = MinJanuaryTempModifier(ecoClimate, species);

            // Liebig's Law of the Minimum is applied to the four multipliers for each year:
            double minMultiplier = System.Math.Min(tempMultiplier, soilMultiplier);

            minMultiplier = System.Math.Min(minJanTempMultiplier, minMultiplier);

            establishProbability += minMultiplier;
            establishProbability *= PlugIn.ProbEstablishAdjust;

            avgSoilMoisturelimit[species.Index, climateRegion.Index, swhc_index] += soilMultiplier;
            avgMATlimit[species.Index, climateRegion.Index, swhc_index]          += tempMultiplier;
            avgJanuaryTlimit[species.Index, climateRegion.Index, swhc_index]     += minJanTempMultiplier;
            avgPest[species.Index, climateRegion.Index, swhc_index] += establishProbability;
            Climate_SWHC_Count[climateRegion.Index, swhc_index]++;

            //if (establishProbability > 0.0)
            //    PlugIn.ModelCore.UI.WriteLine("Spp={0}, Pest={1:0.000}: tM={2:0.0}, sM={3:0.0}, jM={4:0.0}", species.Name, establishProbability, tempMultiplier, soilMultiplier, minJanTempMultiplier);
            return(establishProbability);
        }
        //public static void InitializeLogFile()
        //{
        //    string logFileName   = "NECN-prob-establish-log.csv";
        //    PlugIn.ModelCore.UI.WriteLine("   Opening a NECN log file \"{0}\" ...", logFileName);
        //    try {
        //        log = Landis.Data.CreateTextFile(logFileName);
        //    }
        //    catch (Exception err) {
        //        string mesg = string.Format("{0}", err.Message);
        //        throw new System.ApplicationException(mesg);
        //    }

        //    log.AutoFlush = true;
        //    log.WriteLine("Time, Species, ClimateRegion, NumberSitesChecked, AvgTempMult, AvgMinJanTempMult, AvgSoilMoistureMult, AvgProbEst");
        //}

        public static double Calculate(ISpecies species, ActiveSite site)
        {
            IEcoregion climateRegion = PlugIn.ModelCore.Ecoregion[site];

            double tempMultiplier       = 0.0;
            double soilMultiplier       = 0.0;
            double minJanTempMultiplier = 0.0;
            double establishProbability = 0.0;

            AnnualClimate_Monthly ecoClimate = ClimateRegionData.AnnualWeather[climateRegion];

            if (ecoClimate == null)
            {
                throw new System.ApplicationException("Error in Establishment: CLIMATE NULL.");
            }

            double ecoDryDays = SiteVars.DryDays[site];

            soilMultiplier       = SoilMoistureMultiplier(ecoClimate, species, ecoDryDays);
            tempMultiplier       = BotkinDegreeDayMultiplier(ecoClimate, species);
            minJanTempMultiplier = MinJanuaryTempModifier(ecoClimate, species);

            // Liebig's Law of the Minimum is applied to the four multipliers for each year:
            double minMultiplier = System.Math.Min(tempMultiplier, soilMultiplier);

            minMultiplier = System.Math.Min(minJanTempMultiplier, minMultiplier);

            establishProbability += minMultiplier;
            establishProbability *= PlugIn.ProbEstablishAdjust;

            avgSoilMoisturelimit[species.Index, climateRegion.Index] += soilMultiplier;
            avgMATlimit[species.Index, climateRegion.Index]          += tempMultiplier;
            avgJanuaryTlimit[species.Index, climateRegion.Index]     += minJanTempMultiplier;
            avgPest[species.Index, climateRegion.Index] += establishProbability;

            avgDryDays[species.Index, climateRegion.Index]  += ecoDryDays;
            avgBeginGDD[species.Index, climateRegion.Index] += ecoClimate.BeginGrowing;
            avgEndGDD[species.Index, climateRegion.Index]   += ecoClimate.EndGrowing;

            numberCalculations[species.Index, climateRegion.Index]++;

            return(establishProbability);
        }
Example #4
0
        //---------------------------------------------------------------------------
        private static double CalculateSoilMoisture(AnnualClimate_Monthly weather, IEcoregion ecoregion, int year, ActiveSite site)
        // Calculate fraction of growing season with unfavorable soil moisture
        // for growth (Dry_Days_in_Grow_Seas) used in SoilMoistureMultiplier to determine soil
        // moisture growth multipliers.
        //
        // Simulates method of Thorthwaite and Mather (1957) as modified by Pastor and Post (1984).
        //
        // This method necessary to estimate annual soil moisture at the ECOREGION scale, whereas
        // the SiteVar AvailableWater exists at the site level and is updated monthly.

        //field_cap = centimeters of water the soil can hold at field capacity
        //field_dry = centimeters of water below which tree growth stops
        //            (-15 bars)
        // NOTE:  Because the original LINKAGES calculations were based on a 100 cm rooting depth,
        // 100 cm are used here, although soil depth may be given differently for Century
        // calculations.

        //beg_grow_seas = year day on which the growing season begins
        //end_grow_seas = year day on which the growing season ends
        //latitude = latitude of region (degrees north)

        {
            double xFieldCap,                                                                           //
                   waterAvail,                                                                          //
                   aExponentET,                                                                         //
                   oldWaterAvail,                                                                       //
                   monthlyRain,                                                                         //
                   potWaterLoss,                                                                        //
                   potentialET,
                   tempFac,                                                                             //
                   xAccPotWaterLoss,                                                                    //
                   changeSoilMoisture,                                                                  //
                   oldJulianDay,                                                                        //
                   dryDayInterp;                                                                        //
            double fieldCapacity = SiteVars.SoilFieldCapacity[site] * (double)SiteVars.SoilDepth[site]; // ClimateRegionData.SoilDepth[ecoregion];
            double wiltingPoint  = SiteVars.SoilWiltingPoint[site] * (double)SiteVars.SoilDepth[site];  // ClimateRegionData.SoilDepth[ecoregion];

            //double fieldCapacity = ClimateRegionData.FieldCapacity[ecoregion] * 100.0;
            //double wiltingPoint  = ClimateRegionData.WiltingPoint[ecoregion] * 100.0;

            //Initialize water content of soil in January to Field_Cap (mm)
            xFieldCap  = 10.0 * fieldCapacity;
            waterAvail = fieldCapacity;


            //Initialize Thornwaithe parameters:
            //
            //TE = temperature efficiency
            //aExponentET = exponent of evapotranspiration function
            //pot_et = potential evapotranspiration
            //aet = actual evapotranspiration
            //acc_pot_water_loss = accumulated potential water loss

            double actualET        = 0.0;
            double accPotWaterLoss = 0.0;
            double tempEfficiency  = 0.0;

            for (int i = 0; i < 12; i++)
            {
                tempFac = 0.2 * weather.MonthlyTemp[i];

                if (tempFac > 0.0)
                {
                    tempEfficiency += System.Math.Pow(tempFac, 1.514);
                }
            }

            aExponentET = 0.675 * System.Math.Pow(tempEfficiency, 3) -
                          77.1 * (tempEfficiency * tempEfficiency) +
                          17920.0 * tempEfficiency + 492390.0;
            aExponentET *= (0.000001);

            //Initialize the number of dry days and current day of year
            int    dryDays           = 0;
            double julianDay         = 15.0;
            double annualPotentialET = 0.0;


            for (int i = 0; i < 12; i++)
            {
                double daysInMonth = AnnualClimate.DaysInMonth(i, year);
                oldWaterAvail = waterAvail;
                monthlyRain   = weather.MonthlyPrecip[i];
                tempFac       = 10.0 * weather.MonthlyTemp[i];

                //Calc potential evapotranspiriation (potentialET) Thornwaite and Mather,
                //1957.  Climatology 10:83 - 311.
                if (tempFac > 0.0)
                {
                    potentialET = 1.6 * (System.Math.Pow((tempFac / tempEfficiency), aExponentET)) *
                                  AnnualClimate.LatitudeCorrection(i, PlugIn.Parameters.Latitude); //ClimateRegionData.Latitude[ecoregion]);
                }
                else
                {
                    potentialET = 0.0;
                }

                annualPotentialET += potentialET;

                //Calc potential water loss this month
                potWaterLoss = monthlyRain - potentialET;

                //If monthlyRain doesn't satisfy potentialET, add this month's potential
                //water loss to accumulated water loss from soil
                if (potWaterLoss < 0.0)
                {
                    accPotWaterLoss += potWaterLoss;
                    xAccPotWaterLoss = accPotWaterLoss * 10;

                    //Calc water retained in soil given so much accumulated potential
                    //water loss Pastor and Post. 1984.  Can. J. For. Res. 14:466:467.

                    waterAvail = fieldCapacity *
                                 System.Math.Exp((.000461 - 1.10559 / xFieldCap) * (-1.0 * xAccPotWaterLoss));

                    if (waterAvail < 0.0)
                    {
                        waterAvail = 0.0;
                    }

                    //changeSoilMoisture - during this month
                    changeSoilMoisture = waterAvail - oldWaterAvail;

                    //Calc actual evapotranspiration (AET) if soil water is drawn down
                    actualET += (monthlyRain - changeSoilMoisture);
                }

                //If monthlyRain satisfies potentialET, don't draw down soil water
                else
                {
                    waterAvail = oldWaterAvail + potWaterLoss;
                    if (waterAvail >= fieldCapacity)
                    {
                        waterAvail = fieldCapacity;
                    }
                    changeSoilMoisture = waterAvail - oldWaterAvail;

                    //If soil partially recharged, reduce accumulated potential
                    //water loss accordingly
                    accPotWaterLoss += changeSoilMoisture;

                    //If soil completely recharged, reset accumulated potential
                    //water loss to zero
                    if (waterAvail >= fieldCapacity)
                    {
                        accPotWaterLoss = 0.0;
                    }

                    //If soil water is not drawn upon, add potentialET to AET
                    actualET += potentialET;
                }

                oldJulianDay = julianDay;
                julianDay   += daysInMonth;
                dryDayInterp = 0.0;

                //Increment number of dry days, truncate
                //at end of growing season
                if ((julianDay > weather.BeginGrowing) && (oldJulianDay < weather.EndGrowing))
                {
                    if ((oldWaterAvail >= wiltingPoint) && (waterAvail >= wiltingPoint))
                    {
                        dryDayInterp += 0.0;  // NONE below wilting point
                    }
                    else if ((oldWaterAvail > wiltingPoint) && (waterAvail < wiltingPoint))
                    {
                        dryDayInterp = daysInMonth * (wiltingPoint - waterAvail) /
                                       (oldWaterAvail - waterAvail);
                        if ((oldJulianDay < weather.BeginGrowing) && (julianDay > weather.BeginGrowing))
                        {
                            if ((julianDay - weather.BeginGrowing) < dryDayInterp)
                            {
                                dryDayInterp = julianDay - weather.BeginGrowing;
                            }
                        }

                        if ((oldJulianDay < weather.EndGrowing) && (julianDay > weather.EndGrowing))
                        {
                            dryDayInterp = weather.EndGrowing - julianDay + dryDayInterp;
                        }

                        if (dryDayInterp < 0.0)
                        {
                            dryDayInterp = 0.0;
                        }
                    }
                    else if ((oldWaterAvail < wiltingPoint) && (waterAvail > wiltingPoint))
                    {
                        dryDayInterp = daysInMonth * (wiltingPoint - oldWaterAvail) /
                                       (waterAvail - oldWaterAvail);

                        if ((oldJulianDay < weather.BeginGrowing) && (julianDay > weather.BeginGrowing))
                        {
                            dryDayInterp = oldJulianDay + dryDayInterp - weather.BeginGrowing;
                        }

                        if (dryDayInterp < 0.0)
                        {
                            dryDayInterp = 0.0;
                        }

                        if ((oldJulianDay < weather.EndGrowing) && (julianDay > weather.EndGrowing))
                        {
                            if ((weather.EndGrowing - oldJulianDay) < dryDayInterp)
                            {
                                dryDayInterp = weather.EndGrowing - oldJulianDay;
                            }
                        }
                    }
                    else // ALL below wilting point
                    {
                        dryDayInterp = daysInMonth;

                        if ((oldJulianDay < weather.BeginGrowing) && (julianDay > weather.BeginGrowing))
                        {
                            dryDayInterp = julianDay - weather.BeginGrowing;
                        }

                        if ((oldJulianDay < weather.EndGrowing) && (julianDay > weather.EndGrowing))
                        {
                            dryDayInterp = weather.EndGrowing - oldJulianDay;
                        }
                    }

                    dryDays += (int)dryDayInterp;
                }
            }  //END MONTHLY CALCULATIONS

            //Convert AET from cm to mm
            //actualET *= 10.0;

            //Calculate AET multiplier
            //(used to be done in decomp)
            //float aetMf = min((double)AET,600.0);
            //AET_Mult = (-1. * aetMf) / (-1200. + aetMf);

            return(dryDays);
        }
        //---------------------------------------------------------------------
        // Note:  If the succession time step is > 0, then an average Pest is calculated,
        // based on each ecoregion-climate year.  The average is used because establishment
        // determines reproductive success, which occurs only once for the given successional
        // time step.
        // Note:  If one of the three multipliers dominates,
        // expect to see Pest highly correlated with that multiplier.
        // Note:  N is not included here as it is site level quality and Pest represent
        // ecoregion x climate qualities.  N limits have been folded into PlugIn.SufficientLight.
        public static Species.AuxParm <Ecoregions.AuxParm <double> > GenerateNewEstablishProbabilities(int years)
        {
            Species.AuxParm <Ecoregions.AuxParm <double> > EstablishProbability;
            EstablishProbability = CreateSpeciesEcoregionParm <double>(PlugIn.ModelCore.Species, PlugIn.ModelCore.Ecoregions);

            double[,] avgTempMultiplier       = new double[PlugIn.ModelCore.Species.Count, PlugIn.ModelCore.Ecoregions.Count];
            double[,] avgSoilMultiplier       = new double[PlugIn.ModelCore.Species.Count, PlugIn.ModelCore.Ecoregions.Count];
            double[,] avgMinJanTempMultiplier = new double[PlugIn.ModelCore.Species.Count, PlugIn.ModelCore.Ecoregions.Count];

            for (int y = 0; y < years; ++y)
            {
                foreach (IEcoregion ecoregion in PlugIn.ModelCore.Ecoregions)
                {
                    if (!ecoregion.Active || EcoregionData.ActiveSiteCount[ecoregion] < 1)
                    {
                        continue;
                    }

                    int actualYear = PlugIn.ModelCore.TimeSinceStart + y;

                    //AnnualClimate_Monthly ecoClimate = EcoregionData.AnnualWeather[ecoregion]; //[y];
                    //new AnnualClimate_Monthly(ecoregion, actualYear, EcoregionData.Latitude[ecoregion], Climate.Phase.Future_Climate, actualYear);
                    AnnualClimate_Monthly ecoClimate = EcoregionData.AnnualWeather[ecoregion];

                    if (ecoClimate == null)
                    {
                        throw new System.ApplicationException("Error in Establishment: CLIMATE NULL.");
                    }


                    double ecoDryDays = CalculateSoilMoisture(ecoClimate, ecoregion, y);

                    foreach (ISpecies species in PlugIn.ModelCore.Species)
                    {
                        double tempMultiplier       = BotkinDegreeDayMultiplier(ecoClimate, species);
                        double soilMultiplier       = SoilMoistureMultiplier(ecoClimate, species, ecoDryDays);
                        double minJanTempMultiplier = MinJanuaryTempModifier(ecoClimate, species);

                        // Liebig's Law of the Minimum is applied to the four multipliers for each year:
                        double minMultiplier = System.Math.Min(tempMultiplier, soilMultiplier);
                        minMultiplier = System.Math.Min(minJanTempMultiplier, minMultiplier);

                        EstablishProbability[species][ecoregion] += minMultiplier;

                        avgTempMultiplier[species.Index, ecoregion.Index]       += tempMultiplier;
                        avgSoilMultiplier[species.Index, ecoregion.Index]       += soilMultiplier;
                        avgMinJanTempMultiplier[species.Index, ecoregion.Index] += minJanTempMultiplier;
                    }
                }
            }


            foreach (IEcoregion ecoregion in PlugIn.ModelCore.Ecoregions)
            {
                foreach (ISpecies species in PlugIn.ModelCore.Species)
                {
                    EstablishProbability[species][ecoregion] /= (double)years;
                    EstablishProbability[species][ecoregion] *= PlugIn.ProbEstablishAdjust;

                    if (PlugIn.ModelCore.CurrentTime > 0 && EcoregionData.ActiveSiteCount[ecoregion] > 0)
                    {
                        avgTempMultiplier[species.Index, ecoregion.Index]       /= (double)years;
                        avgSoilMultiplier[species.Index, ecoregion.Index]       /= (double)years;
                        avgMinJanTempMultiplier[species.Index, ecoregion.Index] /= (double)years;

                        log.Write("{0}, {1}, {2},", PlugIn.ModelCore.CurrentTime, ecoregion.Name, species.Name);
                        log.Write("{0:0.00},", avgTempMultiplier[species.Index, ecoregion.Index]);
                        log.Write("{0:0.00},", avgMinJanTempMultiplier[species.Index, ecoregion.Index]);
                        log.Write("{0:0.00},", avgSoilMultiplier[species.Index, ecoregion.Index]);
                        log.Write("{0:0.00},", PlugIn.ProbEstablishAdjust);
                        log.WriteLine("{0:0.00}", EstablishProbability[species][ecoregion]);
                    }
                }
            }

            return(EstablishProbability);
        }
Example #6
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Runs the component for a particular timestep.
        /// </summary>
        /// <param name="currentTime">
        /// The current model timestep.
        /// </param>
        public override void Run()
        {
            // Calculate Local Variables
            foreach (IMapDefinition map in mapDefs)
            {
                List <IForestType> forestTypes = map.ForestTypes;

                foreach (Site site in modelCore.Landscape.AllSites)
                {
                    int mapCode = 0;
                    if (site.IsActive)
                    {
                        mapCode = CalcForestType(forestTypes, site);
                    }
                    else
                    {
                        mapCode = 0;
                    }
                    SiteVars.LocalVars[site][map.Name] = mapCode;
                }
            }

            // Calculate Derived Variables
            foreach (IVariableDefinition var in varDefs)
            {
                foreach (Site site in modelCore.Landscape.AllSites)
                {
                    SiteVars.DerivedVars[site][var.Name] = 0;
                }
                List <string> variables = var.Variables;
                List <string> operators = var.Operators;

                // Parse variable name into mapDef and fortype
                for (int i = 0; i < variables.Count; i++)
                {
                    string fullVar = variables[i];
                    // string[] varSplit = Regex.Split(fullVar, "\\[.*?\\]");
                    string[] varSplit = fullVar.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                    string   mapName  = varSplit[0];
                    string   varName  = varSplit[1];
                    int      mapCode  = 0;

                    foreach (IMapDefinition map in mapDefs)
                    {
                        if (map.Name == mapName)
                        {
                            int forTypeCnt = 1;
                            foreach (IForestType forestType in map.ForestTypes)
                            {
                                if (forestType.Name == varName)
                                {
                                    mapCode = forTypeCnt;
                                }
                                forTypeCnt++;
                            }
                        }
                    }
                    foreach (Site site in modelCore.Landscape.AllSites)
                    {
                        if (SiteVars.LocalVars[site][mapName] == mapCode)
                        {
                            SiteVars.DerivedVars[site][var.Name] = 1;
                        }
                    }
                }
            }

            // Calculate Neighborhood Variables
            foreach (INeighborVariableDefinition neighborVar in neighborVarDefs)
            {
                //Parse LocalVar
                string fullVar = neighborVar.LocalVariable;
                //string[] varSplit = Regex.Split(fullVar, "[]");
                string[] varSplit = fullVar.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
                string   varName  = "";
                int      mapCode  = 0;
                string   mapName  = "";
                if (varSplit.Length > 1)
                {
                    mapName = varSplit[0];
                    varName = varSplit[1];

                    foreach (IMapDefinition map in mapDefs)
                    {
                        if (map.Name == mapName)
                        {
                            int forTypeCnt = 1;
                            foreach (IForestType forestType in map.ForestTypes)
                            {
                                if (forestType.Name == varName)
                                {
                                    mapCode = forTypeCnt;
                                }
                                forTypeCnt++;
                            }
                        }
                    }
                }
                else
                {
                    varName = fullVar;
                }

                // Calculate neighborhood
                double CellLength = PlugIn.ModelCore.CellLength;
                PlugIn.ModelCore.UI.WriteLine("Creating Dispersal Neighborhood List.");

                List <RelativeLocation> neighborhood = new List <RelativeLocation>();
                int neighborRadius = neighborVar.NeighborRadius;
                int numCellRadius  = (int)(neighborRadius / CellLength);
                PlugIn.ModelCore.UI.WriteLine("NeighborRadius={0}, CellLength={1}, numCellRadius={2}",
                                              neighborRadius, CellLength, numCellRadius);
                double centroidDistance = 0;
                double cellLength       = CellLength;

                for (int row = (numCellRadius * -1); row <= numCellRadius; row++)
                {
                    for (int col = (numCellRadius * -1); col <= numCellRadius; col++)
                    {
                        centroidDistance = DistanceFromCenter(row, col);

                        //PlugIn.ModelCore.Log.WriteLine("Centroid Distance = {0}.", centroidDistance);
                        if (centroidDistance <= neighborRadius)
                        {
                            neighborhood.Add(new RelativeLocation(row, col));
                        }
                    }
                }
                // Calculate neighborhood value (% area of forest types)
                foreach (Site site in modelCore.Landscape.AllSites)
                {
                    int totalNeighborCells  = 0;
                    int targetNeighborCells = 0;
                    foreach (RelativeLocation relativeLoc in neighborhood)
                    {
                        Site neighbor = site.GetNeighbor(relativeLoc);
                        if (neighbor != null && neighbor.IsActive)
                        {
                            if (mapName == "")
                            {
                                if (SiteVars.DerivedVars[neighbor][varName] > 0)
                                {
                                    targetNeighborCells++;
                                }
                            }
                            else if (SiteVars.LocalVars[neighbor][mapName] == mapCode)
                            {
                                targetNeighborCells++;
                            }
                            totalNeighborCells++;
                        }
                    }
                    double pctValue = 100.0 * (double)targetNeighborCells / (double)totalNeighborCells;

                    // Calculate transformation
                    double transformValue = pctValue;
                    if (neighborVar.Transform.Equals("log10", StringComparison.OrdinalIgnoreCase))
                    //if (neighborVar.Transform == "log10")
                    {
                        transformValue = Math.Log10(pctValue + 1);
                    }
                    else if (neighborVar.Transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                    //else if (neighborVar.Transform == "ln")
                    {
                        transformValue = Math.Log(pctValue + 1);
                    }

                    // Write Site Variable
                    SiteVars.NeighborVars[site][neighborVar.Name] = (float)transformValue;
                }
            }

            // Calculate Climate Variables

            foreach (IClimateVariableDefinition climateVar in climateVarDefs)
            {
                Dictionary <IEcoregion, Dictionary <string, double> > ecoClimateVars = new Dictionary <IEcoregion, Dictionary <string, double> >();

                string varName       = climateVar.Name;
                string climateLibVar = climateVar.ClimateLibVariable;
                string climateYear   = climateVar.Year;
                int    minMonth      = climateVar.MinMonth;
                int    maxMonth      = climateVar.MaxMonth;
                string transform     = climateVar.Transform;

                int currentYear = PlugIn.ModelCore.CurrentTime;
                int actualYear  = currentYear;

                int firstActiveEco = 0;
                foreach (IEcoregion ecoregion in modelCore.Ecoregions)
                {
                    if (ecoregion.Active)
                    {
                        firstActiveEco = ecoregion.Index;
                        break;
                    }
                }
                if (Climate.Future_MonthlyData != null)
                {
                    AnnualClimate_Monthly AnnualWeather = Climate.Future_MonthlyData[Climate.Future_MonthlyData.Keys.Min()][firstActiveEco];
                    int maxSpinUpYear = Climate.Spinup_MonthlyData.Keys.Max();

                    if (PlugIn.ModelCore.CurrentTime > 0)
                    {
                        currentYear = (PlugIn.ModelCore.CurrentTime - 1) + Climate.Future_MonthlyData.Keys.Min();
                        if (climateYear == "prev")
                        {
                            if (Climate.Future_MonthlyData.ContainsKey(currentYear - 1))
                            {
                                AnnualWeather = Climate.Future_MonthlyData[currentYear - 1][firstActiveEco];
                            }
                            else
                            {
                                AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear][firstActiveEco];
                            }
                        }
                        else
                        {
                            AnnualWeather = Climate.Future_MonthlyData[currentYear][firstActiveEco];
                        }
                    }
                    if (PlugIn.ModelCore.CurrentTime == 0)
                    {
                        if (climateYear == "prev")
                        {
                            AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - 1][firstActiveEco];
                        }
                        else
                        {
                            AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear][firstActiveEco];
                        }
                    }
                    actualYear = AnnualWeather.Year;
                }
                else
                {
                    if (climateYear == "prev")
                    {
                        actualYear = currentYear - 1;
                    }
                }

                if (climateVar.SourceName == "Library")
                {
                    foreach (IEcoregion ecoregion in modelCore.Ecoregions)
                    {
                        if (ecoregion.Active)
                        {
                            if (!ecoClimateVars.ContainsKey(ecoregion))
                            {
                                ecoClimateVars.Add(ecoregion, new Dictionary <string, double>());
                            }
                            AnnualClimate_Monthly AnnualWeather = Climate.Future_MonthlyData[Climate.Future_MonthlyData.Keys.Min()][ecoregion.Index];
                            int maxSpinUpYear = Climate.Spinup_MonthlyData.Keys.Max();

                            if (PlugIn.ModelCore.CurrentTime == 0)
                            {
                                if (climateYear == "prev")
                                {
                                    AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - 1][ecoregion.Index];
                                }
                                else
                                {
                                    AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear][ecoregion.Index];
                                }
                            }
                            else if (climateYear == "prev")
                            {
                                if (!Climate.Future_MonthlyData.ContainsKey(currentYear - 1))
                                {
                                    AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear][ecoregion.Index];
                                }
                                else
                                {
                                    AnnualWeather = Climate.Future_MonthlyData[currentYear - 1][ecoregion.Index];
                                }
                            }
                            else
                            {
                                AnnualWeather = Climate.Future_MonthlyData[currentYear][ecoregion.Index];
                            }

                            double monthTotal = 0;
                            int    monthCount = 0;
                            double varValue   = 0;
                            var    monthRange = Enumerable.Range(minMonth, (maxMonth - minMonth) + 1);
                            foreach (int monthIndex in monthRange)
                            {
                                //if (climateVar.ClimateLibVariable == "PDSI")
                                //{

                                //double monthPDSI = PDSI_Calculator.PDSI_Monthly[monthIndex-1];
                                //   varValue = monthPDSI;
                                //}
                                if (climateVar.ClimateLibVariable.Equals("precip", StringComparison.OrdinalIgnoreCase))
                                //if (climateVar.ClimateLibVariable == "Precip")
                                {
                                    double monthPrecip = AnnualWeather.MonthlyPrecip[monthIndex - 1];
                                    varValue = monthPrecip * 10.0; //Convert cm to mm
                                }
                                else if (climateVar.ClimateLibVariable.Equals("temp", StringComparison.OrdinalIgnoreCase))
                                //else if (climateVar.ClimateLibVariable == "Temp")
                                {
                                    double monthTemp = AnnualWeather.MonthlyTemp[monthIndex - 1];
                                    varValue = monthTemp;
                                }
                                else
                                {
                                    string mesg = string.Format("Climate variable {0} is {1}; expected 'precip' or 'temp'.", climateVar.Name, climateVar.ClimateLibVariable);
                                    throw new System.ApplicationException(mesg);
                                }
                                monthTotal += varValue;
                                monthCount++;
                            }
                            double avgValue       = monthTotal / (double)monthCount;
                            double transformValue = avgValue;
                            if (transform.Equals("log10", StringComparison.OrdinalIgnoreCase))
                            //if (transform == "Log10")
                            {
                                transformValue = Math.Log10(avgValue + 1);
                            }
                            else if (transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                            //else if (transform == "ln")
                            {
                                transformValue = Math.Log(avgValue + 1);
                            }
                            if (!ecoClimateVars[ecoregion].ContainsKey(varName))
                            {
                                ecoClimateVars[ecoregion].Add(varName, 0.0);
                            }
                            ecoClimateVars[ecoregion][varName] = transformValue;
                        }
                    }

                    foreach (Site site in modelCore.Landscape.AllSites)
                    {
                        IEcoregion ecoregion    = PlugIn.ModelCore.Ecoregion[site];
                        double     climateValue = 0;
                        if (ecoregion != null)
                        {
                            climateValue = ecoClimateVars[ecoregion][varName];
                        }
                        // Write Site Variable
                        SiteVars.ClimateVars[site][varName] = (float)climateValue;
                    }
                }
                else
                {
                    double monthTotal = 0;
                    int    monthCount = 0;
                    double varValue   = 0;
                    var    monthRange = Enumerable.Range(minMonth, (maxMonth - minMonth) + 1);
                    foreach (int monthIndex in monthRange)
                    {
                        string    selectString = "Year = '" + actualYear + "' AND Month = '" + monthIndex + "'";
                        DataRow[] rows         = parameters.ClimateDataTable.Select(selectString);
                        if (rows.Length == 0)
                        {
                            string mesg = string.Format("Climate data is empty. No record exists for variable {0} in year {1}.", climateVar.Name, actualYear);
                            if (actualYear == 0)
                            {
                                mesg = mesg + "  Note that if using the options Monthly_AverageAllYears or Daily_AverageAllYears you should provide average values for climate variables listed as Year 0.";
                            }
                            throw new System.ApplicationException(mesg);
                        }
                        foreach (DataRow row in rows)
                        {
                            varValue = Convert.ToDouble(row[climateVar.ClimateLibVariable]);
                        }
                        monthTotal += varValue;
                        monthCount++;
                    }
                    double avgValue       = monthTotal / (double)monthCount;
                    double transformValue = avgValue;
                    if (transform.Equals("log10", StringComparison.OrdinalIgnoreCase))
                    //if (transform == "Log10")
                    {
                        transformValue = Math.Log10(avgValue + 1);
                    }
                    else if (transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                    //else if (transform == "ln")
                    {
                        transformValue = Math.Log(avgValue + 1);
                    }
                    foreach (Site site in modelCore.Landscape.AllSites)
                    {
                        SiteVars.ClimateVars[site][varName] = (float)transformValue;
                    }
                }
            }


            Dictionary <string, float>[] ecoregionAvgValues = new Dictionary <string, float> [ModelCore.Ecoregions.Count];
            Dictionary <string, float>   landscapeAvgValues = new Dictionary <string, float>();

            int[] activeSiteCount = new int[ModelCore.Ecoregions.Count];
            foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
            {
                ecoregionAvgValues[ecoregion.Index] = new Dictionary <string, float>();
                activeSiteCount[ecoregion.Index]    = 0;
            }
            foreach (ActiveSite site in ModelCore.Landscape)
            {
                IEcoregion ecoregion = ModelCore.Ecoregion[site];
                activeSiteCount[ecoregion.Index]++;
            }

            // Calculate Species Models
            foreach (IModelDefinition model in modelDefs)
            {
                float [] ecoregionSum = new float[ModelCore.Ecoregions.Count];
                float    landscapeSum = 0;

                foreach (Site site in modelCore.Landscape.AllSites)
                {
                    IEcoregion ecoregion    = ModelCore.Ecoregion[site];
                    double     modelPredict = 0;
                    int        paramIndex   = 0;
                    foreach (string parameter in model.Parameters)
                    {
                        string paramType  = model.ParamTypes[paramIndex];
                        double paramValue = model.Values[paramIndex];
                        if (paramType.Equals("int", StringComparison.OrdinalIgnoreCase))
                        //if (paramType == "int")
                        {
                            modelPredict += paramValue;
                        }
                        else if (paramType.Equals("neighbor", StringComparison.OrdinalIgnoreCase))
                        //else if (paramType == "neighbor")
                        {
                            double modelValue = SiteVars.NeighborVars[site][parameter] * paramValue;
                            modelPredict += modelValue;
                        }
                        else if (paramType.Equals("climate", StringComparison.OrdinalIgnoreCase))
                        //else if (paramType == "climate")
                        {
                            double modelValue = SiteVars.ClimateVars[site][parameter] * paramValue;
                            modelPredict += modelValue;
                        }
                        else if (paramType.Equals("biomass", StringComparison.OrdinalIgnoreCase))
                        //else if (paramType =="biomass")
                        {
                            double modelValue = Util.ComputeBiomass(SiteVars.Cohorts[site]) * paramValue;
                            modelPredict += modelValue;
                        }
                        else
                        {
                            string mesg = string.Format("For model {0}, parameter {1} has parameter type {2}; expected 'int', 'neighbor','climate' or 'biomass'.", model.Name, parameter, paramType);
                            throw new System.ApplicationException(mesg);
                        }

                        paramIndex++;
                    }
                    // Back-transform model prediction
                    float finalPredict = (float)Math.Exp(modelPredict);
                    // Write Site Variable
                    SiteVars.SpeciesModels[site][model.Name] = (float)finalPredict;
                    if (site.IsActive)
                    {
                        ecoregionSum[ecoregion.Index] += finalPredict;
                        landscapeSum += finalPredict;
                    }
                }
                foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
                {
                    //ecoregionAvgValues[ecoregion.Index].Add(model.Name, 0);
                    ecoregionAvgValues[ecoregion.Index][model.Name] = ecoregionSum[ecoregion.Index] / activeSiteCount[ecoregion.Index];
                }
                landscapeAvgValues[model.Name] = landscapeSum / ModelCore.Landscape.ActiveSiteCount;
            }


            foreach (IModelDefinition model in modelDefs)
            {
                habitatLog.Write("{0},", ModelCore.CurrentTime);
                habitatLog.Write("{0},", model.Name);
                habitatLog.Write("{0}", landscapeAvgValues[model.Name]);
                foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
                {
                    habitatLog.Write(",{0}", ecoregionAvgValues[ecoregion.Index][model.Name]);
                }
                habitatLog.WriteLine("");
            }


            /*
             * foreach (IModelDefinition model in modelDefs)
             * {
             *   foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
             *   {
             *       habitatLog.Clear();
             *       SpeciesHabitatLog shl = new SpeciesHabitatLog();
             *       shl.Time = ModelCore.CurrentTime;
             *       shl.Ecoregion = ecoregion.Name;
             *       shl.EcoregionIndex = ecoregion.Index;
             *       shl.NumSites = activeSiteCount[ecoregion.Index];
             *       //shl.SppHabitat[ecoregion.Index][model.Name] = avgHabitat[ecoregion.Index][;
             *   }
             * }
             * */

            // Ouput Maps
            if (!(parameters.LocalVarMapFileNames == null))
            {
                //----- Write LocalVar maps --------
                foreach (MapDefinition localVar in parameters.ReclassMaps)
                {
                    string localVarPath = MapFileNames.ReplaceTemplateVars(parameters.LocalVarMapFileNames, localVar.Name, PlugIn.ModelCore.CurrentTime);
                    using (IOutputRaster <BytePixel> outputRaster = modelCore.CreateRaster <BytePixel>(localVarPath, modelCore.Landscape.Dimensions))
                    {
                        BytePixel pixel = outputRaster.BufferPixel;
                        foreach (Site site in PlugIn.ModelCore.Landscape.AllSites)
                        {
                            if (site.IsActive)
                            {
                                pixel.MapCode.Value = (byte)(SiteVars.LocalVars[site][localVar.Name] + 1);
                            }
                            else
                            {
                                //  Inactive site
                                pixel.MapCode.Value = 0;
                            }
                            outputRaster.WriteBufferPixel();
                        }
                    }
                }
            }
            if (!(parameters.NeighborMapFileNames == null))
            {
                //----- Write LocalVar maps --------
                foreach (NeighborVariableDefinition neighborVar in parameters.NeighborVars)
                {
                    string neighborVarPath = NeighborMapFileNames.ReplaceTemplateVars(parameters.NeighborMapFileNames, neighborVar.Name, PlugIn.ModelCore.CurrentTime);
                    using (IOutputRaster <ShortPixel> outputRaster = modelCore.CreateRaster <ShortPixel>(neighborVarPath, modelCore.Landscape.Dimensions))
                    {
                        ShortPixel pixel = outputRaster.BufferPixel;
                        foreach (Site site in PlugIn.ModelCore.Landscape.AllSites)
                        {
                            if (site.IsActive)
                            {
                                pixel.MapCode.Value = (short)(System.Math.Round(SiteVars.NeighborVars[site][neighborVar.Name] * 100.0));
                            }
                            else
                            {
                                //  Inactive site
                                pixel.MapCode.Value = 0;
                            }
                            outputRaster.WriteBufferPixel();
                        }
                    }
                }
            }
            if (!(parameters.ClimateMapFileNames == null))
            {
                //----- Write LocalVar maps --------
                foreach (ClimateVariableDefinition climateVar in parameters.ClimateVars)
                {
                    string climateVarPath = ClimateMapFileNames.ReplaceTemplateVars(parameters.ClimateMapFileNames, climateVar.Name, PlugIn.ModelCore.CurrentTime);
                    using (IOutputRaster <ShortPixel> outputRaster = modelCore.CreateRaster <ShortPixel>(climateVarPath, modelCore.Landscape.Dimensions))
                    {
                        ShortPixel pixel = outputRaster.BufferPixel;
                        foreach (Site site in PlugIn.ModelCore.Landscape.AllSites)
                        {
                            if (site.IsActive)
                            {
                                pixel.MapCode.Value = (short)(System.Math.Round(SiteVars.ClimateVars[site][climateVar.Name] * 100.0));
                            }
                            else
                            {
                                //  Inactive site
                                pixel.MapCode.Value = 0;
                            }
                            outputRaster.WriteBufferPixel();
                        }
                    }
                }
            }
            if (!(parameters.SpeciesMapFileNames == null))
            {
                //----- Write Species Model maps --------
                foreach (ModelDefinition sppModel in parameters.Models)
                {
                    string sppModelPath = SpeciesMapFileNames.ReplaceTemplateVars(parameters.SpeciesMapFileNames, sppModel.Name, PlugIn.ModelCore.CurrentTime);
                    using (IOutputRaster <ShortPixel> outputRaster = modelCore.CreateRaster <ShortPixel>(sppModelPath, modelCore.Landscape.Dimensions))
                    {
                        ShortPixel pixel = outputRaster.BufferPixel;
                        foreach (Site site in PlugIn.ModelCore.Landscape.AllSites)
                        {
                            if (site.IsActive)
                            {
                                pixel.MapCode.Value = (short)System.Math.Round(SiteVars.SpeciesModels[site][sppModel.Name] * 100.0);
                                //pixel.MapCode.Value = (short)System.Math.Round(SiteVars.SpeciesModels[site][sppModel.Name]);
                            }
                            else
                            {
                                //  Inactive site
                                pixel.MapCode.Value = 0;
                            }
                            outputRaster.WriteBufferPixel();
                        }
                    }
                }
            }
        }