Exemplo n.º 1
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)
        {
            ecoregion = PlugIn.ModelCore.Ecoregion[site];
            int siteBiomass = SiteVars.TotalBiomass[site];

            //Save the pre-growth root biomass. This needs to be calculated BEFORE growth and mortality
            double TotalRoots = Roots.CalculateRootBiomass(site, cohort.Species, cohort.Biomass);

            SiteVars.soilClass[site].CollectRootBiomass(TotalRoots, 0);

            // 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, SiteVars.PreviousYearMortality[site]);

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

            //  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;
                SiteVars.soilClass[site].DisturbanceImpactsDOM(site, "defol", 0);  //just soil impacts. Dist impacts are handled differently??
            }

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

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

            //if (site.Location.Row == 279 && site.Location.Column == 64 && cohort.Species.Name == "Pl")
            //{
            //    PlugIn.ModelCore.UI.WriteLine("Yr={0},  Age={1}, mortGrow={2}, mortAge={3}, ANPP={4}, totLitter={5}", PlugIn.ModelCore.CurrentTime, cohort.Age, mortalityGrowth, mortalityAge, actualANPP, totalLitter);
            // }

            //if (cohort.Species.Name == "pinubank")
            //{
            //PlugIn.ModelCore.UI.WriteLine("Age={0}, ANPPact={1:0.0}, M={2:0.0}, litter={3:0.00}.", cohort.Age, actualANPP, totalMortality, totalLitter);
            //PlugIn.ModelCore.UI.WriteLine("Name={0}, Age={1}, B={2}, ANPPact={3:0.0}, delta={4:0.0}", cohort.Species.Name, cohort.Age, cohort.Biomass, actualANPP, deltaBiomass);
            //    PlugIn.ModelCore.UI.WriteLine("Name={0}, Age={1}, B={2}, Mage={3:0.0}, Mgrowth={4:0.0}, ANPPact={5:0.0}, delta={6:0.0}, newbiomass={7:0.0}", cohort.Species.Name, cohort.Age, cohort.Biomass, mortalityAge, mortalityGrowth, actualANPP, deltaBiomass, newBiomass);
            //}
            //The KillNow flag indicates that this is the year of growth in which to kill off some cohorts in order to make snags.
            if (SiteVars.soilClass[site].bKillNow && Snags.bSnagsPresent)
            {
                //if (SiteVars.soilClass[site].diedAt == cohort.Age && SiteVars.soilClass[site].spIndex == cohort.Species.Index)
                //there could be more than one species-age combination, so we have to loop through them.
                //However, the user has been asked to put the ages in order from smallest to largest, so we can stop looking
                //as soon as we reach an age that is older than the cohort's age.
                for (int idx = 0; idx < Snags.NUMSNAGS; idx++)
                {
                    if (cohort.Age == Snags.DiedAt[idx] && Snags.initSpecIdx[idx] == cohort.Species.Index)
                    {
                        deltaBiomass = -cohort.Biomass; //set biomass to 0 to make core remove this from the list

                        //when this cohort gets passed to the cohort died event, there is no longer any biomass present, so
                        //we have to capture the biomass information here, while we still can.

                        double foliar = (double)cohort.ComputeNonWoodyBiomass(site);
                        double wood   = ((double)cohort.Biomass - foliar);
                        Snags.bSnagsUsed[idx] = true;

                        SiteVars.soilClass[site].CollectBiomassMortality(cohort.Species, cohort.Age, wood, foliar, 5 + idx);
                    }
                    if (Snags.DiedAt[idx] > cohort.Age || Snags.DiedAt[idx] == 0)
                    {
                        break;
                    }
                }
            }
            if (deltaBiomass > -cohort.Biomass)
            {   //if we didn't kill this cohort to make a snag, then update the post-growth root biomass.
                TotalRoots = Roots.CalculateRootBiomass(site, cohort.Species, newBiomass);
                SiteVars.soilClass[site].CollectRootBiomass(TotalRoots, 1);
            }


            return(deltaBiomass);
        }
Exemplo n.º 2
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.

            // 0.8 was used to calibrate the model to steady-state Nitrogen.  Without this reduction, total N
            // increases by 0.038% each year.
            // Remove jan 2020 to more closely match code with the current Biomass succession model

            //double annualLeafANPP = actualANPP * leafFraction * 0.8;
            double annualLeafANPP = actualANPP * leafFraction;

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

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

            SiteVars.soilClass[site].CollectBiomassMortality(species, cohort.Age, mortality_wood, (mortality_nonwood + annualLeafANPP), 0);

            //add root biomass information - now calculated based on both woody and non-woody biomass
            Roots.CalculateRootTurnover(site, species, cohortBiomass);
            SiteVars.soilClass[site].CollectBiomassMortality(species, cohort.Age, Roots.CoarseRootTurnover, Roots.FineRootTurnover, 1);

            //if biomass is going down, then we need to capture a decrease in the roots as well.
            if (cohortBiomass < cohort.Biomass)
            {
                double preMortRoots  = Roots.CalculateRootBiomass(site, species, cohort.Biomass);
                double preMortCoarse = Roots.CoarseRoot;
                double preMortFine   = Roots.FineRoot;
                double TotRoots      = Roots.CalculateRootBiomass(site, species, cohortBiomass);
                if (preMortRoots > TotRoots) //if the root biomass went down, then we need to allocate that difference.
                {                            //We will allocate the total root decline to the different pools based on the relative proportions
                    //prior to the decline. (Note that we are not calculating actual declines for each type because
                    //sometimes if we are changing calculation methods, we may change the allocation and may cause a large
                    //decrease in one pool and an increase in the other.)
                    double diffFine   = (preMortFine / preMortRoots) * (preMortRoots - TotRoots);
                    double diffCoarse = (preMortRoots - TotRoots) - diffFine;
                    SiteVars.soilClass[site].CollectBiomassMortality(species, cohort.Age, diffCoarse, diffFine, 1);

                    //write a note to the file if the allocation changes unexpectedly, but not during spin-up
                    if (((preMortCoarse - Roots.CoarseRoot) < 0 || (preMortFine - Roots.FineRoot) < 0) && PlugIn.ModelCore.CurrentTime > 0)
                    {
                        string strCombo = "from: " + preMortCoarse;
                        strCombo += " to: " + Roots.CoarseRoot;
                        string strCombo2 = "from: " + preMortFine;
                        strCombo2 += " to: " + Roots.FineRoot;
                        PlugIn.ModelCore.UI.WriteLine("Root Dynamics: Overall root biomass declined but note change in coarse root allocation " + strCombo + " and fine root allocation" + strCombo2);
                    }
                }
                else if (PlugIn.ModelCore.CurrentTime > 0)
                {
                    //write a note to the file if the root biomass increases while abio decreases, but not during spin-up
                    string strCombo = "from: " + cohort.Biomass;
                    strCombo += " to: " + cohortBiomass;
                    string strCombo2 = "from: " + preMortRoots;
                    strCombo2 += " to: " + TotRoots;
                    PlugIn.ModelCore.UI.WriteLine("Root Dynamics: Note that aboveground biomass decreased " + strCombo + " but root biomass increased " + strCombo2);
                }
            }

            if (PlugIn.ModelCore.CurrentTime == 0)
            {
                SiteVars.soilClass[site].CollectBiomassMortality(species, cohort.Age, standing_wood, standing_nonwood, 3);
                Roots.CalculateRootTurnover(site, species, (standing_wood + standing_nonwood));
                SiteVars.soilClass[site].CollectBiomassMortality(species, cohort.Age, Roots.CoarseRootTurnover, Roots.FineRootTurnover, 4);
            }

            return(annualLeafANPP + mortality_nonwood + mortality_wood);
        }