//---------------------------------------------------------------------

        /// <summary>
        /// Gets a neighboring site.
        /// </summary>
        /// <param name="neighborLocation">
        /// The location of the neighboring site relative to the site.
        /// </param>
        /// <returns>
        /// a site that converts to false if the neighbor's location is not
        /// a valid location for the site's landscape.
        /// </returns>
        public Site GetNeighbor(RelativeLocation neighborLocation)
        {
            Location?neighborAbsoluteLocation = location + neighborLocation;

            if (neighborAbsoluteLocation.HasValue)
            {
                return(landscape.GetSite(neighborAbsoluteLocation.Value));
            }
            return(new Site());
        }
 public RelativeLocationWeighted (RelativeLocation location, double weight)
 {
     this.location = location;
     this.weight = weight;
 }
 //---------------------------------------------------------------------
 /// <summary>
 /// Gets a neighboring site.
 /// </summary>
 /// <param name="neighborLocation">
 /// The location of the neighboring site relative to the site.
 /// </param>
 /// <returns>
 /// a site that converts to false if the neighbor's location is not
 /// a valid location for the site's landscape.
 /// </returns>
 public Site GetNeighbor(RelativeLocation neighborLocation)
 {
     Location? neighborAbsoluteLocation = location + neighborLocation;
     if (neighborAbsoluteLocation.HasValue)
         return landscape.GetSite(neighborAbsoluteLocation.Value);
     return new Site();
 }
        //---------------------------------------------------------------------
        /// <summary>
        /// Runs the component for a particular timestep.
        /// </summary>
        /// <param name="currentTime">
        /// The current model timestep.
        /// </param>
        public override void Run()
        {
            double CellLength = PlugIn.ModelCore.CellLength;
            // 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 = 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
                //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 (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                            {
                                if (varName.Equals(PlugIn.ModelCore.Ecoregion[neighbor].Name, StringComparison.OrdinalIgnoreCase))
                                {
                                    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))
                    {

                        transformValue = Math.Log10(pctValue + 1);
                    }
                    else if (neighborVar.Transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                    {
                        transformValue = Math.Log(pctValue + 1);
                    }
                    // Write Neighbhorhood Site Variable
                    SiteVars.NeighborVars[site][neighborVar.Name] = (float)transformValue;
                }
            }

            // Calculate Distance Variables
            foreach (IDistanceVariableDefinition distanceVar in distanceVarDefs)
            {
                //Parse LocalVar
                string fullVar = distanceVar.LocalVariable;
                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 distance value (meters)
                foreach (Site site in modelCore.Landscape.AllSites)
                {
                    double minDistance = double.MaxValue;
                    // Spiral outward algorithm (http://stackoverflow.com/questions/3330181/algorithm-for-finding-nearest-object-on-2d-grid)
                    // Start coordinates
                    int xs = 0;
                    int ys = 0;
                    // Check point (xs, ys)
                    if (mapName == "")
                    {
                        if (SiteVars.DerivedVars[site][varName] > 0)
                            minDistance = 0;
                    }
                    else if (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                    {
                        if (varName.Equals(PlugIn.ModelCore.Ecoregion[site].Name, StringComparison.OrdinalIgnoreCase))
                        {
                            minDistance = 0;
                        }
                    }
                    else if (SiteVars.LocalVars[site][mapName] == mapCode)
                    {
                        minDistance = 0;
                    }

                    int maxD1 = site.Location.Row + site.Location.Column;
                    int maxD2 = site.Location.Row + (PlugIn.ModelCore.Landscape.Columns - site.Location.Column);
                    int maxD3 = (PlugIn.ModelCore.Landscape.Rows - site.Location.Row) + site.Location.Column;
                    int maxD4 = (PlugIn.ModelCore.Landscape.Rows - site.Location.Row) + (PlugIn.ModelCore.Landscape.Columns - site.Location.Column);
                    int maxDistance = Math.Max(maxD1, maxD2);
                    maxDistance = Math.Max(maxDistance, maxD3);
                    maxDistance = Math.Max(maxDistance, maxD4);

                    for (int d = 1; d < maxDistance; d++)
                    {
                        double minCentroidDistance = double.MaxValue;
                        for (int i = 0; i < d + 1; i++)
                        {
                            int x1 = xs - d + i;
                            int y1 = ys - i;
                            // Check point (x1, y1)
                            double centroidDistance = DistanceFromCenter(y1, x1);
                            if (centroidDistance < minCentroidDistance)
                                minCentroidDistance = centroidDistance;
                            if (centroidDistance >= minDistance + CellLength)
                            {
                                break;
                            }
                            if (centroidDistance < minDistance)
                            {
                                RelativeLocation relativeloc = new RelativeLocation(y1, x1);
                                Site neighbor = site.GetNeighbor(relativeloc);
                                int neighborRow = neighbor.Location.Row;
                                int neighborCol = neighbor.Location.Column;
                                if ((neighborRow > 0 && neighborRow <= PlugIn.ModelCore.Landscape.Rows) && ((neighborCol > 0 && neighborCol <= PlugIn.ModelCore.Landscape.Columns)))
                                {
                                    if (mapName == "")
                                    {
                                        if (SiteVars.DerivedVars[neighbor][varName] > 0)
                                            minDistance = centroidDistance;
                                    }
                                    else if (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (varName.Equals(PlugIn.ModelCore.Ecoregion[neighbor].Name, StringComparison.OrdinalIgnoreCase))
                                        {
                                            minDistance = centroidDistance;
                                        }
                                    }
                                    else if (SiteVars.LocalVars[neighbor][mapName] == mapCode)
                                    {
                                        minDistance = centroidDistance;
                                    }
                                }
                            }

                            int x2 = xs + d - i;
                            int y2 = ys + i;
                            // Check point (x2, y2)
                            centroidDistance = DistanceFromCenter(y2, x2);
                            if (centroidDistance < minCentroidDistance)
                                minCentroidDistance = centroidDistance;
                            if (centroidDistance >= minDistance + CellLength)
                            {
                                break;
                            }
                            if (centroidDistance < minDistance)
                            {
                                RelativeLocation relativeloc = new RelativeLocation(y2, x2);
                                Site neighbor = site.GetNeighbor(relativeloc);
                                int neighborRow = neighbor.Location.Row;
                                int neighborCol = neighbor.Location.Column;
                                if ((neighborRow > 0 && neighborRow <= PlugIn.ModelCore.Landscape.Rows) && ((neighborCol > 0 && neighborCol <= PlugIn.ModelCore.Landscape.Columns)))
                                {
                                    if (mapName == "")
                                    {
                                        if (SiteVars.DerivedVars[neighbor][varName] > 0)
                                            minDistance = centroidDistance;
                                    }
                                    else if (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (varName.Equals(PlugIn.ModelCore.Ecoregion[neighbor].Name, StringComparison.OrdinalIgnoreCase))
                                        {
                                            minDistance = centroidDistance;
                                        }
                                    }
                                    else if (SiteVars.LocalVars[neighbor][mapName] == mapCode)
                                    {
                                        minDistance = centroidDistance;
                                    }
                                }
                            }
                        }

                        for (int i = 1; i < d; i++)
                        {
                            int x1 = xs - i;
                            int y1 = ys + d - i;

                            // Check point (x1, y1)
                            double centroidDistance = DistanceFromCenter(y1, x1);
                            if (centroidDistance < minCentroidDistance)
                                minCentroidDistance = centroidDistance;
                            if (centroidDistance >= minDistance + CellLength)
                            {
                                break;
                            }
                            if (centroidDistance < minDistance)
                            {
                                RelativeLocation relativeloc = new RelativeLocation(y1, x1);
                                Site neighbor = site.GetNeighbor(relativeloc);
                                int neighborRow = neighbor.Location.Row;
                                int neighborCol = neighbor.Location.Column;
                                if ((neighborRow > 0 && neighborRow <= PlugIn.ModelCore.Landscape.Rows) && ((neighborCol > 0 && neighborCol <= PlugIn.ModelCore.Landscape.Columns)))
                                {
                                    if (mapName == "")
                                    {
                                        if (SiteVars.DerivedVars[neighbor][varName] > 0)
                                            minDistance = centroidDistance;
                                    }
                                    else if (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (varName.Equals(PlugIn.ModelCore.Ecoregion[neighbor].Name, StringComparison.OrdinalIgnoreCase))
                                        {
                                            minDistance = centroidDistance;
                                        }
                                    }
                                    else if (SiteVars.LocalVars[neighbor][mapName] == mapCode)
                                    {
                                        minDistance = centroidDistance;
                                    }
                                }
                            }
                            int x2 = xs + d - i;
                            int y2 = ys - i;

                            // Check point (x2, y2)
                            centroidDistance = DistanceFromCenter(y2, x2);
                            if (centroidDistance < minCentroidDistance)
                                minCentroidDistance = centroidDistance;
                            if (centroidDistance >= minDistance + CellLength)
                            {
                                break;
                            }
                            if (centroidDistance < minDistance)
                            {
                                RelativeLocation relativeloc = new RelativeLocation(y2, x2);
                                Site neighbor = site.GetNeighbor(relativeloc);
                                int neighborRow = neighbor.Location.Row;
                                int neighborCol = neighbor.Location.Column;
                                if ((neighborRow > 0 && neighborRow <= PlugIn.ModelCore.Landscape.Rows) && ((neighborCol > 0 && neighborCol <= PlugIn.ModelCore.Landscape.Columns)))
                                {
                                    if (mapName == "")
                                    {
                                        if (SiteVars.DerivedVars[neighbor][varName] > 0)
                                            minDistance = centroidDistance;
                                    }
                                    else if (mapName.Equals("ecoregion", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (varName.Equals(PlugIn.ModelCore.Ecoregion[neighbor].Name, StringComparison.OrdinalIgnoreCase))
                                        {
                                            minDistance = centroidDistance;
                                        }
                                    }
                                    else if (SiteVars.LocalVars[neighbor][mapName] == mapCode)
                                    {
                                        minDistance = centroidDistance;
                                    }
                                }
                            }
                        }
                        if (minCentroidDistance > minDistance + CellLength)
                        {
                            break;
                        }
                    }
                    // Calculate transformation
                    double transformValue = minDistance;
                    if (distanceVar.Transform.Equals("log10", StringComparison.OrdinalIgnoreCase))
                    {
                        transformValue = Math.Log10(minDistance + 1);
                    }
                    else if (distanceVar.Transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                    {
                        transformValue = Math.Log(minDistance + 1);
                    }

                    // Write Distance Site Variable
                    SiteVars.DistanceVars[site][distanceVar.Name] = (float)transformValue;
                }
            }

            // If timestep > 1 then calculate average value across years in timestep
            // Landscape variables are static, but climate variabls change annually
            int yearsProcessed = 0;
            for (int time = 1; time <= Timestep; )
            {
                // 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 - Timestep + time;
                    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 = (currentYear - 1) + Climate.Future_MonthlyData.Keys.Min();
                            if (climateYear.Equals("prev", StringComparison.OrdinalIgnoreCase))
                            {
                                if (Climate.Future_MonthlyData.ContainsKey(currentYear - 1))
                                {
                                    AnnualWeather = Climate.Future_MonthlyData[currentYear - 1][firstActiveEco];
                                }
                                else
                                {
                                    AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear][firstActiveEco];
                                }
                            }
                            else if (climateYear.Equals("current", StringComparison.OrdinalIgnoreCase))
                            {
                                AnnualWeather = Climate.Future_MonthlyData[currentYear][firstActiveEco];
                            }
                            else
                            {
                                string mesg = string.Format("Year for climate variable {0} is {1}; expected 'current' or 'prev'.", climateVar.Name, climateVar.Year);
                                throw new System.ApplicationException(mesg);
                            }
                        }
                        if (PlugIn.ModelCore.CurrentTime == 0)
                        {
                            if (climateYear.Equals("prev", StringComparison.OrdinalIgnoreCase))
                                AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - Timestep + time - 1][firstActiveEco];
                            else if (climateYear.Equals("current", StringComparison.OrdinalIgnoreCase))
                                AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - Timestep + time][firstActiveEco];
                            else
                            {
                                string mesg = string.Format("Year for climate variable {0} is {1}; expected 'current' or 'prev'.", climateVar.Name, climateVar.Year);
                                throw new System.ApplicationException(mesg);
                            }
                        }
                        actualYear = AnnualWeather.Year;
                    }
                    else
                    {
                        if (climateYear.Equals("prev", StringComparison.OrdinalIgnoreCase))
                            actualYear = currentYear - 1;
                    }

                    if (climateVar.SourceName.Equals("library", StringComparison.OrdinalIgnoreCase))
                    {
                        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.Equals("prev", StringComparison.OrdinalIgnoreCase))
                                        AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - Timestep + time - 1][ecoregion.Index];
                                    else
                                        AnnualWeather = Climate.Spinup_MonthlyData[maxSpinUpYear - Timestep + time][ecoregion.Index];
                                }
                                else if (climateYear.Equals("prev", StringComparison.OrdinalIgnoreCase))
                                {
                                    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))
                                    {
                                        double monthPrecip = AnnualWeather.MonthlyPrecip[monthIndex - 1];
                                        varValue = monthPrecip * 10.0; //Convert cm to mm
                                    }
                                    else if (climateVar.ClimateLibVariable.Equals("temp", StringComparison.OrdinalIgnoreCase))
                                    {
                                        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))
                                {
                                    transformValue = Math.Log10(avgValue + 1);
                                }
                                else if (transform.Equals("ln", StringComparison.OrdinalIgnoreCase))
                                {
                                    transformValue = Math.Log(avgValue + 1);
                                }
                                if (!ecoClimateVars[ecoregion].ContainsKey(varName))
                                {
                                    ecoClimateVars[ecoregion].Add(varName, 0.0);
                                }
                                ecoClimateVars[ecoregion][varName] = transformValue;
                            }
                        } //foreach (IEcoregion ecoregion in modelCore.Ecoregions)
                        foreach (Site site in modelCore.Landscape.AllSites)
                        {
                            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];
                            double climateValue = 0;
                            if (ecoregion != null)
                            {
                                climateValue = ecoClimateVars[ecoregion][varName];
                            }
                            // Write Climate Site Variable
                            SiteVars.ClimateVars[site][varName] = (float)climateValue;
                        }
                    } //  if (climateVar.SourceName.Equals("library", StringComparison.OrdinalIgnoreCase))
                    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;
                        }
                    } //  not if (climateVar.SourceName.Equals("library", StringComparison.OrdinalIgnoreCase))
                }

                // Calculate Species Models
                foreach (IModelDefinition model in modelDefs)
                {
                    foreach (ActiveSite site in modelCore.Landscape.ActiveSites)
                    {
                        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))
                            {
                                modelPredict += paramValue;
                            }
                            else if (paramType.Equals("neighbor", StringComparison.OrdinalIgnoreCase))
                            {
                                if (SiteVars.NeighborVars[site].ContainsKey(parameter))
                                {
                                    double modelValue = SiteVars.NeighborVars[site][parameter];
                                    modelValue = modelValue * paramValue;
                                    modelPredict += modelValue;
                                }
                                else
                                {
                                    string mesg = string.Format("The Neighborhood parameter {0} is listed for model {1} but is not included under NeighborhoodVariables.", parameter, model.Name);
                                    throw new System.ApplicationException(mesg);
                                }
                            }
                            else if (paramType.Equals("climate", StringComparison.OrdinalIgnoreCase))
                            {
                                if (SiteVars.ClimateVars[site].ContainsKey(parameter))
                                {
                                    double modelValue = SiteVars.ClimateVars[site][parameter];
                                    modelValue = modelValue * paramValue;
                                    modelPredict += modelValue;
                                }
                                else
                                {
                                    string mesg = string.Format("The Climate parameter {0} is listed for model {1} but is not included under ClimateVariables.", parameter, model.Name);
                                    throw new System.ApplicationException(mesg);
                                }
                            }
                            else if (paramType.Equals("distance", StringComparison.OrdinalIgnoreCase))
                            {
                                if (SiteVars.DistanceVars[site].ContainsKey(parameter))
                                {
                                    double modelValue = SiteVars.DistanceVars[site][parameter];
                                    modelValue = modelValue * paramValue;
                                    modelPredict += modelValue;
                                }
                                else
                                {
                                    string mesg = string.Format("The Distance parameter {0} is listed for model {1} but is not included under DistanceVariables.", parameter, model.Name);
                                    throw new System.ApplicationException(mesg);
                                }
                            }
                            else if (paramType.Equals("biomass", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Util.ComputeBiomass(SiteVars.Cohorts[site]);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Equals("lnbiomass", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Math.Log(Util.ComputeBiomass(SiteVars.Cohorts[site]) + 1);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Equals("logbiomass", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Math.Log10(Util.ComputeBiomass(SiteVars.Cohorts[site]) + 1);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Equals("age", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Util.ComputeAge(SiteVars.Cohorts[site]);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Equals("lnage", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Math.Log(Util.ComputeAge(SiteVars.Cohorts[site]) + 1);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Equals("logage", StringComparison.OrdinalIgnoreCase))
                            {
                                double modelValue = Math.Log10(Util.ComputeAge(SiteVars.Cohorts[site]) + 1);
                                modelValue = modelValue * paramValue;
                                modelPredict += modelValue;
                            }
                            else if (paramType.Contains("*"))
                            {
                                string[] paramTypes = paramType.Split('*');
                                string[] splitParameters = parameter.Split('*');
                                double paramProduct = 1.0;
                                if (paramTypes.Length != splitParameters.Length)
                                {
                                    string mesg = string.Format("For model {0}, the number of parameters in {1} does not match the number of paramter types {2}.", model.Name, parameter, paramType);
                                    throw new System.ApplicationException(mesg);
                                }
                                else
                                {
                                    int interactionIndex = 0;
                                    foreach (string pType in paramTypes)
                                    {
                                        string param = splitParameters[interactionIndex];
                                        if (pType.Equals("neighbor", StringComparison.OrdinalIgnoreCase))
                                        {
                                            if (SiteVars.NeighborVars[site].ContainsKey(param))
                                            {
                                                double modelValue = SiteVars.NeighborVars[site][param];
                                                paramProduct *= modelValue;
                                            }
                                            else
                                            {
                                                string mesg = string.Format("The Neighborhood parameter {0} is listed for model {1} but is not included under NeighborhoodVariables.", param, model.Name);
                                                throw new System.ApplicationException(mesg);
                                            }
                                        }
                                        else if (pType.Equals("climate", StringComparison.OrdinalIgnoreCase))
                                        //else if (paramType == "climate")
                                        {
                                            if (SiteVars.ClimateVars[site].ContainsKey(param))
                                            {
                                                double modelValue = SiteVars.ClimateVars[site][param];
                                                paramProduct *= modelValue;
                                            }
                                            else
                                            {
                                                string mesg = string.Format("The Climate parameter {0} is listed for model {1} but is not included under ClimateVariables.", param, model.Name);
                                                throw new System.ApplicationException(mesg);
                                            }
                                        }
                                        else if (pType.Equals("distance", StringComparison.OrdinalIgnoreCase))
                                        //else if (paramType == "climate")
                                        {
                                            if (SiteVars.DistanceVars[site].ContainsKey(param))
                                            {
                                                double modelValue = SiteVars.DistanceVars[site][param];
                                                paramProduct *= modelValue;
                                            }
                                            else
                                            {
                                                string mesg = string.Format("The Distance parameter {0} is listed for model {1} but is not included under DistanceVariables.", param, model.Name);
                                                throw new System.ApplicationException(mesg);
                                            }
                                        }
                                        else if (pType.Equals("biomass", StringComparison.OrdinalIgnoreCase))
                                        //else if (paramType =="biomass")
                                        {
                                            double modelValue = Util.ComputeBiomass(SiteVars.Cohorts[site]);
                                            paramProduct *= modelValue;
                                        }
                                        else
                                        {
                                            string mesg = string.Format("For model {0}, parameter {1} has parameter type {2}; expected 'int', 'neighbor', 'climate', 'distance', 'biomass','lnbiomass', 'logbiomass','age', 'lnage', 'logage', or 'interaction'.", model.Name, param, pType);
                                            throw new System.ApplicationException(mesg);
                                        }
                                        interactionIndex++;
                                    }
                                    double interactionValue = paramProduct * paramValue;
                                    modelPredict += interactionValue;
                                }
                            }
                            else
                            {
                                string mesg = string.Format("For model {0}, parameter {1} has parameter type {2}; expected 'int', 'neighbor', 'climate', 'distance', 'biomass','lnbiomass', 'logbiomass','age', 'lnage', 'logage', or 'interaction'.", model.Name, parameter, paramType);
                                throw new System.ApplicationException(mesg);
                            }
                            paramIndex++;
                        }
                        // Back-transform model prediction
                        float annualPredict = (float)Math.Exp(modelPredict);
                        // Write Site Variable
                        if ((SiteVars.SpeciesModels[site].ContainsKey(model.Name)) && time > 1)
                        {
                            SiteVars.SpeciesModels[site][model.Name] += annualPredict;
                        }
                        else
                        {
                            SiteVars.SpeciesModels[site][model.Name] = annualPredict;
                        }

                    } // foreach (ActiveSite site in modelCore.Landscape.ActiveSites)
                } // foreach (IModelDefinition model in modelDefs)
                // If no climate variables then only process once regardless of timestep
                if (climateVarDefs.Count() == 0)
                {
                    time = Timestep;
                }
                else
                {
                    time += 1;
                }
                yearsProcessed++;
            }  // for (int time = 1; time <= Timestep)

            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 average over timestep
            foreach (IModelDefinition model in modelDefs)
            {
                float[] ecoregionSum = new float[ModelCore.Ecoregions.Count];
                float landscapeSum = 0;
                // Write Site Variable
                foreach (ActiveSite site in ModelCore.Landscape)
                {
                    IEcoregion ecoregion = ModelCore.Ecoregion[site];
                    float averageAnnual = SiteVars.SpeciesModels[site][model.Name] / yearsProcessed;
                    SiteVars.SpeciesModels[site][model.Name] = averageAnnual;

                    ecoregionSum[ecoregion.Index] += averageAnnual;
                    landscapeSum += averageAnnual;

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

            // Write Log File
            if (parameters.LogFileName != null)
            {
                foreach (IModelDefinition model in modelDefs)
                {

                    habitatLog.Clear();
                    SpeciesHabitatLog shlog = new SpeciesHabitatLog();
                    shlog.Time = ModelCore.CurrentTime;
                    shlog.Ecoregion = "TotalLandscape";
                    shlog.SpeciesModelName = model.Name;
                    //shlog.NumSites = activeSiteCount[ecoregion.Index];
                    shlog.Index = landscapeAvgValues[model.Name];
                    habitatLog.AddObject(shlog);
                    habitatLog.WriteToFile();
                    /*
                    foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
                    {
                        habitatLog.Clear();
                        shlog = new SpeciesHabitatLog();
                        shlog.Time = ModelCore.CurrentTime;
                        shlog.Ecoregion = ecoregion.Name;
                        shlog.SpeciesModelName = model.Name;
                        //shl.EcoregionIndex = ecoregion.Index;
                        //shlog.NumSites = activeSiteCount[ecoregion.Index];
                        shlog.Index = ecoregionAvgValues[ecoregion.Index][model.Name];
                        habitatLog.AddObject(shlog);
                        habitatLog.WriteToFile();
                    }
                     * */
                }
            }

            if (parameters.SpeciesLogFileNames != null)
            {
                int selectModelCount = 0;
                foreach (IModelDefinition model in modelDefs)
                {
                    //MetadataTable<IndividualSpeciesHabitatLog> speciesLog = sppLogs[selectModelCount];
                    sppLogs[selectModelCount].Clear();
                    IndividualSpeciesHabitatLog sppLog = new IndividualSpeciesHabitatLog();
                    sppLog.Time = ModelCore.CurrentTime;
                    sppLog.Ecoregion = "TotalLandscape";
                    sppLog.SpeciesModel = model.Name;
                    //shlog.NumSites = activeSiteCount[ecoregion.Index];
                    sppLog.Index = landscapeAvgValues[model.Name];
                    sppLogs[selectModelCount].AddObject(sppLog);
                    sppLogs[selectModelCount].WriteToFile();

                    foreach (IEcoregion ecoregion in ModelCore.Ecoregions)
                    {
                        sppLogs[selectModelCount].Clear();
                        sppLog = new IndividualSpeciesHabitatLog();
                        sppLog.Time = ModelCore.CurrentTime;
                        sppLog.Ecoregion = ecoregion.Name;
                        sppLog.SpeciesModel = model.Name;
                        //shlog.NumSites = activeSiteCount[ecoregion.Index];
                        sppLog.Index = ecoregionAvgValues[ecoregion.Index][model.Name];
                        sppLogs[selectModelCount].AddObject(sppLog);
                        sppLogs[selectModelCount].WriteToFile();
                    }
                    selectModelCount++;
                }
            }

            // Ouput Maps
            if (!(parameters.LocalVarMapFileNames == null))
            {
                //----- Write LocalVar maps --------
                foreach (MapDefinition localVar in parameters.ReclassMaps)
                {
                    string localVarPath = LocalMapFileNames.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.DistanceMapFileNames == null))
            {
                //----- Write DistanceVar maps --------
                foreach (DistanceVariableDefinition distanceVar in parameters.DistanceVars)
                {
                    string distanceVarPath = DistanceMapFileNames.ReplaceTemplateVars(parameters.DistanceMapFileNames, distanceVar.Name, PlugIn.ModelCore.CurrentTime);
                    using (IOutputRaster<ShortPixel> outputRaster = modelCore.CreateRaster<ShortPixel>(distanceVarPath, 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.DistanceVars[site][distanceVar.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();
                        }
                    }
                }
            }
        }
        //---------------------------------------------------------------------

        private List<Site> GetNeighbors(Site   site,
                                        int    windDirection,
                                        double windSpeed)
        {
            if (windDirection > 7)
                windDirection = 7;
            double[] windProbs = 
            {
            (((4.0 - windSpeed)/8.0) * (1+windSpeed)), //Primary direction
            (((4.0 - windSpeed)/8.0) * (1+windSpeed)),
            (((4.0 - windSpeed)/8.0)),
            (((4.0 - windSpeed)/8.0) * (1-windSpeed)),
            (((4.0 - windSpeed)/8.0) * (1-windSpeed)), //Opposite of primary direction
            (((4.0 - windSpeed)/8.0) * (1-windSpeed)),
            (((4.0 - windSpeed)/8.0)),
            (((4.0 - windSpeed)/8.0) * (1+windSpeed)),
            };
            
            double windProb = 0.0;
            int index = 0;
            int success = 0;
            List<Site> neighbors = new List<Site>(9);
            foreach (RelativeLocation relativeLoc in neighborhood) 
            {
                Site neighbor = site.GetNeighbor(relativeLoc);

                if (index + windDirection > 7) 
                    windProb = windProbs[index + windDirection - 8];
                else 
                    windProb = windProbs[index + windDirection];
                if (neighbor != null
                    && PlugIn.ModelCore.NextDouble() < windProb)  
                {
                    neighbors.Add(neighbor);
                    success++;
                }
                index++;
            }
            //Next, add the 9th neighbor, a neighbor one cell beyond the 
            //8 nearest neighbors.
            //array index 0 = north; 1 = northeast, 2 = east,...,8 = northwest
            int[] vertical  ={2,2,0,-2,-2,-2,0,2};
            int[] horizontal={0,2,2,2,0,-2,-2,-2};

            RelativeLocation relativeLoc9 = 
                new RelativeLocation(vertical[windDirection], horizontal[windDirection]);
            Site neighbor9 = site.GetNeighbor(relativeLoc9);
            if (neighbor9 != null && PlugIn.ModelCore.GenerateUniform() < windSpeed)
                neighbors.Add(neighbor9);
            return neighbors;
        }
        //---------------------------------------------------------------------
        //Generate List of 4,8,12, or 24 nearest neighbors.
        //---------------------------------------------------------------------
        private static List<RelativeLocation> GetNeighbors(int numNeighbors)
        {

            RelativeLocation[] neighborhood4 = new RelativeLocation[] {
                new RelativeLocation( 0,  1),   // east
                new RelativeLocation( 1,  0),   // south
                new RelativeLocation( 0, -1),   // west
                new RelativeLocation(-1,  0),   // north
            };

            RelativeLocation[] neighborhood8 = new RelativeLocation[] {
                new RelativeLocation(-1,  1),   // northeast
                new RelativeLocation( 1,  1),   // southeast
                new RelativeLocation( 1,  -1),  // southwest
                new RelativeLocation( -1, -1),  // northwest
            };

            RelativeLocation[] neighborhood12 = new RelativeLocation[] {
                new RelativeLocation(-2,  0),   // north north
                new RelativeLocation( 0,  2),   // east east
                new RelativeLocation( 2,  0),   // south south
                new RelativeLocation( 0, -2),   // west west
            };

            RelativeLocation[] neighborhood24 = new RelativeLocation[] {
                new RelativeLocation(-2,  -2),  // northwest northwest
                new RelativeLocation( -2,  -1),  // northwest south
                new RelativeLocation( -1,  -2),   // northwest east
                new RelativeLocation( -2,  2),   // northeast northeast
                new RelativeLocation( -2,  1),  // northeast west
                new RelativeLocation( -1, 2),   // northeast south
                new RelativeLocation( 2, 2),  // southeast southeast
                new RelativeLocation(1,  2),   // southeast north
                new RelativeLocation(2,  1),   //southeast west
                new RelativeLocation( 2,  -2),   // southwest southwest
                new RelativeLocation( 2,  -1),   // southwest east
                new RelativeLocation( 1, -2),   // southwest north
            };

            //Progressively add neighbors as necessary:
            List<RelativeLocation> neighbors = new List<RelativeLocation>();
            foreach (RelativeLocation relativeLoc in neighborhood4)
                neighbors.Add(relativeLoc);
            if(numNeighbors <= 4)  return neighbors;

            foreach (RelativeLocation relativeLoc in neighborhood8)
                neighbors.Add(relativeLoc);
            if(numNeighbors <= 8)  return neighbors;

            foreach (RelativeLocation relativeLoc in neighborhood12)
                neighbors.Add(relativeLoc);
            if(numNeighbors <= 12)  return neighbors;

            foreach (RelativeLocation relativeLoc in neighborhood24)
                neighbors.Add(relativeLoc);

            return neighbors;

        }
        //---------------------------------------------------------------------
        //Generate a Relative Location array (with WEIGHTS) of neighbors.
        //Check each cell within a block surrounding the center point.  This will
        //create a set of POTENTIAL neighbors.  These potential neighbors
        //will need to be later checked to ensure that they are within the landscape
        // and active.

        private static IEnumerable<RelativeLocationWeighted> GetResourceNeighborhood(IAgent agent)
        {
            float CellLength = PlugIn.ModelCore.CellLength;
            PlugIn.ModelCore.UI.WriteLine("Creating Neighborhood List.");
            int neighborRadius = agent.NeighborRadius;
            int numCellRadius = (int) ((double) neighborRadius / CellLength) ;
            PlugIn.ModelCore.UI.WriteLine("NeighborRadius={0}, CellLength={1}, numCellRadius={2}",
                        neighborRadius, CellLength, numCellRadius);

            double centroidDistance = 0;
            double cellLength = CellLength;
            double neighborWeight = 0;

            List<RelativeLocationWeighted> neighborhood = new List<RelativeLocationWeighted>();

            for(int row=(numCellRadius * -1); row<=numCellRadius; row++)
            {
                for(int col=(numCellRadius * -1); col<=numCellRadius; col++)
                {
                    neighborWeight = 0;
                    centroidDistance = DistanceFromCenter(row ,col);
                    //PlugIn.ModelCore.Log.WriteLine("Centroid Distance = {0}.", centroidDistance);
                    if(centroidDistance  <= neighborRadius && centroidDistance > 0)
                    {

                        if(agent.ShapeOfNeighbor == NeighborShape.uniform)
                            neighborWeight = 1.0;
                        if(agent.ShapeOfNeighbor == NeighborShape.linear)
                        {
                            //neighborWeight = (neighborRadius - centroidDistance + (cellLength/2)) / (double) neighborRadius;
                            neighborWeight = 1.0 - (centroidDistance / (double) neighborRadius);
                        }
                        if(agent.ShapeOfNeighbor == NeighborShape.gaussian)
                        {
                            double halfRadius = neighborRadius / 2;
                                neighborWeight = (float)
                                System.Math.Exp(-1 *
                                System.Math.Pow(centroidDistance, 2) /
                                System.Math.Pow(halfRadius, 2));
                        }

                        RelativeLocation reloc = new RelativeLocation(row, col);
                        neighborhood.Add(new RelativeLocationWeighted(reloc, neighborWeight));
                    }
                }
            }
            return neighborhood;
        }