/// <summary> /// Calculate actual decomposition /// </summary> public SurfaceOrganicMatterDecompType CalculateActualSOMDecomp() { SurfaceOrganicMatterDecompType actualSOMDecomp = new SurfaceOrganicMatterDecompType(); actualSOMDecomp.Pool = new SurfaceOrganicMatterDecompPoolType[PotentialSOMDecomp.Pool.Length]; for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { actualSOMDecomp.Pool[i] = new SurfaceOrganicMatterDecompPoolType(); actualSOMDecomp.Pool[i].Name = PotentialSOMDecomp.Pool[i].Name; actualSOMDecomp.Pool[i].OrganicMatterType = PotentialSOMDecomp.Pool[i].OrganicMatterType; actualSOMDecomp.Pool[i].FOM = new FOMType(); actualSOMDecomp.Pool[i].FOM.amount = PotentialSOMDecomp.Pool[i].FOM.amount; } double InitialResidueC = 0; // Potential residue decomposition provided by surfaceorganicmatter model double FinalResidueC = 0; // How much is left after decomposition double FractionDecomposed; for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { InitialResidueC += PotentialSOMDecomp.Pool[i].FOM.C; } FinalResidueC = SurfaceResidue.C[0]; FractionDecomposed = 1.0 - MathUtilities.Divide(FinalResidueC, InitialResidueC, 0); if (FractionDecomposed < 1) { } for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { actualSOMDecomp.Pool[i].FOM.C = PotentialSOMDecomp.Pool[i].FOM.C * FractionDecomposed; actualSOMDecomp.Pool[i].FOM.N = PotentialSOMDecomp.Pool[i].FOM.N * FractionDecomposed; } return(actualSOMDecomp); }
/// <summary>Notify other modules of the potential to decompose.</summary> /// <returns></returns> private SurfaceOrganicMatterDecompType SendPotDecompEvent() { SurfaceOrganicMatterDecompType SOMDecomp = new SurfaceOrganicMatterDecompType() { Pool = new SurfaceOrganicMatterDecompPoolType[numSurfom] }; if (numSurfom <= 0) { return(SOMDecomp); } double[] c_pot_decomp, n_pot_decomp, p_pot_decomp; PotDecomp(out c_pot_decomp, out n_pot_decomp, out p_pot_decomp); for (int residue = 0; residue < numSurfom; residue++) { SOMDecomp.Pool[residue] = new SurfaceOrganicMatterDecompPoolType() { Name = SurfOM[residue].name, OrganicMatterType = SurfOM[residue].OrganicMatterType, FOM = new FOMType() { amount = MathUtilities.Divide(c_pot_decomp[residue], C_fract[residue], 0.0), C = c_pot_decomp[residue], N = n_pot_decomp[residue], P = p_pot_decomp[residue], AshAlk = 0.0 } } } ; return(SOMDecomp); }
/// <summary> /// Calculate actual decomposition /// </summary> public SurfaceOrganicMatterDecompType CalculateActualSOMDecomp() { SurfaceOrganicMatterDecompType ActualSOMDecomp = new SurfaceOrganicMatterDecompType(); ActualSOMDecomp = ReflectionUtilities.Clone(PotentialSOMDecomp) as SurfaceOrganicMatterDecompType; double InitialResidueC = 0; // Potential residue decomposition provided by surfaceorganicmatter model double FinalResidueC = 0; // How much is left after decomposition double FractionDecomposed; for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { InitialResidueC += PotentialSOMDecomp.Pool[i].FOM.C; } FinalResidueC = SurfaceResidue.C[0]; FractionDecomposed = 1.0 - MathUtilities.Divide(FinalResidueC, InitialResidueC, 0); if (FractionDecomposed < 1) { } for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { ActualSOMDecomp.Pool[i].FOM.C = PotentialSOMDecomp.Pool[i].FOM.C * FractionDecomposed; ActualSOMDecomp.Pool[i].FOM.N = PotentialSOMDecomp.Pool[i].FOM.N * FractionDecomposed; } return(ActualSOMDecomp); }
/// <summary>Calculate actual decomposition</summary> public SurfaceOrganicMatterDecompType CalculateActualSOMDecomp() { // Note: // - If there wasn't enough mineral N to decompose, the rate will be reduced to zero !! - MUST CHECK THE VALIDITY OF THIS SurfaceOrganicMatterDecompType returnSOMDecomp = null; foreach (var patch in patches) { var somDecomp = patch.CalculateActualSOMDecomp(); foreach (var pool in somDecomp.Pool) { pool.FOM.amount = 0; } if (returnSOMDecomp == null) { returnSOMDecomp = somDecomp; } else { returnSOMDecomp.Add(somDecomp); } } return(returnSOMDecomp); }
private void OnDoSurfaceOrganicMatterDecomposition(object sender, EventArgs args) { actualSOMDecomp = SoilNitrogen.CalculateActualSOMDecomp(); if (actualSOMDecomp != null) { DecomposeSurfom(actualSOMDecomp); } }
/// <summary>Decomposes the surfom.</summary> /// <param name="SOMDecomp">The som decomp.</param> private void DecomposeSurfom(SurfaceOrganicMatterDecompType SOMDecomp) { int numSurfom = SOMDecomp.Pool.Length; // local surfom counter from received event; int residue_no; // Index into the global array; double[] cPotDecomp = new double[numSurfom]; // pot amount of C to decompose (kg/ha) double[] nPotDecomp = new double[numSurfom]; // pot amount of N to decompose (kg/ha) double[] pTotDecomp = new double[numSurfom]; // pot amount of P to decompose (kg/ha) double totCDecomp; // total amount of c to decompose; double totNDecomp; // total amount of c to decompose; double totPDecomp; // total amount of c to decompose; double SOMcnr = 0; double SOMc = 0; double SOMn = 0; // calculate potential decompostion of C, N, and P; PotDecomp(out cPotDecomp, out nPotDecomp, out pTotDecomp); for (int counter = 0; counter < numSurfom; counter++) { totCDecomp = SOMDecomp.Pool[counter].FOM.C; totNDecomp = SOMDecomp.Pool[counter].FOM.N; residue_no = GetResidueNumber(SOMDecomp.Pool[counter].Name); if (MathUtilities.IsLessThan(totNDecomp, 0.0) || MathUtilities.IsGreaterThan(totNDecomp, nPotDecomp[residue_no])) { summary.WriteWarning(this, string.Format(@"'Total n decomposition' out of bounds! {0} < {1} < {2}", 0.0, totNDecomp, nPotDecomp[residue_no])); } SOMc = SurfOM[residue_no].Standing.Sum <OMFractionType>(x => x.C) + SurfOM[residue_no].Lying.Sum <OMFractionType>(x => x.C); SOMn = SurfOM[residue_no].Standing.Sum <OMFractionType>(x => x.N) + SurfOM[residue_no].Lying.Sum <OMFractionType>(x => x.N); SOMcnr = MathUtilities.Divide(SOMc, SOMn, 0.0); const double acceptableErr = 1e-4; if (MathUtilities.FloatsAreEqual(totCDecomp, 0.0) && MathUtilities.FloatsAreEqual(totNDecomp, 0.0)) { // all OK - nothing happening; } else if (totCDecomp > cPotDecomp[residue_no] + acceptableErr) { throw new ApsimXException(this, "SurfaceOM - C decomposition exceeds potential rate"); } else if (totNDecomp > nPotDecomp[residue_no] + acceptableErr) { throw new ApsimXException(this, "SurfaceOM - N decomposition exceeds potential rate"); } totPDecomp = totCDecomp * MathUtilities.Divide(pTotDecomp[residue_no], cPotDecomp[residue_no], 0.0); Decomp(totCDecomp, totNDecomp, totPDecomp, residue_no); } }
private void OnDoSoilOrganicMatter(object sender, EventArgs e) { // Get potential residue decomposition from surfaceom. PotentialSOMDecomp = SurfaceOrganicMatter.PotentialDecomposition(); SurfaceResidue.C[0] = 0; SurfaceResidue.N[0] = 0; for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { SurfaceResidue.C[0] += PotentialSOMDecomp.Pool[i].FOM.C; SurfaceResidue.N[0] += PotentialSOMDecomp.Pool[i].FOM.N; } }
private void OnDoSoilOrganicMatter(object sender, EventArgs e) { // Get potential residue decomposition from surfaceom. PotentialSOMDecomp = SurfaceOrganicMatter.PotentialDecomposition(); SurfaceResidue.C[0] = 0; SurfaceResidue.N[0] = 0; SurfaceResidue.LayerFraction[0] = Math.Max(Math.Min(1.0, 100 / Soil.Thickness[0]), 0.0); for (int i = 0; i < PotentialSOMDecomp.Pool.Length; i++) { SurfaceResidue.C[0] += PotentialSOMDecomp.Pool[i].FOM.C; SurfaceResidue.N[0] += PotentialSOMDecomp.Pool[i].FOM.N; } }
/// <summary> /// Gather the information about actual residue decomposition, to be sent back to surface OM /// </summary> /// <remarks> /// Currently P is not being computed by SoilNitrogen, so the corresponding variables are set to zero here /// </remarks> private void PackActualResidueDecomposition() { int nLayers = g.dlayer.Length; // number of layers in the soil soilp_dlt_org_p = new double[nLayers]; double soilp_cpr = MathUtility.Divide(g.SumDoubleArray(g.pot_p_decomp), g.SumDoubleArray(g.pot_c_decomp), 0.0); // C:P ratio for potential decomposition SurfOMActualDecomposition = new SurfaceOrganicMatterDecompType(); Array.Resize(ref SurfOMActualDecomposition.Pool, g.nResidues); for (int residue = 0; residue < g.nResidues; residue++) { double c_summed = g.SumDoubleArray(dlt_c_decomp[residue]); if (Math.Abs(c_summed) < g.epsilon) { c_summed = 0.0; } double n_summed = g.SumDoubleArray(dlt_n_decomp[residue]); if (Math.Abs(n_summed) < g.epsilon) { n_summed = 0.0; } // pack up the structure to return decompositions to SurfaceOrganicMatter SurfOMActualDecomposition.Pool[residue] = new SurfaceOrganicMatterDecompPoolType(); SurfOMActualDecomposition.Pool[residue].FOM = new FOMType(); SurfOMActualDecomposition.Pool[residue].Name = g.residueName[residue]; SurfOMActualDecomposition.Pool[residue].OrganicMatterType = g.residueType[residue]; SurfOMActualDecomposition.Pool[residue].FOM.amount = 0.0F; SurfOMActualDecomposition.Pool[residue].FOM.C = (float)c_summed; SurfOMActualDecomposition.Pool[residue].FOM.N = (float)n_summed; SurfOMActualDecomposition.Pool[residue].FOM.P = 0.0F; SurfOMActualDecomposition.Pool[residue].FOM.AshAlk = 0.0F; // Note: The values for 'amount', 'P', and 'AshAlk' will not be collected by SurfaceOrganicMatter, so send zero as default. } // dsg 131004 calculate the old dlt_org_p (from the old Decomposed event sent by residue2) for getting by soilp double act_c_decomp = 0.0; double tot_pot_c_decomp = g.SumDoubleArray(g.pot_c_decomp); double tot_pot_p_decomp = g.SumDoubleArray(g.pot_p_decomp); for (int layer = 0; layer < nLayers; layer++) { act_c_decomp = dlt_c_res_to_biom[layer] + dlt_c_res_to_hum[layer] + dlt_c_res_to_atm[layer]; soilp_dlt_org_p[layer] = tot_pot_p_decomp * MathUtility.Divide(act_c_decomp, tot_pot_c_decomp, 0.0); } }
private void OnDoSurfaceOrganicMatterDecomposition(object sender, EventArgs args) { actualSOMDecomp = SoilNitrogen.CalculateActualSOMDecomp(); if (actualSOMDecomp != null) { DecomposeSurfom(actualSOMDecomp); } Canopies = new List <ICanopy>(); foreach (SurfOrganicMatterType pool in SurfOM) { if (pool.CanopyLying.CoverTotal > 0) { Canopies.Add(pool.CanopyLying); } if (pool.CanopyStanding.CoverTotal > 0) { Canopies.Add(pool.CanopyStanding); } } }