/// <summary> /// Senesce any leaves matching the given condition. /// </summary> /// <param name="predicate">Any leaves matching this predicate will be senesced.</param> public void SenesceWhere(Func <PerennialLeafCohort, bool> predicate) { foreach (PerennialLeafCohort leaf in leaves.Where(predicate)) { leaf.IsSenesced = true; if (leaf.Live.Wt > 0) { // Move leaf biomass from live to dead pool. live.Subtract(leaf.Live); dead.Add(leaf.Live); // Update the leaf's internal biomass pools. leaf.Dead.Add(leaf.Live); leaf.Senesced.SetTo(leaf.Live); leaf.Live.Clear(); // Move leaf area into dead area. leaf.AreaDead += leaf.Area; LaiDead += leaf.Area; Lai -= leaf.Area; leaf.Area = 0; } } }
protected void DoPlantEnding(object sender, EventArgs e) { if (Wt > 0.0) { Detached.Add(Live); Detached.Add(Dead); SurfaceOrganicMatter.Add(Wt * 10, N * 10, 0, Plant.CropType, Name); } Clear(); }
protected void DoPlantEnding(object sender, EventArgs e) { Biomass total = Live + Dead; if (total.Wt > 0.0) { Detached.Add(Live); Detached.Add(Dead); SurfaceOrganicMatter.Add(total.Wt * 10, total.N * 10, 0, Plant.CropType, Name); } Clear(); }
/// <summary>Removes biomass from live and dead biomass pools, may send to surface organic matter</summary> /// <param name="biomassRemoveType">Name of event that triggered this biomass removal call.</param> /// <param name="amount">The fractions of biomass to remove</param> /// <param name="Live">Live biomass pool</param> /// <param name="Dead">Dead biomass pool</param> /// <param name="Removed">The removed pool to add to.</param> /// <param name="Detached">The detached pool to add to.</param> /// <param name="writeToSummary">Write the biomass removal to summary file?</param> /// <returns>The remaining live fraction.</returns> public double RemoveBiomass(string biomassRemoveType, OrganBiomassRemovalType amount, Biomass Live, Biomass Dead, Biomass Removed, Biomass Detached, bool writeToSummary = true) { if (amount == null) { amount = FindDefault(biomassRemoveType); } else { CheckRemoveFractions(biomassRemoveType, amount); } double liveFractionToRemove = amount.FractionLiveToRemove + amount.FractionLiveToResidue; double deadFractionToRemove = amount.FractionDeadToRemove + amount.FractionDeadToResidue; if (liveFractionToRemove + deadFractionToRemove > 0.0) { Biomass removing; Biomass detaching; double totalBiomass = Live.Wt + Dead.Wt; if (totalBiomass > 0) { double remainingLiveFraction = RemoveBiomassFromLiveAndDead(amount, Live, Dead, out removing, out detaching); // Add the detaching biomass to total removed and detached Removed.Add(removing); Detached.Add(detaching); // Pass the detaching biomass to surface organic matter model. //TODO: in reality, the dead material is different from the live, so it would be better to add them as separate pools to SurfaceOM if (plant.PlantType == null) { throw new Exception($"PlantType is null in plant {plant.Name}. The most likely cause is the use of an unofficial/unreleased plant model."); } surfaceOrganicMatter.Add(detaching.Wt * 10.0, detaching.N * 10.0, 0.0, plant.PlantType, Name); if (writeToSummary) { double totalFractionToRemove = (Removed.Wt + detaching.Wt) * 100.0 / totalBiomass; double toResidue = detaching.Wt * 100.0 / (Removed.Wt + detaching.Wt); double removedOff = Removed.Wt * 100.0 / (Removed.Wt + detaching.Wt); summary.WriteMessage(Parent, "Removing " + totalFractionToRemove.ToString("0.0") + "% of " + Parent.Name.ToLower() + " biomass from " + plant.Name + ". Of this " + removedOff.ToString("0.0") + "% is removed from the system and " + toResidue.ToString("0.0") + "% is returned to the surface organic matter.", MessageType.Diagnostic); summary.WriteMessage(Parent, "Removed " + Removed.Wt.ToString("0.0") + " g/m2 of dry matter weight and " + Removed.N.ToString("0.0") + " g/m2 of N.", MessageType.Diagnostic); } return(remainingLiveFraction); } } return(1.0); }
private void GetSenescingLeafBiomass(out Biomass Senescing) { Senescing = new Biomass(); foreach (PerrenialLeafCohort L in Leaves) { if (L.Age >= LeafResidenceTime.Value()) { Senescing.Add(L.Live); } } }
private void DetachLeaves(out Biomass Detached) { Detached = new Biomass(); foreach (PerrenialLeafCohort L in Leaves) { if (L.Age >= (LeafResidenceTime.Value() + LeafDetachmentTime.Value())) { Detached.Add(L.Dead); } } Leaves.RemoveAll(L => L.Age >= (LeafResidenceTime.Value() + LeafDetachmentTime.Value())); }
private Biomass DetachLeaves() { Detached = new Biomass(); double LRT = LeafResidenceTime.Value(); double LDT = LeafDetachmentTime.Value(); foreach (PerrenialLeafCohort L in Leaves) { if (L.Age >= (LRT + LDT)) { Detached.Add(L.Dead); } } Leaves.RemoveAll(L => L.Age >= (LRT + LDT)); return(Detached); }
/// <summary>Removes biomass from live and dead biomass pools and send to soil</summary> /// <param name="biomassRemoveType">Name of event that triggered this biomass remove call.</param> /// <param name="removal">The fractions of biomass to remove</param> /// <param name="Live">Live biomass pool</param> /// <param name="Dead">Dead biomass pool</param> /// <param name="Removed">The removed pool to add to.</param> /// <param name="Detached">The detached pool to add to.</param> public void RemoveBiomassToSoil(string biomassRemoveType, OrganBiomassRemovalType removal, Biomass[] Live, Biomass[] Dead, Biomass Removed, Biomass Detached) { if (removal == null) { removal = FindDefault(biomassRemoveType); } //NOTE: roots don't have dead biomass double totalFractionToRemove = removal.FractionLiveToRemove + removal.FractionLiveToResidue; if (totalFractionToRemove > 0) { //NOTE: at the moment Root has no Dead pool FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[Live.Length]; double remainingFraction = 1.0 - (removal.FractionLiveToResidue + removal.FractionLiveToRemove); for (int layer = 0; layer < Live.Length; layer++) { Biomass removing; Biomass detaching; double remainingLiveFraction = RemoveBiomassFromLiveAndDead(removal, Live[layer], Dead[layer], out removing, out detaching); // Add the detaching biomass to total removed and detached Removed.Add(removing); Detached.Add(detaching); // Pass the detaching biomass to surface organic matter model. FOMType fom = new FOMType(); fom.amount = (float)(detaching.Wt * 10); fom.N = (float)(detaching.N * 10); fom.C = (float)(0.40 * detaching.Wt * 10); fom.P = 0.0; fom.AshAlk = 0.0; FOMLayerLayerType Layer = new FOMLayerLayerType(); Layer.FOM = fom; Layer.CNR = 0.0; Layer.LabileP = 0.0; FOMLayers[layer] = Layer; } FOMLayerType FomLayer = new FOMLayerType(); FomLayer.Type = plant.PlantType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); } }
/// <summary>Recalculate live and dead biomass if necessary</summary> private void RecalculateLiveDead() { if (needToRecalculateLiveDead) { needToRecalculateLiveDead = false; liveBiomass.Clear(); deadBiomass.Clear(); foreach (Biomass b in PlantZone.LayerLive) { liveBiomass.Add(b); } foreach (Biomass b in PlantZone.LayerDead) { deadBiomass.Add(b); } } }
/// <summary> /// Detach any leaves older than the specified age. /// </summary> /// <param name="predicate">Any leaves matching this predicate will be deatched..</param> public Biomass DetachWhere(Func <PerennialLeafCohort, bool> predicate) { Biomass detached = new Biomass(); foreach (PerennialLeafCohort leaf in leaves.Where(predicate)) { detached.Add(leaf.Dead); // Need to check this. The assumption here is that leaves will // be senesced before they are detached. If this assumption // doesn't hold up, mass balance will be violated. if (leaf.IsSenesced) { LaiDead -= leaf.AreaDead; dead.Subtract(leaf.Senesced); } } leaves.RemoveAll(l => predicate(l)); return(detached); }
protected void OnDoActualPlantGrowth(object sender, EventArgs e) { if (Plant.IsAlive) { // Do senescence double senescedFrac = SenescenceRate.Value(); if (Live.Wt * (1.0 - senescedFrac) < BiomassToleranceValue) { senescedFrac = 1.0; // remaining amount too small, senesce all } Biomass Loss = Live * senescedFrac; Live.Subtract(Loss); Dead.Add(Loss); Senesced.Add(Loss); // Do detachment double detachedFrac = DetachmentRateFunction.Value(); if (Dead.Wt * (1.0 - detachedFrac) < BiomassToleranceValue) { detachedFrac = 1.0; // remaining amount too small, detach all } Biomass detaching = Dead * detachedFrac; Dead.Multiply(1.0 - detachedFrac); if (detaching.Wt > 0.0) { Detached.Add(detaching); SurfaceOrganicMatter.Add(detaching.Wt * 10, detaching.N * 10, 0, Plant.CropType, Name); } // Do maintenance respiration MaintenanceRespiration += Live.MetabolicWt * MaintenanceRespirationFunction.Value(); Live.MetabolicWt *= (1 - MaintenanceRespirationFunction.Value()); MaintenanceRespiration += Live.StorageWt * MaintenanceRespirationFunction.Value(); Live.StorageWt *= (1 - MaintenanceRespirationFunction.Value()); } }
private void GetSenescingLeafBiomass(out Biomass Senescing) { Senescing = new Biomass(); foreach (PerrenialLeafCohort L in Leaves) if (L.Age >= LeafResidenceTime.Value) Senescing.Add(L.Live); }
private void DetachLeaves(out Biomass Detached) { Detached = new Biomass(); foreach (PerrenialLeafCohort L in Leaves) if (L.Age >= (LeafResidenceTime.Value+ LeafDetachmentTime.Value)) Detached.Add(L.Dead); Leaves.RemoveAll(L => L.Age >= (LeafResidenceTime.Value + LeafDetachmentTime.Value)); }
/// <summary>Removes biomass from live and dead biomass pools</summary> /// <param name="amount">The fractions of biomass to remove</param> /// <param name="Live">Live biomass pool</param> /// <param name="Dead">Dead biomass pool</param> /// <param name="Removed">The removed pool to add to.</param> /// <param name="Detached">The detached pool to add to.</param> /// <param name="detaching">The amount of detaching material</param> private static double RemoveBiomassFromLiveAndDead(OrganBiomassRemovalType amount, Biomass Live, Biomass Dead, out Biomass Removed, Biomass Detached, out Biomass detaching) { double remainingLiveFraction = 1.0 - (amount.FractionLiveToResidue + amount.FractionLiveToRemove); double remainingDeadFraction = 1.0 - (amount.FractionDeadToResidue + amount.FractionDeadToRemove); detaching = Live * amount.FractionLiveToResidue + Dead * amount.FractionDeadToResidue; Removed = Live * amount.FractionLiveToRemove + Dead * amount.FractionDeadToRemove; Detached.Add(detaching); Live.Multiply(remainingLiveFraction); Dead.Multiply(remainingDeadFraction); return remainingLiveFraction; }