/// <summary>Return senescent roots to fresh organic matter pool in the soil</summary> /// <param name="amountDM">DM amount to return</param> /// <param name="amountN">N amount to return</param> private void DoIncorpFomEvent(double amountDM, double amountN) { Soils.FOMLayerLayerType[] FOMdataLayer = new Soils.FOMLayerLayerType[nLayers]; // **** RCichota, Jun/2014 // root senesced are returned to soil (as FOM) considering return is proportional to root mass for (int layer = 0; layer < nLayers; layer++) { Soils.FOMType fomData = new Soils.FOMType(); fomData.amount = amountDM * swardRootFraction[layer]; fomData.N = amountN * swardRootFraction[layer]; fomData.C = amountDM * swardRootFraction[layer] * CinDM; fomData.P = 0.0; // P not considered here fomData.AshAlk = 0.0; // Ash not considered here Soils.FOMLayerLayerType layerData = new Soils.FOMLayerLayerType(); layerData.FOM = fomData; layerData.CNR = 0.0; // not used here layerData.LabileP = 0; // not used here FOMdataLayer[layer] = layerData; } if (IncorpFOM != null) { Soils.FOMLayerType FOMData = new Soils.FOMLayerType(); FOMData.Type = "Pasture"; FOMData.Layer = FOMdataLayer; IncorpFOM.Invoke(FOMData); } }
/// <summary>Return scenescent roots to fresh organic matter pool in the soil</summary> /// <param name="amountDM">DM amount to return</param> /// <param name="amountN">N amount to return</param> private void DoIncorpFomEvent(double amountDM, double amountN) { Soils.FOMLayerLayerType[] FOMdataLayer = new Soils.FOMLayerLayerType[nLayers]; // **** RCichota, Jun/2014 // root senesced are returned to soil (as FOM) considering return is proportional to root mass double dAmtLayer = 0.0; //amount of root litter in a layer double dNLayer = 0.0; for (int layer = 0; layer < nLayers; layer++) { dAmtLayer = amountDM * rootFraction[layer]; dNLayer = amountN * rootFraction[layer]; float amt = (float)dAmtLayer; Soils.FOMType fomData = new Soils.FOMType(); fomData.amount = amountDM * rootFraction[layer]; fomData.N = amountN * rootFraction[layer]; fomData.C = amountDM * rootFraction[layer] * CarbonFractionInDM; fomData.P = 0.0; // P not considered here fomData.AshAlk = 0.0; // Ash not considered here Soils.FOMLayerLayerType layerData = new Soils.FOMLayerLayerType(); layerData.FOM = fomData; layerData.CNR = 0.0; // not used here layerData.LabileP = 0; // not used here FOMdataLayer[layer] = layerData; } if (IncorpFOM != null) { Soils.FOMLayerType FOMData = new Soils.FOMLayerType(); FOMData.Type = speciesFamily; FOMData.Layer = FOMdataLayer; IncorpFOM.Invoke(FOMData); } }
/// <summary>Returns a given amount of DM (and N) to fresh organic matter pool in the soil</summary> /// <param name="amountDM">DM amount to return (kg/ha)</param> /// <param name="amountN">N amount to return (kg/ha)</param> private void DoIncorpFomEvent(double amountDM, double amountN) { FOMLayerLayerType[] FOMdataLayer = new FOMLayerLayerType[nLayers]; // **** RCichota, Jun/2014 // root senesced are returned to soil (as FOM) considering return is proportional to root mass for (int layer = 0; layer < nLayers; layer++) { FOMType fomData = new FOMType(); fomData.amount = amountDM * roots.Tissue[0].FractionWt[layer]; fomData.N = amountN * roots.Tissue[0].FractionWt[layer]; fomData.C = amountDM * CarbonFractionInDM * roots.Tissue[0].FractionWt[layer]; fomData.P = 0.0; // P not considered here fomData.AshAlk = 0.0; // Ash not considered here FOMLayerLayerType layerData = new FOMLayerLayerType(); layerData.FOM = fomData; layerData.CNR = 0.0; // not used here layerData.LabileP = 0; // not used here FOMdataLayer[layer] = layerData; } if (IncorpFOM != null) { FOMLayerType FOMData = new FOMLayerType(); FOMData.Type = mySpeciesFamily.ToString(); FOMData.Layer = FOMdataLayer; IncorpFOM.Invoke(FOMData); } }
//called above /// <summary> /// Crop_root_incorps the specified i_dlt_dm_root. /// </summary> /// <param name="i_dlt_dm_root">The i_dlt_dm_root.</param> /// <param name="i_dlt_n_root">The i_dlt_n_root.</param> /// <param name="i_dlayer">The i_dlayer.</param> /// <param name="i_root_length">The i_root_length.</param> /// <param name="i_root_depth">The i_root_depth.</param> /// <param name="c_crop_type">The c_crop_type.</param> /// <param name="i_max_layer">The i_max_layer.</param> /// <exception cref="ApsimXException">Too many layers for crop routines</exception> void crop_root_incorp(double i_dlt_dm_root, double i_dlt_n_root, double[] i_dlayer, double[] i_root_length, double i_root_depth, string c_crop_type, int i_max_layer) { //!+ Sub-Program Arguments // real dlt_dm_root ! (INPUT) new root residue dm (g/m^2) // real dlt_N_root ! (INPUT) new root residue N (g/m^2) // real g_dlayer(*) ! (INPUT) layer thicknesses (mm) // real g_root_length(*) ! (INPUT) layered root length (mm) // real g_root_depth ! (INPUT) root depth (mm) // character c_crop_type*(*) ! (INPUT) crop type // integer max_layer ! (INPUT) maximum no of soil layers // integer incorpFOMID ! (INPUT) ID of incorp fom event. //!+ Purpose //! Calculate and provide root matter incorporation information //! to the APSIM messaging system. //!+ Mission Statement //! Pass root material to the soil modules (based on root length distribution) //!+ Changes //! <insert here> //! 280800 jngh changed literal incorp_fom to ACTION_incorp_fom //! 011100 dph added event_interface as a parameter. int l_crop_max_layer = 100; //! maximum soil layers //sv- taken from FortranInfrastructure\ConstantsModule.f90 double[] l_dlt_dm_incorp = new double[l_crop_max_layer]; //! root residue (kg/ha) double[] l_dlt_N_incorp = new double[l_crop_max_layer]; //! root residue N (kg/ha) if (i_max_layer > l_crop_max_layer) { throw new ApsimXException(this, "Too many layers for crop routines"); } else { if (i_dlt_dm_root > 0.0) { //! send out root residue crop_root_dist(i_dlayer, i_root_length, i_root_depth, ref l_dlt_dm_incorp, i_dlt_dm_root * gm2kg / sm2ha); bound_check_real_array(l_dlt_dm_incorp, 0.0, i_dlt_dm_root * gm2kg / sm2ha, "dlt_dm_incorp", i_max_layer); crop_root_dist(i_dlayer, i_root_length, i_root_depth, ref l_dlt_N_incorp, i_dlt_n_root * gm2kg / sm2ha); bound_check_real_array(l_dlt_N_incorp, 0.0, i_dlt_n_root * gm2kg / sm2ha, "dlt_n_incorp", i_max_layer); //sv- FOMLayerType and FOMLayerLayerType are confusing but what I think they mean is, // FOMLayer means FOM "IN" the soil as opposed to "ON" the surface of the SOIL // I think they already used the term FOMType for the Surface Residue so they needed a name // for the class when they were refering to FOM "in" the soil. So they used the term FOMLayer. // This then meant when they needed a name for the class for an actual specific Layer they // then used the silly name of FOMLayerLayer. Meaning a Layer of the FOMLayer type. // This is silly naming but I think that this is what they have done. // They should have called it FOMInSoil or something, rather than FOMLayer. FOMLayerLayerType[] allLayers = new FOMLayerLayerType[dlayer.Length]; for (int layer = 0; layer < dlayer.Length; layer++) { FOMType fom_in_layer = new FOMType(); fom_in_layer.amount = (float)l_dlt_dm_incorp[layer]; fom_in_layer.N = (float)l_dlt_N_incorp[layer]; fom_in_layer.P = (float)0.0; fom_in_layer.C = (float)0.0; fom_in_layer.AshAlk = (float)0.0; FOMLayerLayerType thisLayer = new FOMLayerLayerType(); thisLayer.FOM = fom_in_layer; thisLayer.CNR = (float)0.0; thisLayer.LabileP = (float)0.0; allLayers[layer] = thisLayer; } FOMLayerType fomInSoil = new FOMLayerType(); fomInSoil.Type = c_crop_type; fomInSoil.Layer = allLayers; IncorpFOM.Invoke(fomInSoil); //trigger/invoke the IncorpFOM Event } else { //! no roots to incorporate } } }
/// <summary> /// Sugar_hill_ups the specified canefr. /// </summary> /// <param name="canefr">The canefr.</param> /// <param name="topsfr">The topsfr.</param> /// <exception cref="ApsimXException">Can only hill up during emergence phase</exception> void sugar_hill_up(double canefr, double topsfr) { //*+ Purpose //* Mound soil around base of crop and bury some plant material //*+ Mission Statement //* Mound soil around base of crop double[] fom = new double[max_layer]; double[] fon = new double[max_layer]; if ((int)g_current_stage == emerg) { //Send Event to IncorpOM //create Arrays fill_real_array(ref fom, 0.0, max_layer); fill_real_array(ref fon, 0.0, max_layer); fom[0] = topsfr * (g_dm_green[leaf] + g_dm_green[cabbage] + g_dm_senesced[leaf] + g_dm_senesced[cabbage] + g_dm_dead[leaf] + g_dm_dead[cabbage]) + canefr * (g_dm_green[sstem] + g_dm_green[sucrose] + g_dm_senesced[sstem] + g_dm_senesced[sucrose] + g_dm_dead[sstem] + g_dm_dead[sucrose]); fon[0] = topsfr * (g_n_green[leaf] + g_n_green[cabbage] + g_n_senesced[leaf] + g_n_senesced[cabbage] + g_n_dead[leaf] + g_n_dead[cabbage]) + canefr * (g_n_green[sstem] + g_n_green[sucrose] + g_n_senesced[sstem] + g_n_senesced[sucrose] + g_n_dead[sstem] + g_n_dead[sucrose]); //do dotnet event sending FOMLayerLayerType[] allLayers = new FOMLayerLayerType[dlayer.Length]; for (int layer = 0; layer < dlayer.Length; layer++) { FOMType fom_in_layer = new FOMType(); fom_in_layer.amount = (float)fom[layer]; fom_in_layer.N = (float)fon[layer]; fom_in_layer.P = (float)0.0; fom_in_layer.C = (float)0.0; fom_in_layer.AshAlk = (float)0.0; FOMLayerLayerType thisLayer = new FOMLayerLayerType(); thisLayer.FOM = fom_in_layer; thisLayer.CNR = (float)0.0; thisLayer.LabileP = (float)0.0; allLayers[layer] = thisLayer; } FOMLayerType fomInSoil = new FOMLayerType(); fomInSoil.Type = crop_type; fomInSoil.Layer = allLayers; IncorpFOM.Invoke(fomInSoil); //trigger/invoke the IncorpFOM Event //Change Global Variables //dm variables g_dm_green[leaf] = g_dm_green[leaf] * (1.0 - topsfr); g_dm_green[cabbage] = g_dm_green[cabbage] * (1.0 - topsfr); g_dm_senesced[leaf] = g_dm_senesced[leaf] * (1.0 - topsfr); g_dm_senesced[cabbage] = g_dm_senesced[cabbage] * (1.0 - topsfr); g_dm_dead[leaf] = g_dm_dead[leaf] * (1.0 - topsfr); g_dm_dead[cabbage] = g_dm_dead[cabbage] * (1.0 - topsfr); g_dm_green[sstem] = g_dm_green[sstem] * (1.0 - canefr); g_dm_green[sucrose] = g_dm_green[sucrose] * (1.0 - canefr); g_dm_senesced[sstem] = g_dm_senesced[sstem] * (1.0 - canefr); g_dm_senesced[sucrose] = g_dm_senesced[sucrose] * (1.0 - canefr); g_dm_dead[sstem] = g_dm_dead[sstem] * (1.0 - canefr); g_dm_dead[sucrose] = g_dm_dead[sucrose] * (1.0 - canefr); //nitrogen variables g_n_green[leaf] = g_n_green[leaf] * (1.0 - topsfr); g_n_green[cabbage] = g_n_green[cabbage] * (1.0 - topsfr); g_n_senesced[leaf] = g_n_senesced[leaf] * (1.0 - topsfr); g_n_senesced[cabbage] = g_n_senesced[cabbage] * (1.0 - topsfr); g_n_dead[leaf] = g_n_dead[leaf] * (1.0 - topsfr); g_n_dead[cabbage] = g_n_dead[cabbage] * (1.0 - topsfr); g_n_green[sstem] = g_n_green[sstem] * (1.0 - canefr); g_n_green[sucrose] = g_n_green[sucrose] * (1.0 - canefr); g_n_senesced[sstem] = g_n_senesced[sstem] * (1.0 - canefr); g_n_senesced[sucrose] = g_n_senesced[sucrose] * (1.0 - canefr); g_n_dead[sstem] = g_n_dead[sstem] * (1.0 - canefr); g_n_dead[sucrose] = g_n_dead[sucrose] * (1.0 - canefr); //! Now we need to update the leaf tracking info g_lai = g_lai * (1.0 - topsfr); g_slai = g_slai * (1.0 - topsfr); for (int leaf_no = 0; leaf_no < max_leaf; leaf_no++) { g_leaf_area_zb[leaf_no] = g_leaf_area_zb[leaf_no] * (1.0 - topsfr); g_leaf_dm_zb[leaf_no] = g_leaf_dm_zb[leaf_no] * (1.0 - topsfr); } } else { throw new ApsimXException(this, "Can only hill up during emergence phase"); } }
/// <summary>Does the root growth.</summary> /// <param name="Allocation">The allocation.</param> /// <exception cref="System.Exception">Error trying to partition root biomass</exception> private void DoRootGrowth(double Allocation) { int RootLayer = LayerIndex(RootDepth); RootDepth = RootDepth + RootFrontVelocity.Value * soilCrop.XF[RootLayer]; RootDepth = Math.Min(MaximumRootDepth, RootDepth); RootDepth = Math.Min(MathUtilities.Sum(Soil.Thickness), RootDepth); // Calculate Root Activity Values for water and nitrogen double[] RAw = new double[Soil.Thickness.Length]; double[] RAn = new double[Soil.Thickness.Length]; double TotalRAw = 0; double TotalRAn = 0; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { if (layer <= LayerIndex(RootDepth)) if (Roots[layer].Mass > 0) { RAw[layer] = SWUptake[layer] / Roots[layer].Mass * Soil.Thickness[layer] * RootProportion(layer, RootDepth); RAw[layer] = Math.Max(RAw[layer], 1e-20); // Make sure small numbers to avoid lack of info for partitioning RAn[layer] = NUptake[layer] / Roots[layer].Mass * Soil.Thickness[layer] * RootProportion(layer, RootDepth); RAn[layer] = Math.Max(RAw[layer], 1e-10); // Make sure small numbers to avoid lack of info for partitioning } else if (layer > 0) { RAw[layer] = RAw[layer - 1]; RAn[layer] = RAn[layer - 1]; } else { RAw[layer] = 0; RAn[layer] = 0; } TotalRAw += RAw[layer]; TotalRAn += RAn[layer]; } double allocated = 0; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { if (TotalRAw > 0) Roots[layer].Mass += Allocation * RAw[layer] / TotalRAw; else if (Allocation > 0) throw new Exception("Error trying to partition root biomass"); allocated += Allocation * RAw[layer] / TotalRAw; } // Do Root Senescence FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[Soil.Thickness.Length]; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { double Fr = RootSenescenceRate.Value; double DM = Roots[layer].Mass * Fr * 10.0; double N = Roots[layer].N * Fr * 10.0; Roots[layer].Mass *= (1.0 - Fr); Roots[layer].N *= (1.0 - Fr); Roots[layer].Length *= (1.0 - Fr); FOMType fom = new FOMType(); fom.amount = (float)DM; fom.N = (float)N; fom.C = (float)(0.44 * DM); fom.P = 0; fom.AshAlk = 0; FOMLayerLayerType Layer = new FOMLayerLayerType(); Layer.FOM = fom; Layer.CNR = 0; Layer.LabileP = 0; FOMLayers[layer] = Layer; } FOMLayerType FomLayer = new FOMLayerType(); FomLayer.Type = CanopyType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); }
/// <summary>Adds a given amount of detached root material (DM and N) to the soil's FOM pool.</summary> /// <param name="amountDM">The DM amount to send (kg/ha)</param> /// <param name="amountN">The N amount to send (kg/ha)</param> private void DoAddDetachedRootToSoilFOM(double amountDM, double amountN) { FOMLayerLayerType[] FOMdataLayer = new FOMLayerLayerType[nLayers]; for (int layer = 0; layer < nLayers; layer++) { FOMType fomData = new FOMType(); fomData.amount = amountDM * RootWtFraction[layer]; fomData.N = amountN * RootWtFraction[layer]; fomData.C = amountDM * RootWtFraction[layer] * CarbonInDM; fomData.P = 0.0; // P not considered here fomData.AshAlk = 0.0; // Ash not considered here FOMLayerLayerType layerData = new FOMLayerLayerType(); layerData.FOM = fomData; layerData.CNR = 0.0; // not used here layerData.LabileP = 0; // not used here FOMdataLayer[layer] = layerData; } if (IncorpFOM != null) { FOMLayerType FOMData = new FOMLayerType(); FOMData.Type = "Pasture"; FOMData.Layer = FOMdataLayer; IncorpFOM.Invoke(FOMData); } }
private void OnPlantEnding(object sender, EventArgs e) { if (sender == Plant) { FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[Soil.Thickness.Length]; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { double DM = (LayerLive[layer].Wt + LayerDead[layer].Wt) * 10.0; double N = (LayerLive[layer].N + LayerDead[layer].N) * 10.0; FOMType fom = new FOMType(); fom.amount = (float)DM; fom.N = (float)N; fom.C = (float)(0.40 * DM); fom.P = 0; fom.AshAlk = 0; FOMLayerLayerType Layer = new FOMLayerLayerType(); Layer.FOM = fom; Layer.CNR = 0; Layer.LabileP = 0; FOMLayers[layer] = Layer; } FOMLayerType FomLayer = new FOMLayerType(); FomLayer.Type = Plant.CropType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); Clear(); } }
private void OnDoActualPlantGrowth(object sender, EventArgs e) { if (Plant.IsAlive) { // Do Root Front Advance int RootLayer = LayerIndex(Depth); double TEM = (TemperatureEffect == null) ? 1 : TemperatureEffect.Value; Depth = Depth + RootFrontVelocity.Value * soilCrop.XF[RootLayer] * TEM; double MaxDepth = 0; for (int i = 0; i < Soil.Thickness.Length; i++) if (soilCrop.XF[i] > 0) MaxDepth += Soil.Thickness[i]; Depth = Math.Min(Depth, MaxDepth); // Do Root Senescence FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[Soil.Thickness.Length]; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { double DM = LayerLive[layer].Wt * _SenescenceRate * 10.0; double N = LayerLive[layer].StructuralN * _SenescenceRate * 10.0; LayerLive[layer].StructuralWt *= (1.0 - _SenescenceRate); LayerLive[layer].NonStructuralWt *= (1.0 - _SenescenceRate); LayerLive[layer].StructuralN *= (1.0 - _SenescenceRate); LayerLive[layer].NonStructuralN *= (1.0 - _SenescenceRate); FOMType fom = new FOMType(); fom.amount = (float)DM; fom.N = (float)N; fom.C = (float)(0.40 * DM); fom.P = 0; fom.AshAlk = 0; FOMLayerLayerType Layer = new FOMLayerLayerType(); Layer.FOM = fom; Layer.CNR = 0; Layer.LabileP = 0; FOMLayers[layer] = Layer; } FOMLayerType FomLayer = new FOMLayerType(); FomLayer.Type = Plant.CropType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); } }
/// <summary>return scenescent roots into fresh organic matter pool in soil</summary> /// <param name="rootSen">The root sen.</param> /// <param name="NinRootSen">The nin root sen.</param> private void DoIncorpFomEvent(double rootSen, double NinRootSen) { Soils.FOMLayerLayerType[] fomLL = new Soils.FOMLayerLayerType[Soil.Thickness.Length]; // **** RCichota, Jun, 2014 change how RootFraction (rlvp) is used in here **************************************** // root senesced are returned to soil (as FOM) considering return is proportional to root mass double dAmtLayer = 0.0; //amount of root litter in a layer double dNLayer = 0.0; for (int i = 0; i < Soil.Thickness.Length; i++) { dAmtLayer = rootSen * RootFraction[i]; dNLayer = NinRootSen * RootFraction[i]; Soils.FOMType fom = new Soils.FOMType(); fom.amount = dAmtLayer; fom.N = dNLayer;// 0.03F * amt; // N in dead root fom.C = 0.40 * dAmtLayer; //40% of OM is C. Actually, 'C' is not used, as shown in DataTypes.xml fom.P = 0; //to consider later fom.AshAlk = 0; //to consider later Soils.FOMLayerLayerType Layer = new Soils.FOMLayerLayerType(); Layer.FOM = fom; Layer.CNR = 0; //not used Layer.LabileP = 0; //not used fomLL[i] = Layer; } if (IncorpFOM != null) { Soils.FOMLayerType FomLayer = new Soils.FOMLayerType(); FomLayer.Type = "agpasture"; FomLayer.Layer = fomLL; IncorpFOM.Invoke(FomLayer); } }
/// <summary>Performs the removal of roots</summary> /// <param name="detachFraction">Fraction to send to residue (soil FOM)</param> /// <param name="removeFraction">Fraction to remove from the system</param> private void DoRootBiomassRemoval(double detachFraction, double removeFraction = 0.0) { //NOTE: at the moment Root has no Dead pool FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[Soil.Thickness.Length]; double RemainingFraction = 1.0 - (detachFraction + removeFraction); double detachingWt = 0.0; double detachingN = 0.0; for (int layer = 0; layer < Soil.Thickness.Length; layer++) { detachingWt = LayerLive[layer].Wt * detachFraction; detachingN = LayerLive[layer].N * detachFraction; RemovedWt += LayerLive[layer].Wt * removeFraction; RemovedN += LayerLive[layer].N * removeFraction; DetachedWt += detachingWt; DetachedN += detachingN; LayerLive[layer].StructuralWt *= RemainingFraction; LayerLive[layer].NonStructuralWt *= RemainingFraction; LayerLive[layer].MetabolicWt *= RemainingFraction; LayerLive[layer].StructuralN *= RemainingFraction; LayerLive[layer].NonStructuralN *= RemainingFraction; LayerLive[layer].MetabolicN *= RemainingFraction; FOMType fom = new FOMType(); fom.amount = (float) (detachingWt * 10); fom.N = (float) (detachingN * 10); fom.C = (float) (0.40 * detachingWt * 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.CropType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); }
/// <summary>Removes biomass from root layers when harvest, graze or cut events are called.</summary> public override void DoRemoveBiomass(OrganBiomassRemovalType removal) { //NOTE: roots don't have dead biomass double totalFractionToRemove = removal.FractionLiveToRemove + removal.FractionLiveToResidue; if (totalFractionToRemove > 1.0 || totalFractionToRemove < 0) throw new Exception("The sum of FractionToResidue and FractionToRemove is greater than 1 or less than 0."); if (totalFractionToRemove > 0) { //NOTE: at the moment Root has no Dead pool FOMLayerLayerType[] FOMLayers = new FOMLayerLayerType[PlantZone.soil.Thickness.Length]; double remainingFraction = 1.0 - (removal.FractionLiveToResidue + removal.FractionLiveToRemove); double detachingWt = 0.0; double detachingN = 0.0; for (int layer = 0; layer < PlantZone.soil.Thickness.Length; layer++) { detachingWt = PlantZone.LayerLive[layer].Wt * removal.FractionLiveToResidue; detachingN = PlantZone.LayerLive[layer].N * removal.FractionLiveToResidue; RemovedWt += PlantZone.LayerLive[layer].Wt * removal.FractionLiveToRemove; RemovedN += PlantZone.LayerLive[layer].N * removal.FractionLiveToRemove; DetachedWt += detachingWt; DetachedN += detachingN; PlantZone.LayerLive[layer].StructuralWt *= remainingFraction; PlantZone.LayerLive[layer].NonStructuralWt *= remainingFraction; PlantZone.LayerLive[layer].MetabolicWt *= remainingFraction; PlantZone.LayerLive[layer].StructuralN *= remainingFraction; PlantZone.LayerLive[layer].NonStructuralN *= remainingFraction; PlantZone.LayerLive[layer].MetabolicN *= remainingFraction; FOMType fom = new FOMType(); fom.amount = (float)(detachingWt * 10); fom.N = (float)(detachingN * 10); fom.C = (float)(0.40 * detachingWt * 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.CropType; FomLayer.Layer = FOMLayers; IncorpFOM.Invoke(FomLayer); } }