//--------------------------------------------------------------------- public void CohortPartialMortality(object sender, Landis.Library.BiomassCohorts.PartialDeathEventArgs eventArgs) { ExtensionType disturbanceType = eventArgs.DisturbanceType; ActiveSite site = eventArgs.Site; double reduction = eventArgs.Reduction; ICohort cohort = (Landis.Library.LeafBiomassCohorts.ICohort)eventArgs.Cohort; float fractionPartialMortality = (float)eventArgs.Reduction; //PlugIn.ModelCore.UI.WriteLine("Cohort experienced partial mortality: species={0}, age={1}, wood_biomass={2}, fraction_mortality={3:0.0}.", cohort.Species.Name, cohort.Age, cohort.WoodBiomass, fractionPartialMortality); AgeOnlyDisturbances.PoolPercentages cohortReductions = AgeOnlyDisturbances.Module.Parameters.CohortReductions[disturbanceType]; float foliar = cohort.LeafBiomass * fractionPartialMortality; float wood = cohort.WoodBiomass * fractionPartialMortality; float foliarInput = AgeOnlyDisturbances.Events.ReduceInput(foliar, cohortReductions.Foliar, site); float woodInput = AgeOnlyDisturbances.Events.ReduceInput(wood, cohortReductions.Wood, site); ForestFloor.AddWoodLitter(woodInput, cohort.Species, site); ForestFloor.AddFoliageLitter(foliarInput, cohort.Species, site); Roots.AddCoarseRootLitter(woodInput, cohort, cohort.Species, site); // All of cohorts roots are killed. Roots.AddFineRootLitter(foliarInput, cohort, cohort.Species, site); //PlugIn.ModelCore.UI.WriteLine("EVENT: Cohort Partial Mortality: species={0}, age={1}, disturbance={2}.", cohort.Species.Name, cohort.Age, disturbanceType); //PlugIn.ModelCore.UI.WriteLine(" Cohort Reductions: Foliar={0:0.00}. Wood={1:0.00}.", cohortReductions.Foliar, cohortReductions.Wood); //PlugIn.ModelCore.UI.WriteLine(" InputB/TotalB: Foliar={0:0.00}/{1:0.00}, Wood={2:0.0}/{3:0.0}.", foliarInput, foliar, woodInput, wood); return; }
/// <summary> /// Summarize cohort C&N for output. /// </summary> private static void CalculateCohortCN(ActiveSite site, ICohort cohort) { ISpecies species = cohort.Species; double leafC = cohort.LeafBiomass * 0.47; double woodC = cohort.WoodBiomass * 0.47; double fRootC = Roots.CalculateFineRoot(cohort, leafC); double cRootC = Roots.CalculateCoarseRoot(cohort, woodC); double totalC = leafC + woodC + fRootC + cRootC; double leafN = leafC / (double)SpeciesData.LeafCN[species]; double woodN = woodC / (double)SpeciesData.WoodCN[species]; double cRootN = cRootC / (double)SpeciesData.CoarseRootCN[species]; double fRootN = fRootC / (double)SpeciesData.FineRootCN[species]; //double totalN = woodN + cRootN + leafN + fRootN; //PlugIn.ModelCore.UI.WriteLine("month={0}, species={1}, leafB={2:0.0}, leafC={3:0.00}, leafN={4:0.0}, woodB={5:0.0}, woodC={6:0.000}, woodN={7:0.0}", Month, cohort.Species.Name, cohort.LeafBiomass, leafC, leafN, cohort.WoodBiomass, woodC, woodN); SiteVars.CohortLeafC[site] += leafC; SiteVars.CohortFRootC[site] += fRootC; SiteVars.CohortLeafN[site] += leafN; SiteVars.CohortFRootN[site] += fRootN; SiteVars.CohortWoodC[site] += woodC; SiteVars.CohortCRootC[site] += cRootC; SiteVars.CohortWoodN[site] += woodN; SiteVars.CohortCRootN[site] += cRootN; return; }
//--------------------------------------------------------------------- // Method for calculating Mineral N allocation, called from Century.cs Run method before calling Grow // Iterates through cohorts, assigning each a portion of mineral N based on coarse root biomass. Uses an exponential function to "distribute" // the N more evenly between spp. so that the ones with the most woody biomass don't get all the N (L122). public static void CalculateMineralNfraction(Site site) { AvailableN.CohortMineralNfraction = new Dictionary <int, Dictionary <int, double> >(); double NAllocTotal = 0.0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); //PlugIn.ModelCore.UI.WriteLine("CALCMineralNfraction: year={0}, mo={1}, species={2}, cohortAge={3}, cohortAddYear={4}.", PlugIn.ModelCore.CurrentTime, Century.Month, cohort.Species.Name, cohort.Age, cohortAddYear); //Nallocation is a measure of how much N a cohort can gather relative to other cohorts //double Nallocation = Roots.CalculateFineRoot(cohort.LeafBiomass); double Nallocation = 1 - Math.Exp((-Roots.CalculateCoarseRoot(cohort, cohort.WoodBiomass) * 0.02)); if (Nallocation <= 0.0) { Nallocation = Math.Max(Nallocation, cohort.WoodBiomass * 0.01); } NAllocTotal += Nallocation; Dictionary <int, double> newEntry = new Dictionary <int, double>(); newEntry.Add(cohortAddYear, Nallocation); if (CohortMineralNfraction.ContainsKey(cohort.Species.Index)) { if (!CohortMineralNfraction[cohort.Species.Index].ContainsKey(cohortAddYear)) { CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = Nallocation; } } else { CohortMineralNfraction.Add(cohort.Species.Index, newEntry); } } } // Next relativize foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { //PlugIn.ModelCore.UI.WriteLine(" SpeciesCohorts = {0}", speciesCohorts.Species.Name); foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); double Nallocation = CohortMineralNfraction[cohort.Species.Index][cohortAddYear]; double relativeNallocation = Nallocation / NAllocTotal; CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = relativeNallocation; if (Double.IsNaN(relativeNallocation) || Double.IsNaN(Nallocation) || Double.IsNaN(NAllocTotal)) { PlugIn.ModelCore.UI.WriteLine(" N ALLOCATION CALCULATION = NaN! "); PlugIn.ModelCore.UI.WriteLine(" Site_Row={0:0}, Site_Column={1:0}.", site.Location.Row, site.Location.Column); PlugIn.ModelCore.UI.WriteLine(" Nallocation={0:0.00}, NAllocTotal={1:0.00}, relativeNallocation={2:0.00}.", Nallocation, NAllocTotal, relativeNallocation); PlugIn.ModelCore.UI.WriteLine(" Wood={0:0.00}, Leaf={1:0.00}.", cohort.WoodBiomass, cohort.LeafBiomass); } } } }
//--------------------------------------------------------------------- public void CohortDied(object sender, Landis.Library.BiomassCohorts.DeathEventArgs eventArgs) { //PlugIn.ModelCore.UI.WriteLine("Cohort Died! :-("); ExtensionType disturbanceType = eventArgs.DisturbanceType; ActiveSite site = eventArgs.Site; ICohort cohort = (Landis.Library.LeafBiomassCohorts.ICohort)eventArgs.Cohort; double foliar = (double)cohort.LeafBiomass; double wood = (double)cohort.WoodBiomass; if (disturbanceType == null) { ForestFloor.AddWoodLitter(wood, cohort.Species, eventArgs.Site); ForestFloor.AddFoliageLitter(foliar, cohort.Species, eventArgs.Site); Roots.AddCoarseRootLitter(wood, cohort, cohort.Species, eventArgs.Site); Roots.AddFineRootLitter(foliar, cohort, cohort.Species, eventArgs.Site); } if (disturbanceType != null) { Disturbed[site] = true; if (disturbanceType.IsMemberOf("disturbance:fire")) { Landis.Library.Succession.Reproduction.CheckForPostFireRegen(eventArgs.Cohort, site); } else { Landis.Library.Succession.Reproduction.CheckForResprouting(eventArgs.Cohort, site); } } }
//--------------------------------------------------------------------- public void CohortPartialMortality(object sender, Landis.Library.BiomassCohorts.PartialDeathEventArgs eventArgs) { ExtensionType disturbanceType = eventArgs.DisturbanceType; ActiveSite site = eventArgs.Site; double reduction = eventArgs.Reduction; ICohort cohort = (Landis.Library.LeafBiomassCohorts.ICohort)eventArgs.Cohort; float fractionPartialMortality = (float)eventArgs.Reduction; AgeOnlyDisturbances.PoolPercentages cohortReductions = AgeOnlyDisturbances.Module.Parameters.CohortReductions[disturbanceType]; float foliar = cohort.LeafBiomass * fractionPartialMortality; float wood = cohort.WoodBiomass * fractionPartialMortality; float foliarInput = AgeOnlyDisturbances.Events.ReduceInput(foliar, cohortReductions.Foliar, site); float woodInput = AgeOnlyDisturbances.Events.ReduceInput(wood, cohortReductions.Wood, site); ForestFloor.AddWoodLitter(woodInput, cohort.Species, site); ForestFloor.AddFoliageLitter(foliarInput, cohort.Species, site); Roots.AddCoarseRootLitter(woodInput, cohort, cohort.Species, site); // All of cohorts roots are killed. Roots.AddFineRootLitter(foliarInput, cohort, cohort.Species, site); return; }
//--------------------------------------------------------------------- /// <summary> /// Calculates cohort N demand depending upon how much N would be removed through growth (ANPP) of leaves, wood, coarse roots and fine roots. /// Demand is then used to determine the amount of N that a cohort "wants". /// </summary> public static double CalculateCohortNDemand(ISpecies species, ActiveSite site, ICohort cohort, double[] ANPP) { if (ANPP[1] <= 0.0) { return(0.0); } //return 0.01; if (SpeciesData.NFixer[species]) // We fix our own N! { return(0.0); } double ANPPwood = 0.0; double ANPPleaf = 0.0; double ANPPcoarseRoot = 0.0; double ANPPfineRoot = 0.0; double woodN = 0.0; double coarseRootN = 0.0; double leafN = 0.0; double fineRootN = 0.0; if (ANPP[0] > 0.0) // Wood { ANPPwood = ANPP[0]; ANPPcoarseRoot = Roots.CalculateCoarseRoot(cohort, ANPPwood); woodN = ANPPwood * 0.47 / SpeciesData.WoodCN[species]; coarseRootN = ANPPcoarseRoot * 0.47 / SpeciesData.CoarseRootCN[species]; } if (ANPP[1] > 0.0) // Leaf { ANPPleaf = ANPP[1]; ANPPfineRoot = Roots.CalculateFineRoot(cohort, ANPPleaf); leafN = ANPPleaf * 0.47 / SpeciesData.LeafCN[species]; fineRootN = ANPPfineRoot * 0.47 / SpeciesData.FineRootCN[species]; } double totalANPP_C = (ANPPleaf + ANPPwood + ANPPcoarseRoot + ANPPfineRoot) * 0.47; double Ndemand = leafN + woodN + coarseRootN + fineRootN; if (Ndemand < 0.0) { PlugIn.ModelCore.UI.WriteLine(" ERROR: TotalANPP-C={0:0.00} Nreduction={1:0.00}.", totalANPP_C, Ndemand); throw new ApplicationException("Error: N Reduction is < 0. See AvailableN.cs"); } return(Ndemand); }
//--------------------------------------------------------------------- /// <summary> /// Summarize NPP /// </summary> private static void CalculateNPPcarbon(ActiveSite site, ICohort cohort, double[] AGNPP) { double NPPwood = AGNPP[0] * 0.47; double NPPleaf = AGNPP[1] * 0.47; double NPPcoarseRoot = Roots.CalculateCoarseRoot(cohort, NPPwood); double NPPfineRoot = Roots.CalculateFineRoot(cohort, NPPleaf); if (Double.IsNaN(NPPwood) || Double.IsNaN(NPPleaf) || Double.IsNaN(NPPcoarseRoot) || Double.IsNaN(NPPfineRoot)) { PlugIn.ModelCore.UI.WriteLine(" EITHER WOOD or LEAF NPP or COARSE ROOT or FINE ROOT = NaN! Will set to zero."); PlugIn.ModelCore.UI.WriteLine(" Yr={0},Mo={1}. WoodNPP={0}, LeafNPP={1}, CRootNPP={2}, FRootNPP={3}.", NPPwood, NPPleaf, NPPcoarseRoot, NPPfineRoot); if (Double.IsNaN(NPPleaf)) { NPPleaf = 0.0; } if (Double.IsNaN(NPPwood)) { NPPwood = 0.0; } if (Double.IsNaN(NPPcoarseRoot)) { NPPcoarseRoot = 0.0; } if (Double.IsNaN(NPPfineRoot)) { NPPfineRoot = 0.0; } } SiteVars.AGNPPcarbon[site] += NPPwood + NPPleaf; SiteVars.BGNPPcarbon[site] += NPPcoarseRoot + NPPfineRoot; SiteVars.MonthlyAGNPPcarbon[site][Century.Month] += NPPwood + NPPleaf; SiteVars.MonthlyBGNPPcarbon[site][Century.Month] += NPPcoarseRoot + NPPfineRoot; if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode) { Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", NPPwood, NPPleaf); } }
//--------------------------------------------------------------------- private void UpdateDeadBiomass(ICohort cohort, ActiveSite site, double[] totalMortality) { double mortality_wood = totalMortality[0]; double mortality_nonwood = totalMortality[1]; // Add mortality to dead biomass pools. // Coarse root mortality is assumed proportional to aboveground woody mortality // mass is assumed 25% of aboveground wood (White et al. 2000, Niklas & Enquist 2002) if (mortality_wood > 0.0) { ForestFloor.AddWoodLitter(mortality_wood, cohort.Species, site); Roots.AddCoarseRootLitter(mortality_wood, cohort, cohort.Species, site); } if (mortality_nonwood > 0.0) { AvailableN.AddResorbedN(cohort, totalMortality[1], site); //ignoring input from scorching, which is rare, but not resorbed. ForestFloor.AddResorbedFoliageLitter(mortality_nonwood, cohort.Species, site); Roots.AddFineRootLitter(mortality_nonwood, cohort, cohort.Species, site); } }
/// <summary> /// Summarize cohort C&N for output. /// </summary> private static void CalculateCohortCN(ActiveSite site, ICohort cohort) { ISpecies species = cohort.Species; double leafC = cohort.LeafBiomass * 0.47; double woodC = cohort.WoodBiomass * 0.47; double fRootC = Roots.CalculateFineRoot(cohort, leafC); double cRootC = Roots.CalculateCoarseRoot(cohort, woodC); double leafN = leafC / SpeciesData.LeafCN[species]; double woodN = woodC / SpeciesData.WoodCN[species]; double cRootN = cRootC / SpeciesData.CoarseRootCN[species]; double fRootN = fRootC / SpeciesData.FineRootCN[species]; SiteVars.CohortLeafC[site] += leafC; SiteVars.CohortFRootC[site] += fRootC; SiteVars.CohortLeafN[site] += leafN; SiteVars.CohortFRootN[site] += fRootN; SiteVars.CohortWoodC[site] += woodC; SiteVars.CohortCRootC[site] += cRootC; SiteVars.CohortWoodN[site] += woodN; SiteVars.CohortCRootN[site] += cRootN; }
//--------------------------------------------------------------------- // Method for calculating Mineral N allocation, called from Century.cs Run method before calling Grow // Iterates through cohorts, assigning each a portion of mineral N based on coarse root biomass. Uses an exponential function to "distribute" // the N more evenly between spp. so that the ones with the most woody biomass don't get all the N (L122). public static void CalculateMineralNfraction(Site site) { AvailableN.CohortMineralNfraction = new Dictionary <int, Dictionary <int, double> >(); double NAllocTotal = 0.0; foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); //PlugIn.ModelCore.UI.WriteLine("CALCMineralNfraction: year={0}, mo={1}, species={2}, cohortAge={3}, cohortAddYear={4}.", PlugIn.ModelCore.CurrentTime, Century.Month, cohort.Species.Name, cohort.Age, cohortAddYear); //Nallocation is a measure of how much N a cohort can gather relative to other cohorts //double Nallocation = Roots.CalculateFineRoot(cohort.LeafBiomass); double Nallocation = 1 - Math.Exp((-Roots.CalculateCoarseRoot(cohort, cohort.WoodBiomass) * 0.02)); if (Nallocation <= 0.0) //PlugIn.ModelCore.CurrentTime == 0) { Nallocation = Math.Max(Nallocation, cohort.WoodBiomass * 0.01); } NAllocTotal += Nallocation; Dictionary <int, double> newEntry = new Dictionary <int, double>(); newEntry.Add(cohortAddYear, Nallocation); if (CohortMineralNfraction.ContainsKey(cohort.Species.Index)) { //CohortMineralNfraction[cohort.Species.Index].Add(cohortAddYear, Nallocation); // option 1: regardless of whether cohortAddYear already exists, create (or replace) the new value //CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = Nallocation; // end of option 1 // option 2: if the cohortAddYear already exists, add the new value to the existing one //double currentNallocation; //CohortMineralNfraction[cohort.Species.Index].TryGetValue(cohortAddYear, out currentNallocation); // currentNallocation will be set to 0.0 if the cohortAddYear key does not exist //CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = currentNallocation + Nallocation; // end of option 2 //if key is already present, then don't trigger an error. if (!CohortMineralNfraction[cohort.Species.Index].ContainsKey(cohortAddYear)) { CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = Nallocation; } } else { CohortMineralNfraction.Add(cohort.Species.Index, newEntry); } } } // Next relativize foreach (ISpeciesCohorts speciesCohorts in SiteVars.Cohorts[site]) { //PlugIn.ModelCore.UI.WriteLine(" SpeciesCohorts = {0}", speciesCohorts.Species.Name); foreach (ICohort cohort in speciesCohorts) { int cohortAddYear = GetAddYear(cohort); double Nallocation = CohortMineralNfraction[cohort.Species.Index][cohortAddYear]; double relativeNallocation = Nallocation / NAllocTotal; CohortMineralNfraction[cohort.Species.Index][cohortAddYear] = relativeNallocation; if (Double.IsNaN(relativeNallocation) || Double.IsNaN(Nallocation) || Double.IsNaN(NAllocTotal)) { PlugIn.ModelCore.UI.WriteLine(" N ALLOCATION CALCULATION = NaN! "); PlugIn.ModelCore.UI.WriteLine(" Nallocation={0:0.00}, NAllocTotal={1:0.00}, relativeNallocation={2:0.00}.", Nallocation, NAllocTotal, relativeNallocation); PlugIn.ModelCore.UI.WriteLine(" Wood={0:0.00}, Leaf={1:0.00}.", cohort.WoodBiomass, cohort.LeafBiomass); } } } }