예제 #1
0
        private void OnNitrogenChanged(NitrogenChangedType NitrogenChanges)
        {
            // Note:
            //     Send deltas to each patch, if delta comes from soil or plant then the values are modified (partioned)
            //      based on N content. If sender is any other module then values are passed to patches as they come

            string module = NitrogenChanges.SenderType.ToLower();

            if ((Patch.Count > 1) && (module == "WaterModule".ToLower()) || (module == "Plant".ToLower()))
            {
                // values supplied by a module from which a different treatment for each patch is required,
                //  they will be partitioned according to the N content in each patch, following:
                //  - If module is Plant (uptake): partition is based on the relative concentration, at each layer, of all patches
                //  - If module is WaterModule (leaching):
                //        . if is removal (negative): partition is equal to a plant uptake
                //        . if is incoming leaching: partition is based on relative concentration on the layer and above

                // 1- consider urea:
                if (hasValues(NitrogenChanges.DeltaUrea, EPSILON))
                {
                    // 1.1-send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaUrea, "urea", NPartitionApproach.ToLower());
                    // 1.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                    {
                        Patch[k].dlt_urea = newDelta[k];
                    }
                }

                // 2- consider nh4:
                if (hasValues(NitrogenChanges.DeltaNH4, EPSILON))
                {
                    // 2.1- send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaNH4, "NH4", NPartitionApproach.ToLower());
                    // 2.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                    {
                        Patch[k].dlt_nh4 = newDelta[k];
                    }
                }

                // 3- consider no3:
                if (hasValues(NitrogenChanges.DeltaNO3, EPSILON))
                {
                    // 3.1- send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaNO3, "NO3", NPartitionApproach.ToLower());
                    // 3.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                    {
                        Patch[k].dlt_no3 = newDelta[k];
                    }
                }
            }
            else
            {
                // values will passed to patches as they come
                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].dlt_urea = NitrogenChanges.DeltaUrea;
                    Patch[k].dlt_nh4  = NitrogenChanges.DeltaNH4;
                    Patch[k].dlt_no3  = NitrogenChanges.DeltaNO3;
                }
            }
        }
예제 #2
0
 /// <summary>Gets the changes in mineral N made by other modules</summary>
 /// <param name="NitrogenChanges">The nitrogen changes.</param>
 public void SetNitrogenChanged(NitrogenChangedType NitrogenChanges)
 {
     OnNitrogenChanged(NitrogenChanges);
 }
예제 #3
0
        private void OnNitrogenChanged(NitrogenChangedType NitrogenChanges)
        {
            // Note:
            //     Send deltas to each patch, if delta comes from soil or plant then the values are modified (partioned)
            //      based on N content. If sender is any other module then values are passed to patches as they come

            string module = NitrogenChanges.SenderType.ToLower();
            if ((Patch.Count > 1) && (module == "WaterModule".ToLower()) || (module == "Plant".ToLower()))
            {
                // values supplied by a module from which a different treatment for each patch is required,
                //  they will be partitioned according to the N content in each patch, following:
                //  - If module is Plant (uptake): partition is based on the relative concentration, at each layer, of all patches
                //  - If module is WaterModule (leaching):
                //        . if is removal (negative): partition is equal to a plant uptake
                //        . if is incoming leaching: partition is based on relative concentration on the layer and above

                // 1- consider urea:
                if (hasValues(NitrogenChanges.DeltaUrea, EPSILON))
                {
                    // 1.1-send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaUrea, "urea", NPartitionApproach.ToLower());
                    // 1.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                        Patch[k].dlt_urea = newDelta[k];
                }

                // 2- consider nh4:
                if (hasValues(NitrogenChanges.DeltaNH4, EPSILON))
                {
                    // 2.1- send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaNH4, "NH4", NPartitionApproach.ToLower());
                    // 2.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                        Patch[k].dlt_nh4 = newDelta[k];
                }

                // 3- consider no3:
                if (hasValues(NitrogenChanges.DeltaNO3, EPSILON))
                {
                    // 3.1- send incoming dlt to be partitioned amongst patches
                    double[][] newDelta = partitionDelta(NitrogenChanges.DeltaNO3, "NO3", NPartitionApproach.ToLower());
                    // 3.2- send dlt's to each patch
                    for (int k = 0; k < Patch.Count; k++)
                        Patch[k].dlt_no3 = newDelta[k];
                }
            }
            else
            {
                // values will passed to patches as they come
                for (int k = 0; k < Patch.Count; k++)
                {
                    Patch[k].dlt_urea = NitrogenChanges.DeltaUrea;
                    Patch[k].dlt_nh4 = NitrogenChanges.DeltaNH4;
                    Patch[k].dlt_no3 = NitrogenChanges.DeltaNO3;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Computes the distribution of N uptake over the soil profile and send the delta to soil module
        /// </summary>
        /// <exception cref="System.Exception">
        ///  Error on computing N uptake
        ///  or
        ///  N uptake source was not recognised. Please specify it as either \"sward\" or \"species\".
        /// </exception>
        private void DoSoilNitrogenUptake()
        {
            if (nUptakeSource.ToLower() == "sward")
            {
                if (soilAvailableN.Sum() > 0.0 && swardSoilNuptake > 0.0)
                {
                    // there is N in the soil and there is plant uptake
                    Soils.NitrogenChangedType NTakenUp = new Soils.NitrogenChangedType();
                    NTakenUp.Sender = Name;
                    NTakenUp.SenderType = "Plant";
                    NTakenUp.DeltaNO3 = new double[nLayers];
                    NTakenUp.DeltaNH4 = new double[nLayers];

                    double uptakeFraction = Math.Min(1.0, swardSoilNuptake / soilAvailableN.Sum());
                    double speciesFraction = 0.0;

                    if (useAltNUptake == "no")
                    {
                        // calc the amount of each N form taken up
                        for (int layer = 0; layer <= RootFrontier; layer++)
                        {
                            NTakenUp.DeltaNH4[layer] = -Soil.NH4N[layer] * uptakeFraction;
                            NTakenUp.DeltaNO3[layer] = -Soil.NO3N[layer] * uptakeFraction;
                        }

                        // partition the amount taken up between species, considering amount actually taken up
                        foreach (PastureSpecies mySpecies in mySward)
                        {
                            mySpecies.mySoilNitrogenTakenUp = new double[nLayers];
                            if (swardSoilNuptake > 0.0)
                            {
                                speciesFraction = mySpecies.mySoilNuptake / swardSoilNuptake;
                                for (int layer = 0; layer <= RootFrontier; layer++)
                                    mySpecies.mySoilNitrogenTakenUp[layer] = -(NTakenUp.DeltaNH4[layer] + NTakenUp.DeltaNO3[layer]) * speciesFraction;
                            }
                        }
                    }
                    else
                    { // Method implemented by RCichota,
                        // Uptake is distributed over the profile according to N availability,
                        //  this means that N and water status as well as root distribution have been taken into account

                        double[] adjustedNH4Available;
                        double[] adjustedNO3Available;

                        double[] sumNH4Available = new double[nLayers];
                        double[] sumNO3Available = new double[nLayers];
                        for (int layer = 0; layer < RootFrontier; layer++)
                        {
                            sumNH4Available[layer] = mySward.Sum(mySpecies => mySpecies.SoilAvailableWater[layer]);
                            sumNO3Available[layer] = mySward.Sum(mySpecies => mySpecies.SoilAvailableWater[layer]);
                        }
                        foreach (PastureSpecies mySpecies in mySward)
                        {
                            // get adjusted N available
                            adjustedNH4Available = new double[nLayers];
                            adjustedNO3Available = new double[nLayers];
                            for (int layer = 0; layer <= mySpecies.RootFrontier; layer++)
                            {
                                adjustedNH4Available[layer] = soilNH4Available[layer] * mySpecies.mySoilNH4available[layer] / sumNH4Available[layer];
                                adjustedNO3Available[layer] = soilNO3Available[layer] * mySpecies.mySoilNO3available[layer] / sumNO3Available[layer];
                            }

                            // get fraction of demand supplied by the soil
                            uptakeFraction = Math.Min(1.0, mySpecies.mySoilNuptake / (adjustedNH4Available.Sum() + adjustedNO3Available.Sum()));

                            // get the actual amounts taken up from each layer
                            mySpecies.mySoilNitrogenTakenUp = new double[nLayers];
                            for (int layer = 0; layer <= mySpecies.RootFrontier; layer++)
                            {
                                mySpecies.mySoilNitrogenTakenUp[layer] = (adjustedNH4Available[layer] + adjustedNO3Available[layer]) * uptakeFraction;
                                NTakenUp.DeltaNH4[layer] -= Soil.NH4N[layer] * uptakeFraction;
                                NTakenUp.DeltaNO3[layer] -= Soil.NO3N[layer] * uptakeFraction;
                            }
                        }
                    }
                    double totalUptake = mySward.Sum(mySpecies => mySpecies.UptakeN.Sum());
                    if ((Math.Abs(swardSoilNuptake - totalUptake) > 0.0001) || (Math.Abs(NTakenUp.DeltaNH4.Sum() + NTakenUp.DeltaNO3.Sum() + totalUptake) > 0.0001))
                        throw new Exception("Error on computing N uptake");

                    // do the actual N changes
                    NitrogenChanged.Invoke(NTakenUp);
                }
                else
                {
                    // No uptake, just zero out the arrays
                    foreach (PastureSpecies mySpecies in mySward)
                        mySpecies.mySoilNitrogenTakenUp = new double[nLayers];
                }
            }
            else
            {
                // N uptake calculated by other modules (e.g., SWIM) - not actually implemented
                string msg = "N uptake source was not recognised. Please specify it as either \"sward\" or \"species\".";
                throw new Exception(msg);
            }
        }
예제 #5
0
파일: SoilWater.cs 프로젝트: hut104/ApsimX
        /// <summary>
        /// Sends the nitrogen changed event.
        /// </summary>
        private void SendNitrogenChangedEvent()
        {
            NitrogenChangedType NitrogenDeltas = new NitrogenChangedType();
            NitrogenDeltas.Sender = "SoilWater";
            NitrogenDeltas.SenderType = "WaterModule";

            NitrogenDeltas.DeltaUrea = SoilObject.GetDeltaArrayForASolute("urea");
            NitrogenDeltas.DeltaNH4 = SoilObject.GetDeltaArrayForASolute("NH4");
            NitrogenDeltas.DeltaNO3 = SoilObject.GetDeltaArrayForASolute("NO3");

            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NitrogenDeltas);
        }
예제 #6
0
파일: Arbitrator.cs 프로젝트: hol353/ApsimX
        /// <summary>Old_s the on do nutrient arbitration.</summary>
        /// <exception cref="System.Exception">Invalid potential uptake method selected</exception>
        private void Old_OnDoNutrientArbitration()
        {
            // use i for the plant loop and j for the layer loop

            NitrogenChangedType NUptakeType = new NitrogenChangedType();
            NUptakeType.Sender = Name;
            NUptakeType.SenderType = "Plant";
            NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length];
            NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length];

            double tempSupply = 0.0;  // this zeros the variable for each crop - calculates the potentialSupply for the crop for all layers - will be used to compare against demand
            // calculate the potentially available water and sum the demand
            for (int i = 0; i < plants.Count; i++)
            {
                if (NutrientUptakeMethod == 2)
                {
                    demandNitrogen[i] = Math.Min(plants[i].demandNitrogen, plants[i].RootProperties.MaximumDailyNUptake); //HEB added in Maximum daily uptake constraint
                }
                else
                {
                    demandNitrogen[i] = plants[i].demandNitrogen;
                }

                tempSupply = 0.0;  // this is the sum of potentialSupplyNitrogenPlantLayer[i, j] across j for each plant - used in the limitation to demand
                for (int j = 0; j < Soil.Thickness.Length; j++)
                {
                    if (NutrientUptakeMethod == 1) // use the soil KL with no water effect
                    {
                        potentialSupplyNitrogenPlantLayer[i, j] = MathUtilities.Divide(plants[i].RootProperties.KL[j], plants.Count, 0.0)
                                                                * (Soil.NO3N[j] + Soil.NH4N[j])
                                                                * plants[i].RootProperties.RootExplorationByLayer[j];
                        tempSupply += potentialSupplyNitrogenPlantLayer[i, j]; // temporary add up the supply of water across all layers for this crop, then scale back if needed below

                        double tempNO3OnlySupply = MathUtilities.Divide(plants[i].RootProperties.KL[j], plants.Count, 0.0)
                                                 * Soil.NO3N[j]
                                                 * plants[i].RootProperties.RootExplorationByLayer[j];
                        potentialSupplyPropNO3PlantLayer[i, j] = MathUtilities.Divide(tempNO3OnlySupply, potentialSupplyNitrogenPlantLayer[i, j], 0.0);
                    }
                    else if (NutrientUptakeMethod == 2)
                    {
                        //I blocked the N arbitration out to get water working correctly with the arbitrator first.
                        /*   //Fixme.  The PMF implementation was not adjusting N Uptake in partially rooted layer.  I have left it as this for testing but will need to introduce it soon.
                        //method from PMF - based on concentration
                        //HEB.  I have rewritten this section of code to make it function identically to current PMF implementation for purposes of testing

                        double relativeSoilWaterContent = 0;
                        if (Plants[i].RootProperties.RootLengthDensityByVolume[j] > 0.0) // Test to see if there are roots in this layer.
                        {

                            relativeSoilWaterContent = (Soil.SoilWater.sw_dep[j] - Soil.SoilWater.ll15_dep[j]) / (Soil.SoilWater.dul_dep[j] - Soil.SoilWater.ll15_dep[j]);
                            relativeSoilWaterContent = MathUtilities.Constrain(relativeSoilWaterContent, 0, 1.0);
                            potentialSupplyNitrogenPlantLayer[i, j] = Soil.NO3Nppm[j] * Soil.NO3N[j] * plants[i].RootProperties.KNO3 * relativeSoilWaterContent;
                        }
                        else
                        {
                            potentialSupplyNitrogenPlantLayer[i, j] = 0;
                        }

                        double tempNO3OnlySupply = 0;
                        tempNO3OnlySupply = potentialSupplyNitrogenPlantLayer[i, j];
                        potentialSupplyNitrogenPlantLayer[i, j] += Soil.NH4Nppm[j] * Soil.NH4N[j] * plants[i].RootProperties.KNH4 * relativeSoilWaterContent;
                        tempSupply += potentialSupplyNitrogenPlantLayer[i, j]; // temporary add up the supply of water across all layers for this crop, then scale back if needed below

                        if (potentialSupplyNitrogenPlantLayer[i, j] == 0)
                            potentialSupplyPropNO3PlantLayer[i, j] = 1;
                        else
                            potentialSupplyPropNO3PlantLayer[i, j] = tempNO3OnlySupply / potentialSupplyNitrogenPlantLayer[i, j];
                    */
                    }
                    else if (NutrientUptakeMethod == 3)
                    {
                        //method from OilPlam - based on amount
                        double relativeSoilWaterContent = 0;
                        relativeSoilWaterContent = MathUtilities.Constrain(MathUtilities.Divide((Soil.Water[j] - Soil.SoilWater.LL15mm[j]), (Soil.SoilWater.DULmm[j] - Soil.SoilWater.LL15mm[j]), 0.0), 0.0, 1.0);

                        potentialSupplyNitrogenPlantLayer[i, j] = Math.Max(0.0, plants[i].RootProperties.RootExplorationByLayer[j] * (MathUtilities.Divide(plants[i].RootProperties.KNO3, plants.Count, 0.0) * Soil.NO3N[j] + MathUtilities.Divide(plants[i].RootProperties.KNH4, plants.Count, 0.0) * Soil.NH4N[j]) * relativeSoilWaterContent);
                        tempSupply += potentialSupplyNitrogenPlantLayer[i, j]; // temporary add up the supply of water across all layers for this crop, then scale back if needed below

                        double tempNO3OnlySupply = 0;
                        tempNO3OnlySupply = Math.Max(0.0, plants[i].RootProperties.RootExplorationByLayer[j] * (MathUtilities.Divide(plants[i].RootProperties.KNO3, plants.Count, 0.0) * Soil.NO3N[j]) * relativeSoilWaterContent);
                        potentialSupplyPropNO3PlantLayer[i, j] = MathUtilities.Divide(tempNO3OnlySupply, potentialSupplyNitrogenPlantLayer[i, j], 0.0);
                    }
                    else
                    {
                        throw new Exception("Invalid potential uptake method selected");
                    }
                }
                for (int j = 0; j < Soil.Thickness.Length; j++)
                {
                    // if the potential supply calculated above is greater than demand then scale it back - note that this is still a potential supply as a solo crop
                    potentialSupplyNitrogenPlantLayer[i, j] = potentialSupplyNitrogenPlantLayer[i, j] * Math.Min(1.0, MathUtilities.Divide(demandNitrogen[i], tempSupply, 0.0));
                }
            }  // close the plants loop - by here have the potentialSupply by plant and layer.  This is the sole plant demand - no competition yet

            // calculate the maximum amount of nitrogen available in each layer
            double[] totalAvailableNitrogen;
            totalAvailableNitrogen = new double[Soil.Thickness.Length];
            for (int j = 0; j < Soil.Thickness.Length; j++)
            {
                totalAvailableNitrogen[j] = Soil.NO3N[j] + Soil.NH4N[j];
            }

            // compare the potential nitrogen supply against the total available nitrogen
            // if supply exceeds demand then satisfy all demands, otherwise scale back by relative demand
            for (int j = 0; j < Soil.Thickness.Length; j++) // loop through the layers in the outer loop
            {
                for (int i = 0; i < plants.Count; i++)
                {
                    uptakeNitrogenPlantLayer[i, j] = potentialSupplyNitrogenPlantLayer[i, j]
                                                   * MathUtilities.Constrain(MathUtilities.Divide(MathUtilities.Sum(totalAvailableNitrogen), MathUtilities.Sum(demandNitrogen), 0.0), 0.0, 1.0);
                    uptakeNitrogenPropNO3PlantLayer[i, j] = 0.0;
                    NUptakeType.DeltaNO3[j] += -1.0 * uptakeNitrogenPlantLayer[i, j] * potentialSupplyPropNO3PlantLayer[i, j];  // -ve to reduce water content in the soil
                    NUptakeType.DeltaNH4[j] += -1.0 * uptakeNitrogenPlantLayer[i, j] * (1.0 - potentialSupplyPropNO3PlantLayer[i, j]);  // -ve to reduce water content in the soil

                    if ((i == plants.Count - 1) && (j == 0))
                    {
                        //Summary.WriteMessage(this, potentialSupplyNitrogenPlantLayer[0, j] + " " + potentialSupplyNitrogenPlantLayer[i, j] + " " + NUptakeType.DeltaNO3[j]);
                    }
                }
            }  // close the layer loop

            for (int i = 0; i < plants.Count; i++)
            {
                double[] dummyArray1 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing
                double[] dummyArray2 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing
                for (int j = 0; j < Soil.Thickness.Length; j++)           // cannot set a particular dimension from a 2D arrary into a 1D array directly so need a temporary variable
                {
                    dummyArray1[j] = uptakeNitrogenPlantLayer[i, j];
                    dummyArray2[j] = uptakeNitrogenPropNO3PlantLayer[i, j];
                }
                double testingvalue = MathUtilities.Sum(dummyArray1);
                plants[i].uptakeNitrogen = dummyArray1;
                plants[i].uptakeNitrogenPropNO3 = dummyArray2;
                // debugging into SummaryFile
                //Summary.WriteMessage(FullPath, "Arbitrator is setting the value of plants[" + i.ToString() + "].supplyWater(3) to  " + plants[i].supplyWater[3].ToString());
            }

            // send the change in soil soil nitrate and ammonium to the soil nitrogen module

            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NUptakeType);
        }
예제 #7
0
파일: AgPasture.cs 프로젝트: hut104/ApsimX
        /// <summary>Nitrogen uptake process</summary>
        /// <returns></returns>
        /// <exception cref="System.Exception"></exception>
        private double SNUptakeProcess()
        {
            //Uptake from the root_zone
            Soils.NitrogenChangedType NUptake = new Soils.NitrogenChangedType();
            NUptake.Sender = Name;
            NUptake.SenderType = "Plant";
            NUptake.DeltaNO3 = new double[Soil.Thickness.Length];
            NUptake.DeltaNH4 = new double[Soil.Thickness.Length];

            double Fraction = 0;
            if (p_soilNavailable > 0)
            {
                Fraction = Math.Min(1.0, p_soilNuptake / p_soilNavailable);
            }

            double n_uptake = 0;

            if (alt_N_uptake == "yes")
            {
                double
                    uptake_multiplier = double.MaxValue,
                    totSWUptake = SWUptake.Sum();

                double[]
                    availableNH4_bylayer = new double[Soil.Thickness.Length],
                    availableNO3_bylayer = new double[Soil.Thickness.Length],
                    diffNH4_bylayer = new double[Soil.Thickness.Length],
                    diffNO3_bylayer = new double[Soil.Thickness.Length];

                for (int layer = 0; layer < Soil.Thickness.Length; layer++)
                {
                    double
                        totN = Soil.NH4N[layer] + Soil.NO3N[layer],
                        fracH2O = SWUptake[layer] / totSWUptake;

                    if (totN > 0)
                    {
                        availableNH4_bylayer[layer] = fracH2O * Soil.NH4N[layer] / totN;
                        availableNO3_bylayer[layer] = fracH2O * Soil.NO3N[layer] / totN;

                        //if we have no3 and nh4 in this layer then calculate our uptake multiplier, otherwise set it to 0
                        //the idea behind the multiplier is that it allows us to calculate the max amount of N we can extract
                        //without forcing any of the layers below 0 AND STILL MAINTAINING THE RATIO as calculated with fracH2O
                        //NOTE: it doesn't matter whether we use nh4 or no3 for this calculation, we will get the same answer regardless
                        uptake_multiplier = Soil.NH4N[layer] * Soil.NO3N[layer] > 0 ? Math.Min(uptake_multiplier, Soil.NH4N[layer] / availableNH4_bylayer[layer]) : 0;
                    }
                    else
                    {
                        availableNH4_bylayer[layer] = 0;
                        availableNO3_bylayer[layer] = 0;
                    }
                }

                //adjust availability values with the multiplier we just calculated
                availableNH4_bylayer = availableNH4_bylayer.Select(x => x * uptake_multiplier).ToArray();
                availableNO3_bylayer = availableNO3_bylayer.Select(x => x * uptake_multiplier).ToArray();

                //calculate how much no3/nh4 will be left in the soil layers (diff_nxx[layer] = nxx[layer] - availableNH4_bylayer[layer])
                diffNH4_bylayer = Soil.NH4N.Select((x, layer) => Math.Max(0, x - availableNH4_bylayer[layer])).ToArray();
                diffNO3_bylayer = Soil.NO3N.Select((x, layer) => Math.Max(0, x - availableNO3_bylayer[layer])).ToArray();

                //adjust this by the sum of all leftover so we get a ratio we can use later
                double sum_diff = diffNH4_bylayer.Sum() + diffNO3_bylayer.Sum();
                diffNH4_bylayer = diffNH4_bylayer.Select(x => x / sum_diff).ToArray();
                diffNO3_bylayer = diffNO3_bylayer.Select(x => x / sum_diff).ToArray();

                double
                    //available N from our 'withwater' calcs (still some left in the 'diff' arrays if this isn't enough)
                    avail_withwater = availableNH4_bylayer.Sum() + availableNO3_bylayer.Sum(),
                    //if not enough N was available via the 'withwater' calcs this will be positive and will require more from the 'diffs' we calculated
                    shortfall_withwater = p_soilNuptake - avail_withwater;

                if (shortfall_withwater > 0)
                {
                    //this cap should not be needed because shortfall is already capped via the math.min in the scaled_demand calcs (leave it here though)
                    double scaled_diff = Math.Min(shortfall_withwater / avail_withwater, 1);

                    availableNH4_bylayer = availableNH4_bylayer.Select((x, layer) => x + shortfall_withwater * diffNH4_bylayer[layer]).ToArray();
                    availableNO3_bylayer = availableNO3_bylayer.Select((x, layer) => x + shortfall_withwater * diffNO3_bylayer[layer]).ToArray();
                }

                NUptake.DeltaNH4 = availableNH4_bylayer.Select(x => x * -1).ToArray();
                NUptake.DeltaNO3 = availableNO3_bylayer.Select(x => x * -1).ToArray();

                for (int layer = 0; layer < p_bottomRootLayer; layer++)
                    n_uptake += SNUptake[layer] = (NUptake.DeltaNH4[layer] + NUptake.DeltaNO3[layer]) * -1;

                double[] diffs = NUptake.DeltaNO3.Select((x, i) => Math.Max(Soil.NO3N[i] + x + 0.00000001, 0)).ToArray();
                if (diffs.Any(x => x == 0))
                    throw new Exception();

            }

            /*if (ValsMode == "withwater")
            {
                NUptake.DeltaNO3 = SP[0].availableNO3_bylayer.Select(x => x * -1).ToArray();
                NUptake.DeltaNH4 = SP[0].availableNH4_bylayer.Select(x => x * -1).ToArray();

                for (int layer = 0; layer < p_bottomRootLayer; layer++)
                    SNUptake[layer] = SP[0].availableNO3_bylayer[layer] + SP[0].availableNH4_bylayer[layer];
                n_uptake = SNUptake.Sum();
            }*/
            else
            {
                for (int layer = 0; layer < p_bottomRootLayer; layer++)
                {   //N are taken up only in top layers that root can reach (including buffer Zone).
                    n_uptake += (Soil.NO3N[layer] + Soil.NH4N[layer]) * Fraction;
                    SNUptake[layer] = (Soil.NO3N[layer] + Soil.NH4N[layer]) * Fraction;

                    NUptake.DeltaNO3[layer] = -Soil.NO3N[layer] * Fraction;
                    NUptake.DeltaNH4[layer] = -Soil.NH4N[layer] * Fraction;
                }
            }

            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NUptake);
            return n_uptake;
        }
예제 #8
0
파일: Sugarcane.cs 프로젝트: hol353/ApsimX
        //called at end of OnProcess() Event Handler.
        /// <summary>
        /// Sugar_set_other_variableses the specified i_dlt_no3gsm.
        /// </summary>
        /// <param name="i_dlt_no3gsm">The i_dlt_no3gsm.</param>
        /// <param name="i_dlt_nh4gsm">The i_dlt_nh4gsm.</param>
        /// <param name="i_dlt_sw_dep">The i_dlt_sw_dep.</param>
        void sugar_set_other_variables(double[] i_dlt_no3gsm, double[] i_dlt_nh4gsm, double[] i_dlt_sw_dep)
        {
            //*+  Purpose
            //*      Set the value of a variable or array in other module/s.

            //*+  Mission Statement
            //*     Set value of variable or array in other module/s

            //*+  Notes
            //*      a flag is set if any of the totals is requested.  The totals are
            //*      reset during the next process phase when this happens.

            double[] l_dlt_NO3 = new double[max_layer];    //! soil NO3 change (kg/ha)
            double[] l_dlt_NH4 = new double[max_layer];    //! soil NO3 change (kg/ha)
            int num_layers;            //! number of layers

            if (uptake_source == "calc")
                {

                num_layers = count_of_real_vals(dlayer, max_layer);

                //sv- I added this resize, from max_layer to num_layer.
                //    Done so the NitrogenChanges.DeltaNO3 etc. gets an array of a sensible size.
                Array.Resize(ref l_dlt_NO3, num_layers);
                Array.Resize(ref l_dlt_NH4, num_layers);
                Array.Resize(ref i_dlt_sw_dep, num_layers);

                for (int layer = 0; layer < num_layers; layer++)
                    {
                    l_dlt_NO3[layer] = i_dlt_no3gsm[layer] * gm2kg / sm2ha;
                    l_dlt_NH4[layer] = i_dlt_nh4gsm[layer] * gm2kg / sm2ha;
                    }

                NitrogenChangedType NitrogenChanges = new NitrogenChangedType();
                NitrogenChanges.Sender = "Sugarcane";
                NitrogenChanges.DeltaNO3 = l_dlt_NO3;
                NitrogenChanges.DeltaNH4 = l_dlt_NH4;

                NitrogenChanged.Invoke(NitrogenChanges);  //trigger/invoke the Nitrogen Changed Event

                WaterChangedType WaterChanges = new WaterChangedType();
                WaterChanges.DeltaWater = i_dlt_sw_dep;

                WaterChanged.Invoke(WaterChanges);      //trigger/invoke the Water Changed Event

                }
            else if (uptake_source == "swim3")
                {
                num_layers = count_of_real_vals(dlayer, max_layer);

                //sv- I added this resize, from max_layer to num_layer
                //    Done so the NitrogenChanges.DeltaNO3 etc. gets an array of the sensible size.
                Array.Resize(ref l_dlt_NO3, num_layers);
                Array.Resize(ref l_dlt_NH4, num_layers);

                for (int layer = 0; layer < num_layers; layer++)
                    {
                    l_dlt_NO3[layer] = i_dlt_no3gsm[layer] * gm2kg / sm2ha;
                    l_dlt_NH4[layer] = i_dlt_nh4gsm[layer] * gm2kg / sm2ha;
                    }

                NitrogenChangedType NitrogenChanges = new NitrogenChangedType();
                NitrogenChanges.Sender = "Sugarcane";
                NitrogenChanges.DeltaNO3 = l_dlt_NO3;
                NitrogenChanges.DeltaNH4 = l_dlt_NH4;

                NitrogenChanged.Invoke(NitrogenChanges);  //trigger/invoke the Nitrogen Changed Event
                }
            else
                {
                //! assume that the module that calculated uptake has also updated these pools.
                }
        }
예제 #9
0
 /// <summary>Gets the changes in mineral N made by other modules</summary>
 /// <param name="NitrogenChanges">The nitrogen changes.</param>
 public void SetNitrogenChanged(NitrogenChangedType NitrogenChanges)
 {
     OnNitrogenChanged(NitrogenChanges);
 }
예제 #10
0
파일: OilPalm.cs 프로젝트: hol353/ApsimX
        /// <summary>Does the n balance.</summary>
        /// <exception cref="System.Exception">Error in N Allocation</exception>
        private void DoNBalance()
        {
            NitrogenChangedType NUptakeType = new NitrogenChangedType();
            NUptakeType.Sender = Name;
            NUptakeType.SenderType = "Plant";
            NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length];
            NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length];

            double StartN = PlantN;

            double StemNDemand = StemGrowth * StemNConcentration.Value / 100.0 * 10.0;  // factor of 10 to convert g/m2 to kg/ha
            double RootNDemand = Math.Max(0.0, (RootMass * RootNConcentration.Value / 100.0 - RootN)) * 10.0;  // kg/ha
            double FrondNDemand = Math.Max(0.0, (FrondMass * FrondMaximumNConcentration.Value / 100.0 - FrondN)) * 10.0;  // kg/ha
            double BunchNDemand = Math.Max(0.0, (BunchMass * BunchNConcentration.Value / 100.0 - BunchN)) * 10.0;  // kg/ha

            Ndemand = StemNDemand + FrondNDemand + RootNDemand + BunchNDemand;  //kg/ha

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
            {
                double swaf = 0;
                swaf = (Soil.Water[j] - Soil.SoilWater.LL15mm[j]) / (Soil.SoilWater.DULmm[j] - Soil.SoilWater.LL15mm[j]);
                swaf = Math.Max(0.0, Math.Min(swaf, 1.0));
                double no3ppm = Soil.NO3N[j] * (100.0 / (Soil.BD[j] * Soil.Thickness[j]));
                PotNUptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * KNO3.Value * Soil.NO3N[j] * swaf);
            }

            double TotPotNUptake = MathUtilities.Sum(PotNUptake);
            double Fr = Math.Min(1.0, Ndemand / TotPotNUptake);

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
            {
                NUptake[j] = PotNUptake[j] * Fr;
                NUptakeType.DeltaNO3[j] = -NUptake[j];
            }

            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NUptakeType);

            Fr = Math.Min(1.0, Math.Max(0, MathUtilities.Sum(NUptake) / BunchNDemand));
            double DeltaBunchN = BunchNDemand * Fr;

            double Tot = 0;
            foreach (BunchType B in Bunches)
            {
                Tot += Math.Max(0.0, B.Mass * BunchNConcentration.Value / 100.0 - B.N) * Fr / SowingData.Population;
                B.N += Math.Max(0.0, B.Mass * BunchNConcentration.Value / 100.0 - B.N) * Fr;
            }

            // Calculate fraction of N demand for Vegetative Parts
            if ((Ndemand - DeltaBunchN) > 0)
                Fr = Math.Max(0.0, ((MathUtilities.Sum(NUptake) - DeltaBunchN) / (Ndemand - DeltaBunchN)));
            else
                Fr = 0.0;

            StemN += StemNDemand / 10 * Fr;

            double[] RootNDef = new double[Soil.SoilWater.LL15mm.Length];
            double TotNDef = 1e-20;
            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
            {
                RootNDef[j] = Math.Max(0.0, Roots[j].Mass * RootNConcentration.Value / 100.0 - Roots[j].N);
                TotNDef += RootNDef[j];
            }
            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
                Roots[j].N += RootNDemand / 10 * Fr * RootNDef[j] / TotNDef;

            foreach (FrondType F in Fronds)
                F.N += Math.Max(0.0, F.Mass * FrondMaximumNConcentration.Value / 100.0 - F.N) * Fr;

            double EndN = PlantN;
            double Change = EndN - StartN;
            double Uptake = MathUtilities.Sum(NUptake) / 10.0;
            if (Math.Abs(Change - Uptake) > 0.001)
                throw new Exception("Error in N Allocation");

            double Nact = FrondNConc;
            double Ncrit = FrondCriticalNConcentration.Value;
            double Nmin = FrondMinimumNConcentration.Value;
            Fn = Math.Min(Math.Max(0.0, (Nact - Nmin) / (Ncrit - Nmin)), 1.0);
        }
예제 #11
0
파일: Root1.cs 프로젝트: hol353/ApsimX
        /// <summary>Update the water and N balance.</summary>
        private void UpdateWaterAndNBalance()
        {
            NitrogenChangedType NitrogenUptake = new NitrogenChangedType();
            NitrogenUptake.Sender = "Plant";
            NitrogenUptake.SenderType = "Plant";
            NitrogenUptake.DeltaNO3 = MathUtilities.Multiply_Value(dlt_no3gsm, Conversions.gm2kg / Conversions.sm2ha);
            NitrogenUptake.DeltaNH4 = MathUtilities.Multiply_Value(dlt_nh4gsm, Conversions.gm2kg / Conversions.sm2ha);
            Util.Debug("Root.NitrogenUptake.DeltaNO3=%f", MathUtilities.Sum(NitrogenUptake.DeltaNO3));
            Util.Debug("Root.NitrogenUptake.DeltaNH4=%f", MathUtilities.Sum(NitrogenUptake.DeltaNH4));
            NitrogenChanged.Invoke(NitrogenUptake);

            // Send back delta water and nitrogen back to APSIM.
            if (!SwimIsPresent)
            {
                WaterChangedType WaterUptake = new WaterChangedType();
                WaterUptake.DeltaWater = dlt_sw_dep;
                Util.Debug("Root.WaterUptake=%f", MathUtilities.Sum(WaterUptake.DeltaWater));
                WaterChanged.Invoke(WaterUptake);

            }
        }
예제 #12
0
파일: SimpleTree.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// Set the n uptake for today
        /// </summary>
        public void SetNUptake(List<ZoneWaterAndN> info)
        {
            NitrogenChangedType NUptakeType = new NitrogenChangedType();
            NUptakeType.Sender = Name;
            NUptakeType.SenderType = "Plant";
            NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length];
            NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length];
            NO3Uptake = info[0].NO3N;
            NH4Uptake = info[0].NH4N;

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
            {
                    NUptakeType.DeltaNO3[j] = -NO3Uptake[j];
                    NUptakeType.DeltaNH4[j] = -NH4Uptake[j];
            }

            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NUptakeType);
        }
예제 #13
0
파일: Root.cs 프로젝트: hol353/ApsimX
        /// <summary>Does the Nitrogen uptake.</summary>
        /// <param name="zonesFromSoilArbitrator">List of zones from soil arbitrator</param>
        public void DoNitrogenUptake(List<ZoneWaterAndN> zonesFromSoilArbitrator)
        {
            foreach (ZoneWaterAndN thisZone in zonesFromSoilArbitrator)
            {
                ZoneState zone = Zones.Find(z => z.Name == thisZone.Name);
                if (zone == null)
                    throw new Exception("Cannot find a zone called " + thisZone.Name);

                // Send the delta water back to SoilN that we're going to uptake.
                NitrogenChangedType NitrogenUptake = new NitrogenChangedType();
                NitrogenUptake.DeltaNO3 = MathUtilities.Multiply_Value(thisZone.NO3N, -1.0);
                NitrogenUptake.DeltaNH4 = MathUtilities.Multiply_Value(thisZone.NH4N, -1.0);

                zone.NitUptake = MathUtilities.Add(NitrogenUptake.DeltaNO3, NitrogenUptake.DeltaNH4);
                zone.soil.SoilNitrogen.SetNitrogenChanged(NitrogenUptake);
            }
        }
예제 #14
0
파일: Root.cs 프로젝트: kiwiroy/ApsimX
        /// <summary>Does the Nitrogen uptake.</summary>
        /// <param name="NO3NAmount">The NO3NAmount.</param>
        /// <param name="NH4NAmount">The NH4NAmount.</param>
        public override void DoNitrogenUptake(double[] NO3NAmount, double[] NH4NAmount)
        {
            // Send the delta water back to SoilN that we're going to uptake.
            NitrogenChangedType NitrogenUptake = new NitrogenChangedType();
            NitrogenUptake.DeltaNO3 = MathUtilities.Multiply_Value(NO3NAmount, -1.0);
            NitrogenUptake.DeltaNH4 = MathUtilities.Multiply_Value(NH4NAmount, -1.0);

            NitUptake = MathUtilities.Add(NitrogenUptake.DeltaNO3, NitrogenUptake.DeltaNH4);
            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NitrogenUptake);
        }
예제 #15
0
파일: Fertiliser.cs 프로젝트: hol353/ApsimX
        /// <summary>Apply fertiliser.</summary>
        /// <param name="Amount">The amount.</param>
        /// <param name="Type">The type.</param>
        /// <param name="Depth">The depth.</param>
        /// <exception cref="ApsimXException">Cannot find fertiliser type ' + Type + '</exception>
        public void Apply(double Amount, Types Type, double Depth = 0.0)
        {
            if (Amount > 0 && NitrogenChanged != null)
            {
                // find the layer that the fertilizer is to be added to.
                int layer = GetLayerDepth(Depth, Soil.Thickness);

                FertiliserType fertiliserType = Definitions.FirstOrDefault(f => f.Name == Type.ToString());
                if (fertiliserType == null)
                    throw new ApsimXException(this, "Cannot find fertiliser type '" + Type + "'");

                NitrogenChangedType NitrogenChanges = new NitrogenChangedType();
                NitrogenChanges.Sender = Apsim.FullPath(this);

                if (fertiliserType.FractionNO3 != 0)
                {
                    NitrogenChanges.DeltaNO3 = new double[Soil.Thickness.Length];
                    NitrogenChanges.DeltaNO3[layer] = Amount * fertiliserType.FractionNO3;
                    NitrogenApplied += Amount * fertiliserType.FractionNO3;
                }
                if (fertiliserType.FractionNH4 != 0)
                {
                    NitrogenChanges.DeltaNH4 = new double[Soil.Thickness.Length];
                    NitrogenChanges.DeltaNH4[layer] = Amount * fertiliserType.FractionNH4;
                    NitrogenApplied += Amount * fertiliserType.FractionNH4;
                }
                if (fertiliserType.FractionUrea != 0)
                {
                    NitrogenChanges.DeltaUrea = new double[Soil.Thickness.Length];
                    NitrogenChanges.DeltaUrea[layer] = Amount * fertiliserType.FractionUrea;
                    NitrogenApplied += Amount * fertiliserType.FractionUrea;
                }

                NitrogenChanged.Invoke(NitrogenChanges);
                Summary.WriteMessage(this, string.Format("{0} kg/ha of {1} added at depth {2} layer {3}", Amount, Type, Depth, layer + 1));
            }
        }
예제 #16
0
        /// <summary>
        /// Computes the distribution of N uptake over the soil profile and send the delta to soil module
        /// </summary>
        /// <exception cref="System.Exception">
        /// Error on computing N uptake
        /// or
        /// N uptake source was not recognised. Please specify it as either \"sward\" or \"species\".
        /// </exception>
        private void DoSoilNitrogenUptake()
        {
            if (myNitrogenUptakeSource.ToLower() == "species")
            {
                // check whether there is any uptake
                if (mySoilAvailableN.Sum() > 0.0 && mySoilNuptake > 0.0)
                {

                    Soils.NitrogenChangedType NUptake = new Soils.NitrogenChangedType();
                    NUptake.Sender = Name;
                    NUptake.SenderType = "Plant";
                    NUptake.DeltaNO3 = new double[nLayers];
                    NUptake.DeltaNH4 = new double[nLayers];

                    mySoilNitrogenTakenUp = new double[nLayers];
                    double uptakeFraction = 0;

                    if (useAltNUptake == "no")
                    {
                        if (mySoilAvailableN.Sum() > 0.0)
                            uptakeFraction = Math.Min(1.0, MathUtilities.Divide(mySoilNuptake, mySoilAvailableN.Sum(), 0.0));

                        for (int layer = 0; layer <= myRootFrontier; layer++)
                        {
                            NUptake.DeltaNH4[layer] = -Soil.NH4N[layer] * uptakeFraction;
                            NUptake.DeltaNO3[layer] = -Soil.NO3N[layer] * uptakeFraction;

                            mySoilNitrogenTakenUp[layer] = -(NUptake.DeltaNH4[layer] + NUptake.DeltaNO3[layer]);
                        }
                    }
                    else
                    { // Method implemented by RCichota,
                        // N uptake is distributed considering water uptake and N availability
                        double[] fNH4Avail = new double[nLayers];
                        double[] fNO3Avail = new double[nLayers];
                        double[] fWUptake = new double[nLayers];
                        double totNH4Available = mySoilAvailableN.Sum();
                        double totNO3Available = mySoilAvailableN.Sum();
                        double totWuptake = mySoilWaterTakenUp.Sum();
                        for (int layer = 0; layer < nLayers; layer++)
                        {
                            fNH4Avail[layer] = Math.Min(1.0, MathUtilities.Divide(mySoilAvailableN[layer], totNH4Available, 0.0));
                            fNO3Avail[layer] = Math.Min(1.0, MathUtilities.Divide(mySoilAvailableN[layer], totNO3Available, 0.0));
                            fWUptake[layer] = Math.Min(1.0, MathUtilities.Divide(mySoilWaterTakenUp[layer], totWuptake, 0.0));
                        }
                        double totFacNH4 = fNH4Avail.Sum() + fWUptake.Sum();
                        double totFacNO3 = fNO3Avail.Sum() + fWUptake.Sum();
                        for (int layer = 0; layer < nLayers; layer++)
                        {
                            uptakeFraction = Math.Min(1.0, MathUtilities.Divide(fNH4Avail[layer] + fWUptake[layer], totFacNH4, 0.0));
                            NUptake.DeltaNH4[layer] = -Soil.NH4N[layer] * uptakeFraction;

                            uptakeFraction = Math.Min(1.0, MathUtilities.Divide(fNO3Avail[layer] + fWUptake[layer], totFacNO3, 0.0));
                            NUptake.DeltaNO3[layer] = -Soil.NO3N[layer] * uptakeFraction;

                            mySoilNitrogenTakenUp[layer] = NUptake.DeltaNH4[layer] + NUptake.DeltaNO3[layer];
                        }
                    }

                    //mySoilUptakeN.Sum()	2.2427998752781684	double

                    if (Math.Abs(mySoilNuptake - mySoilNitrogenTakenUp.Sum()) > 0.0001)
                        throw new Exception("Error on computing N uptake");

                    // do the actual N changes
                    NitrogenChanged.Invoke(NUptake);
                }
                else
                {
                    // no uptake, just zero out the array
                    mySoilNitrogenTakenUp = new double[nLayers];
                }
            }
            else
            {
                // N uptake calculated by other modules (e.g., SWIM)
                string msg = "N uptake source was not recognised. Please specify it as either \"sward\" or \"species\".";
                throw new Exception(msg);
            }
        }
예제 #17
0
파일: Swim.cs 프로젝트: hut104/ApsimX
        /// <summary>
        /// Sets the values of solute variables from other modules
        /// </summary>
        /// <exception cref="System.Exception">
        /// -ve concentration in apswim_set_solute_variables + Environment.NewLine + mess
        /// or
        /// -ve value for solute concentration + Environment.NewLine + mess
        /// </exception>
        private void SetSoluteVariables()
        {
            //+  Purpose
            //      Set the values of solute variables from other modules

            //+  Changes
            //   21-6-96 NIH - Changed set_double_array to post construct
            //   RCichota - 26/01/2010 - Add test to make sure SWIM will not send a -ve value
            //   RCichota - 12/Jul/2010 - add simple test for -ve solution concentration

            NitrogenChangedType ndata = new NitrogenChangedType();
            double[] solute_n = new double[n + 1];     // solute concn in layers(kg/ha)
            double[] dlt_solute_s = new double[n + 1]; // solute concn in layers(kg/ha)

            // initialise the NitrogenChanged data to zero
            ndata.DeltaUrea = new double[n + 1];
            ndata.DeltaNH4 = new double[n + 1];
            ndata.DeltaNO3 = new double[n + 1];

            for (int solnum = 0; solnum < num_solutes; solnum++)
            {
                for (int node = 0; node <= n; node++)
                {
                    // Step One - calculate total solute in node from solute in
                    // water and Freundlich isotherm.

                    if (csl[solnum][node] < 0.0)
                    {
                        string mess = String.Format(" solution {0}({1,3}) = {2,12:G6}",
                                     solute_names[solnum],
                                     node,
                                     csl[solnum][node]);
                        throw new Exception("-ve concentration in apswim_set_solute_variables" + Environment.NewLine + mess);
                    }
                    double Ctot, dCtot;
                    Freundlich(node, solnum, ref csl[solnum][node], out Ctot, out dCtot);

                    // Note:- Sometimes small numerical errors can leave
                    // -ve concentrations. Test if values are within limits.

                    if (Math.Abs(Ctot) < 1e-100)
                    {
                        // Ctot is REALLY small, its value can be disregarded
                        // set to zero to avoid underflow with reals

                        Ctot = 0.0;
                    }

                    else if (Ctot < 0.0)
                    {
                        // Ctot is negative and a fatal error is thrown. Should not happen as it has been tested on apswim_freundlich
                        string mess = String.Format(" Total {0}({1,3}) = {2,12:G6}",
                                            solute_names[solnum],
                                            node,
                                            Ctot);
                        throw new Exception("-ve value for solute concentration" + Environment.NewLine + mess);
                        // Ctot = 0.0;
                    }
                    //else Ctot is positive

                    // convert solute ug/cc soil to kg/ha for node
                    //
                    //  kg      ug        cc soil      kg
                    //  -- = -------- p%x -------- p%x --
                    //  ha    cc soil        ha        ug

                    Ctot = Ctot                   // ug/cc soil
                         * (dx[node] * 1.0e8)     // cc soil/ha
                         * 1e-9;                  // kg/ug

                    // finished testing - assign value to array element
                    solute_n[node] = Ctot;
                    dlt_solute_s[node] = Ctot - cslstart[solnum][node];
                }

                // Added by RCichota - using NitrogenChanged event to modify dlt_N's
                if (solute_names[solnum] == "urea")
                    Array.Copy(dlt_solute_s, ndata.DeltaUrea, n + 1);
                else if (solute_names[solnum] == "nh4")
                    Array.Copy(dlt_solute_s, ndata.DeltaNH4, n + 1);
                else if (solute_names[solnum] == "no3")
                    Array.Copy(dlt_solute_s, ndata.DeltaNO3, n + 1);
                else
                {
                    ///// TODO:
                    /////                    string compName = paddock.SiblingNameFromId(solute_owners[solnum]);
                    /////                    My.Set(compName + ".dlt_" + solute_names[solnum], dlt_solute_s);
                }
            }

            // Send a NitrogenChanged event to the system
            ndata.Sender = "SWIM";
            ndata.SenderType = "WaterModule";
            NitrogenChanged.Invoke(ndata);
        }
예제 #18
0
        /// <summary>Sends the delta nitrogen to the soil module.</summary>
        private void DoSoilNitrogenUptake()
        {
            if ((mySoilNH4Uptake.Sum() + mySoilNO3Uptake.Sum()) > Epsilon)
            {
                NitrogenChangedType nitrogenTakenUp = new NitrogenChangedType();
                nitrogenTakenUp.Sender = Name;
                nitrogenTakenUp.SenderType = "Plant";
                nitrogenTakenUp.DeltaNO3 = new double[nLayers];
                nitrogenTakenUp.DeltaNH4 = new double[nLayers];

                for (int layer = 0; layer <= roots.BottomLayer; layer++)
                {
                    nitrogenTakenUp.DeltaNH4[layer] = -mySoilNH4Uptake[layer];
                    nitrogenTakenUp.DeltaNO3[layer] = -mySoilNO3Uptake[layer];
                }

                if (NitrogenChanged != null)
                    NitrogenChanged.Invoke(nitrogenTakenUp);
            }
        }
예제 #19
0
파일: Arbitrator.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// Send the nitrogen uptake arrays back to the plants and send the change in nitrogen back to the soil
        /// </summary>
        /// <param name="resourceToArbitrate">The resource to arbitrate.</param>
        private void SetNitrogenUptake(string resourceToArbitrate)
        {
            NitrogenChangedType NUptakeType = new NitrogenChangedType();
            NUptakeType.Sender = Name;
            NUptakeType.SenderType = "Plant";
            NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length];
            NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length];

            for (int p = 0; p < plants.Count; p++)
            {
                double[] dummyArray1 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in
                double[] dummyArray2 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in
                for (int l = 0; l < Soil.Thickness.Length; l++)
                {
                    for (int z = 0; z < zones; z++) // for now set zones is to 1
                    {
                        for (int b = 0; b < bounds; b++)
                        {
                            for (int f = 0; f < forms; f++)
                            {
                                dummyArray1[l] += uptake[p, l, z, b, f];       // add the forms together to give the total nitrogen uptake
                                if (f == 0)
                                {
                                    NUptakeType.DeltaNO3[l] += -1.0 * uptake[p, l, z, b, f];
                                    dummyArray2[l] += uptake[p, l, z, b, f];   // nitrate only uptake so can do the proportion before sending to the plant
                                }
                                else
                                {
                                    NUptakeType.DeltaNH4[l] += -1.0 * uptake[p, l, z, b, f];
                                }
                            }
                        }
                    }
                }
                // set uptakes in each plant
                plants[p].uptakeNitrogen = dummyArray1;
                for (int l = 0; l < Soil.Thickness.Length; l++)  // don't forget to deal with zones at some point
                {
                    dummyArray2[l] = MathUtilities.Divide(dummyArray2[l], dummyArray1[l], 0.0);
                }
                plants[p].uptakeNitrogenPropNO3 = dummyArray2;
            }
            // and finally set the changed soil resources
            if (NitrogenChanged != null)
                NitrogenChanged.Invoke(NUptakeType);
        }
예제 #20
0
        /// <summary>
        /// Send the nitrogen uptake arrays back to the plants and send the change in nitrogen back to the soil
        /// </summary>
        /// <param name="resourceToArbitrate"></param>
        private void SetNitrogenUptake(string resourceToArbitrate)
        {
            zones = -1;
            int maxPlants = 0;
            int maxLayers = 0;
            foreach (Zone zone in Apsim.FindAll(Simulation, typeof(Zone)))  //foreach (Zone zone in Simulation.FindAll(typeof(Zone)))
            {
                zones += 1;

                // Find plants in paddock.
                List<ICrop2> plants = zone.Plants;
                maxPlants = Math.Max(plants.Count, maxPlants);

                // Find soil in paddock.
                Soil Soil = (Soil)Apsim.Find(zone, typeof(Soil));
                maxLayers = Math.Max(Soil.Thickness.Length, maxLayers);

                double[] dummyArray1 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in
                double[] dummyArray2 = new double[Soil.Thickness.Length];  // have to create a new array for each plant to avoid the .NET pointer thing - will have to re-think this with when zones come in

                // move this inside the zone loop - needs to get zeroed for each seperate zone
                NitrogenChangedType NUptakeType = new NitrogenChangedType();
                NUptakeType.Sender = Name;
                NUptakeType.SenderType = "Plant";
                NUptakeType.DeltaNO3 = new double[Soil.Thickness.Length];
                NUptakeType.DeltaNH4 = new double[Soil.Thickness.Length];

                for (int p = 0; p < maxPlants; p++)
                {
                    for (int l = 0; l < maxLayers; l++)
                    {
                        for (int b = 0; b < bounds; b++)
                        {
                            for (int f = 0; f < forms; f++)
                            {
                                dummyArray1[l] += uptake[p, l, z, b, f];       // add the forms together to give the total nitrogen uptake
                                if (f == 0)
                                {
                                    NUptakeType.DeltaNO3[l] += -1.0 * uptake[p, l, z, b, f];
                                    dummyArray2[l] += uptake[p, l, z, b, f];   // nitrate only uptake so can do the proportion before sending to the plant
                                }
                                else
                                {
                                    NUptakeType.DeltaNH4[l] += -1.0 * uptake[p, l, z, b, f];
                                }
                            }
                        }
                    }
                    // set uptakes in each plant
                    plants[p].uptakeNitrogen = dummyArray1;
                    for (int l = 0; l < Soil.Thickness.Length; l++)  // don't forget to deal with zones at some point
                    {
                        dummyArray2[l] = MathUtilities.Divide(dummyArray2[l], dummyArray1[l], 0.0);  // would be nice to have a utility for this
                    }
                    plants[p].uptakeNitrogenPropNO3 = dummyArray2;
                }
                // and finally set the changed soil resources
                if (NitrogenChanged != null)
                    NitrogenChanged.Invoke(NUptakeType);
            }
        }