//---------------------------------------------------------------------
 /// <summary>
 /// Initializes a new instance for a site on a landscape.
 /// </summary>
 /// <param name="landscape">
 ///  The landscape where the site is located.
 /// </param>
 /// <param name="location">
 ///  The location of the site.
 /// </param>
 /// <param name="dataIndex">
 ///  The index of the site's data for site variables.
 /// </param>
 internal Site(ILandscape landscape,
     Location   location,
     uint       dataIndex)
 {
     Debug.Assert( landscape.IsValid(location) );
     this.landscape = landscape;
     this.location = location;
     this.dataIndex = dataIndex;
 }
 //---------------------------------------------------------------------
 /// <summary>
 /// Initializes a new instance for an active site on a landscape.
 /// </summary>
 /// <param name="landscape">
 ///  The landscape where the site is located.
 /// </param>
 /// <param name="location">
 ///  The location of the site.
 /// </param>
 /// <param name="dataIndex">
 ///  The index of the site's data for site variables.
 /// </param>
 internal ActiveSite(ILandscape landscape,
     Location   location,
     uint       dataIndex)
 {
     Debug.Assert( landscape.IsValid(location) );
     this.landscape = landscape;
     this.location = location;
     Debug.Assert( dataIndex != InactiveSite.DataIndex );
     this.dataIndex = dataIndex;
 }
        public static void MapCells(Dictionary<string, Parameter<string>> outputfiles, ref Dictionary<ActiveSite, string> OutputSiteNames)
        {
            foreach (KeyValuePair<string, Parameter<string>> site in outputfiles)
            {
                Location OutputLocation;

                // If the location parameters are supplied through MapCoordinatesX/MapCoordinatesY
                if (site.Value.ContainsKey(ParameterNames.MapCoordinatesX) && site.Value.ContainsKey(ParameterNames.MapCoordinatesY))
                {
                    // Get X location
                    float X = float.Parse(site.Value[ParameterNames.MapCoordinatesX]);

                    // Get Y location
                    float Y = float.Parse(site.Value[ParameterNames.MapCoordinatesY]);

                    // Get X border
                    float MaxX = float.Parse(site.Value[ParameterNames.MapCoordinatesMaxX]);

                    // Get Y border
                    float MaxY = float.Parse(site.Value[ParameterNames.MapCoordinatesMaxY]);

                    if (Y >= MaxY) throw new System.Exception("Cannot assign output location, Y coordinate " + Y + " should be larger than MaxY" + MaxY);
                    if (X >= MaxX) throw new System.Exception("Cannot assign output location, X coordinate " + X + " should be larger than MaxY" + MaxX);

                    OutputLocation = GetLandisLocation(X, Y, MaxX, MaxY);

                }
                else
                {
                    OutputLocation = new Location(int.Parse(site.Value[ParameterNames.Row]), int.Parse(site.Value[ParameterNames.Column]));
                }

                // Locate output sites by location
                List<Landis.SpatialModeling.ActiveSite> outputSites =
                    PlugIn.ModelCore.Landscape.Where(localSite => localSite.Location == OutputLocation).ToList();

                if (outputSites.Count() == 0)
                {
                    string msg = "Cannot determine location of " + site.Key;
                    foreach (KeyValuePair<string, string> v in site.Value)
                    {
                        msg += v.Key + " " + v.Value;
                    }
                    msg += " returned " + OutputLocation;

                    throw new System.Exception(msg);
                }
                else
                {
                    OutputSiteNames.Add(outputSites.First(), site.Key);
                }

            }
        }
        public static void MapCells(Dictionary<string, Parameter<string>> outputfiles, ref Dictionary<ActiveSite, string> OutputSiteNames)
        {
            foreach (KeyValuePair<string, Parameter<string>> site in outputfiles)
            {
                Location OutputLocation;
                Parameter<string> p = site.Value;
                if (p.ContainsKey(ParameterNames.MapCoordinatesX) && p.ContainsKey(ParameterNames.MapCoordinatesY))
                {
                    float X = float.Parse(site.Value[ParameterNames.MapCoordinatesX]);
                    float Y = float.Parse(site.Value[ParameterNames.MapCoordinatesY]);
                    float MaxX = float.Parse(site.Value[ParameterNames.MapCoordinatesMaxX]);
                    float MaxY = float.Parse(site.Value[ParameterNames.MapCoordinatesMaxY]);

                    if (Y >= MaxY) throw new System.Exception("Cannot assign output location, Y coordinate " + Y + " should be larger than MaxY" + MaxY);
                    if (X >= MaxX) throw new System.Exception("Cannot assign output location, X coordinate " + X + " should be larger than MaxY" + MaxX);

                    OutputLocation = GetLocations.GetLandisLocation(X, Y, MaxX, MaxY);

                }
                else
                {
                    OutputLocation = new Location(int.Parse(p[ParameterNames.Row]), int.Parse(p[ParameterNames.Column]));
                }

                bool foundsite = false;
                foreach (Landis.SpatialModeling.ActiveSite lsite in PlugIn.ModelCore.Landscape)
                {
                    if (lsite.Location == OutputLocation)
                    {
                        OutputSiteNames.Add(lsite, site.Key);

                        DisplayInLog(lsite);

                        foundsite = true;
                    }
                }
                if (foundsite == false)
                {
                    string msg = "Cannot determine location of " + site.Key;
                    foreach (KeyValuePair<string, string> v in p)
                    {
                        msg += v.Key + " " + v.Value;
                    }
                    msg += " returned " + OutputLocation;

                    throw new System.Exception(msg);
                }
            }
        }
 //---------------------------------------------------------------------
 /// <summary>
 /// The data index for a particular location.
 /// </summary>
 /// <exception cref="System.IndexOutOfRangeException">
 /// The location's row is 0 or > the # of rows in the landscape, or
 /// or the location's column is 0 or > the # of columns in the
 /// landscape.
 /// </exception>
 public abstract uint this[Location location]
 {
     get;
 }
            //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            public override bool MoveNext()
            {
                if (CurrentState == State.AfterLast)
                    return false;

                if (CurrentState == State.BeforeFirst) {
                    if (locations.ActiveLocationCount == 0 &&
                            locations.InactiveLocationCount == 0)
                        return MoveNextReachedEnd();
                    CurrentLocation = new Location(1, 1);
                }
                else {
                    //  CurrentState == State.InCollection
                    CurrentLocation = RowMajor.Next(CurrentLocation, Columns);
                }

                if (CurrentLocation.Row <= Rows) {
                    CurrentDataIndex = locations.indexes[CurrentLocation.Row-1,
                                                         CurrentLocation.Column-1];
                    return MoveNextSucceeded();
                }

                ResetLocationAndIndex();
                return MoveNextReachedEnd();
            }
 //---------------------------------------------------------------------
 /// <summary>
 /// The data index for a particular location.
 /// </summary>
 /// <exception cref="System.IndexOutOfRangeException">
 /// The location's row is 0 or > the # of rows in the landscape, or
 /// or the location's column is 0 or > the # of columns in the
 /// landscape.
 /// </exception>
 public override uint this[Location location]
 {
     get {
         return indexes[location.Row-1, location.Column-1];
     }
 }
 //---------------------------------------------------------------------
 /// <summary>
 /// Resets the current location to (0,0) and the current data index to
 /// InactiveSite.DataIndex.
 /// </summary>
 protected void ResetLocationAndIndex()
 {
     currentLocation = new Location();
     currentDataIndex = InactiveSite.DataIndex;
 }
        /// <summary>
        /// Grows all cohorts at a site for a specified number of years.
        /// Litter is decomposed following the Century model.
        /// </summary>
        public static SiteCohorts Run(
                                       SiteCohorts siteCohorts,
                                       Location location,
                                       int         years,
                                       bool        isSuccessionTimeStep)
        {
            ActiveSite site = (ActiveSite) PlugIn.ModelCore.Landscape.GetSite(location);
            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];

            for (int y = 0; y < years; ++y) {

                SiteVars.ResetAnnualValues(site);

                if(y == 0 && SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0)
                    FireEffects.ReduceLayers(SiteVars.FireSeverity[site], site);

                // Do not reset annual climate if it has already happend for this year.
                if(!EcoregionData.ClimateUpdates[ecoregion][y + PlugIn.ModelCore.CurrentTime])
                {
                    EcoregionData.SetAnnualClimate(PlugIn.ModelCore.Ecoregion[site], y);

                    EcoregionData.ClimateUpdates[ecoregion][y + PlugIn.ModelCore.CurrentTime] = true;
                }

                // if spin-up phase, allow each initial community to have a unique climate
                if(PlugIn.ModelCore.CurrentTime == 0)
                {
                    EcoregionData.SetAnnualClimate(PlugIn.ModelCore.Ecoregion[site], y);
                }

                // Next, Grow and Decompose each month
                int[] months = new int[12]{6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5};

                if(OtherData.CalibrateMode)
                    months = new int[12]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

                for (int i = 0; i < 12; i++)
                {

                    int month = months[i];

                    SiteVars.MonthlyAGNPPcarbon[site][month] = 0.0;
                    SiteVars.MonthlyBGNPPcarbon[site][month] = 0.0;
                    SiteVars.MonthlyNEE[site][month] = 0.0;
                    SiteVars.MonthlyResp[site][month] = 0.0;
                    SiteVars.SourceSink[site].Carbon = 0.0;
                    SiteVars.TotalWoodBiomass[site] = Century.ComputeWoodBiomass((ActiveSite) site);

                    double monthlyNdeposition = EcoregionData.AnnualWeather[PlugIn.ModelCore.Ecoregion[site]].MonthlyNdeposition[month];
                    SiteVars.MineralN[site] += monthlyNdeposition;
                    //PlugIn.ModelCore.Log.WriteLine("Month={0}, Ndeposition={1}.", i+1, monthlyNdeposition);

                    double liveBiomass = (double) ComputeLivingBiomass(siteCohorts);
                    SoilWater.Run(y, month, liveBiomass, site);
                    //SpeciesData.CalculateNGrowthLimits(site);

                    // Calculate N limitations for each cohort
                    AvailableN.CohortNlimits = new Dictionary<int, Dictionary<int,double>>();
                    AvailableN.CalculateNLimits(site);

                    CohortBiomass.month = month;
                    if(month==11)
                        siteCohorts.Grow(site, (y == years && isSuccessionTimeStep), true);
                    else
                        siteCohorts.Grow(site, (y == years && isSuccessionTimeStep), false);

                    WoodLayer.Decompose(site);
                    LitterLayer.Decompose(site);
                    SoilLayer.Decompose(site);

                    //...Volatilization loss as a function of the mineral n which
                    //     remains after uptake by plants
                    double volatilize = SiteVars.MineralN[site] * 0.02 * OtherData.MonthAdjust; // value from ffix.100
                    SiteVars.MineralN[site] -= volatilize;
                    SiteVars.SourceSink[site].Nitrogen += volatilize;
                    //SoilWater.Leach(site);

                    SiteVars.MonthlyNEE[site][month] -= SiteVars.MonthlyAGNPPcarbon[site][month];
                    SiteVars.MonthlyNEE[site][month] -= SiteVars.MonthlyBGNPPcarbon[site][month];
                    SiteVars.MonthlyNEE[site][month] += SiteVars.SourceSink[site].Carbon;

                }
            }

            ComputeTotalCohortCN(site, siteCohorts);

            return siteCohorts;
        }