Example #1
0
            public void Process()
            {
                // + Purpose
                //     This routine performs the soil C and N balance, daily.
                //      - Assesses potential decomposition of surface residues (adjust decompostion if needed, accounts for mineralisation/immobilisation of N)
                //      - Calculates hydrolysis of urea, denitrification, transformations on soil organic matter (including N mineralisation/immobilition) and nitrification.

                int nLayers = g.dlayer.Length;                    // number of layers in the soil
                double[,] dlt_fom_n = new double[3, nLayers];   // fom N mineralised in each fraction (kg/ha)

                if (g.is_pond_active)
                {
                    // dsg 190508,  If there is a pond, the POND module will decompose residues - not SoilNitrogen
                    // dsg 110708   Get the biom & hum C decomposed in the pond and add to soil - on advice of MEP

                    // increment the hum and biom C pools in top soil layer
                    hum_c[0] += g.pond_hum_C;         // humic material from breakdown of residues in pond
                    biom_c[0] += g.pond_biom_C;       // biom material from breakdown of residues in pond

                    // reset the N amounts of N in hum and biom pools
                    hum_n[0] = MathUtilities.Divide(hum_c[0], g.hum_cn, 0.0);
                    biom_n[0] = MathUtilities.Divide(biom_c[0], g.biom_cn, 0.0);
                }
                else
                {
                    // Decompose residues
                    //  assess the potential decomposition of surface residues and calculate actual mineralisation/immobilisation
                    DecomposeResidues();

                    // update C content in hum and biom pools
                    for (int layer = 0; layer < nLayers; layer++)
                    {
                        hum_c[layer] += SumDoubleArray(dlt_c_res_2_hum[layer]);
                        biom_c[layer] += SumDoubleArray(dlt_c_res_2_biom[layer]);
                    }

                    // update N content in hum and biom pools as well as the mineral N
                    for (int layer = 0; layer < nLayers; layer++)
                    {
                        hum_n[layer] = MathUtilities.Divide(hum_c[layer], g.hum_cn, 0.0);
                        biom_n[layer] = MathUtilities.Divide(biom_c[layer], g.biom_cn, 0.0);

                        // update soil mineral N
                        _nh4[layer] += dlt_nh4_decomp[layer];
                        _no3[layer] += dlt_no3_decomp[layer];
                    }
                }

                // now take each layer in turn and compute N processes
                for (int layer = 0; layer < nLayers; layer++)
                {
                    // urea hydrolysis
                    dlt_urea_hydrolised[layer] = UreaHydrolysis(layer);
                    _nh4[layer] += dlt_urea_hydrolised[layer];
                    _urea[layer] -= dlt_urea_hydrolised[layer];

                    // nitrate-N denitrification
                    switch (g.n2o_approach)
                    {
                        case 1:
                            dlt_no3_dnit[layer] = Denitrification_NEMIS(layer);
                            //n2o_atm[layer] is calculated in Nitrification_NEMIS
                            break;
                        case 2:
                            dlt_no3_dnit[layer] = Denitrification_WNMM(layer);
                            //n2o_atm[layer] is calculated in Nitrification_WNMM
                            break;
                        case 3:
                            dlt_no3_dnit[layer] = Denitrification_CENT(layer);
                            //n2o_atm[layer] is calculated in Nitrification_CENT
                            break;
                        case 0:
                        default:
                            dlt_no3_dnit[layer] = Denitrification(layer);
                            break;
                    }
                    _no3[layer] -= dlt_no3_dnit[layer];

                    // N2O loss to atmosphere - due to denitrification
                    n2o_atm[layer] = 0.0;
                    double N2N2O = Denitrification_Nratio(layer);
                    n2o_atm[layer] = dlt_no3_dnit[layer] / (N2N2O + 1.0);

                    // Calculate transformations of soil organic matter (C and N)

                    // humic pool mineralisation
                    MineraliseHumus(layer);

                    // microbial biomass pool mineralisation
                    MineraliseBiomass(layer);

                    // mineralisation of fresh organic matter pools
                    // need to be revisited - create FOM pools as array
                    //for (int fract = 0; fract < 3; fract++)
                    //{
                    //    MinFom(layer, fract);
                    //    dlt_c_fom_2_biom[fract][layer] = dlt_fc_biom[fract];
                    //    dlt_c_fom_2_hum[fract][layer] = dlt_fc_hum[fract];
                    //    dlt_c_fom_2_atm[fract][layer] = dlt_fc_atm[fract];
                    //    dlt_fom_n[fract, layer] = dlt_f_n[fract];
                    //}

                    double[] dlt_f_n;
                    double[] dlt_fc_biom;
                    double[] dlt_fc_hum;
                    double[] dlt_fc_atm;
                    FOMdecompData MineralisedFOM = new FOMdecompData();
                    if (g.useNewProcesses)
                    {
                        MineralisedFOM = MineraliseFOM1(layer);
                        for (int fract = 0; fract < 3; fract++)
                        {
                            dlt_c_fom_2_hum[fract][layer] = MineralisedFOM.dlt_c_hum[fract];
                            dlt_c_fom_2_biom[fract][layer] = MineralisedFOM.dlt_c_biom[fract];
                            dlt_c_fom_2_atm[fract][layer] = MineralisedFOM.dlt_c_atm[fract];
                            dlt_fom_n[fract, layer] = MineralisedFOM.dlt_fom_n[fract];
                        }
                        dlt_n_fom_2_min[layer] = MineralisedFOM.dlt_n_min;
                    }
                    else
                    {
                        MineraliseFOM(layer, out dlt_fc_biom, out dlt_fc_hum, out dlt_fc_atm, out dlt_f_n, out dlt_n_fom_2_min[layer]);

                        for (int fract = 0; fract < 3; fract++)
                        {
                            dlt_c_fom_2_biom[fract][layer] = dlt_fc_biom[fract];
                            dlt_c_fom_2_hum[fract][layer] = dlt_fc_hum[fract];
                            dlt_c_fom_2_atm[fract][layer] = dlt_fc_atm[fract];
                            dlt_fom_n[fract, layer] = dlt_f_n[fract];
                        }
                    }
                    // update pools C an N contents

                    hum_c[layer] += dlt_c_biom_2_hum[layer] - dlt_c_hum_2_biom[layer] - dlt_c_hum_2_atm[layer] +
                                   dlt_c_fom_2_hum[0][layer] + dlt_c_fom_2_hum[1][layer] + dlt_c_fom_2_hum[2][layer];

                    hum_n[layer] = MathUtilities.Divide(hum_c[layer], g.hum_cn, 0.0);

                    biom_c[layer] += dlt_c_hum_2_biom[layer] - dlt_c_biom_2_hum[layer] - dlt_c_biom_2_atm[layer] +
                                   dlt_c_fom_2_biom[0][layer] + dlt_c_fom_2_biom[1][layer] + dlt_c_fom_2_biom[2][layer];

                    biom_n[layer] = MathUtilities.Divide(biom_c[layer], g.biom_cn, 0.0);

                    fom_c_pool1[layer] -= (dlt_c_fom_2_hum[0][layer] + dlt_c_fom_2_biom[0][layer] + dlt_c_fom_2_atm[0][layer]);
                    fom_c_pool2[layer] -= (dlt_c_fom_2_hum[1][layer] + dlt_c_fom_2_biom[1][layer] + dlt_c_fom_2_atm[1][layer]);
                    fom_c_pool3[layer] -= (dlt_c_fom_2_hum[2][layer] + dlt_c_fom_2_biom[2][layer] + dlt_c_fom_2_atm[2][layer]);

                    fom_n_pool1[layer] -= dlt_fom_n[0, layer];
                    fom_n_pool2[layer] -= dlt_fom_n[1, layer];
                    fom_n_pool3[layer] -= dlt_fom_n[2, layer];

                    // dsg  these 3 dlts are calculated for the benefit of soilp which needs to 'get' them
                    dlt_fom_c_pool1[layer] = dlt_c_fom_2_hum[0][layer] + dlt_c_fom_2_biom[0][layer] + dlt_c_fom_2_atm[0][layer];
                    dlt_fom_c_pool2[layer] = dlt_c_fom_2_hum[1][layer] + dlt_c_fom_2_biom[1][layer] + dlt_c_fom_2_atm[1][layer];
                    dlt_fom_c_pool3[layer] = dlt_c_fom_2_hum[2][layer] + dlt_c_fom_2_biom[2][layer] + dlt_c_fom_2_atm[2][layer];

                    // add up fom in each layer in each of the pools
                    //double fom_c = fom_c_pool1[layer] + fom_c_pool2[layer] + fom_c_pool3[layer];
                    //fom_n[layer] = fom_n_pool1[layer] + fom_n_pool2[layer] + fom_n_pool3[layer];

                    // update soil mineral N after mineralisation/immobilisation

                    // starts with nh4
                    _nh4[layer] += dlt_n_hum_2_min[layer] + dlt_n_biom_2_min[layer] + dlt_n_fom_2_min[layer];

                    // check whether there is enough NH4 to be immobilised
                    nh4_deficit_immob = new double[g.dlayer.Length];
                    if (_nh4[layer] < g.nh4_min[layer])
                    {
                        nh4_deficit_immob[layer] = g.nh4_min[layer] - _nh4[layer];
                        _nh4[layer] = g.nh4_min[layer];
                    }

                    // now change no3
                    _no3[layer] -= nh4_deficit_immob[layer];
                    if (_no3[layer] < g.no3_min[layer] - g.EPSILON)
                    {
                        // note: tests for adequate mineral N for immobilisation have been made so this no3 should not go below no3_min
                        throw new Exception("N immobilisation resulted in mineral N in layer(" + (layer + 1).ToString() + ") to go below minimum");
                    }

                    // NITRIFICATION
                    switch (g.n2o_approach)
                    {
                        case 1:
                            dlt_nitrification[layer] = Nitrification(layer);                //using default APSIM process for NEMIS
                            dlt_nh4_dnit[layer] = N2OLostInNitrification_ApsimSoilNitrogen(layer);
                            break;
                        case 2:
                            dlt_nitrification[layer] = Nitrification_WNMM(layer);
                            // dlt_nh4_dnit[layer] & n2o_atm[layer] are calculated in Nitrification_WNMM
                            break;
                        case 3:
                            dlt_nitrification[layer] = Nitrification_CENT(layer);
                            // dlt_nh4_dnit[layer] & n2o_atm[layer] are calculated in Nitrification_CENT
                            break;
                        case 0:
                        default:
                            // nitrification of ammonium-N (total)
                            dlt_nitrification[layer] = Nitrification(layer);
                            // denitrification loss during nitrification  (- n2o_atm )
                            dlt_nh4_dnit[layer] = N2OLostInNitrification_ApsimSoilNitrogen(layer);
                            // N2O loss to atmosphere from nitrification
                            n2o_atm[layer] += dlt_nh4_dnit[layer];
                            break;
                    }

                    // effective or net nitrification
                    effective_nitrification[layer] = dlt_nitrification[layer] - dlt_nh4_dnit[layer];

                    // update soil mineral N
                    _no3[layer] += effective_nitrification[layer];
                    _nh4[layer] -= dlt_nitrification[layer];

                    // check some of the values
                    if (Math.Abs(_urea[layer]) < g.EPSILON)
                        _urea[layer] = 0.0;
                    if (Math.Abs(_nh4[layer]) < g.EPSILON)
                        _nh4[layer] = 0.0;
                    if (Math.Abs(_no3[layer]) < g.EPSILON)
                        _no3[layer] = 0.0;
                    if (_urea[layer] < g.urea_min[layer] || _urea[layer] > 9000.0)
                        throw new Exception("Value for urea(layer) is out of range");
                    if (_nh4[layer] < g.nh4_min[layer] || _nh4[layer] > 9000.0)
                        throw new Exception("Value for NH4(layer) is out of range");
                    if (_no3[layer] < g.no3_min[layer] || _no3[layer] > 9000.0)
                        throw new Exception("Value for NO3(layer) is out of range");

                    // net N tansformations
                    nh4_transform_net[layer] = dlt_nh4_decomp[layer] + dlt_n_fom_2_min[layer] + dlt_n_biom_2_min[layer] + dlt_n_hum_2_min[layer] - dlt_nitrification[layer] + dlt_urea_hydrolised[layer] + nh4_deficit_immob[layer];
                    no3_transform_net[layer] = dlt_no3_decomp[layer] - dlt_no3_dnit[layer] + effective_nitrification[layer] - nh4_deficit_immob[layer];

                    // net deltas
                    dlt_nh4_net[layer] = _nh4[layer] - nh4_yesterday[layer];
                    dlt_no3_net[layer] = _no3[layer] - no3_yesterday[layer];

                    // store these values so they may be used tomorrow
                    nh4_yesterday[layer] = _nh4[layer];
                    no3_yesterday[layer] = _no3[layer];
                }
            }
Example #2
0
            private FOMdecompData MineraliseFOM1(int layer)
            {
                // + Purpose
                //     Calculate the daily transformation of the soil fresh organic matter pools, mineralisation (+ve) or immobilisation (-ve)

                double[] dlt_c_hum = new double[3];     // dlt_c from fom to humus
                double[] dlt_c_biom = new double[3];    // dlt_c from fom to biomass
                double[] dlt_c_atm = new double[3];     // dlt_c from fom to atmosphere
                double[] dlt_fom_n = new double[3];     // dlt_n from fom pools to OM
                double dlt_n_min = 0.0;                 // dlt_n from fom to mineral

                // dsg 200508  use different values for some constants when anaerobic conditions dominate
                // index = 1 for aerobic conditions, 2 for anaerobic conditions
                int index = (!g.is_pond_active) ? 1 : 2;

                // get total available mineral N (kg/ha)
                double nitTot = Math.Max(0.0, (_no3[layer] - g.no3_min[layer]) + (_nh4[layer] - g.nh4_min[layer]));

                // fresh organic carbon (kg/ha)
                double fomC = fom_c_pool1[layer] + fom_c_pool2[layer] + fom_c_pool3[layer];

                // fresh organic nitrogen (kg/ha)
                double fomN = fom_n_pool1[layer] + fom_n_pool2[layer] + fom_n_pool3[layer];

                // ratio of C in fresh OM to N available for decay
                double cnr = MathUtilities.Divide(fomC, fomN + nitTot, 0.0);

                // calculate the C:N ratio factor - Bound to [0, 1]
                double cnrf = Math.Max(0.0, Math.Min(1.0, Math.Exp(-g.cnrf_coeff * (cnr - g.cnrf_optcn) / g.cnrf_optcn)));
                if (g.useNewProcesses)
                    cnrf = CNratioFactor(layer, index, g.CNFactorMinerFOM_OptCN, g.CNFactorMinerFOM_RateCN);

                // get the soil temperature factor
                double tf = (g.SoilCNParameterSet == "rothc") ? RothcTF(layer, index) : TF(layer, index);
                if (g.useNewSTFFunction)
                    if (g.useSingleMinerFactors)
                    {
                        tf = SoilTempFactor(layer, index, g.TempFactorData_MinerSOM);
                    }
                    else
                    {
                        if (g.useFactorsByFOMpool)
                        {
                        }
                        else
                        {
                            tf = SoilTempFactor(layer, index, g.TempFactorData_MinerFOM);
                        }
                    }

                // get the soil water factor
                double wf = WF(layer, index);
                if (g.useNewSWFFunction)
                    if (g.useSingleMinerFactors)
                    {
                        wf = SoilMoistFactor(layer, index, g.MoistFactorData_MinerSOM);
                    }
                    else
                    {
                        if (g.useFactorsByFOMpool)
                        {
                        }
                        else
                        {
                            wf = SoilMoistFactor(layer, index, g.MoistFactorData_MinerFOM);
                        }
                    }

                // calculate gross amount of C & N released due to mineralisation of the fresh organic matter.
                if (fomC >= g.fom_min)
                {
                    double dlt_n_min_fom = 0.0; // amount of fresh organic N mineralised across fpools (kg/ha)
                    double dlt_c_min_fom = 0.0; // total C mineralised (kg/ha) summed across fpools
                    double[] dlt_n_min_tot = new double[3]; // amount of fresh organic N mineralised in each pool (kg/ha)
                    double[] dlt_c_min_tot = new double[3]; // amount of C mineralised (kg/ha) from each pool

                    // C:N ratio of fom
                    double fom_cn = MathUtilities.Divide(fomC, fomN, 0.0);

                    // get the decomposition of carbohydrate-like, cellulose-like and lignin-like fractions (fpools) in turn.
                    for (int fractn = 0; fractn < 3; fractn++)
                    {
                        // get the max decomposition rate for each fpool
                        double decomp_rate = FractRDFom(fractn)[index - 1] * cnrf * tf * wf;

                        // calculate the gross amount of fresh organic carbon mineralised (kg/ha)
                        double gross_c_decomp = decomp_rate * FractFomC(fractn)[layer];

                        // calculate the gross amount of N released from fresh organic matter (kg/ha)
                        double gross_n_decomp = decomp_rate * FractFomN(fractn)[layer];

                        dlt_n_min_fom += gross_n_decomp;
                        dlt_c_min_tot[fractn] = gross_c_decomp;
                        dlt_n_min_tot[fractn] = gross_n_decomp;
                        dlt_c_min_fom += gross_c_decomp;
                    }

                    // calculate potential transfers of C mineralised to biomass
                    double dlt_c_biom_tot = dlt_c_min_fom * g.ef_fom * g.fr_fom_biom;

                    // calculate potential transfers of C mineralised to humus
                    double dlt_c_hum_tot = dlt_c_min_fom * g.ef_fom * (1.0 - g.fr_fom_biom);

                    // test whether there is adequate N available to meet immobilisation demand
                    double n_demand = MathUtilities.Divide(dlt_c_biom_tot, g.biom_cn, 0.0) + MathUtilities.Divide(dlt_c_hum_tot, g.hum_cn, 0.0);
                    double n_avail = nitTot + dlt_n_min_fom;

                    // factor to reduce mineralisation rates if insufficient N to meet immobilisation demand
                    double Navail_factor = 1.0;
                    if (n_demand > n_avail)
                        Navail_factor = Math.Max(0.0, Math.Min(1.0, MathUtilities.Divide(nitTot, n_demand - dlt_n_min_fom, 0.0)));

                    // now adjust carbon transformations etc. and similarly for npools
                    for (int fractn = 0; fractn < 3; fractn++)
                    {
                        dlt_c_hum[fractn] = dlt_c_min_tot[fractn] * g.ef_fom * (1.0 - g.fr_fom_biom) * Navail_factor;
                        dlt_c_biom[fractn] = dlt_c_min_tot[fractn] * g.ef_fom * g.fr_fom_biom * Navail_factor;
                        dlt_c_atm[fractn] = dlt_c_min_tot[fractn] * (1.0 - g.ef_fom) * Navail_factor;
                        dlt_fom_n[fractn] = dlt_n_min_tot[fractn] * Navail_factor;

                        dlt_c_hum[fractn] = MathUtilities.RoundToZero(dlt_c_hum[fractn]);
                        dlt_c_biom[fractn] = MathUtilities.RoundToZero(dlt_c_biom[fractn]);
                        dlt_c_atm[fractn] = MathUtilities.RoundToZero(dlt_c_atm[fractn]);
                        dlt_fom_n[fractn] = MathUtilities.RoundToZero(dlt_fom_n[fractn]);
                    }

                    dlt_n_min = (dlt_n_min_fom - n_demand) * Navail_factor;
                }

                FOMdecompData Result = new FOMdecompData();
                Result.dlt_c_hum = dlt_c_hum;
                Result.dlt_c_biom = dlt_c_biom;
                Result.dlt_c_atm = dlt_c_atm;
                Result.dlt_fom_n = dlt_fom_n;
                Result.dlt_n_min = dlt_n_min;

                return Result;
            }