private void OnDoSoilOrganicMatter(object sender, EventArgs e) { // Get potential residue decomposition from surfaceom. SurfaceOrganicMatterDecompType SurfaceOrganicMatterDecomp = SurfaceOrganicMatter.PotentialDecomposition(); foreach (soilCNPatch aPatch in Patch) { aPatch.OnPotentialResidueDecompositionCalculated(SurfaceOrganicMatterDecomp); } num_residues = SurfaceOrganicMatterDecomp.Pool.Length; sw_dep = Soil.Water; // calculate C and N processes // - Assesses potential decomposition of surface residues; // . adjust decomposition if needed; // . accounts for mineralisation/immobilisation of N; // - Compute the transformations on soil organic matter (including N mineralisation/immobilition); // - Calculates hydrolysis of urea, nitrification, and denitrification; for (int k = 0; k < Patch.Count; k++) { Patch[k].Process(); } // send actual decomposition back to surface OM if (!is_pond_active) { SendActualResidueDecompositionCalculated(); } }
private void OnDoSoilOrganicMatter(object sender, EventArgs e) { // Get potential residue decomposition from surfaceom. SurfaceOrganicMatterDecompType SurfaceOrganicMatterDecomp = SurfaceOrganicMatter.PotentialDecomposition(); foreach (soilCNPatch aPatch in Patch) { aPatch.OnPotentialResidueDecompositionCalculated(SurfaceOrganicMatterDecomp); } num_residues = SurfaceOrganicMatterDecomp.Pool.Length; sw_dep = Soil.Water; // update soil temperature if (use_external_st) { Tsoil = ave_soil_temp; } else { // initialise soil temperature if (simpleST == null) { simpleST = new simpleSoilTemp(MetFile.Latitude, MetFile.Tav, MetFile.Amp, MetFile.MinT, MetFile.MaxT); } Tsoil = simpleST.SoilTemperature(Clock.Today, MetFile.MinT, MetFile.MaxT, MetFile.Radn, salb, dlayer, bd, ll15_dep, sw_dep); } // calculate C and N processes // - Assesses potential decomposition of surface residues; // . adjust decomposition if needed; // . accounts for mineralisation/immobilisation of N; // - Compute the transformations on soil organic matter (including N mineralisation/immobilition); // - Calculates hydrolysis of urea, nitrification, and denitrification; for (int k = 0; k < Patch.Count; k++) { Patch[k].Process(); } // send actual decomposition back to surface OM if (!is_pond_active) { SendActualResidueDecompositionCalculated(); } }
/// <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() { soilp_dlt_org_p = new double[g.nLayers]; double soilp_cpr = MathUtilities.Divide(g.SumDoubleArray(g.pot_p_decomp), g.SumDoubleArray(g.pot_c_decomp), 0.0); 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 = c_summed; SurfOMActualDecomposition.Pool[residue].FOM.N = 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 < g.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 * MathUtilities.Divide(act_c_decomp, tot_pot_c_decomp, 0.0); } }
/// <summary>Send back to SurfaceOM the information about residue decomposition</summary> private void SendActualResidueDecompositionCalculated() { // Note: // Potential decomposition was given to this module by a residue/surfaceOM module. // Now we explicitly tell the module the actual decomposition // rate for each of its residues. If there wasn't enough mineral N to decompose, the rate will be reduced from the potential value. // will have to pack the SOMdecomp data from each patch and then invoke the event //int num_residues = Patch[0].SOMDecomp.Pool.Length; int nLayers = dlayer.Length; SurfaceOrganicMatterDecompType ActualSOMDecomp = new SurfaceOrganicMatterDecompType(); Array.Resize(ref ActualSOMDecomp.Pool, num_residues); for (int residue = 0; residue < num_residues; residue++) { double c_summed = 0.0F; double n_summed = 0.0F; for (int k = 0; k < Patch.Count; k++) { c_summed += Patch[k].SOMDecomp.Pool[residue].FOM.C * Patch[k].RelativeArea; n_summed += Patch[k].SOMDecomp.Pool[residue].FOM.N * Patch[k].RelativeArea; } ActualSOMDecomp.Pool[residue] = new SurfaceOrganicMatterDecompPoolType(); ActualSOMDecomp.Pool[residue].FOM = new FOMType(); ActualSOMDecomp.Pool[residue].Name = Patch[0].SOMDecomp.Pool[residue].Name; ActualSOMDecomp.Pool[residue].OrganicMatterType = Patch[0].SOMDecomp.Pool[residue].OrganicMatterType; ActualSOMDecomp.Pool[residue].FOM.amount = 0.0F; ActualSOMDecomp.Pool[residue].FOM.C = c_summed; ActualSOMDecomp.Pool[residue].FOM.N = n_summed; ActualSOMDecomp.Pool[residue].FOM.P = 0.0F; ActualSOMDecomp.Pool[residue].FOM.AshAlk = 0.0F; } SurfaceOrganicMatter.ActualSOMDecomp = ActualSOMDecomp; }
public void OnPotentialResidueDecompositionCalculated(SurfaceOrganicMatterDecompType SurfaceOrganicMatterDecomp) { //+ Purpose // Get information of potential residue decomposition num_residues = SurfaceOrganicMatterDecomp.Pool.Length; Array.Resize(ref residue_name, num_residues); Array.Resize(ref residue_type, num_residues); Array.Resize(ref pot_c_decomp, num_residues); Array.Resize(ref pot_n_decomp, num_residues); Array.Resize(ref pot_p_decomp, num_residues); for (int layer = 0; layer < dlt_c_res_2_biom.Length; layer++) { Array.Resize(ref dlt_c_res_2_biom[layer], num_residues); Array.Resize(ref dlt_c_res_2_hum[layer], num_residues); Array.Resize(ref dlt_c_res_2_atm[layer], num_residues); Array.Resize(ref dlt_c_decomp[layer], num_residues); Array.Resize(ref dlt_n_decomp[layer], num_residues); } for (int residue = 0; residue < num_residues; residue++) { residue_name[residue] = SurfaceOrganicMatterDecomp.Pool[residue].Name; residue_type[residue] = SurfaceOrganicMatterDecomp.Pool[residue].OrganicMatterType; pot_c_decomp[residue] = SurfaceOrganicMatterDecomp.Pool[residue].FOM.C; pot_n_decomp[residue] = SurfaceOrganicMatterDecomp.Pool[residue].FOM.N; pot_p_decomp[residue] = SurfaceOrganicMatterDecomp.Pool[residue].FOM.P; } }
/// <summary> /// Send back the information about actual residue decomposition /// </summary> private void PackActualResidueDecomposition() { // Notes: // Potential decomposition was given to this module by a residue/surfaceOM module. Now we explicitly tell the // module the actual decomposition rate for each of its residues. If there isn't enough mineral N to decompose, // the rate will be reduced from the potential value. int nLayers = g.dlayer.Length; soilp_dlt_res_c_atm = new double[nLayers]; soilp_dlt_res_c_hum = new double[nLayers]; soilp_dlt_res_c_biom = new double[nLayers]; soilp_dlt_org_p = new double[nLayers]; double soilp_cpr = MathUtilities.Divide(SumDoubleArray(pot_p_decomp), SumDoubleArray(pot_c_decomp), 0.0); // C:P ratio for potential decomposition //SurfaceOrganicMatterDecompType SOMDecomp = new SurfaceOrganicMatterDecompType(); SOMDecomp = new SurfaceOrganicMatterDecompType(); Array.Resize(ref SOMDecomp.Pool, num_residues); for (int residue = 0; residue < num_residues; residue++) { double c_summed = 0.0; double n_summed = 0.0; double[] dlt_res_c_decomp = new double[nLayers]; double[] dlt_res_n_decomp = new double[nLayers]; for (int layer = 0; layer < nLayers; layer++) { dlt_res_c_decomp[layer] = dlt_c_res_2_hum[layer][residue] + dlt_c_res_2_biom[layer][residue] + dlt_c_res_2_atm[layer][residue]; c_summed += dlt_res_c_decomp[layer]; //dlt_res_n_decomp[layer] = this.dlt_n_decomp[layer][residue]; dlt_res_n_decomp[layer] = dlt_n_decomp[layer][residue]; n_summed += dlt_res_n_decomp[layer]; } // dsg 131103 Now, pack up the structure to return decompositions to SurfaceOrganicMatter SOMDecomp.Pool[residue] = new SurfaceOrganicMatterDecompPoolType(); SOMDecomp.Pool[residue].FOM = new FOMType(); SOMDecomp.Pool[residue].Name = residue_name[residue]; SOMDecomp.Pool[residue].OrganicMatterType = residue_type[residue]; // dsg 131103 The 'amount' value will not be used by SurfaceOrganicMatter, so send zero as default SOMDecomp.Pool[residue].FOM.amount = 0.0F; if (Math.Abs(c_summed) < g.EPSILON) c_summed = 0.0; if (Math.Abs(n_summed) < g.EPSILON) n_summed = 0.0; SOMDecomp.Pool[residue].FOM.C = (float)c_summed; SOMDecomp.Pool[residue].FOM.N = (float)n_summed; // dsg 131103 The 'P' value will not be collected by SurfaceOrganicMatter, so send zero as default. SOMDecomp.Pool[residue].FOM.P = 0.0F; SOMDecomp.Pool[residue].FOM.AshAlk = 0.0F; // dsg 131004 soilp needs some stuff - very ugly process - needs to be streamlined // create some variables which soilp can "get" - layer based arrays independent of residues for (int layer = 0; layer < nLayers; layer++) { soilp_dlt_res_c_atm[layer] += dlt_c_res_2_atm[layer][residue]; soilp_dlt_res_c_hum[layer] += dlt_c_res_2_hum[layer][residue]; soilp_dlt_res_c_biom[layer] += dlt_c_res_2_biom[layer][residue]; soilp_dlt_org_p[layer] += dlt_res_c_decomp[layer] * soilp_cpr; } } }