コード例 #1
0
 /// <summary>
 /// Adds some biomass for a species to the WOODY pools at a site.
 /// </summary>
 public static void AddWoody(double     woodyBiomass,
     ISpecies   species,
     ActiveSite site)
 {
     SiteVars.WoodyDebris[site].AddMass(woodyBiomass,
                             SpeciesData.WoodyDebrisDecay[species]);
 }
コード例 #2
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Assigns an active site to a particular stand.
        /// </summary>
        /// <param name="activeSite">
        /// The active site that is being assigned to a stand.
        /// </param>
        /// <param name="mapCode">
        /// The map code of the stand that the site is being assigned to.
        /// </param>
        public static void AssignSiteToStand(ActiveSite activeSite,
                                             ushort     mapCode)
        {
            double blockArea = (activeSite.SharesData ? Model.BlockArea : Model.Core.CellArea)
            
            //  Skip the site if its management area is not active.
            if (SiteVars.ManagementArea[activeSite] == null)
                return;

            Stand stand;
            //check if this stand is already in the dictionary
            if (stands.TryGetValue(mapCode, out stand)) {
                //if the stand is already in the dictionary, check if it is in the same management area.
                //if it's not in the same MA, throw exception.
                if (SiteVars.ManagementArea[activeSite] != stand.ManagementArea) {
                    throw new PixelException(activeSite.Location,
                                             "Stand {0} is in management areas {1} and {2}",
                                             stand.MapCode,
                                             stand.ManagementArea.MapCode,
                                             SiteVars.ManagementArea[activeSite].MapCode);
                }

            }
            //valid site location which has not been keyed by the dictionary.
            else {
                //assign stand (trygetvalue set it to null when it wasn't found in the dictionary)
                stand = new Stand(mapCode, blockArea);
                //add this stand to the correct management area (pointed to by the site)
                SiteVars.ManagementArea[activeSite].Add(stand);
                stands[mapCode] = stand;
            }                        

            //add this site to this stand
            stand.Add(activeSite);
        }
コード例 #3
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Grows all cohorts at a site for a specified number of years.  The
        /// dead pools at the site also decompose for the given time period.
        /// </summary>
        public static void GrowCohorts(Landis.Library.BiomassCohorts.SiteCohorts cohorts,
                                       ActiveSite site,
                                       int years,
                                       bool isSuccessionTimestep)
        {
            if (SiteVars.Cohorts[site] == null)
                return;

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

                SpeciesData.ChangeDynamicParameters(PlugIn.ModelCore.CurrentTime + y - 1);

                SiteVars.ResetAnnualValues(site);
                CohortBiomass.SubYear = y - 1;
                CohortBiomass.CanopyLightExtinction = 0.0;

                // SiteVars.LAI[site] = 0.0;
                SiteVars.PercentShade[site] = 0.0;
                SiteVars.LightTrans[site] = 1.0;

                SiteVars.Cohorts[site].Grow(site, (y == years && isSuccessionTimestep));
                SiteVars.WoodyDebris[site].Decompose();
                SiteVars.Litter[site].Decompose();
            }
        }
コード例 #4
0
        //---------------------------------------------------------------------

        public static void MyAddNewCohort(ISpecies   species,
                                          ActiveSite site)
        {
            Assert.IsTrue(speciesThatReproduce.Contains(species));
            Assert.AreEqual(expectedSite, site);
            actualSpecies_AddNewCohort.Add(species);
        }
コード例 #5
0
 //---------------------------------------------------------------------
 public void AddNewCohort(ISpecies   species,
     ActiveSite site)
 {
     cohorts[site].AddNewCohort(species,
                                CohortBiomass.InitialBiomass(cohorts[site],
                                                             site, species));
 }
コード例 #6
0
 public static bool Algorithm(ISpecies   species,
                              ActiveSite site)
 {
     return Reproduction.SufficientLight(species, site) &&
            Reproduction.Establish(species, site) &&
            Reproduction.MaturePresent(species, site);
 }
コード例 #7
0
        //---------------------------------------------------------------------

        public static bool MySeedingAlgorithm(ISpecies   species,
                                              ActiveSite site)
        {
            Assert.IsTrue(expectedSpecies.Contains(species));
            Assert.AreEqual(expectedSite, site);
            actualSpecies_SeedingAlg.Add(species);
            return speciesThatReproduce.Contains(species);
        }
コード例 #8
0
        //public static bool Establish(double[,] establishment)
        //---------------------------------------------------------------------
        /// <summary>
        /// Determines if a species can establish on a site.
        /// </summary>
        public static bool Establish(ISpecies species, ActiveSite site)
        {
            double establishProbability = 0; // Reproduction.GetEstablishProbability(species, site);

            //return Landis.Model.GenerateUniform() < establishment;

            return Model.Core.GenerateUniform() < establishProbability;
        }
コード例 #9
0
 public static bool Algorithm(ISpecies   species,
     ActiveSite site)
 {
     return Reproduction.SufficientResources(species, site) &&
            Reproduction.Establish(species, site) &&
            //Reproduction.MaturePresent(species, site);
            SiteVars.Cohorts[site].IsMaturePresent(species);
 }
コード例 #10
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Raises a Cohort.DeathEvent.
        /// </summary>
        public static void Died(object     sender,
                                ICohort    cohort,
                                ActiveSite site,
                                PlugInType disturbanceType)
        {
            if (DeathEvent != null)
                DeathEvent(sender, new DeathEventArgs(cohort, site, disturbanceType));
        }
コード例 #11
0
 //---------------------------------------------------------------------
 public override byte ComputeShade(ActiveSite site)
 {
     byte shade = 0;
     foreach (SpeciesCohorts speciesCohorts in cohorts[site]) {
         ISpecies species = speciesCohorts.Species;
         if (species.ShadeTolerance > shade)
             shade = species.ShadeTolerance;
     }
     return shade;
 }
コード例 #12
0
 /// <summary>
 /// The default method for determining if there is sufficient light at
 /// a site for a species to germinate/resprout.
 /// </summary>
 public static bool SufficientResources(ISpecies   species,
     ActiveSite site)
 {
     byte siteShade = SiteVars.Shade[site];
     bool sufficientLight;
     sufficientLight = (species.ShadeTolerance <= 4 && species.ShadeTolerance > siteShade) ||
            (species.ShadeTolerance == 5 && siteShade > 1);
     //  pg 14, Model description, this ----------------^ may be 2?
     return sufficientLight;
 }
コード例 #13
0
        public void Init()
        {
            species = Data.Species[0];
            expectedSender = null;
            deadCohorts = new List<ICohort>();

            ILandscape landscape = Data.Make1by1Landscape();
            activeSite = landscape[1,1];

            Cohort.DeathEvent += MySenescenceDeathMethod;
        }
コード例 #14
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Assigns an active site to a particular management area.
        /// </summary>
        /// <param name="activeSite">
        /// The active site that is being assigned to a management area.
        /// </param>
        /// <param name="mapCode">
        /// The map code of the management area that the site is being assigned
        /// to.
        /// </param>
        public static void AssignSiteToMgmtArea(ActiveSite activeSite,
                                                ushort     mapCode)
        {
            ManagementArea mgmtArea = mgmtAreas.Find(mapCode);
            if (mgmtArea == null) {
                if (! inactiveMgmtAreas.Contains(mapCode))
                    inactiveMgmtAreas.Add(mapCode);
            }
            else {
                mgmtArea.OnMap = true;
                SiteVars.ManagementArea[activeSite] = mgmtArea;
            }
        }
コード例 #15
0
        public void Init()
        {
            species = Data.Species[0];
            expectedSender = null;
            deadCohorts = new List<ICohort>();

            bool[,] grid = new bool[,]{ {true} };
            DataGrid<bool> dataGrid = new DataGrid<bool>(grid);
            ILandscape landscape = new Landscape(dataGrid);
            activeSite = landscape[1,1];

            Cohort.DeathEvent += MySenescenceDeathMethod;
        }
コード例 #16
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Computes the actual biomass at a site.  The biomass is the total
        /// of all the site's cohorts except young ones.  The total is limited
        /// to being no more than the site's maximum biomass less the previous
        /// year's mortality at the site.
        /// </summary>
        public static double ActualSiteBiomass(SiteCohorts    siteCohorts,
            ActiveSite     site,
            out IEcoregion ecoregion)
        {
            int youngBiomass;
            int totalBiomass = Cohorts.ComputeBiomass(siteCohorts, out youngBiomass);
            double B_ACT = totalBiomass - youngBiomass;

            int lastMortality = siteCohorts.PrevYearMortality;
            ecoregion = Model.Core.Ecoregion[site];
            B_ACT = Math.Min( B_MAX[ecoregion] - lastMortality, B_ACT);

            return B_ACT;
        }
コード例 #17
0
        public void Init()
        {
            abiebals = Data.Species["abiebals"];
            betualle = Data.Species["betualle"];

            ILandscape landscape = Data.Make1by1Landscape();
            activeSite = landscape[1,1];

            disturbance = new MockSpeciesCohortsDisturbance();
            disturbance.CurrentSite = activeSite;
            deadCohorts = new Dictionary<ISpecies, List<ushort>>();

            Cohort.DeathEvent += MyCohortDiedMethod;
        }
コード例 #18
0
        public void Init()
        {
            abiebals = Data.Species["abiebals"];
            betualle = Data.Species["betualle"];

            bool[,] grid = new bool[,]{ {true} };
            DataGrid<bool> dataGrid = new DataGrid<bool>(grid);
            ILandscape landscape = new Landscape(dataGrid);
            activeSite = landscape[1,1];

            disturbance = new MockSpeciesCohortsDisturbance();
            disturbance.CurrentSite = activeSite;
            deadCohorts = new Dictionary<ISpecies, List<ushort>>();

            Cohort.DeathEvent += MyCohortDiedMethod;
        }
コード例 #19
0
        //---------------------------------------------------------------------

        bool IFormOfReproduction.TryAt(ActiveSite site)
        {
            bool success = false;
            BitArray selectedSpeciesAtSite = selectedSpecies[site];

            for (int index = 0; index < speciesDataset.Count; ++index) {
                if (selectedSpeciesAtSite.Get(index)) {
                    ISpecies species = speciesDataset[index];
                    if (PreconditionsSatisfied(species, site)) {
                        Reproduction.AddNewCohort(species, site);
                        success = true;
                    }
                }
            }

            return success;
        }
コード例 #20
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Adds some biomass for a species to the LITTER pools at a site.
        /// </summary>
        public static void AddLitter(double nonWoodyBiomass,
            ISpecies   species,
            ActiveSite site)
        {
            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];
            double siteAET = (double)EcoregionData.AET[ecoregion];

            //Calculation of decomposition rate for species litter cohort
            // Decay rate from Meentemeyer 1978.  Ecology 59: 465-472.
            double leafKReg = (-0.5365 + (0.00241 * siteAET)) - (((-0.01586 + (0.000056 * siteAET)) * SpeciesData.LeafLignin[species] * 100));

            // From  Fan et al. 1998 Ecological Applications 8: 734-737:
            //double leafKReg = ((0.10015 * siteAET - 3.44618) - (0.01341 + 0.00147 * siteAET) *
            //SpeciesData.LeafLignin[species]) / 100;

            //PlugIn.ModelCore.Log.WriteLine("Decay rate for {0} within {1} = {2}.  LL = {3}.", species.Name, ecoregion.Name, leafKReg, SpeciesData.LeafLignin[species]);

            double decayValue = leafKReg;

            SiteVars.Litter[site].AddMass(nonWoodyBiomass, decayValue);
        }
コード例 #21
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Schedules a list of species to be planted at a site.
        /// </summary>
        public static void PreventEstablishment(ActiveSite site)
        {
            noEstablish[site] = true;
        }
コード例 #22
0
 public RemoveAgeBetween5And30_AgeOnly(ActiveSite currentSite)
     : base(currentSite)
 {
 }
コード例 #23
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Schedules a list of species to be planted at a site.
        /// </summary>
        public static void ScheduleForPlanting(Planting.SpeciesList speciesToPlant,
                                               ActiveSite site)
        {
            planting.Schedule(speciesToPlant, site);
        }
コード例 #24
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Grows all the cohorts by advancing their ages by 1 year and
        /// updating their biomasses accordingly.
        /// </summary>
        /// <param name="site">
        /// The site where the cohorts are located.
        /// </param>
        private void GrowFor1Year(ActiveSite site)
        {
            //  Create a list of iterators, one iterator per set of species
            //  cohorts.  Iterators go through a species' cohorts from oldest
            //  to youngest.  The list is sorted by age, oldest to youngest;
            //  so the first iterator in the list is the iterator's whose
            //  current cohort has the oldest age.
            List <OldToYoungIterator> itors = new List <OldToYoungIterator>();

            foreach (SpeciesCohorts speciesCohorts in cohorts)
            {
                OldToYoungIterator itor = speciesCohorts.OldToYoung;
                InsertIterator(itor, itors);
            }

            int siteMortality = 0;

            //  Loop through iterators until they're exhausted
            while (itors.Count > 0)
            {
                //  Grow the current cohort of the first iterator in the list.
                //  The cohort's biomass is updated for 1 year's worth of
                //  growth and mortality.
                OldToYoungIterator itor = itors[0];
                siteMortality += itor.GrowCurrentCohort(site,
                                                        ref totalBiomass,
                                                        prevYearMortality);

                if (itor.MoveNext())
                {
                    //  Iterator has been moved to the next cohort, so see if
                    //  the age of this cohort is the oldest.
                    if (itors.Count > 1 && itor.Age < itors[1].Age)
                    {
                        //  Pop the first iterator of the list, and then re-
                        //  insert it into proper place.
                        itors.RemoveAt(0);
                        InsertIterator(itor, itors);
                    }
                }
                else
                {
                    //  Iterator has no more cohorts, so remove it from list.
                    itors.RemoveAt(0);

                    if (itor.SpeciesCohorts.Count > 0)
                    {
                        itor.SpeciesCohorts.UpdateMaturePresent();
                    }
                    else
                    {
                        //  The set of species cohorts is now empty, so remove
                        //  it from the list of species cohorts.
                        for (int i = 0; i < cohorts.Count; i++)
                        {
                            if (cohorts[i] == itor.SpeciesCohorts)
                            {
                                cohorts.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }
            }

            prevYearMortality = siteMortality;
        }
コード例 #25
0
        //---------------------------------------------------------------------
        public void DecomposeMetabolic(ActiveSite site)
        {
            double litterC = this.Carbon;
            double anerb   = SiteVars.AnaerobicEffect[site];

            if (litterC > 0.0000001)
            {
                // Determine C/N ratios for flows to SOM1
                double ratioCNtoSOM1 = 0.0;
                double co2loss       = 0.0;

                // Compute ratios for surface  metabolic residue
                if (this.Type == LayerType.Surface)
                {
                    ratioCNtoSOM1 = Layer.AbovegroundDecompositionRatio(this.Nitrogen, litterC);
                }

                //Compute ratios for soil metabolic residue
                else
                {
                    ratioCNtoSOM1 = Layer.BelowgroundDecompositionRatio(site,
                                                                        OtherData.MinCNenterSOM1,
                                                                        OtherData.MaxCNenterSOM1,
                                                                        OtherData.MinContentN_SOM1);
                }

                //Compute total C flow out of metabolic layer
                double totalCFlow = litterC
                                    * SiteVars.DecayFactor[site]
                                    * OtherData.LitterParameters[(int)this.Type].DecayRateMetabolicC
                                    * OtherData.MonthAdjust;

                //PlugIn.ModelCore.UI.WriteLine("DecomposeMeta1.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                //Added impact of soil anerobic conditions
                if (this.Type == LayerType.Soil)
                {
                    totalCFlow *= anerb;
                }

                //Make sure metabolic C does not go negative.
                if (totalCFlow > litterC)
                {
                    totalCFlow = litterC;
                }

                //If decomposition can occur,
                if (this.DecomposePossible(ratioCNtoSOM1, SiteVars.MineralN[site]))
                {
                    //CO2 loss
                    if (this.Type == LayerType.Surface)
                    {
                        co2loss = totalCFlow * OtherData.MetabolicToCO2Surface;
                    }
                    else
                    {
                        co2loss = totalCFlow * OtherData.MetabolicToCO2Soil;
                    }

                    //PlugIn.ModelCore.UI.WriteLine("BeforeResp.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                    this.Respiration(co2loss, site);
                    //PlugIn.ModelCore.UI.WriteLine("AfterResp.  MineralN={0:0.00}.", SiteVars.MineralN[site]);

                    //Decompose metabolic into som1
                    double netCFlow = totalCFlow - co2loss;

                    if (netCFlow > litterC)
                    {
                        PlugIn.ModelCore.UI.WriteLine("   ERROR:  Decompose Metabolic:  netCFlow={0:0.000} > layer.Carbon={0:0.000}.", netCFlow, this.Carbon);
                    }

                    // -- CARBON AND NITROGEN ---------------------------
                    // Partition and schedule C flows
                    // Compute and schedule N flows and update mineralization accumulators.
                    if ((int)this.Type == (int)LayerType.Surface)
                    {
                        this.TransferCarbon(SiteVars.SOM1surface[site], netCFlow);
                        this.TransferNitrogen(SiteVars.SOM1surface[site], netCFlow, litterC, ratioCNtoSOM1, site);
                        //PlugIn.ModelCore.UI.WriteLine("DecomposeMetabolic.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                    }
                    else
                    {
                        this.TransferCarbon(SiteVars.SOM1soil[site], netCFlow);
                        this.TransferNitrogen(SiteVars.SOM1soil[site], netCFlow, litterC, ratioCNtoSOM1, site);
                    }
                }
            }
            //}
        }
コード例 #26
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Computes the change in a cohort's biomass due to Annual Net Primary
        /// Productivity (ANPP), age-related mortality (M_AGE), and development-
        /// related mortality (M_BIO).
        /// </summary>
        public float[] ComputeChange(ICohort cohort, ActiveSite site)
        {
            ecoregion = PlugIn.ModelCore.Ecoregion[site];

            // First call to the Calibrate Log:
            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                Outputs.CalibrateLog.Write("{0},{1},{2},{3},{4},{5:0.0},{6:0.0},", PlugIn.ModelCore.CurrentTime, Century.Month + 1, ecoregion.Index, cohort.Species.Name, cohort.Age, cohort.WoodBiomass, cohort.LeafBiomass);
            }


            double siteBiomass = Century.ComputeLivingBiomass(SiteVars.Cohorts[site]);

            if (siteBiomass < 0)
            {
                throw new ApplicationException("Error: Site biomass < 0");
            }

            // ****** Mortality *******
            // Age-related mortality includes woody and standing leaf biomass.
            double[] mortalityAge = ComputeAgeMortality(cohort, site);

            //  Growth-related mortality
            double[] mortalityGrowth = ComputeGrowthMortality(cohort, site);

            double[] totalMortality = new double[2] {
                Math.Min(cohort.WoodBiomass, mortalityAge[0] + mortalityGrowth[0]), Math.Min(cohort.LeafBiomass, mortalityAge[1] + mortalityGrowth[1])
            };
            double nonDisturbanceLeafFall = totalMortality[1];

            // ****** Growth *******
            double[] actualANPP = ComputeActualANPP(cohort, site, siteBiomass, mortalityAge);

            double scorch = 0.0;

            defoliatedLeafBiomass = 0.0;

            if (Century.Month == 6)  //July = 6
            {
                if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0)
                {
                    scorch = FireEffects.CrownScorching(cohort, SiteVars.FireSeverity[site]);
                }

                if (scorch > 0.0)  // NEED TO DOUBLE CHECK WHAT CROWN SCORCHING RETURNS
                {
                    totalMortality[1] = Math.Min(cohort.LeafBiomass, scorch + totalMortality[1]);
                }

                // Defoliation (index) ranges from 1.0 (total) to none (0.0).
                if (PlugIn.ModelCore.CurrentTime > 0) //Skip this during initialization
                {
                    //defoliation = Landis.Library.LeafBiomassCohorts.CohortDefoliation.Compute(cohort, site,  (int)siteBiomass);
                    int cohortBiomass = (int)(cohort.LeafBiomass + cohort.WoodBiomass);
                    defoliation = Landis.Library.Biomass.CohortDefoliation.Compute(site, cohort.Species, cohortBiomass, (int)siteBiomass);
                }

                if (defoliation > 1.0)
                {
                    defoliation = 1.0;
                }

                if (defoliation > 0.0)
                {
                    defoliatedLeafBiomass = (cohort.LeafBiomass) * defoliation;
                    if (totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass > 0.001)
                    {
                        defoliatedLeafBiomass = cohort.LeafBiomass - totalMortality[1];
                    }
                    //PlugIn.ModelCore.UI.WriteLine("Defoliation.Month={0:0.0}, LeafBiomass={1:0.00}, DefoliatedLeafBiomass={2:0.00}, TotalLeafMort={2:0.00}", Century.Month, cohort.LeafBiomass, defoliatedLeafBiomass , mortalityAge[1]);

                    ForestFloor.AddFrassLitter(defoliatedLeafBiomass, cohort.Species, site);
                }
            }
            else
            {
                defoliation           = 0.0;
                defoliatedLeafBiomass = 0.0;
            }

            // RMS 03/2016: Additional mortality as reaching capacity limit:  SAVE FOR NEXT RELEASE
            //double maxBiomass = SpeciesData.B_MAX_Spp[cohort.Species][ecoregion];
            //double limitCapacity = Math.Min(1.0, Math.Exp(siteBiomass / maxBiomass * 5.0) / Math.Exp(5.0));  // 1.0 = total limit; 0.0 = No limit
            //totalMortality[0] += (actualANPP[0] * limitCapacity); // totalMortality not to exceed ANPP allocation


            if (totalMortality[0] <= 0.0 || cohort.WoodBiomass <= 0.0)
            {
                totalMortality[0] = 0.0;
            }

            if (totalMortality[1] <= 0.0 || cohort.LeafBiomass <= 0.0)
            {
                totalMortality[1] = 0.0;
            }


            if ((totalMortality[0]) > cohort.WoodBiomass)
            {
                PlugIn.ModelCore.UI.WriteLine("Warning: WOOD Mortality exceeds cohort wood biomass. M={0:0.0}, B={1:0.0}", (totalMortality[0]), cohort.WoodBiomass);
                PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.0}, Mgrow={1:0.0},", mortalityAge[0], mortalityGrowth[0]);
                throw new ApplicationException("Error: WOOD Mortality exceeds cohort biomass");
            }
            if ((totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass) > 0.01)
            {
                PlugIn.ModelCore.UI.WriteLine("Warning: LEAF Mortality exceeds cohort biomass. Mortality={0:0.000}, Leafbiomass={1:0.000}", (totalMortality[1] + defoliatedLeafBiomass), cohort.LeafBiomass);
                PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.00}, Mgrow={1:0.00}, Mdefo={2:0.000},", mortalityAge[1], mortalityGrowth[1], defoliatedLeafBiomass);
                throw new ApplicationException("Error: LEAF Mortality exceeds cohort biomass");
            }
            float deltaWood = (float)(actualANPP[0] - totalMortality[0]);
            float deltaLeaf = (float)(actualANPP[1] - totalMortality[1] - defoliatedLeafBiomass);

            float[] deltas = new float[2] {
                deltaWood, deltaLeaf
            };

            //if((totalMortality[1] + defoliatedLeafBiomass) > cohort.LeafBiomass)
            //   PlugIn.ModelCore.UI.WriteLine("Warning: Leaf Mortality exceeds cohort leaf biomass. M={0:0.0}, B={1:0.0}, DefoLeafBiomass={2:0.0}, defoliationIndex={3:0.0}", totalMortality[1], cohort.LeafBiomass, defoliatedLeafBiomass, defoliation);

            UpdateDeadBiomass(cohort, site, totalMortality);

            CalculateNPPcarbon(site, cohort, actualANPP);

            AvailableN.AdjustAvailableN(cohort, site, actualANPP);

            if (OtherData.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0)
            {
                Outputs.CalibrateLog.WriteLine("{0:0.00},{1:0.00},{2:0.00},{3:0.00},", deltaWood, deltaLeaf, totalMortality[0], totalMortality[1]);
                //Outputs.CalibrateLog.WriteLine("{0:0.00}, {1:0.00}, {2:0.00}", resorbedNused, mineralNused, totalNdemand);
            }

            return(deltas);
        }
コード例 #27
0
        /// <summary>
        /// Grows all cohorts at a site for a specified number of years.
        /// Litter is decomposed following the Century model.
        /// </summary>
        public static ISiteCohorts Run(ActiveSite site,
                                       int years,
                                       bool isSuccessionTimeStep)
        {
            ISiteCohorts siteCohorts = SiteVars.Cohorts[site];
            IEcoregion   ecoregion   = PlugIn.ModelCore.Ecoregion[site];

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

                //if (PlugIn.ModelCore.CurrentTime > 0 && Climate.Future_MonthlyData.ContainsKey(PlugIn.FutureClimateBaseYear + y + PlugIn.ModelCore.CurrentTime- years))
                if (Climate.Future_MonthlyData.ContainsKey(PlugIn.FutureClimateBaseYear + y + PlugIn.ModelCore.CurrentTime - years))
                {
                    ClimateRegionData.AnnualWeather[ecoregion] = Climate.Future_MonthlyData[PlugIn.FutureClimateBaseYear + y - years + PlugIn.ModelCore.CurrentTime][ecoregion.Index];
                }

                //PlugIn.ModelCore.UI.WriteLine("PlugIn_FutureClimateBaseYear={0}, y={1}, ModelCore_CurrentTime={2}, CenturyTimeStep = {3}, SimulatedYear = {4}.", PlugIn.FutureClimateBaseYear, y, PlugIn.ModelCore.CurrentTime, years, (PlugIn.FutureClimateBaseYear + y - years + PlugIn.ModelCore.CurrentTime));

                SiteVars.ResetAnnualValues(site);

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

                // 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}; This output will not match normal mode due to differences in initialization
                    months = new int[12] {
                        6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5
                    }
                }
                ;

                PlugIn.AnnualWaterBalance = 0;

                for (MonthCnt = 0; MonthCnt < 12; MonthCnt++)
                {
                    // Calculate mineral N fractions based on coarse root biomass.  Only need to do once per year.
                    if (MonthCnt == 0)
                    {
                        AvailableN.CalculateMineralNfraction(site);
                    }
                    //PlugIn.ModelCore.UI.WriteLine("SiteVars.MineralN = {0:0.00}, month = {1}.", SiteVars.MineralN[site], i);

                    Month = months[MonthCnt];

                    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.MonthlyStreamN[site][Month]     = 0.0;
                    SiteVars.SourceSink[site].Carbon         = 0.0;
                    SiteVars.TotalWoodBiomass[site]          = Century.ComputeWoodBiomass((ActiveSite)site);
                    //SiteVars.LAI[site] = Century.ComputeLAI((ActiveSite)site);

                    double ppt = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPrecip[Century.Month];

                    double monthlyNdeposition;
                    if (PlugIn.AtmosNintercept != -1 && PlugIn.AtmosNslope != -1)
                    {
                        monthlyNdeposition = PlugIn.AtmosNintercept + (PlugIn.AtmosNslope * ppt);
                    }
                    else
                    {
                        monthlyNdeposition = ClimateRegionData.AnnualWeather[ecoregion].MonthlyNDeposition[Century.Month];
                    }

                    if (monthlyNdeposition < 0)
                    {
                        throw new System.ApplicationException("Error: Nitrogen deposition less than zero.");
                    }

                    ClimateRegionData.MonthlyNDeposition[ecoregion][Month] = monthlyNdeposition;
                    ClimateRegionData.AnnualNDeposition[ecoregion]        += monthlyNdeposition;
                    SiteVars.MineralN[site] += monthlyNdeposition;
                    //PlugIn.ModelCore.UI.WriteLine("Ndeposition={0},MineralN={1:0.00}.", monthlyNdeposition, SiteVars.MineralN[site]);

                    double liveBiomass = (double)ComputeLivingBiomass(siteCohorts);
                    double baseFlow, stormFlow, AET;
                    SoilWater.Run(y, Month, liveBiomass, site, out baseFlow, out stormFlow, out AET);

                    PlugIn.AnnualWaterBalance += ppt - AET;

                    // Calculate N allocation for each cohort
                    AvailableN.SetMineralNallocation(site);

                    if (MonthCnt == 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.  ML added a correction factor for wetlands since their denitrification rate is double that of wetlands
                    //based on a review paper by Seitziner 2006.

                    double volatilize = (SiteVars.MineralN[site] * PlugIn.DenitrificationRate); //ClimateRegionData.Denitrif[ecoregion]); // monthly value

                    //PlugIn.ModelCore.UI.WriteLine("BeforeVol.  MineralN={0:0.00}.", SiteVars.MineralN[site]);

                    SiteVars.MineralN[site]            -= volatilize;
                    SiteVars.SourceSink[site].Nitrogen += volatilize;
                    SiteVars.Nvol[site] += volatilize;

                    SoilWater.Leach(site, baseFlow, stormFlow);

                    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);
        }
コード例 #28
0
            //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            public RemoveAgeBetween5And30(ActiveSite currentSite)
            {
                this.currentSite = currentSite;
            }
コード例 #29
0
        //---------------------------------------------------------------------
        // Total mortality, including from disturbance or senescence.

        public void CohortTotalMortality(object sender, Landis.Library.BiomassCohorts.DeathEventArgs eventArgs)
        {
            //PlugIn.ModelCore.UI.WriteLine("Cohort Total Mortality: {0}", eventArgs.Site);

            ExtensionType disturbanceType = eventArgs.DisturbanceType;
            ActiveSite    site            = eventArgs.Site;

            ICohort cohort      = (Landis.Library.LeafBiomassCohorts.ICohort)eventArgs.Cohort;
            double  foliarInput = (double)cohort.LeafBiomass;
            double  woodInput   = (double)cohort.WoodBiomass;

            if (disturbanceType != null)
            {
                //PlugIn.ModelCore.UI.WriteLine("DISTURBANCE EVENT: Cohort Died: species={0}, age={1}, disturbance={2}.", cohort.Species.Name, cohort.Age, eventArgs.DisturbanceType);

                if (disturbanceType.IsMemberOf("disturbance:fire"))
                {
                    SiteVars.FireSeverity = PlugIn.ModelCore.GetSiteVar <byte>("Fire.Severity");
                    Landis.Library.Succession.Reproduction.CheckForPostFireRegen(eventArgs.Cohort, site);

                    if (!Disturbed[site])  // the first cohort killed/damaged
                    {
                        SiteVars.SmolderConsumption[site] = 0.0;
                        SiteVars.FlamingConsumption[site] = 0.0;
                        if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0)
                        {
                            FireEffects.ReduceLayers(SiteVars.FireSeverity[site], site);
                        }
                    }

                    double woodFireConsumption   = woodInput * (float)FireEffects.ReductionsTable[(int)SiteVars.FireSeverity[site]].CoarseLitterReduction;
                    double foliarFireConsumption = foliarInput * (float)FireEffects.ReductionsTable[(int)SiteVars.FireSeverity[site]].FineLitterReduction;

                    SiteVars.SmolderConsumption[site] += woodFireConsumption;
                    SiteVars.FlamingConsumption[site] += foliarFireConsumption;
                    SiteVars.SourceSink[site].Carbon  += woodFireConsumption * 0.47;
                    SiteVars.SourceSink[site].Carbon  += foliarFireConsumption * 0.47;
                    woodInput   -= woodFireConsumption;
                    foliarInput -= foliarFireConsumption;
                }
                else
                {
                    if (disturbanceType.IsMemberOf("disturbance:harvest"))
                    {
                        SiteVars.HarvestPrescriptionName = PlugIn.ModelCore.GetSiteVar <string>("Harvest.PrescriptionName");
                        if (!Disturbed[site])  // the first cohort killed/damaged
                        {
                            HarvestEffects.ReduceLayers(SiteVars.HarvestPrescriptionName[site], site);
                        }
                        double woodLoss   = woodInput * (float)HarvestEffects.GetCohortWoodRemoval(site);
                        double foliarLoss = foliarInput * (float)HarvestEffects.GetCohortLeafRemoval(site);
                        SiteVars.SourceSink[site].Carbon += woodLoss * 0.47;
                        SiteVars.SourceSink[site].Carbon += foliarLoss * 0.47;
                        woodInput   -= woodLoss;
                        foliarInput -= foliarLoss;
                    }

                    // If not fire, check for resprouting:
                    Landis.Library.Succession.Reproduction.CheckForResprouting(eventArgs.Cohort, site);
                }
            }


            //PlugIn.ModelCore.UI.WriteLine("Cohort Died: species={0}, age={1}, wood={2:0.00}, foliage={3:0.00}.", cohort.Species.Name, cohort.Age, wood, foliar);
            ForestFloor.AddWoodLitter(woodInput, cohort.Species, eventArgs.Site);
            ForestFloor.AddFoliageLitter(foliarInput, cohort.Species, eventArgs.Site);

            // Assume that ALL dead root biomass stays on site.
            Roots.AddCoarseRootLitter(Roots.CalculateCoarseRoot(cohort, cohort.WoodBiomass), cohort, cohort.Species, eventArgs.Site);
            Roots.AddFineRootLitter(Roots.CalculateFineRoot(cohort, cohort.LeafBiomass), cohort, cohort.Species, eventArgs.Site);

            if (disturbanceType != null)
            {
                Disturbed[site] = true;
            }

            return;
        }
        //---------------------------------------------------------------------
        // Initialize landscape with patches of defoliation during the first year
        public static void InitializeDefoliationPatches(IInsect insect)
        {
            PlugIn.ModelCore.UI.WriteLine("   Initializing Defoliation Patches... ");
            SiteVars.InitialOutbreakProb.ActiveSiteValues   = 0.0;
            insect.Disturbed.ActiveSiteValues               = false;
            insect.NeighborhoodDefoliation.ActiveSiteValues = 0.0;

            foreach (ActiveSite site in PlugIn.ModelCore.Landscape)
            {
                double suscIndexSum = 0.0;
                double sumBio       = 0.0;


                foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site])
                {
                    foreach (ICohort cohort in speciesCohorts)
                    {
                        suscIndexSum += cohort.Biomass * (insect.SppTable[cohort.Species.Index].Susceptibility);
                        sumBio       += cohort.Biomass;
                    }
                }


                // If no biomass, no chance of defoliation, go to the next site.
                if (suscIndexSum <= 0 || sumBio <= 0)
                {
                    SiteVars.InitialOutbreakProb[site] = 0.0;
                    continue;
                }

                int suscIndex = (int)Math.Round(suscIndexSum / sumBio) - 1;

                if (suscIndex > 2.0 || suscIndex < 0)
                {
                    PlugIn.ModelCore.UI.WriteLine("SuscIndex < 0 || > 2.  Site R/C={0}/{1},suscIndex={2},suscIndexSum={3},sumBio={4}.", site.Location.Row, site.Location.Column, suscIndex, suscIndexSum, sumBio);
                    throw new ApplicationException("Error: SuscIndex is not between 2.0 and 0.0");
                }
                // Assume that there are no neighbors whatsoever:
                DistributionType dist = insect.SusceptibleTable[suscIndex].Distribution_80.Name;


                // PlugIn.ModelCore.UI.WriteLine("suscIndex={0},suscIndexSum={1},cohortBiomass={2}.", suscIndex,suscIndexSum,sumBio);
                double value1 = insect.SusceptibleTable[suscIndex].Distribution_80.Value1;
                double value2 = insect.SusceptibleTable[suscIndex].Distribution_80.Value2;

                double probability = Distribution.GenerateRandomNum(dist, value1, value2);
                if (probability > 1.0 || probability < 0)
                {
                    PlugIn.ModelCore.UI.WriteLine("Initial Defoliation Probility < 0 || > 1.  Site R/C={0}/{1}.", site.Location.Row, site.Location.Column);
                    throw new ApplicationException("Error: Probability is not between 1.0 and 0.0");
                }

                SiteVars.InitialOutbreakProb[site] = probability;
                // PlugIn.ModelCore.UI.WriteLine("Susceptiblity index={0}.  Outbreak Probability={1:0.00}.  R/C={2}/{3}.", suscIndex, probability, site.Location.Row, site.Location.Column);
            }

            foreach (ActiveSite site in PlugIn.ModelCore.Landscape)
            {
                //get a random site from the stand
                double randomNum  = PlugIn.ModelCore.GenerateUniform();
                double randomNum2 = PlugIn.ModelCore.GenerateUniform();

                //Create random variability in outbreak area within a simulation so outbreaks are more variable.
                double initialAreaCalibratorRandomNum = (randomNum2 - 0.5) * insect.InitialPatchOutbreakSensitivity / 2;

                //Start spreading!
                if (randomNum < SiteVars.InitialOutbreakProb[site] * (insect.InitialPatchOutbreakSensitivity + initialAreaCalibratorRandomNum))

                {
                    //start with this site (if it's active)
                    ActiveSite currentSite = site;

                    //queue to hold sites to defoliate
                    Queue <ActiveSite> sitesToConsider = new Queue <ActiveSite>();

                    //put initial site on queue
                    sitesToConsider.Enqueue(currentSite);

                    DistributionType dist       = insect.InitialPatchDistr;
                    double           targetArea = Distribution.GenerateRandomNum(dist, insect.InitialPatchValue1, insect.InitialPatchValue2);

                    //PlugIn.ModelCore.UI.WriteLine("  Target Patch Area={0:0.0}.", targetArea);
                    double areaSelected = 0.0;

                    //loop through stand, defoliating patches of size target area
                    while (sitesToConsider.Count > 0 && areaSelected < targetArea)
                    {
                        currentSite = sitesToConsider.Dequeue();

                        // Because this is the first year, neighborhood defoliation is given a value.
                        // The value is used in Defoliate.DefoliateCohort()
                        insect.NeighborhoodDefoliation[currentSite] = SiteVars.InitialOutbreakProb[currentSite];
                        areaSelected += PlugIn.ModelCore.CellArea;
                        //insect.Disturbed[currentSite] = true;

                        //Next, add site's neighbors to the list of
                        //sites to consider.
                        //loop through the site's neighbors enqueueing all the good ones.

                        //double maxNeighborProb = 0.0;
                        //Site maxNeighbor = currentSite;
                        //bool foundNewNeighbor = false;

                        foreach (RelativeLocation loc in all_neighbor_locations)
                        {
                            Site neighbor = currentSite.GetNeighbor(loc);

                            //get a neighbor site (if it's non-null and active)
                            if (neighbor != null &&
                                neighbor.IsActive &&
                                !sitesToConsider.Contains((ActiveSite)neighbor) &&
                                !insect.Disturbed[neighbor])
                            {
                                insect.Disturbed[currentSite] = true;
                                randomNum = PlugIn.ModelCore.GenerateUniform();

                                /*if (SiteVars.InitialOutbreakProb[neighbor] > maxNeighborProb)
                                 * {
                                 *  maxNeighbor = currentSite.GetNeighbor(loc);
                                 *  maxNeighborProb = SiteVars.InitialOutbreakProb[neighbor];
                                 *  foundNewNeighbor = true;
                                 * }*/

                                //check if it's a valid neighbor:
                                if (SiteVars.InitialOutbreakProb[neighbor] * insect.InitialPatchShapeCalibrator > randomNum)
                                {
                                    sitesToConsider.Enqueue((ActiveSite)neighbor);
                                }
                            }
                        }

                        //if(foundNewNeighbor)
                        //    sitesToConsider.Enqueue((ActiveSite) maxNeighbor);
                    }

                    //PlugIn.ModelCore.UI.WriteLine("   Initial Patch Area Selected={0:0.0}.", areaSelected);
                }
            }
        }
コード例 #31
0
 public void BiomassDisturbance()
 {
     expectedDistType = RemoveAgeBetween5And30.DisturbanceType;
     expectedSite     = activeSite;
     CohortsRemoved(new RemoveAgeBetween5And30_Biomass(activeSite));
 }
コード例 #32
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Determines if there is a mature cohort at a site.
        /// This is a Delegate method to base succession.
        /// </summary>
        public bool MaturePresent(ISpecies species, ActiveSite site)
        {
            return(SiteVars.Cohorts[site].IsMaturePresent(species));
        }
コード例 #33
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Add a new cohort to a site.
        /// This is a Delegate method to base succession.
        /// </summary>

        public void AddNewCohort(ISpecies species, ActiveSite site)
        {
            float[] initialBiomass = CohortBiomass.InitialBiomass(species, SiteVars.Cohorts[site], site);
            SiteVars.Cohorts[site].AddNewCohort(species, 1, initialBiomass[0], initialBiomass[1]);
        }
コード例 #34
0
 //---------------------------------------------------------------------
 //Grows the cohorts for future climate
 protected override void AgeCohorts(ActiveSite site,
                                    ushort years,
                                    int?successionTimestep)
 {
     Main.Run(site, years, successionTimestep.HasValue);
 }
コード例 #35
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Does the appropriate forms of reproduction at a site.
        /// </summary>
        public static void Reproduce(ActiveSite site)
        {
            if (noEstablish[site])
            {
                return;
            }

            bool plantingOccurred = planting.TryAt(site);

            bool sufficientLight;

            bool serotinyOccurred = false;

            if (!plantingOccurred)
            {
                for (int index = 0; index < speciesDataset.Count; ++index)
                {
                    if (serotiny[site].Get(index))
                    {
                        ISpecies species = speciesDataset[index];
                        sufficientLight = SufficientResources(species, site);
                        if (sufficientLight && Establish(species, site))
                        {
                            AddNewCohort(species, site);
                            serotinyOccurred = true;
                            if (isDebugEnabled)
                            {
                                log.DebugFormat("site {0}: {1} post-fire regenerated",
                                                site.Location, species.Name);
                            }
                        }
                        else
                        {
                            if (isDebugEnabled)
                            {
                                log.DebugFormat("site {0}: {1} post-fire regen failed: {2}",
                                                site.Location, species.Name,
                                                !sufficientLight ? "insufficient light"
                                                                  : "didn't establish");
                            }
                        }
                    }
                }
            }
            serotiny[site].SetAll(false);

            bool speciesResprouted = false;

            if (!serotinyOccurred)
            {
                for (int index = 0; index < speciesDataset.Count; ++index)
                {
                    if (resprout[site].Get(index))
                    {
                        ISpecies species = speciesDataset[index];
                        sufficientLight = SufficientResources(species, site);
                        if (sufficientLight &&
                            (Model.Core.GenerateUniform() < species.VegReprodProb))
                        {
                            AddNewCohort(species, site);
                            speciesResprouted = true;
                            if (isDebugEnabled)
                            {
                                log.DebugFormat("site {0}: {1} resprouted",
                                                site.Location, species.Name);
                            }
                        }
                        else
                        {
                            if (isDebugEnabled)
                            {
                                log.DebugFormat("site {0}: {1} resprouting failed: {2}",
                                                site.Location, species.Name,
                                                !sufficientLight ? "insufficient light"
                                                                  : "random # >= probability");
                            }
                        }
                    }
                }
            }
            resprout[site].SetAll(false);

            if (!plantingOccurred && !serotinyOccurred && !speciesResprouted)
            {
                seeding.Do(site);
            }
        }
コード例 #36
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Computes the initial biomass for a cohort at a site.
        /// </summary>
        public static int InitialBiomass(ISpecies species,
                                            SiteCohorts siteCohorts,
                                            ActiveSite site)
        {
            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];
            //double B_ACT = ActualSiteBiomass(siteCohorts, site, out ecoregion);

            double B_ACT = (double)Cohorts.ComputeNonYoungBiomass(siteCohorts);

            double maxBiomass = SpeciesData.B_MAX_Spp[species][ecoregion];

            double maxANPP = SpeciesData.ANPP_MAX_Spp[species][ecoregion];

            //  Initial biomass exponentially declines in response to
            //  competition.
            //double initialBiomass = 0.025 * maxBiomass * Math.Exp(-1.6 * B_ACT / EcoregionData.B_MAX[ecoregion]);
            double initialBiomass = maxANPP * Math.Exp(-1.6 * B_ACT / EcoregionData.B_MAX[ecoregion]);

            // Initial biomass cannot be greater than maxANPP
            initialBiomass = Math.Min(maxANPP, initialBiomass);

            //  Initial biomass cannot be less than 1.
            initialBiomass = Math.Max(1.0, initialBiomass);

            return (int)initialBiomass;
        }
コード例 #37
0
        //--------------------------------------------------------------------------
        // Originally from lacalc.f of CENTURY model

        private static double calculateLAI_Limit(ICohort cohort, ActiveSite site)
        {
            //...Calculate true LAI using leaf biomass and a biomass-to-LAI
            //     conversion parameter which is the slope of a regression
            //     line derived from LAI vs Foliar Mass for Slash Pine.

            //...Calculate theoretical LAI as a function of large wood mass.
            //     There is no strong consensus on the true nature of the relationship
            //     between LAI and stemwood mass.  Version 3.0 used a negative exponential
            //     relationship between leaf mass and large wood mass, which tended to
            //     break down in very large forests.  Many sutdies have cited as "general"
            //      an increase of LAI up to a maximum, then a decrease to a plateau value
            //     (e.g. Switzer et al. 1968, Gholz and Fisher 1982).  However, this
            //     response is not general, and seems to mostly be a feature of young
            //     pine plantations.  Northern hardwoods have shown a monotonic increase
            //     to a plateau  (e.g. Switzer et al. 1968).  Pacific Northwest conifers
            //     have shown a steady increase in LAI with no plateau evident (e.g.
            //     Gholz 1982).  In this version, we use a simple saturation fucntion in
            //     which LAI increases linearly against large wood mass initially, then
            //     approaches a plateau value.  The plateau value can be set very large to
            //     give a response of steadily increasing LAI with stemwood.

            //     References:
            //             1)  Switzer, G.L., L.E. Nelson and W.H. Smith 1968.
            //                 The mineral cycle in forest stands.  'Forest
            //                 Fertilization:  Theory and Practice'.  pp 1-9
            //                 Tenn. Valley Auth., Muscle Shoals, AL.
            //
            //             2)  Gholz, H.L., and F.R. Fisher 1982.  Organic matter
            //                 production and distribution in slash pine (Pinus
            //                 elliotii) plantations.  Ecology 63(6):  1827-1839.
            //
            //             3)  Gholz, H.L.  1982.  Environmental limits on aboveground
            //                 net primary production and biomass in vegetation zones of
            //                 the Pacific Northwest.  Ecology 63:469-481.

            //...Local variables
            double leafC      = (double)cohort.LeafBiomass * 0.47;
            double largeWoodC = (double)cohort.WoodBiomass * 0.47;

            double lai    = 0.0;
            double laitop = -0.47;  // This is the value given for all biomes in the tree.100 file.
            double btolai = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].BTOLAI;
            double klai   = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].KLAI;
            double maxlai = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].MAXLAI;

            double rlai = (Math.Max(0.0, 1.0 - Math.Exp(btolai * leafC)));

            if (SpeciesData.LeafLongevity[cohort.Species] > 1.0)
            {
                rlai = 1.0;
            }

            double tlai = maxlai * largeWoodC / (klai + largeWoodC);

            //...Choose the LAI reducer on production.  I don't really understand
            //     why we take the average in the first case, but it will probably
            //     change...

            //if (rlai < tlai) lai = (rlai + tlai) / 2.0;
            lai = tlai * rlai;
            //else lai = tlai;

            // This will allow us to set MAXLAI to zero such that LAI is completely dependent upon
            // foliar carbon, which may be necessary for simulating defoliation events.
            if (tlai <= 0.0)
            {
                lai = rlai;
            }

            //lai = tlai;  // Century 4.5 ignores rlai.


            // Limit aboveground wood production by leaf area
            //  index.
            //
            //       REF:    Efficiency of Tree Crowns and Stemwood
            //               Production at Different Canopy Leaf Densities
            //               by Waring, Newman, and Bell
            //               Forestry, Vol. 54, No. 2, 1981

            //totalLAI += lai;
            // if (totalLAI > ClimateRegionData.MaxLAI)
            // lai = 0.1;

            // The minimum LAI to calculate effect is 0.2.
            //if (lai < 0.5) lai = 0.5;
            if (lai < 0.1)
            {
                lai = 0.1;
            }

            if (Century.Month == 6)
            {
                SiteVars.LAI[site] += lai; //Tracking LAI.
            }
            double LAI_limit = Math.Max(0.0, 1.0 - Math.Exp(laitop * lai));

            //This allows LAI to go to zero for deciduous trees.

            if (SpeciesData.LeafLongevity[cohort.Species] <= 1.0 &&
                (Century.Month > FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].LeafNeedleDrop || Century.Month < 3))
            {
                lai       = 0.0;
                LAI_limit = 0.0;
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},", lai, tlai, rlai);
            }


            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}. Spp={2}, leafC={3:0.0}, woodC={4:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, species.Name, leafC, largeWoodC);
            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}. Spp={2}, lai={3:0.0}, woodC={4:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, species.Name, lai, largeWoodC);
            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}.     LAI Limits:  lai={2:0.0}, woodLAI={3:0.0}, leafLAI={4:0.0}, LAIlimit={5:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, lai, woodLAI, leafLAI, LAI_limit);

            return(LAI_limit);
        }
コード例 #38
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Computes the percentage of a cohort's standing biomass that is non-woody.
        /// This method is designed for external calls that need to
        /// estimate the amount of non-wood biomass.
        /// </summary>
        public Percentage ComputeNonWoodyPercentage(ICohort cohort,
                                                    ActiveSite site)
        {
            SiteCohorts siteCohorts = SiteVars.Cohorts[site];

            double mortalityAge = ComputeAgeMortality(cohort);

            //if(siteCohorts == null) return new Percentage(0.0);

            double actualANPP = ComputeActualANPP(cohort, site, siteCohorts.TotalBiomass,
                                siteCohorts.PrevYearMortality);

            //  Age mortality is discounted from ANPP to prevent the over-
            //  estimation of mortality.  ANPP cannot be negative.
            actualANPP = Math.Max(0, actualANPP - mortalityAge);

            return new Percentage(ComputeStandingLeafBiomass(actualANPP, cohort) / cohort.Biomass);
        }
コード例 #39
0
        //---------------------------------------------------------------------

        private double[] ComputeActualANPP(ICohort cohort,
                                           ActiveSite site,
                                           double siteBiomass,
                                           double[]   mortalityAge)
        {
            double leafFractionNPP = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].FCFRACleaf;
            double maxBiomass      = SpeciesData.Max_Biomass[cohort.Species]; //.B_MAX_Spp[cohort.Species][ecoregion];
            double sitelai         = SiteVars.LAI[site];
            double maxNPP          = SpeciesData.Max_ANPP[cohort.Species];    //.ANPP_MAX_Spp[cohort.Species][ecoregion];

            double limitT = calculateTemp_Limit(site, cohort.Species);

            double limitH20 = calculateWater_Limit(site, ecoregion, cohort.Species);

            double limitLAI = calculateLAI_Limit(cohort, site);

            // RMS 03/2016: Testing alternative more similar to how Biomass Succession operates: REMOVE FOR NEXT RELEASE
            double limitCapacity = 1.0 - Math.Min(1.0, Math.Exp(siteBiomass / maxBiomass * 5.0) / Math.Exp(5.0));

            //double potentialNPP = maxNPP * limitLAI * limitH20 * limitT; // * limitCapacity;
            double potentialNPP = maxNPP * limitLAI * limitH20 * limitT * limitCapacity;

            double limitN = calculateN_Limit(site, cohort, potentialNPP, leafFractionNPP);

            potentialNPP *= limitN;

            //if (Double.IsNaN(limitT) || Double.IsNaN(limitH20) || Double.IsNaN(limitLAI) || Double.IsNaN(limitCapacity) || Double.IsNaN(limitN))
            //{
            //    PlugIn.ModelCore.UI.WriteLine("  A limit = NaN!  Will set to zero.");
            //    PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     GROWTH LIMITS: LAI={2:0.00}, H20={3:0.00}, N={4:0.00}, T={5:0.00}, Capacity={6:0.0}", PlugIn.ModelCore.CurrentTime, month + 1, limitLAI, limitH20, limitN, limitT, limitCapacity);
            //    PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     Other Information: MaxB={2}, Bsite={3}, Bcohort={4:0.0}, SoilT={5:0.0}.", PlugIn.ModelCore.CurrentTime, month + 1, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
            //}


            //  Age mortality is discounted from ANPP to prevent the over-
            //  estimation of growth.  ANPP cannot be negative.
            double actualANPP = Math.Max(0.0, potentialNPP - mortalityAge[0] - mortalityAge[1]);

            // Growth can be reduced by another extension via this method.
            // To date, no extension has been written to utilize this hook.
            double growthReduction = CohortGrowthReduction.Compute(cohort, site);

            if (growthReduction > 0.0)
            {
                actualANPP *= (1.0 - growthReduction);
            }

            double leafNPP = actualANPP * leafFractionNPP;
            double woodNPP = actualANPP * (1.0 - leafFractionNPP);

            if (Double.IsNaN(leafNPP) || Double.IsNaN(woodNPP))



            {
                PlugIn.ModelCore.UI.WriteLine("  EITHER WOOD or LEAF NPP = NaN!  Will set to zero.");
                //PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}, SpeciesName={2}, CohortAge={3}.   GROWTH LIMITS: LAI={4:0.00}, H20={5:0.00}, N={6:0.00}, T={7:0.00}, Capacity={8:0.0}.", PlugIn.ModelCore.CurrentTime, Century.Month + 1, cohort.Species.Name, cohort.Age, limitLAI, limitH20, limitN, limitT, limitCapacity);
                PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     Other Information: MaxB={2}, Bsite={3}, Bcohort={4:0.0}, SoilT={5:0.0}.", PlugIn.ModelCore.CurrentTime, Century.Month + 1, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
                PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     WoodNPP={2:0.00}, LeafNPP={3:0.00}.", PlugIn.ModelCore.CurrentTime, Century.Month + 1, woodNPP, leafNPP);
                if (Double.IsNaN(leafNPP))
                {
                    leafNPP = 0.0;
                }
                if (Double.IsNaN(woodNPP))
                {
                    woodNPP = 0.0;
                }
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                //Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},{3:0.00}, {4:0.00},", limitLAI, limitH20, limitT, limitCapacity, limitN);
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},{3:0.00},", limitLAI, limitH20, limitT, limitN);
                Outputs.CalibrateLog.Write("{0},{1},{2},{3:0.0},{4:0.0},", maxNPP, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", woodNPP, leafNPP);
            }

            return(new double[2] {
                woodNPP, leafNPP
            });
        }
コード例 #40
0
        //---------------------------------------------------------------------
        // New method for calculating competition limits.
        // Iterates through cohorts, assigning each a competitive efficiency
        private static double CalculateCompetition(ActiveSite site, ICohort cohort)
        {
            double competitionPower = 0.95;
            double CMultiplier = Math.Max(Math.Pow(cohort.Biomass, competitionPower), 1.0);
            double CMultTotal = CMultiplier;
            //PlugIn.ModelCore.Log.WriteLine("Competition:  spp={0}, age={1}, CMultiplier={2:0}, CMultTotal={3:0}.", cohort.Species.Name, cohort.Age, CMultiplier, CMultTotal);

            foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site])
            {
                foreach (ICohort xcohort in speciesCohorts)
                {
                    if (xcohort.Age+1 != cohort.Age || xcohort.Species.Index != cohort.Species.Index)
                    {
                        double tempMultiplier = Math.Max(Math.Pow(xcohort.Biomass, competitionPower), 1.0);
                        CMultTotal += tempMultiplier;
                        //PlugIn.ModelCore.Log.WriteLine("Competition:  spp={0}, age={1}, CMultiplier={2:0}, CMultTotal={3:0}.", xcohort.Species.Name, xcohort.Age, tempMultiplier, CMultTotal);
                    }
                }
            }

            double Cfraction = CMultiplier / CMultTotal;
            //PlugIn.ModelCore.Log.WriteLine("Competition:  spp={0}, age={1}, CMultiplier={2:0}, CMultTotal={3:0}, CI={4:0.00}.", cohort.Species.Name, cohort.Age, CMultiplier, CMultTotal, Cfraction);

            return Cfraction;
        }
コード例 #41
0
        public static void PartitionResidue(
            double inputMass,
            double inputDecayValue,
            double inputCNratio,
            double fracLignin,
            double ratioCNstructural,
            //double CNratiofrass,
            LayerName name,
            LayerType type,
            ActiveSite site)
        {
            double cAddToMetabolic, cAddToStructural, directAbsorb;
            double NAddToMetabolic, NAddToStructural, Npart;
            double fracStructuralLignin, fracMetabolic, fracN, ratioCNtotal, ratioLigninN;
            double totalNitrogen = 0.0;

            double totalC = inputMass * 0.47;

            if (totalC < 0.0000001)
            {
                //PlugIn.ModelCore.UI.WriteLine("C inputs to litter layer below threshold");
                return;
            }

            // ...For each mineral element..
            // ...Compute amount of element in residue.
            Npart = totalC / inputCNratio;

            // ...Direct absorption of mineral element by residue
            //      (mineral will be transferred to donor compartment
            //      and then partitioned into structural and metabolic
            //      using flow routines.)

            // ...If minerl(SRFC,iel) is negative then directAbsorb = zero.
            if (SiteVars.MineralN[site] <= 0.0)
            {
                directAbsorb = 0.0;
            }
            else
            {
                directAbsorb = SiteVars.MineralN[site]
                               * OtherData.FractionSurfNAbsorbed
                               * System.Math.Max(totalC / OtherData.ResidueMaxDirectAbsorb, 1.0);
            }


            // ...If C/N ratio is too low, transfer just enough to make
            //       C/N of residue = damrmn
            if (Npart + directAbsorb <= 0.0)
            {
                ratioCNtotal = 0.0;
            }
            else
            {
                ratioCNtotal = totalC / (Npart + directAbsorb);
            }

            if (ratioCNtotal < OtherData.MinResidueCN)
            {
                directAbsorb = (totalC / OtherData.MinResidueCN) - Npart;
            }

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

            if (directAbsorb > SiteVars.MineralN[site])
            {
                directAbsorb = SiteVars.MineralN[site];
            }

            SiteVars.MineralN[site] -= directAbsorb;

            totalNitrogen = directAbsorb + Npart;

            // ...Partition carbon into structural and metabolic fraction of
            //      residue (including direct absorption) which is nitrogen
            fracN = totalNitrogen / inputMass; // (totalC * 2.0);

            // ...Lignin/nitrogen ratio of residue
            ratioLigninN = fracLignin / fracN;

            // METABOLIC calculations
            // ...Carbon added to metabolic
            //      Compute the fraction of carbon that goes to metabolic.

            fracMetabolic = OtherData.MetaStructSplitIntercept - OtherData.MetaStructSplitSlope * ratioLigninN;

            // ...Make sure the fraction of residue which is lignin isn't
            //      greater than the fraction which goes to structural.  -rm 12/91
            if (fracLignin > (1.0 - fracMetabolic))
            {
                fracMetabolic = (1.0 - fracLignin);
            }

            // ...Make sure at least 1% goes to metabolic
            if (fracMetabolic < 0.20)
            {
                fracMetabolic = 0.20;
            }

            // ...Compute amounts to flow
            cAddToMetabolic = totalC * fracMetabolic;
            if (cAddToMetabolic < 0.0)
            {
                cAddToMetabolic = 0.0;
            }

            if ((int)type == (int)LayerType.Surface)
            {
                SiteVars.SurfaceMetabolic[site].Carbon += cAddToMetabolic;
            }
            else
            {
                SiteVars.SoilMetabolic[site].Carbon += cAddToMetabolic;
            }

            // STRUCTURAL calculations

            cAddToStructural = totalC - cAddToMetabolic;

            // ...Adjust lignin content of structural.
            // ...fracStructuralLignin is the fraction of incoming structural residue
            //      which is lignin; restricting it to a maximum of .8
            fracStructuralLignin = fracLignin / (cAddToStructural / totalC);

            if ((int)type == (int)LayerType.Surface && cAddToMetabolic <= 0.0)
            {
                //PlugIn.ModelCore.UI.WriteLine("   SURFACE cAddToMetabolic={0}.", cAddToMetabolic);

                // ...Changed allowable maximum fraction from .6 to 1.0  -lh 1/93
                if (fracStructuralLignin > 1.0)
                {
                    fracStructuralLignin = 1.0;
                }
            }

            if ((int)type == (int)LayerType.Surface)
            {
                SiteVars.SurfaceStructural[site].Carbon += cAddToStructural;
            }
            else
            {
                SiteVars.SoilStructural[site].Carbon += cAddToStructural;
            }

            // ...Adjust lignin in Structural Layers
            // adjlig(strucc(lyr), fracStructuralLignin, cAddToStructural, strlig(lyr));

            Layer structuralLayer;

            if ((int)type == (int)LayerType.Surface)
            {
                structuralLayer = SiteVars.SurfaceStructural[site];
            }
            else
            {
                structuralLayer = SiteVars.SoilStructural[site];
            }

            structuralLayer.AdjustLignin(cAddToStructural, fracStructuralLignin);

            // Don't adjust litter decay rate: the base decay rate is
            // always 1.0
            // AdjustDecayRate();

            // ...Partition mineral elements into structural and metabolic
            // ...Flow into structural
            // ...Flow into metabolic
            NAddToStructural = cAddToStructural / ratioCNstructural;  //RATIO CN STRUCTURAL from species data
            NAddToMetabolic  = totalNitrogen - NAddToStructural;

            if ((int)type == (int)LayerType.Surface)
            {
                SiteVars.SurfaceStructural[site].Nitrogen += NAddToStructural;
                SiteVars.SurfaceMetabolic[site].Nitrogen  += NAddToMetabolic;
            }
            else
            {
                SiteVars.SoilStructural[site].Nitrogen += NAddToStructural;
                SiteVars.SoilMetabolic[site].Nitrogen  += NAddToMetabolic;
                //PlugIn.ModelCore.UI.WriteLine("  N added to Structural Soil: {0}.", NAddToStructural);
            }

            return;

            //}
        }
コード例 #42
0
        // --------------------------------------------------
        public void DecomposeLignin(double totalCFlow, ActiveSite site)
        // Originally from declig.f for decomposition of compartment lignin
        {
            double carbonToSOM1;    //Net C flow to SOM1
            double carbonToSOM2;    //Net C flow to SOM2
            double litterC = this.Carbon;
            double ratioCN = litterC / this.Nitrogen;


            //See if Layer can decompose to SOM1.
            //If it can decompose to SOM1, it will also go to SOM2.
            //If it can't decompose to SOM1, it can't decompose at all.

            //If Wood Object can decompose
            if (this.DecomposePossible(ratioCN, SiteVars.MineralN[site]))
            {
                // Decompose Wood Object to SOM2
                // -----------------------
                // Gross C flow to som2
                carbonToSOM2 = totalCFlow * this.FractionLignin;

                //MicrobialRespiration associated with decomposition to som2
                double co2loss = carbonToSOM2 * OtherData.LigninRespirationRate;

                this.Respiration(co2loss, site);

                //Net C flow to SOM2
                double netCFlow = carbonToSOM2 - co2loss;

                // Partition and schedule C flows
                this.TransferCarbon(SiteVars.SOM2[site], netCFlow);
                this.TransferNitrogen(SiteVars.SOM2[site], netCFlow, litterC, ratioCN, site);
                //PlugIn.ModelCore.UI.WriteLine("Decompose1.  MineralN={0:0.00}.", SiteVars.MineralN[site]);

                // ----------------------------------------------
                // Decompose Wood Object to SOM1
                // Gross C flow to som1

                carbonToSOM1 = totalCFlow - carbonToSOM2 - co2loss;

                //MicrobialRespiration associated with decomposition to som1
                if (this.Type == LayerType.Surface)
                {
                    co2loss = carbonToSOM1 * OtherData.StructuralToCO2Surface;
                }
                else
                {
                    co2loss = carbonToSOM1 * OtherData.StructuralToCO2Soil;
                }

                this.Respiration(co2loss, site);

                //Net C flow to SOM1
                carbonToSOM1 -= co2loss;

                if (this.Type == LayerType.Surface)
                {
                    this.TransferCarbon(SiteVars.SOM1surface[site], carbonToSOM1);
                    this.TransferNitrogen(SiteVars.SOM1surface[site], carbonToSOM1, litterC, ratioCN, site);
                }
                else
                {
                    this.TransferCarbon(SiteVars.SOM1soil[site], carbonToSOM1);
                    this.TransferNitrogen(SiteVars.SOM1soil[site], carbonToSOM1, litterC, ratioCN, site);
                }
            }
            //PlugIn.ModelCore.UI.WriteLine("Decompose2.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
            return;
        }
コード例 #43
0
        public void TransferNitrogen(Layer destination, double CFlow, double totalC, double ratioCNtoDestination, ActiveSite site)
        {
            // this is the source.

            double mineralNFlow = 0.0;

            //...N flow is proportional to C flow.
            double NFlow = this.Nitrogen * CFlow / totalC;

            //...This was added to avoid a 0/0 error on the pc.
            if (CFlow <= 0.0 || NFlow <= 0.0)
            {
                return;
            }

            if ((NFlow - this.Nitrogen) > 0.01)
            {
                //PlugIn.ModelCore.UI.WriteLine("  Transfer N:  N flow > source N.");
                //PlugIn.ModelCore.UI.WriteLine("     NFlow={0:0.000}, SourceN={1:0.000}", NFlow, this.Nitrogen);
                //PlugIn.ModelCore.UI.WriteLine("     CFlow={0:0.000}, totalC={1:0.000}", CFlow, totalC);
                //PlugIn.ModelCore.UI.WriteLine("     this.Name={0}, this.Type={1}", this.Name, this.Type);
                //PlugIn.ModelCore.UI.WriteLine("     dest.Name  ={0}, dest.Type  ={1}", destination.Name, destination.Type);
                //PlugIn.ModelCore.UI.WriteLine("     ratio CN to dest={0}", ratioCNtoDestination);
            }

            //...If C/N of Box A > C/N of new material entering Box B
            if ((CFlow / NFlow) > ratioCNtoDestination)
            {
                //...IMMOBILIZATION occurs.
                //...Compute the amount of N immobilized.
                //     since  ratioCNtoDestination = netCFlow / (Nflow + immobileN),
                //     where immobileN is the extra N needed from the mineral pool
                double immobileN = (CFlow / ratioCNtoDestination) - NFlow;

                //PlugIn.ModelCore.UI.WriteLine("     CFlow={0:0.000}, totalC={1:0.000}", CFlow, totalC);

                // PlugIn.ModelCore.UI.WriteLine("     this.Name={0}, this.Type={1}", this.Name, this.Type);
                //PlugIn.ModelCore.UI.WriteLine("     NFlow={0:0.000}, SourceN={1:0.000},CNdestination={2:0}", NFlow, this.Nitrogen,ratioCNtoDestination);

                //PlugIn.ModelCore.UI.WriteLine("CalculatingImmobil.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                //...Schedule flow from Box A to Box B (outofa)
                //flow(anps,bnps,time,outofa);
                this.Nitrogen        -= NFlow;
                destination.Nitrogen += NFlow;

                //PlugIn.ModelCore.UI.WriteLine("NFlow.  MineralN={0:0.00}, ImmobileN={1:0.000}.", SiteVars.MineralN[site],immobileN);

                // Schedule flow from mineral pool to Box B (immobileN)
                // flow(labile,bnps,time,immflo);
                //Don't allow mineral N to go to zero or negative.- ML

                if (immobileN > SiteVars.MineralN[site])
                {
                    immobileN = SiteVars.MineralN[site] - 0.01; //leave some small amount of mineral N
                }
                SiteVars.MineralN[site] -= immobileN;
                //PlugIn.ModelCore.UI.WriteLine("AfterImmobil.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                destination.Nitrogen += immobileN;

                //PlugIn.ModelCore.UI.WriteLine("AdjustImmobil.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
                //PlugIn.ModelCore.UI.WriteLine("   TransferN immobileN={0:0.000}, C={1:0.000}, N={2:0.000}, ratioCN={3:0.000}.", immobileN, CFlow, NFlow, ratioCNtoDestination);
                //PlugIn.ModelCore.UI.WriteLine("     source={0}-{1}, destination={2}-{3}.", this.Name, this.Type, destination.Name, destination.Type);

                //...Return mineralization value.
                mineralNFlow = -1 * immobileN;
                //PlugIn.ModelCore.UI.WriteLine("MineralNflow.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
            }
            else

            //...MINERALIZATION occurs
            //...Schedule flow from Box A to Box B
            {
                //PlugIn.ModelCore.UI.WriteLine("  Transfer Nitrogen Min.");
                double mineralizedN = (CFlow / ratioCNtoDestination);


                this.Nitrogen        -= mineralizedN;
                destination.Nitrogen += mineralizedN;

                //...Schedule flow from Box A to mineral pool

                mineralNFlow = NFlow - mineralizedN;

                if ((mineralNFlow - this.Nitrogen) > 0.01)
                {
                    //PlugIn.ModelCore.UI.WriteLine("  Transfer N mineralization:  mineralN > source N.");
                    //PlugIn.ModelCore.UI.WriteLine("     MineralNFlow={0:0.000}, SourceN={1:0.000}", mineralNFlow, this.Nitrogen);
                    //PlugIn.ModelCore.UI.WriteLine("     CFlow={0:0.000}, totalC={1:0.000}", CFlow, totalC);
                    //PlugIn.ModelCore.UI.WriteLine("     this.Name={0}, this.Type={1}", this.Name, this.Type);
                    // PlugIn.ModelCore.UI.WriteLine("     dest.Name  ={0}, dest.Type  ={1}", destination.Name, destination.Type);
                    //PlugIn.ModelCore.UI.WriteLine("     ratio CN to dest={0}", ratioCNtoDestination);
                }

                this.Nitrogen -= mineralNFlow;

                SiteVars.MineralN[site] += mineralNFlow;
                //PlugIn.ModelCore.UI.WriteLine("     this.Name={0}, this.Type={1}", this.Name, this.Type);
                //PlugIn.ModelCore.UI.WriteLine("IfMinOccurs.  MineralN={0:0.00}.", SiteVars.MineralN[site]);

                //PlugIn.ModelCore.UI.WriteLine("  TransferN NFlow={0:0.000}, mineralizedN = {1:0.000}, N mineralalization = {1:0.000}", NFlow, mineralizedN, mineralNFlow);
                //PlugIn.ModelCore.UI.WriteLine("     Source:  this.Name={0}, this.Type={1}", this.Name, this.Type);
            }

            if (mineralNFlow > 0)
            {
                SiteVars.GrossMineralization[site] += mineralNFlow;
            }

            //...Net mineralization
            this.NetMineralization += mineralNFlow;

            //PlugIn.ModelCore.UI.WriteLine("     this.Nitrogen={0:0.000}.", this.Nitrogen);

            //PlugIn.ModelCore.UI.WriteLine("AfterMinOccurs.  MineralN={0:0.00}.", SiteVars.MineralN[site]);
            return;
        }
コード例 #44
0
        //---------------------------------------------------------------------------
        //... Originally from pprdwc(wc,x,pprpts) of CENTURY

        //...This funtion returns a value for potential plant production
        //     due to water content.  Basically you have an equation of a
        //     line with a moveable y-intercept depending on the soil type.
        //     The value passed in for x is ((avh2o(1) + prcurr(month) + irract)/pet)

        //     pprpts(1):  The minimum ratio of available water to pet which
        //                 would completely limit production assuming wc=0.
        //     pprpts(2):  The effect of wc on the intercept, allows the
        //                 user to increase the value of the intercept and
        //                 thereby increase the slope of the line.
        //     pprpts(3):  The lowest ratio of available water to pet at which
        //                 there is no restriction on production.
        private static double calculateWater_Limit(ActiveSite site, IEcoregion ecoregion, ISpecies species)
        {
            // Ratio_AvailWaterToPET used to be pptprd and WaterLimit used to be pprdwc
            double Ratio_AvailWaterToPET = 0.0;
            double waterContent          = SiteVars.SoilFieldCapacity[site] - SiteVars.SoilWiltingPoint[site];
            //ClimateRegionData.FieldCapacity[ecoregion] - ClimateRegionData.WiltingPoint[ecoregion];  // Difference between two fractions (FC - WP), not the actual water content, per se.
            double tmin = ClimateRegionData.AnnualWeather[ecoregion].MonthlyMinTemp[Century.Month];

            double H2Oinputs = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPrecip[Century.Month]; //rain + irract;

            double pet = ClimateRegionData.AnnualWeather[ecoregion].MonthlyPET[Century.Month];

            //PlugIn.ModelCore.UI.WriteLine("pet={0}, waterContent={1}, precip={2}.", pet, waterContent, H2Oinputs);

            if (pet >= 0.01)
            {   //       Trees are allowed to access the whole soil profile -rm 2/97
                //         pptprd = (avh2o(1) + tmoist) / pet
                // pptprd = (SiteVars.AvailableWater[site] + H2Oinputs) / pet;
                Ratio_AvailWaterToPET = (SiteVars.AvailableWater[site] / pet);  //Modified by ML so that we weren't double-counting precip as in above equation
                //PlugIn.ModelCore.UI.WriteLine("RatioAvailWaterToPET={0}, AvailableWater={1}.", Ratio_AvailWaterToPET, SiteVars.AvailableWater[site]);
            }
            else
            {
                Ratio_AvailWaterToPET = 0.01;
            }

            //...The equation for the y-intercept (intcpt) is A+B*WC.  A and B
            //     determine the effect of soil texture on plant production based
            //     on moisture.

            //...Old way:
            //      intcpt = 0.0 + 1.0 * wc
            //      The second point in the equation is (.8,1.0)
            //      slope = (1.0-0.0)/(.8-intcpt)
            //      pprdwc = 1.0+slope*(x-.8)

            //PPRPTS naming convention is imported from orginal Century model. Now replaced with 'MoistureCurve' to be more intuitive
            //...New way (with updated naming convention):

            double moisturecurve1 = OtherData.MoistureCurve1;
            double moisturecurve2 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve2;
            double moisturecurve3 = FunctionalType.Table[SpeciesData.FuncType[species]].MoistureCurve3;

            double intcpt = moisturecurve1 + (moisturecurve2 * waterContent);
            double slope  = 1.0 / (moisturecurve3 - intcpt);

            double WaterLimit = 1.0 + slope * (Ratio_AvailWaterToPET - moisturecurve3);

            if (WaterLimit > 1.0)
            {
                WaterLimit = 1.0;
            }
            if (WaterLimit < 0.01)
            {
                WaterLimit = 0.01;
            }

            //PlugIn.ModelCore.UI.WriteLine("Intercept={0}, Slope={1}, WaterLimit={2}.", intcpt, slope, WaterLimit);

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                Outputs.CalibrateLog.Write("{0:0.00},", SiteVars.AvailableWater[site]);
            }

            return(WaterLimit);
        }
コード例 #45
0
        //---------------------------------------------------------------------


        public void Grow(ushort years, ActiveSite site, int?successionTimestep, ICore mCore)
        {
        }
コード例 #46
0
 public RemoveAgeBetween5And30_Biomass(ActiveSite currentSite)
     : base(currentSite)
 {
 }
コード例 #47
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Determines if a species can establish on a site.
        /// This is a Delegate method to base succession.
        /// </summary>
        public bool Establish(ISpecies species, ActiveSite site)
        {
            double establishProbability = Establishment.Calculate(species, site);

            return(modelCore.GenerateUniform() < establishProbability);
        }
コード例 #48
0
 public void Grow(ActiveSite site, bool isSuccessionTimestep)
 {
     throw new System.Exception("Incompatibility issue");
 }
コード例 #49
0
 //---------------------------------------------------------------------
 protected override void InitializeSite(ActiveSite site,
     ICommunity initialCommunity)
 {
     InitialBiomass initialBiomass = InitialBiomass.Compute(site, initialCommunity);
     cohorts[site] = initialBiomass.Cohorts.Clone();
     Dead.Pools.Woody[site] = initialBiomass.DeadWoodyPool;
     Dead.Pools.NonWoody[site] = initialBiomass.DeadNonWoodyPool;
 }
コード例 #50
0
        //---------------------------------------------------------------------
        /// <summary>
        /// The mortality caused by development processes,
        /// including self-thinning and loss of branches, twigs, etc.
        /// See equation 5 in Scheller and Mladenoff, 2004.
        /// </summary>
        private double ComputeGrowthMortality(ICohort cohort, ActiveSite site, int siteBiomass)
        {
            //double percentDefoliation = CohortDefoliation.Compute(cohort, site, siteBiomass);

            //const double y0 = 0.01;
            //const double r = 0.08;
            double maxANPP = SpeciesData.ANPP_MAX_Spp[cohort.Species][ecoregion];
            double M_BIO = 0.0;

            //Michaelis-Menton function:
            if (B_AP > 1.0)
                M_BIO = maxANPP * B_PM;
            else
                M_BIO = maxANPP * (2.0 * B_AP) / (1.0 + B_AP) * B_PM;

            //double M_BIO = maxANPP *
            //        (y0 / (y0 + (1 - y0) * Math.Exp(-r / y0 * B_AP))) *
            //        B_PM;

            //  Mortality should not exceed the amount of living biomass
            M_BIO = Math.Min(cohort.Biomass, M_BIO);

            //  Calculated actual ANPP can not exceed the limit set by the
            //  maximum ANPP times the ratio of potential to maximum biomass.
            //  This down regulates actual ANPP by the available growing space.

            M_BIO = Math.Min(maxANPP * B_PM, M_BIO);

            if (growthReduction > 0)
                M_BIO *= (1.0 - growthReduction);

            return M_BIO;
        }
コード例 #51
0
 //---------------------------------------------------------------------
 public override byte ComputeShade(ActiveSite site)
 {
     return LivingBiomass.ComputeShade(site);
 }
コード例 #52
0
 /// <summary>
 /// Default method for computing how much a cohort is defoliated at
 /// a site.
 /// </summary>
 /// <returns>
 /// 0%
 /// </returns>
 public static double Compute(ICohort cohort,
                              ActiveSite site)
 //int        siteBiomass)
 {
     return(0.0);
 }
コード例 #53
0
        //---------------------------------------------------------------------
        /// <summary>
        /// Computes the change in a cohort's biomass due to Annual Net Primary
        /// Productivity (ANPP), age-related mortality (M_AGE), and development-
        /// related mortality (M_BIO).
        /// </summary>
        public int ComputeChange(ICohort cohort,
                                 ActiveSite site,
                                 int siteBiomass,
                                 int prevYearSiteMortality)
        {
            ecoregion = PlugIn.ModelCore.Ecoregion[site];

            // First, calculate age-related mortality.
            // Age-related mortality will include woody and standing leaf biomass (=0 for deciduous trees).
            double mortalityAge = ComputeAgeMortality(cohort);

            double actualANPP = ComputeActualANPP(cohort, site, siteBiomass, prevYearSiteMortality);

            //  Age mortality is discounted from ANPP to prevent the over-
            //  estimation of mortality.  ANPP cannot be negative.
            actualANPP = Math.Max(1, actualANPP - mortalityAge);

            SiteVars.AGNPP[site] += actualANPP;

            //  Growth-related mortality
            double mortalityGrowth = ComputeGrowthMortality(cohort, site, siteBiomass);

            //  Age-related mortality is discounted from growth-related
            //  mortality to prevent the under-estimation of mortality.  Cannot be negative.
            mortalityGrowth = Math.Max(0, mortalityGrowth - mortalityAge);

            //  Also ensure that growth mortality does not exceed actualANPP.
            mortalityGrowth = Math.Min(mortalityGrowth, actualANPP);

            //  Total mortality for the cohort
            double totalMortality = mortalityAge + mortalityGrowth;

            if (totalMortality > cohort.Biomass)
                throw new ApplicationException("Error: Mortality exceeds cohort biomass");

            // Defoliation ranges from 1.0 (total) to none (0.0).
            defoliation = CohortDefoliation.Compute(cohort, site, siteBiomass);
            double defoliationLoss = 0.0;
            if (defoliation > 0)
            {
                double standing_nonwood = ComputeFractionANPPleaf(cohort.Species) * actualANPP;
                defoliationLoss = standing_nonwood * defoliation;
            }

            int deltaBiomass = (int)(actualANPP - totalMortality - defoliationLoss);
            double newBiomass = cohort.Biomass + (double)deltaBiomass;

            double totalLitter = UpdateDeadBiomass(cohort, actualANPP, totalMortality, site, newBiomass);

            //CalculateCohortLAI(cohort, actualANPP, newBiomass, site);
            CalculateCohortLight(cohort, actualANPP, newBiomass, site);

            if (PlugIn.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0)
            {
                PlugIn.ModelCore.Log.WriteLine("Yr={0}. Calculate Delta Biomass...", (PlugIn.ModelCore.CurrentTime+SubYear));
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.    Spp={1}, Age={2}.", (PlugIn.ModelCore.CurrentTime+SubYear), cohort.Species.Name, cohort.Age);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.    ANPPact={1:0.0}, Mtotal={2:0.0}, litter={3:0.00}.", (PlugIn.ModelCore.CurrentTime+SubYear), actualANPP, totalMortality, totalLitter);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.    DeltaB={1:0.0}, CohortB={2}, Bsite={3}", (PlugIn.ModelCore.CurrentTime+SubYear), deltaBiomass, cohort.Biomass, (int) siteBiomass);
            }

            return deltaBiomass;
        }
コード例 #54
0
        //---------------------------------------------------------------------

        /// <summary>
        /// Re-enables establishment at a site for a list of species
        /// </summary>
        public static void EnableEstablishment(ActiveSite site)
        {
            noEstablish[site] = false;
        }
コード例 #55
0
        //---------------------------------------------------------------------
        // Added 10/5/09 - BRM
        // Replaces CalculateCohortLAI
        private static void CalculateCohortLight(ICohort cohort, double actualANPP, double newBiomass, ActiveSite site)
        {
            ISpecies species = cohort.Species;
            double pctBioMaxLAI = SpeciesData.PctBioMaxLAI[species];
            double cohortBiomass = newBiomass;

            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];

            //double maxBiomass = SpeciesData.B_MAX_Spp[species][ecoregion];
            double maxBiomass = EcoregionData.B_MAX[ecoregion];
            double maxlai = SpeciesData.MAXLAI[species];
            double LAIactual = 0;
            double pctBiomass = (cohortBiomass / maxBiomass) * 100;
            if (pctBiomass >= pctBioMaxLAI)
            {
                LAIactual = maxlai;
            }
            else
            {
                double slope = 100.0 / pctBioMaxLAI;
                double pctLAI = pctBiomass * slope;
                LAIactual = (pctLAI * maxlai) / 100;
            }
            double cohortLightExt = SpeciesData.LightExtinctionCoeff[species] * LAIactual;
            double cohortLightTrans = Math.Exp(-1.0 * cohortLightExt);

            SiteVars.LightTrans[site] *= cohortLightTrans; //Combine cohortLightTrans for all cohorts on the site
        }
コード例 #56
0
        public static void PartitionResidue(
            double inputMass,
            double inputDecayValue,
            double inputCNratio,
            double fracLignin,
            LayerName name,
            LayerType type,
            ActiveSite site)
        {
            double directAbsorb  = 0.0;
            double ratioCNtotal  = 0.0;
            double totalNitrogen = 0.0;

            // from dry matter to C, 0.47 ratio
            double totalC = inputMass * 0.47;

            if (totalC < 0.0000001)
            {
                return;
            }

            // ...For each mineral element..
            // ...Compute amount of element in residue.
            double Npart = totalC / inputCNratio;

            //PlugIn.ModelCore.UI.WriteLine("                totalCadded={0:0.00}, inputCNratio={1}, name={2}, type={3}.", totalC, inputCNratio, name, type);

            // ...Direct absorption of mineral element by residue
            //      (mineral will be transferred to donor compartment
            //      and then partitioned into structural and metabolic
            //      using flow routines.)

            // ...If minerl(SRFC,iel) is negative then directAbsorb = zero.
            if (SiteVars.MineralN[site] <= 0.0)
            {
                directAbsorb = 0.0;
            }
            else
            {
                directAbsorb = OtherData.FractionSurfNAbsorbed
                               * SiteVars.MineralN[site]
                               * System.Math.Max(totalC / OtherData.ResidueMaxDirectAbsorb, 1.0);
            }


            // ...If C/N ratio is too low, transfer just enough to make
            //       C/N of residue = damrmn
            if (Npart + directAbsorb <= 0.0)
            {
                ratioCNtotal = 0.0;
            }
            else
            {
                ratioCNtotal = totalC / (Npart + directAbsorb);
            }

            if (ratioCNtotal < OtherData.MinResidueCN)
            {
                directAbsorb = (totalC / OtherData.MinResidueCN) - Npart;
            }

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

            if (directAbsorb > SiteVars.MineralN[site])
            {
                directAbsorb = SiteVars.MineralN[site];
            }

            SiteVars.MineralN[site] -= directAbsorb;

            totalNitrogen = directAbsorb + Npart;

            //PlugIn.ModelCore.UI.WriteLine("                totalNadded={0:0.00}, totalC={1:0.0}, inputCNratio={2}, name={3}, type={4}.", totalNitrogen, totalC, inputCNratio, name, type);


            if ((int)name == (int)LayerName.Wood)
            {
                SiteVars.SurfaceDeadWood[site].Carbon   += totalC;
                SiteVars.SurfaceDeadWood[site].Nitrogen += totalNitrogen;
                SiteVars.SurfaceDeadWood[site].AdjustLignin(totalC, fracLignin);
                SiteVars.SurfaceDeadWood[site].AdjustDecayRate(totalC, inputDecayValue);
            }
            else  // Dead Coarse Roots
            {
                SiteVars.SoilDeadWood[site].Carbon   += totalC;
                SiteVars.SoilDeadWood[site].Nitrogen += totalNitrogen;
                SiteVars.SoilDeadWood[site].AdjustLignin(totalC, fracLignin);
                SiteVars.SoilDeadWood[site].AdjustDecayRate(totalC, inputDecayValue);
            }

            return;
        }
コード例 #57
0
        //---------------------------------------------------------------------
        private double ComputeActualANPP(ICohort cohort,
                                         ActiveSite site,
                                         int siteBiomass,
                                         int prevYearSiteMortality)
        {
            growthReduction = CohortGrowthReduction.Compute(cohort, site, siteBiomass);
            double growthShape = SpeciesData.GrowthCurveShapeParm[cohort.Species];

            double cohortBiomass = cohort.Biomass;
            double capacityReduction = 1.0;

            if(SiteVars.CapacityReduction != null && SiteVars.CapacityReduction[site] > 0)
            {
                capacityReduction = 1.0 - SiteVars.CapacityReduction[site];
                if(PlugIn.CalibrateMode)
                    PlugIn.ModelCore.Log.WriteLine("Yr={0}. Capacity Remaining={1:0.00}, Spp={2}, Age={3} B={4}.", (PlugIn.ModelCore.CurrentTime+SubYear), capacityReduction, cohort.Species.Name, cohort.Age, cohort.Biomass);
            }

            double maxBiomass  = SpeciesData.B_MAX_Spp[cohort.Species][ecoregion] * capacityReduction;
            double maxANPP = SpeciesData.ANPP_MAX_Spp[cohort.Species][ecoregion];

            //  Potential biomass, equation 3 in Scheller and Mladenoff, 2004
            double potentialBiomass = Math.Max(1.0, maxBiomass - siteBiomass + cohortBiomass);

            //  Species can use new space from mortality immediately
            //  but not in the case of capacity reduction due to harvesting.
            if(capacityReduction >= 1.0)
                potentialBiomass = Math.Max(potentialBiomass, prevYearSiteMortality);

            //  Ratio of cohort's actual biomass to potential biomass
            B_AP = cohortBiomass / potentialBiomass;

            double indexC = CalculateCompetition(site, cohort);

            if ((indexC <= 0.0 && cohortBiomass > 0) || indexC > 1.0)
            {
                PlugIn.ModelCore.Log.WriteLine("Error: Competition Index [{0:0.00}] is <= 0.0 or > 1.0", indexC);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}. SPECIES={1}, AGE={2}, B={3}", (PlugIn.ModelCore.CurrentTime + SubYear), cohort.Species.Name, cohort.Age, cohortBiomass);

                throw new ApplicationException("Application terminating.");
            }

            //  Ratio of cohort's potential biomass to maximum biomass.  The
            //  ratio cannot be exceed 1.
            double indexOldSchool = Math.Min(1.0, potentialBiomass / maxBiomass);
            double initialMultiplier = (CanopyLightExtinction == 0.0 ? indexC : 1.0);
            double indexLightC = initialMultiplier * Math.Exp(CanopyLightExtinction);
            B_PM = indexLightC;
            PlugIn.ModelCore.Log.WriteLine("indexC={0:0.00}, lightIndexC={1:0.00}, OldSchool={2:0.00}.", indexC, indexLightC, indexOldSchool);

            //  Actual ANPP: equation (4) from Scheller & Mladenoff, 2004.
            //  Constants k1 and k2 control whether growth rate declines with
            //  age.  Set to default = 1.
            //double actualANPP = maxANPP * Math.E * B_AP * Math.Exp(-1 * B_AP) * B_PM;
            double actualANPP = maxANPP * Math.E * Math.Pow(B_AP, growthShape) * Math.Exp(-1 * Math.Pow(B_AP, growthShape)) * B_PM;

            // Calculated actual ANPP can not exceed the limit set by the
            //  maximum ANPP times the ratio of potential to maximum biomass.
            //  This down regulates actual ANPP by the available growing space.

            actualANPP = Math.Min(maxANPP * B_PM, actualANPP);

            if (growthReduction > 0)
                actualANPP *= (1.0 - growthReduction);

            double LAIactual = SpeciesData.MAXLAI[cohort.Species] * actualANPP / maxANPP;
            CanopyLightExtinction += (-1.0 * SpeciesData.LightExtinctionCoeff[cohort.Species] * LAIactual) * indexC;

            if(PlugIn.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0)
            {
                PlugIn.ModelCore.Log.WriteLine("Yr={0}. Calculate ANPPactual...", (PlugIn.ModelCore.CurrentTime+SubYear));
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.     Spp={1}, Age={2}.", (PlugIn.ModelCore.CurrentTime+SubYear), cohort.Species.Name, cohort.Age);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.     MaxANPP={1}, MaxB={2:0}, Bsite={3}, Bcohort={4:0.0}.", (PlugIn.ModelCore.CurrentTime+SubYear), maxANPP, maxBiomass, (int) siteBiomass, cohort.Biomass);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.     B_PM={1:0.0}, B_AP={2:0.0}, actualANPP={3:0.0}, capacityReduction={4:0.0}.", (PlugIn.ModelCore.CurrentTime+SubYear), B_PM, B_AP, actualANPP, capacityReduction);
                PlugIn.ModelCore.Log.WriteLine("Yr={0}.     CanopyLightExtinction = {1:0.00}, LightTransmittance = {2:0.00}, LAIactual={3:0.0}.", (PlugIn.ModelCore.CurrentTime + SubYear), CanopyLightExtinction, B_PM, LAIactual);
            }

            return actualANPP;
        }
コード例 #58
0
        //---------------------------------------------------------------------

        public static bool Algorithm(ISpecies species,
                                     ActiveSite site)
        {
            if (species.EffectiveSeedDist == EffectiveSeedDist.Universal)
            {
                return(UniversalDispersal.Algorithm(species, site));
            }

            if (!Reproduction.SufficientLight(species, site) ||
                !Reproduction.Establish(species, site))
            {
                return(false);
            }

            if (Reproduction.MaturePresent(species, site))
            {
                return(true);
            }

            int row = (int)site.Location.Row;
            int col = (int)site.Location.Column;

            int cellDiam = (int)Model.CellLength;
            int EffD     = species.EffectiveSeedDist;
            int MaxD     = species.MaxSeedDist;

            double ratio = 0.95;            //the portion of the probability in the effective distance
            //lambda1 parameterized for effective distance
            double lambda1 = Math.Log((1 - ratio) / EffD);
            //lambda2 parameterized for maximum distance
            double lambda2 = Math.Log(0.01) / MaxD;

            double lowBound = 0, upBound = 0;
            //bool suitableDist=false;//flag to trigger if seed (plural) can get to a site based on distance probability
            double distanceProb = 0.0;
            int    pixRange     = Math.Max((int)((float)MaxD / (float)cellDiam), 1);
            int    maxrow       = (int)Math.Min(row + pixRange, Model.Landscape.Rows);
            int    minrow       = Math.Max(row - pixRange, 1);

            for (int i = minrow; i <= maxrow; i++)
            {
                int x1, x2;
                //float b = 5.0;
                findX1X2(out x1, out x2, col, row, i, pixRange);
                for (int j = x1; j <= x2; j++)
                {
                    Location loc = new Location((uint)i, (uint)j);
                    if (Model.Landscape.GetSite(loc, ref neighbor) && neighbor.IsActive)
                    {
                        if (Reproduction.MaturePresent(species, neighbor))
                        {
                            float distance = (float)Math.Sqrt((float)((row - i) * (row - i) + (col - j) * (col - j))) * cellDiam;              //Pythag

                            //set lower boundary to the theoretical (straight-line) edge of parent cell
                            lowBound = distance - cellDiam;
                            if (lowBound < 0)
                            {
                                lowBound = 0;
                            }

                            //set upper boundary to the outer theoretical boundary of the cell
                            upBound = distance;

                            if (cellDiam <= EffD)
                            {                            //Draw probabilities from either EffD or MaxD curves
                                if (distance <= (float)EffD)
                                {                        //BCW May 04
                                    distanceProb = Math.Exp(lambda1 * lowBound) - Math.Exp(lambda1 * upBound);
                                }
                                else
                                {                                //BCW May 04
                                    distanceProb = (1 - ratio) * Math.Exp(lambda2 * (lowBound - EffD)) - (1 - ratio) * Math.Exp(lambda2 * (upBound - EffD));
                                }
                            }
                            else
                            {
                                if (distance <= cellDiam)
                                {                                //Draw probabilities from both EffD and MaxD curves
                                    distanceProb = Math.Exp(lambda1 * lowBound) - (1 - ratio) * Math.Exp(lambda2 * (upBound - EffD));
                                }
                                else
                                {
                                    distanceProb = (1 - ratio) * Math.Exp(lambda2 * (lowBound - EffD)) - (1 - ratio) * Math.Exp(lambda2 * (upBound - EffD));
                                }
                            }
                            if (distanceProb > Landis.Util.Random.GenerateUniform())                            // && frand() < l->probRepro(speciesNum))  Modified BCW May '04
                            {
                                //  success = sites(row,col)->addNewCohort(s, sa, 10);
                                return(true);
                            }
                        }
                    }     // if neighor is active
                }         // for each column, j, of current row in neighborhood
            }             // for each row, i, in the neighborhood

            //  Search failed.
            return(false);
        }
コード例 #59
0
        //---------------------------------------------------------------------
        private double UpdateDeadBiomass(ICohort cohort, double actualANPP, double totalMortality, ActiveSite site, double newBiomass)
        {
            ISpecies species = cohort.Species;
            double leafLongevity = SpeciesData.LeafLongevity[species];
            double cohortBiomass = newBiomass; // Mortality is for the current year's biomass.
            double leafFraction = ComputeFractionANPPleaf(species);

            // First, deposit the a portion of the leaf mass directly onto the forest floor.
            // In this way, the actual amount of leaf biomass is added for the year.
            // In addition, add the equivalent portion of fine roots to the surface layer.

            double annualLeafANPP = actualANPP * leafFraction;

            ForestFloor.AddLitter(annualLeafANPP, species, site);

            // --------------------------------------------------------------------------------
            // The next section allocates mortality from standing (wood and leaf) biomass, i.e.,
            // biomass that has accrued from previous years' growth.

            // Subtract annual leaf growth as that was taken care of above.
            totalMortality -= annualLeafANPP;

            // Assume that standing foliage is equal to this years annualLeafANPP * leaf longevity
            // minus this years leaf ANPP.  This assumes that actual ANPP has been relatively constant
            // over the past 2 or 3 years (if coniferous).

            double standing_nonwood = (annualLeafANPP * leafLongevity) - annualLeafANPP;
            double standing_wood = Math.Max(0, cohortBiomass - standing_nonwood);

            double fractionStandingNonwood = standing_nonwood / cohortBiomass;

            //  Assume that the remaining mortality is divided proportionally
            //  between the woody mass and non-woody mass (Niklaus & Enquist,
            //  2002).   Do not include current years growth.
            double mortality_nonwood = Math.Max(0.0, totalMortality * fractionStandingNonwood);
            double mortality_wood = Math.Max(0.0, totalMortality - mortality_nonwood);

            if (mortality_wood < 0 || mortality_nonwood < 0)
                throw new ApplicationException("Error: Woody input is < 0");

            //  Add mortality to dead biomass pools.
            //  Coarse root mortality is assumed equal to aboveground woody mortality
            //    mass is assumed 25% of aboveground wood (White et al. 2000, Niklas & Enquist 2002)
            if (mortality_wood > 0)
            {
                //  Add mortality to dead biomass pools.
                ForestFloor.AddWoody((ushort)mortality_wood, species, site);
            }

            if (mortality_nonwood > 0)
            {
                ForestFloor.AddLitter(mortality_nonwood, species, site);
            }

            //  Total mortality not including annual leaf litter
            M_noLeafLitter = (int)mortality_wood;

            return (annualLeafANPP + mortality_nonwood + mortality_wood);
        }
コード例 #60
0
        //---------------------------------------------------------------------

        public ushort ComputeNonWoodyBiomass(ActiveSite site)
        {
            Percentage nonWoodyPercentage = Cohorts.BiomassCalculator.ComputeNonWoodyPercentage(this, site);

            return((ushort)(data.Biomass * nonWoodyPercentage));
        }