예제 #1
0
파일: SoilState.cs 프로젝트: ndb01/ApsimX
        /// <summary>Implements the operator -.</summary>
        /// <param name="state">The soil state.</param>
        /// <param name="estimate">The estimate to subtract from the soil state.</param>
        /// <returns>The result of the operator.</returns>
        public static SoilState operator -(SoilState state, Estimate estimate)
        {
            SoilState NewState = new SoilState(state.Parent);

            foreach (ZoneWaterAndN Z in state.Zones)
            {
                ZoneWaterAndN NewZ = new ZoneWaterAndN();
                NewZ.Name  = Z.Name;
                NewZ.Water = Z.Water;
                NewZ.NO3N  = Z.NO3N;
                NewZ.NH4N  = Z.NH4N;
                NewState.Zones.Add(NewZ);
            }

            foreach (CropUptakes C in estimate.Values)
            {
                foreach (ZoneWaterAndN Z in C.Zones)
                {
                    foreach (ZoneWaterAndN NewZ in NewState.Zones)
                    {
                        if (Z.Name == NewZ.Name)
                        {
                            NewZ.Water = MathUtilities.Subtract(NewZ.Water, Z.Water);
                            NewZ.NO3N  = MathUtilities.Subtract(NewZ.NO3N, Z.NO3N);
                            NewZ.NH4N  = MathUtilities.Subtract(NewZ.NH4N, Z.NH4N);
                        }
                    }
                }
            }
            return(NewState);
        }
예제 #2
0
        /// <summary>Implements the operator *.</summary>
        /// <param name="zone">The zone</param>
        /// <param name="value">The value.</param>
        /// <returns>The result of the operator.</returns>
        public static ZoneWaterAndN operator *(ZoneWaterAndN zone, double value)
        {
            ZoneWaterAndN NewZ = new ZoneWaterAndN(zone.Zone);

            NewZ.Water = MathUtilities.Multiply_Value(zone.Water, value);
            NewZ.NO3N  = MathUtilities.Multiply_Value(zone.NO3N, value);
            NewZ.NH4N  = MathUtilities.Multiply_Value(zone.NH4N, value);
            return(NewZ);
        }
예제 #3
0
 /// <summary>Implements the operator *.</summary>
 /// <param name="zone">The zone</param>
 /// <param name="value">The value.</param>
 /// <returns>The result of the operator.</returns>
 public static ZoneWaterAndN operator *(ZoneWaterAndN zone, double value)
 {
     ZoneWaterAndN NewZ = new ZoneWaterAndN();
     NewZ.Name = zone.Name;
     NewZ.Water = MathUtilities.Multiply_Value(zone.Water, value);
     NewZ.NO3N = MathUtilities.Multiply_Value(zone.NO3N, value);
     NewZ.NH4N = MathUtilities.Multiply_Value(zone.NH4N, value);
     return NewZ;
 }
예제 #4
0
        /// <summary>
        /// Constructor. Copy state from another instance.
        /// </summary>
        /// <param name="from">The instance to copy from.</param>
        public ZoneWaterAndN(ZoneWaterAndN from)
        {
            NO3Solute  = from.NO3Solute;
            NH4Solute  = from.NH4Solute;
            soilInZone = from.soilInZone;
            Zone       = from.Zone;

            Water = from.Water;
            NO3N  = from.NO3N;
            NH4N  = from.NH4N;
        }
예제 #5
0
 /// <summary>Implements the operator +.</summary>
 /// <param name="zone1">Zone 1</param>
 /// <param name="zone2">Zone 2</param>
 /// <returns>The result of the operator.</returns>
 /// <exception cref="System.Exception">Cannot add zones with different names</exception>
 public static ZoneWaterAndN operator +(ZoneWaterAndN zone1, ZoneWaterAndN zone2)
 {
     if (zone1.Name != zone2.Name)
         throw new Exception("Cannot add zones with different names");
     ZoneWaterAndN NewZ = new ZoneWaterAndN();
     NewZ.Name = zone1.Name;
     NewZ.Water = MathUtilities.Add(zone1.Water, zone2.Water);
     NewZ.NO3N = MathUtilities.Add(zone1.NO3N, zone2.NO3N);
     NewZ.NH4N = MathUtilities.Add(zone1.NH4N, zone2.NH4N);
     return NewZ;
 }
예제 #6
0
파일: SoilState.cs 프로젝트: ndb01/ApsimX
 /// <summary>Initialises this instance.</summary>
 public void Initialise()
 {
     foreach (Zone Z in Apsim.Children(this.Parent, typeof(Zone)))
     {
         ZoneWaterAndN NewZ = new ZoneWaterAndN();
         NewZ.Name = Z.Name;
         Soil soil = Apsim.Child(Z, typeof(Soil)) as Soil;
         NewZ.Water = soil.Water;
         NewZ.NO3N  = soil.NO3N;
         NewZ.NH4N  = soil.NH4N;
         Zones.Add(NewZ);
     }
 }
예제 #7
0
        /// <summary>Implements the operator -.</summary>
        /// <param name="ZWN1">Zone 1</param>
        /// <param name="ZWN2">Zone 2</param>
        /// <returns>The result of the operator.</returns>
        /// <exception cref="System.Exception">Cannot subtract zones with different names</exception>
        public static ZoneWaterAndN operator -(ZoneWaterAndN ZWN1, ZoneWaterAndN ZWN2)
        {
            if (ZWN1.Zone.Name != ZWN2.Zone.Name)
            {
                throw new Exception("Cannot subtract zones with different names");
            }
            ZoneWaterAndN NewZ = new ZoneWaterAndN(ZWN1.Zone);

            NewZ.Water = MathUtilities.Subtract(ZWN1.Water, ZWN2.Water);
            NewZ.NO3N  = MathUtilities.Subtract(ZWN1.NO3N, ZWN2.NO3N);
            NewZ.NH4N  = MathUtilities.Subtract(ZWN1.NH4N, ZWN2.NH4N);
            return(NewZ);
        }
예제 #8
0
        /// <summary>Implements the operator -.</summary>
        /// <param name="zone1">Zone 1</param>
        /// <param name="zone2">Zone 2</param>
        /// <returns>The result of the operator.</returns>
        /// <exception cref="System.Exception">Cannot subtract zones with different names</exception>
        public static ZoneWaterAndN operator -(ZoneWaterAndN zone1, ZoneWaterAndN zone2)
        {
            if (zone1.Name != zone2.Name)
            {
                throw new Exception("Cannot subtract zones with different names");
            }
            ZoneWaterAndN NewZ = new ZoneWaterAndN();

            NewZ.Name  = zone1.Name;
            NewZ.Water = MathUtilities.Subtract(zone1.Water, zone2.Water);
            NewZ.NO3N  = MathUtilities.Subtract(zone1.NO3N, zone2.NO3N);
            NewZ.NH4N  = MathUtilities.Subtract(zone1.NH4N, zone2.NH4N);
            return(NewZ);
        }
예제 #9
0
        /// <summary>Implements the operator +.</summary>
        /// <param name="ZWN1">Zone 1</param>
        /// <param name="ZWN2">Zone 2</param>
        /// <returns>The result of the operator.</returns>
        /// <exception cref="System.Exception">Cannot add zones with different names</exception>
        public static ZoneWaterAndN operator +(ZoneWaterAndN ZWN1, ZoneWaterAndN ZWN2)
        {
            if (ZWN1.Zone.Name != ZWN2.Zone.Name)
            {
                throw new Exception("Cannot add zones with different names");
            }
            ZoneWaterAndN NewZ = new ZoneWaterAndN(ZWN1);

            NewZ.Water = MathUtilities.Add(ZWN1.Water, ZWN2.Water);
            NewZ.NO3N  = MathUtilities.Add(ZWN1.NO3N, ZWN2.NO3N);
            NewZ.NH4N  = MathUtilities.Add(ZWN1.NH4N, ZWN2.NH4N);
            NewZ.PlantAvailableNO3N = MathUtilities.Add(ZWN1.PlantAvailableNO3N, ZWN2.PlantAvailableNO3N);
            NewZ.PlantAvailableNH4N = MathUtilities.Add(ZWN1.PlantAvailableNH4N, ZWN2.PlantAvailableNH4N);
            return(NewZ);
        }
예제 #10
0
 /// <summary>Initialises this instance.</summary>
 public void Initialise()
 {
     foreach (Zone Z in Apsim.ChildrenRecursively(this.Parent, typeof(Zone)))
     {
         Soil soil = Apsim.Child(Z, typeof(Soil)) as Soil;
         if (soil != null)
         {
             ZoneWaterAndN NewZ = new ZoneWaterAndN(Z);
             NewZ.Water = soil.Water;
             NewZ.NO3N  = soil.NO3N;
             NewZ.NH4N  = soil.NH4N;
             Zones.Add(NewZ);
         }
     }
 }
예제 #11
0
 /// <summary>Initialises this instance.</summary>
 public void Initialise(List <IModel> zones)
 {
     foreach (Zone Z in zones)
     {
         Soil soil = Apsim.Child(Z, typeof(Soil)) as Soil;
         if (soil != null)
         {
             ZoneWaterAndN NewZ = new ZoneWaterAndN(Z);
             NewZ.Water = soil.Water;
             NewZ.NO3N  = soil.NO3N;
             NewZ.NH4N  = soil.NH4N;
             Zones.Add(NewZ);
         }
     }
 }
예제 #12
0
파일: Estimate.cs 프로젝트: pre078/ApsimX
        /// <summary>Implements the operator *.</summary>
        /// <param name="E">The estimate</param>
        /// <param name="value">The value to multiply the estimate by.</param>
        /// <returns>The resulting estimate</returns>
        public static Estimate operator *(Estimate E, double value)
        {
            Estimate NewE = new Estimate(E.Parent);

            foreach (CropUptakes U in E.Values)
            {
                CropUptakes NewU = new CropUptakes();
                NewE.Values.Add(NewU);
                foreach (ZoneWaterAndN Z in U.Zones)
                {
                    ZoneWaterAndN NewZ = Z * value;
                    NewU.Zones.Add(NewZ);
                }
            }

            return(NewE);
        }
예제 #13
0
        /// <summary>
        /// General soil arbitration method (water or nutrients) based upon Runge-Kutta method
        /// </summary>
        /// <param name="arbitrationType">Water or Nitrogen</param>
        private void DoArbitration(Estimate.CalcType arbitrationType)
        {
            SoilState InitialSoilState = new SoilState(this.Parent);

            InitialSoilState.Initialise(zones);

            Estimate UptakeEstimate1 = new Estimate(this.Parent, arbitrationType, InitialSoilState, uptakeModels);
            Estimate UptakeEstimate2 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate1 * 0.5, uptakeModels);
            Estimate UptakeEstimate3 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate2 * 0.5, uptakeModels);
            Estimate UptakeEstimate4 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate3, uptakeModels);

            List <ZoneWaterAndN> listOfZoneUptakes = new List <ZoneWaterAndN>();
            List <CropUptakes>   ActualUptakes     = new List <CropUptakes>();

            foreach (CropUptakes U in UptakeEstimate1.Values)
            {
                CropUptakes CU = new CropUptakes();
                CU.Crop = U.Crop;
                foreach (ZoneWaterAndN ZU in U.Zones)
                {
                    ZoneWaterAndN NewZone = UptakeEstimate1.UptakeZone(CU.Crop, ZU.Zone.Name) * (1.0 / 6.0)
                                            + UptakeEstimate2.UptakeZone(CU.Crop, ZU.Zone.Name) * (1.0 / 3.0)
                                            + UptakeEstimate3.UptakeZone(CU.Crop, ZU.Zone.Name) * (1.0 / 3.0)
                                            + UptakeEstimate4.UptakeZone(CU.Crop, ZU.Zone.Name) * (1.0 / 6.0);
                    CU.Zones.Add(NewZone);
                    listOfZoneUptakes.Add(NewZone);
                }

                ActualUptakes.Add(CU);
            }

            ScaleWaterAndNIfNecessary(InitialSoilState.Zones, listOfZoneUptakes);

            foreach (CropUptakes Uptake in ActualUptakes)
            {
                if (arbitrationType == Estimate.CalcType.Water)
                {
                    Uptake.Crop.SetActualWaterUptake(Uptake.Zones);
                }
                else
                {
                    Uptake.Crop.SetActualNitrogenUptakes(Uptake.Zones);
                }
            }
        }
예제 #14
0
        /// <summary>
        /// General soil arbitration method (water or nutrients) based upon Runge-Kutta method
        /// </summary>
        /// <param name="arbitrationType">Water or Nitrogen</param>
        private void DoArbitration(Estimate.CalcType arbitrationType)
        {
            SoilState InitialSoilState = new SoilState(this.Parent);

            InitialSoilState.Initialise(zones);

            Estimate UptakeEstimate1 = new Estimate(this.Parent, arbitrationType, InitialSoilState, uptakeModels);
            Estimate UptakeEstimate2 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate1 * 0.5, uptakeModels);
            Estimate UptakeEstimate3 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate2 * 0.5, uptakeModels);
            Estimate UptakeEstimate4 = new Estimate(this.Parent, arbitrationType, InitialSoilState - UptakeEstimate3, uptakeModels);

            List <ZoneWaterAndN> listOfZoneWaterAndNs = new List <ZoneWaterAndN>();
            List <CropUptakes>   UptakesFinal         = new List <CropUptakes>();

            foreach (CropUptakes U in UptakeEstimate1.Values)
            {
                CropUptakes CWU = new CropUptakes();
                CWU.Crop = U.Crop;
                foreach (ZoneWaterAndN ZW1 in U.Zones)
                {
                    ZoneWaterAndN NewZ = UptakeEstimate1.UptakeZone(CWU.Crop, ZW1.Zone.Name) * (1.0 / 6.0)
                                         + UptakeEstimate2.UptakeZone(CWU.Crop, ZW1.Zone.Name) * (1.0 / 3.0)
                                         + UptakeEstimate3.UptakeZone(CWU.Crop, ZW1.Zone.Name) * (1.0 / 3.0)
                                         + UptakeEstimate4.UptakeZone(CWU.Crop, ZW1.Zone.Name) * (1.0 / 6.0);
                    CWU.Zones.Add(NewZ);
                    listOfZoneWaterAndNs.Add(NewZ);
                }

                UptakesFinal.Add(CWU);
            }

            ScaleWaterAndNIfNecessary(InitialSoilState.Zones, listOfZoneWaterAndNs);

            foreach (CropUptakes Uptake in UptakesFinal)
            {
                if (arbitrationType == Estimate.CalcType.Water)
                {
                    Uptake.Crop.SetSWUptake(Uptake.Zones);
                }
                else
                {
                    Uptake.Crop.SetNUptake(Uptake.Zones);
                }
            }
        }
예제 #15
0
        /// <summary>Implements the operator -.</summary>
        /// <param name="state">The soil state.</param>
        /// <param name="estimate">The estimate to subtract from the soil state.</param>
        /// <returns>The result of the operator.</returns>
        public static SoilState operator -(SoilState state, Estimate estimate)
        {
            SoilState NewState = new SoilState(state.Parent);
            foreach (ZoneWaterAndN Z in state.Zones)
            {
                ZoneWaterAndN NewZ = new ZoneWaterAndN();
                NewZ.Name = Z.Name;
                NewZ.Water = Z.Water;
                NewZ.NO3N = Z.NO3N;
                NewZ.NH4N = Z.NH4N;
                NewState.Zones.Add(NewZ);
            }

            foreach (CropUptakes C in estimate.Values)
                foreach (ZoneWaterAndN Z in C.Zones)
                    foreach (ZoneWaterAndN NewZ in NewState.Zones)
                        if (Z.Name == NewZ.Name)
                        {
                            NewZ.Water = MathUtilities.Subtract(NewZ.Water, Z.Water);
                            NewZ.NO3N = MathUtilities.Subtract(NewZ.NO3N, Z.NO3N);
                            NewZ.NH4N = MathUtilities.Subtract(NewZ.NH4N, Z.NH4N);
                        }
            return NewState;
        }
예제 #16
0
        /// <summary>Estimates the amount of plant available nitrogen in each soil layer of the root zone.</summary>
        /// <remarks>
        /// This method considers soil water as the main factor controlling N availability/uptake.
        /// Availability is given by the proportion of water taken up in each layer, further modified by uptake factors
        /// Uptake is caped for a maximum value plants can take in one day.
        /// </remarks>
        /// <param name="myZone">Soil information</param>
        private void PlantAvailableSoilNAlternativeWup(ZoneWaterAndN myZone)
        {
            double layerFrac; // the fraction of layer within the root zone
            double swuFac;  // the soil water factor
            double potAvailableN; // potential available N
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                swuFac = MathUtilities.Divide(mySoilWaterUptake[layer], myZone.Water[layer], 0.0);

                // get NH4 available
                potAvailableN = myZone.NH4N[layer] * layerFrac;
                mySoilNH4Available[layer] = potAvailableN * Math.Min(1.0, swuFac * kuNH4);

                // get NO3 available
                potAvailableN = myZone.NO3N[layer] * layerFrac;
                mySoilNO3Available[layer] = potAvailableN * Math.Min(1.0, swuFac * kuNO3);
            }

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > MaximumNUptake)
            {
                double upFraction = MaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= roots.BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
예제 #17
0
 /// <summary>Estimates the amount of plant available nitrogen in each soil layer of the root zone.</summary>
 /// <remarks>This is a basic method, used as default in old AgPasture, all N in the root zone is available</remarks>
 /// <param name="myZone">Soil information</param>
 private void PlantAvailableSoilNBasicAgPasture(ZoneWaterAndN myZone)
 {
     double layerFrac; // the fraction of layer within the root zone
     for (int layer = 0; layer <= roots.BottomLayer; layer++)
     {
         layerFrac = FractionLayerWithRoots(layer);
         mySoilNH4Available[layer] = myZone.NH4N[layer] * layerFrac;
         mySoilNO3Available[layer] = myZone.NO3N[layer] * layerFrac;
     }
 }
예제 #18
0
        /// <summary>Performs the nitrogen uptake calculations.</summary>
        private void DoNitrogenCalculations()
        {
            if (myNUptakeSource.ToLower() == "sward")
            {
                // Pack the soil information
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                myZone.Name = this.Parent.Name;
                myZone.Water = mySoil.Water;
                myZone.NO3N = mySoil.NO3N;
                myZone.NH4N = mySoil.NH4N;

                // Get the N amount available in the soil
                GetSoilAvailableN(myZone);

                foreach (PastureSpecies species in mySpecies)
                {
                    // Get the N amount fixed through symbiosis
                    species.EvaluateNitrogenFixation();

                    // Evaluate the use of N remobilised and get N amount demanded from soil
                    species.EvaluateSoilNitrogenDemand();

                    // Get N amount taken up from the soil
                    species.EvaluateSoilNitrogenUptake();
                    for (int layer = 0; layer < RootFrontier; layer++)
                    {
                        swardSoilNH4Uptake[layer] += species.SoilNH4Uptake[layer];
                        swardSoilNO3Uptake[layer] += species.SoilNO3Uptake[layer];
                    }

                    // Evaluate whether remobilisation of luxury N is needed
                    species.EvaluateNLuxuryRemobilisation();
                }

                // Send delta N to the soil model
                DoSoilNitrogenUptake();
            }
            else
            {
                //N uptake is controlled at species level, get sward totals
                for (int layer = 0; layer < RootFrontier; layer++)
                {
                    foreach (PastureSpecies species in mySpecies)
                    {
                        swardSoilNH4Available[layer] += species.SoilNH4Available[layer];
                        swardSoilNO3Available[layer] += species.SoilNO3Available[layer];
                        swardSoilNH4Uptake[layer] += species.SoilNH4Uptake[layer];
                        swardSoilNO3Uptake[layer] += species.SoilNO3Uptake[layer];
                    }
                }

                // Send delta N to the soil model
                DoSoilNitrogenUptake();
            }
        }
예제 #19
0
        /// <summary>Estimates the amount of plant available nitrogen in each soil layer of the root zone.</summary>
        /// <remarks>
        /// This method considers soil water status and root length density to define factors controlling N availability.
        /// Soil water stauts is used to define a factor that varies from zero at LL, below which no uptake can happen, 
        ///  to one at DUL, above which no restrictions to uptake exist.
        /// Root length density is used to define a factor varying from zero if there are no roots to one when root length
        ///  density is equal to a ReferenceRLD, above which there are no restrictions for uptake.
        /// Factors for each N form can also alter the amount available.
        /// Uptake is caped for a maximum value plants can take in one day.
        /// </remarks>
        /// <param name="myZone">Soil information</param>
        private void PlantAvailableSoilNAlternativeRLD(ZoneWaterAndN myZone)
        {
            double layerFrac; // the fraction of layer within the root zone
            double swFac;  // the soil water factor
            double rldFac;  // the root density factor
            double potAvailableN; // potential available N
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                rldFac = Math.Min(1.0, MathUtilities.Divide(RLD[layer], ReferenceRLD, 1.0));
                if (myZone.Water[layer] >= mySoil.SoilWater.DULmm[layer])
                    swFac = 1.0;
                else if (myZone.Water[layer] <= mySoil.SoilWater.LL15mm[layer])
                    swFac = 0.0;
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.SoilWater.LL15mm[layer]) /
                                        (mySoil.SoilWater.DULmm[layer] - mySoil.SoilWater.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, ExponentSoilMoisture);
                }

                // get NH4 available
                potAvailableN = myZone.NH4N[layer] * layerFrac;
                mySoilNH4Available[layer] = potAvailableN * Math.Min(1.0, swFac * rldFac * kuNH4);

                // get NO3 available
                potAvailableN = myZone.NO3N[layer] * layerFrac;
                mySoilNO3Available[layer] = potAvailableN * Math.Min(1.0, swFac * rldFac * kuNO3);
            }

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > MaximumNUptake)
            {
                double upFraction = MaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= roots.BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
예제 #20
0
        /// <summary>
        /// Calculate the potential sw uptake for today. Should return null if crop is not in the ground.
        /// </summary>
        public List<Soils.Arbitrator.ZoneWaterAndN> GetNUptakes(SoilState soilstate)
        {
            if (Plant.IsAlive)
            {
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    ZoneWaterAndN UptakeDemands = new ZoneWaterAndN();
                    if (Plant.Phenology != null)
                    {
                        if (Plant.Phenology.Emerged == true)
                        {
                            DoPotentialNutrientUptake(ref N, zone);  //Work out how much N the uptaking organs (roots) would take up in the absence of competition

                            //Pack results into uptake structure
                            UptakeDemands.NO3N = PotentialNO3NUptake;
                            UptakeDemands.NH4N = PotentialNH4NUptake;
                        }
                        else //Uptakes are zero
                        {
                            UptakeDemands.NO3N = new double[zone.NO3N.Length];
                            for (int i = 0; i < UptakeDemands.NO3N.Length; i++) { UptakeDemands.NO3N[i] = 0; }
                            UptakeDemands.NH4N = new double[zone.NH4N.Length];
                            for (int i = 0; i < UptakeDemands.NH4N.Length; i++) { UptakeDemands.NH4N[i] = 0; }
                        }
                    }
                    else
                    {
                        DoPotentialNutrientUptake(ref N, zone);  //Work out how much N the uptaking organs (roots) would take up in the absence of competition

                        //Pack results into uptake structure
                        UptakeDemands.NO3N = PotentialNO3NUptake;
                        UptakeDemands.NH4N = PotentialNH4NUptake;
                    }

                    UptakeDemands.Name = zone.Name;
                    UptakeDemands.Water = new double[UptakeDemands.NO3N.Length];

                    List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>();
                    zones.Add(UptakeDemands);
                    return zones;
                }
            }

            return null;
        }
예제 #21
0
        /// <summary>Does the uptake from the specified zone.</summary>
        /// <param name="BAT">The bat.</param>
        /// <param name="MyZone">The zone.</param>
        public virtual void DoPotentialNutrientUptake(ref BiomassArbitrationType BAT, ZoneWaterAndN MyZone)
        {
            PotentialNO3NUptake = new double[MyZone.NO3N.Length];
            PotentialNH4NUptake = new double[MyZone.NH4N.Length];

            //Get Nuptake supply from each organ and set the PotentialUptake parameters that are passed to the soil arbitrator
            for (int i = 0; i < Organs.Length; i++)
            {
                double[] organNO3Supply;
                double[] organNH4Supply;

                Organs[i].CalcNSupply(MyZone, out organNO3Supply, out organNH4Supply);

                if (organNO3Supply != null)
                {
                    PotentialNO3NUptake = MathUtilities.Add(PotentialNO3NUptake, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator
                    BAT.UptakeSupply[i] = MathUtilities.Sum(organNO3Supply) * kgha2gsm;    //Populate uptakeSupply for each organ for internal allocation routines
                }

                if (organNH4Supply != null)
                {
                    PotentialNH4NUptake = MathUtilities.Add(PotentialNH4NUptake, organNH4Supply);
                    BAT.UptakeSupply[i] += MathUtilities.Sum(organNH4Supply) * kgha2gsm;
                }
            }

            //Calculate plant level supply totals.
            BAT.TotalUptakeSupply = MathUtilities.Sum(BAT.UptakeSupply);
            BAT.TotalPlantSupply = BAT.TotalReallocationSupply + BAT.TotalUptakeSupply + BAT.TotalFixationSupply + BAT.TotalRetranslocationSupply;

            //If NUsupply is greater than uptake (total demand - reallocatio nsupply) reduce the PotentialUptakes that we pass to the soil arbitrator
            if (BAT.TotalUptakeSupply > (BAT.TotalPlantDemand - BAT.TotalReallocation))
            {
                double ratio = Math.Min(1.0, (BAT.TotalPlantDemand - BAT.TotalReallocation) / BAT.TotalUptakeSupply);
                PotentialNO3NUptake = MathUtilities.Multiply_Value(PotentialNO3NUptake, ratio);
                PotentialNH4NUptake = MathUtilities.Multiply_Value(PotentialNH4NUptake, ratio);
            }
        }
예제 #22
0
        /// <summary>Estimates the amount of plant available water in each soil layer of the root zone.</summary>
        /// <remarks>
        /// This is an alternative method, which does not use kl. A factor based on Ksat is used instead. This is further modified
        ///  by soil water content and a plant related factor, defined based on root length density. All three factors are normalised 
        ///  (using ReferenceKSat and ReferenceRLD for KSat and root and DUL for soil water content). The effect of all factors are
        ///  assumed to vary between zero and one following exponential functions, such that the effect is 90% at the reference value.
        /// </remarks>
        /// <param name="myZone">Soil information</param>
        /// <returns>Amount of available water (mm)</returns>
        private double[] PlantAvailableSoilWaterAlternativeKS(ZoneWaterAndN myZone)
        {
            double[] result = new double[nLayers];
            double condFac = 0.0;
            double rldFac = 0.0;
            double swFac = 0.0;
            SoilCrop soilCropData = (SoilCrop)mySoil.Crop(Name);
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                condFac = 1.0 - Math.Pow(10, -mySoil.KS[layer] / ReferenceKSuptake);
                rldFac = 1.0 - Math.Pow(10, -RLD[layer] / ReferenceRLD);
                if (mySoil.SoilWater.SWmm[layer] >= mySoil.SoilWater.DULmm[layer])
                    swFac = 1.0;
                else if (mySoil.SoilWater.SWmm[layer] <= mySoil.SoilWater.LL15mm[layer])
                    swFac = 0.0;
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.SoilWater.LL15mm[layer]) /
                                        (mySoil.SoilWater.DULmm[layer] - mySoil.SoilWater.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, ExponentSoilMoisture);
                }

                // Theoretical total available water
                result[layer] = Math.Max(0.0, myZone.Water[layer] - soilCropData.LL[layer]) * mySoil.Thickness[layer];

                // Actual available water
                result[layer] *= FractionLayerWithRoots(layer) * rldFac * condFac * swFac;
            }

            return result;
        }
예제 #23
0
파일: Plant15.cs 프로젝트: hol353/ApsimX
        /// <summary>Placeholder for SoilArbitrator</summary>
        /// <param name="soilstate">soil state</param>
        /// <returns></returns>
        public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate)
        {
            if (IsAlive)
            {
                List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();
                ZoneWaterAndN Uptake = new ZoneWaterAndN();

                ZoneWaterAndN MyZone = new ZoneWaterAndN();
                foreach (ZoneWaterAndN Z in soilstate.Zones)
                    if (Z.Name == this.Parent.Name)
                        MyZone = Z;

                double[] NO3N = MyZone.NO3N;
                double[] NH4N = MyZone.NH4N;

                double[] NO3NUp = new double[NO3N.Length];
                double[] NH4NUp = new double[NH4N.Length];

                Root.CalculateNUptake(NO3N, NH4N, ref NO3NUp, ref NH4NUp);
                Uptake.NO3N = NO3NUp;
                Uptake.NH4N = NH4NUp;
                Uptake.Water = new double[NO3N.Length];
                Uptake.Name = this.Parent.Name;

                Uptakes.Add(Uptake);
                return Uptakes;
            }
            else
                return null;
        }
예제 #24
0
        /// <summary>
        /// Returns soil Nitrogen uptake from each zone by the static tree model
        /// </summary>
        /// <param name="soilstate"></param>
        /// <returns></returns>
        public List<Soils.Arbitrator.ZoneWaterAndN> GetNUptakes(Soils.Arbitrator.SoilState soilstate)
        {
            List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();

            foreach (ZoneWaterAndN Z in soilstate.Zones)
            {
                foreach (ZoneInfo ZI in ZoneInfoList)
                {
                    if (Z.Name == ZI.zone.Name)
                    {
                        ZoneWaterAndN Uptake = new ZoneWaterAndN();
                        //Find the soil for this zone
                        Zone ThisZone = new Zone();
                        Soils.Soil ThisSoil = new Soils.Soil();

                        foreach (Zone SearchZ in Apsim.ChildrenRecursively(Parent, typeof(Zone)))
                            if (SearchZ.Name == Z.Name)
                                ThisSoil = Apsim.Find(SearchZ, typeof(Soils.Soil)) as Soils.Soil;

                        Uptake.Name = Z.Name;
                        double[] SW = Z.Water;
                        Uptake.NO3N = new double[SW.Length];
                        Uptake.NH4N = new double[SW.Length];
                        Uptake.Water = new double[SW.Length];
                        //for (int i = 0; i <= SW.Length-1; i++)
                        //    Uptake.NO3N[i] = Z.NO3N[i] * ZI.RLD[i];

                        Uptakes.Add(Uptake);
                    }
                }
            }
            return Uptakes;
        }
예제 #25
0
        /// <summary>Estimates the amount of plant available nitrogen in each soil layer of the root zone.</summary>
        /// <remarks>
        /// This method approximates the default approach in APSIM plants (method 3 in Plant1 models)
        /// Soil water status and uptake coefficient control the availability, which is a square function of N content.
        /// Uptake is capped for a maximum value plants can take in one day.
        /// </remarks>
        /// <param name="myZone">Soil information</param>
        private void PlantAvailableSoilNDefaultAPSIM(ZoneWaterAndN myZone)
        {
            double layerFrac; // the fraction of layer within the root zone
            double swFac;  // the soil water factor
            double bdFac;  // the soil density factor
            double potAvailableN; // potential available N
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                bdFac = 100.0 / (mySoil.Thickness[layer] * mySoil.BD[layer]);
                if (myZone.Water[layer] >= mySoil.SoilWater.DULmm[layer])
                    swFac = 1.0;
                else if (myZone.Water[layer] <= mySoil.SoilWater.LL15mm[layer])
                    swFac = 0.0;
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.SoilWater.LL15mm[layer]) /
                                        (mySoil.SoilWater.DULmm[layer] - mySoil.SoilWater.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, ExponentSoilMoisture);
                }

                // get NH4 available
                potAvailableN = Math.Pow(myZone.NH4N[layer] * layerFrac, 2.0) * swFac * bdFac * KNH4;
                mySoilNH4Available[layer] = Math.Min(myZone.NH4N[layer] * layerFrac, potAvailableN);

                // get NO3 available
                potAvailableN = Math.Pow(myZone.NO3N[layer] * layerFrac, 2.0) * swFac * bdFac * KNO3;
                mySoilNO3Available[layer] = Math.Min(myZone.NO3N[layer] * layerFrac, potAvailableN);
            }

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > MaximumNUptake)
            {
                double upFraction = MaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= roots.BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
예제 #26
0
파일: SimpleTree.cs 프로젝트: hol353/ApsimX
        /// <summary>Placeholder for SoilArbitrator</summary>
        /// <param name="soilstate">soil state</param>
        /// <returns></returns>
        public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate)
        {
            ZoneWaterAndN MyZone = new ZoneWaterAndN();
            foreach (ZoneWaterAndN Z in soilstate.Zones)
                if (Z.Name == this.Parent.Name)
                    MyZone = Z;

            double[] PotNO3Uptake = new double[Soil.NO3N.Length];
            double[] PotNH4Uptake = new double[Soil.NH4N.Length];
            NO3Uptake = new double[Soil.NO3N.Length];
            NH4Uptake = new double[Soil.NH4N.Length];

            SoilCrop soilCrop = Soil.Crop(this.Name) as SoilCrop;

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
            {
                PotNO3Uptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * MyZone.NO3N[j]);
                PotNH4Uptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * MyZone.NH4N[j]);
            }
            double TotPotNUptake = MathUtilities.Sum(PotNO3Uptake) + MathUtilities.Sum(PotNH4Uptake);

            for (int j = 0; j < Soil.NO3N.Length; j++)
            {
                NO3Uptake[j] = PotNO3Uptake[j] * Math.Min(1.0, NDemand / TotPotNUptake);
                NH4Uptake[j] = PotNH4Uptake[j] * Math.Min(1.0, NDemand / TotPotNUptake);
            }
            List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();
            ZoneWaterAndN Uptake = new ZoneWaterAndN();

            Uptake.Name = this.Parent.Name;
            Uptake.NO3N = NO3Uptake;
            Uptake.NH4N = NH4Uptake;
            Uptake.Water = new double[NO3Uptake.Length];
            Uptakes.Add(Uptake);
            return Uptakes;
        }
예제 #27
0
파일: SimpleTree.cs 프로젝트: hol353/ApsimX
        /// <summary>Calculate the potential sw uptake for today</summary>
        /// <param name="soilstate"></param>
        /// <returns>list of uptakes</returns>
        /// <exception cref="ApsimXException">Could not find root zone in Zone  + this.Parent.Name +  for SimpleTree</exception>
        public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate)
        {
            ZoneWaterAndN MyZone = new ZoneWaterAndN();
            foreach (ZoneWaterAndN Z in soilstate.Zones)
                if (Z.Name == this.Parent.Name)
                    MyZone = Z;

            double[] PotSWUptake = new double[Soil.LL15.Length];
            SWUptake = new double[Soil.LL15.Length];

            SoilCrop soilCrop = Soil.Crop(this.Name) as SoilCrop;

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
                PotSWUptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * (MyZone.Water[j] - Soil.SoilWater.LL15mm[j]));

            double TotPotSWUptake = MathUtilities.Sum(PotSWUptake);

            for (int j = 0; j < Soil.SoilWater.LL15mm.Length; j++)
                SWUptake[j] = PotSWUptake[j] * Math.Min(1.0, PotentialEP / TotPotSWUptake);

            List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();
            ZoneWaterAndN Uptake = new ZoneWaterAndN();

            Uptake.Name = this.Parent.Name;
            Uptake.Water = SWUptake;
            Uptake.NO3N = new double[SWUptake.Length];
            Uptake.NH4N = new double[SWUptake.Length];
            Uptakes.Add(Uptake);
            return Uptakes;
        }
예제 #28
0
        /// <summary>Performs the water uptake calculations.</summary>
        private void DoWaterCalculations()
        {
            if (myWaterUptakeSource == "sward")
            {
                // Pack the soil information
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                myZone.Name = this.Parent.Name;
                myZone.Water = mySoil.Water;
                myZone.NO3N = mySoil.NO3N;
                myZone.NH4N = mySoil.NH4N;

                // Get the amount of soil available water
                GetSoilAvailableWater(myZone);

                // Water demand computed by MicroClimate

                // Get the amount of water taken up
                GetSoilWaterUptake();

                // Send the delta water to soil water module
                DoSoilWaterUptake();
            }
            else
            {
                //water uptake is controlled at species level, get sward totals
                for (int layer = 0; layer <= RootFrontier; layer++)
                {
                    foreach (PastureSpecies species in mySpecies)
                    {
                        swardSoilWaterAvailable[layer] += species.SoilAvailableWater[layer];
                        swardSoilWaterUptake[layer] += species.WaterUptake[layer];
                    }
                }

                // Send the delta water to soil water module
                DoSoilWaterUptake();
            }
        }
예제 #29
0
        /// <summary>Finds out the amount of plant available water in the soil, consider all species.</summary>
        /// <param name="myZone">Soil information</param>
        private void GetSoilAvailableWater(ZoneWaterAndN myZone)
        {
            double totalPlantWater;
            double totalSoilWater;
            double maxPlantWater = 0.0;
            double waterFraction = 1.0;
            double layerFraction = 1.0;

            // Get the water available as seen by each species
            foreach (PastureSpecies species in mySpecies)
               species.EvaluateSoilWaterAvailable(myZone);

            // Evaluate the available water for whole sward and adjust availability for each species if needed
            for (int layer = 0; layer <= RootFrontier; layer++)
            {
                // Get total as seen by each species
                totalPlantWater = 0.0;
                if (layer == RootFrontier) layerFraction = 0.0;
                foreach (PastureSpecies species in mySpecies)
                {
                    totalPlantWater += species.SoilAvailableWater[layer];
                    maxPlantWater = Math.Max(maxPlantWater, species.SoilAvailableWater[layer]);
                    if (layer == RootFrontier)
                        layerFraction = Math.Max(layerFraction, species.FractionLayerWithRoots(layer));
                }

                // Get total in the soil
                totalSoilWater = Math.Max(0.0, myZone.Water[layer] - mySoil.SoilWater.LL15mm[layer]) * layerFraction;
                totalSoilWater = Math.Max(totalSoilWater, maxPlantWater); //allows for a plant to uptake below LL15

                // Sward total is the minimum of the two totals
                swardSoilWaterAvailable[layer] = Math.Min(totalPlantWater, totalSoilWater);
                if (totalPlantWater > totalSoilWater)
                {
                    // adjust the water available for each species
                    waterFraction = MathUtilities.Divide(totalSoilWater, totalPlantWater, 0.0);
                    foreach (PastureSpecies species in mySpecies)
                        species.UpdateAvailableWater(waterFraction);
                }
            }
        }
예제 #30
0
        /// <summary>Finds out the amount of plant available nitrogen (NH4 and NO3) in the soil, consider all species.</summary>
        /// <param name="myZone">Soil information</param>
        private void GetSoilAvailableN(ZoneWaterAndN myZone)
        {
            double totalSoilNH4;
            double totalSoilNO3;
            double totalPlantNH4;
            double totalPlantNO3;
            double nh4Fraction = 1.0;
            double no3Fraction = 1.0;
            double layerFraction = 1.0;

            // Get the N available as seen by each species
            foreach (PastureSpecies species in mySpecies)
                species.EvaluateSoilNitrogenAvailable(myZone);

            // Evaluate the available N for whole sward and adjust availability for each species if needed
                for (int layer = 0; layer <= RootFrontier; layer++)
            {
                // Get total as seen by each species
                totalPlantNH4 = 0.0;
                totalPlantNO3 = 0.0;
                if (layer == RootFrontier) layerFraction = 0.0;
                    foreach (PastureSpecies species in mySpecies)
                {
                    totalPlantNH4 += species.SoilNH4Available[layer];
                    totalPlantNO3 += species.SoilNO3Available[layer];
                    if (layer == RootFrontier)
                        layerFraction = Math.Max(layerFraction, species.FractionLayerWithRoots(layer));
                }

                // Get total in the soil
                totalSoilNH4 = myZone.NH4N[layer] * layerFraction;
                totalSoilNO3 = myZone.NO3N[layer] * layerFraction;

                // Sward total is the minimum of the two totals
                swardSoilNH4Available[layer] = Math.Min(totalPlantNH4, totalSoilNH4);
                swardSoilNO3Available[layer] = Math.Min(totalPlantNO3, totalSoilNO3);
                if ((totalPlantNH4 > totalSoilNH4) || (totalPlantNO3 > totalSoilNO3))
                {
                    // adjust the N available for each species
                    nh4Fraction = Math.Min(1.0, MathUtilities.Divide(totalSoilNH4, totalPlantNH4, 0.0));
                    no3Fraction = Math.Min(1.0, MathUtilities.Divide(totalSoilNO3, totalPlantNO3, 0.0));
                    foreach (PastureSpecies species in mySpecies)
                    {
                        species.UpdateAvailableNitrogen(nh4Fraction, no3Fraction);
                    }
                }
            }
        }
예제 #31
0
        /// <summary>Estimates the amount of plant available  water in each soil layer of the root zone.</summary>
        /// <remarks>
        /// This is an alternative method, kl representing a soil limiting factor for water extraction (clayey soils have lower values)
        ///  this is further modiied by soil water content (a reduction for dry soil). A plant related factor is defined based on root
        ///  length density (limiting conditions when RLD is below ReferenceRLD)
        /// </remarks>
        /// <param name="myZone">Soil information</param>
        /// <returns>Amount of available water (mm)</returns>
        private double[] PlantAvailableSoilWaterAlternativeKL(ZoneWaterAndN myZone)
        {
            double[] result = new double[nLayers];
            SoilCrop soilCropData = (SoilCrop)mySoil.Crop(Name);
            double rldFac;
            double swFac;
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                rldFac = Math.Min(1.0, RLD[layer] / ReferenceRLD);
                if (mySoil.SoilWater.SWmm[layer] >= mySoil.SoilWater.DULmm[layer])
                    swFac = 1.0;
                else if (mySoil.SoilWater.SWmm[layer] <= mySoil.SoilWater.LL15mm[layer])
                    swFac = 0.0;
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.SoilWater.LL15mm[layer]) /
                                        (mySoil.SoilWater.DULmm[layer] - mySoil.SoilWater.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, ExponentSoilMoisture);
                }

                result[layer] = Math.Max(0.0, myZone.Water[layer] - (soilCropData.LL[layer] * mySoil.Thickness[layer]));
                result[layer] *= FractionLayerWithRoots(layer) * Math.Min(1.0, soilCropData.KL[layer] * swFac * rldFac);
            }

            return result;
        }
예제 #32
0
        /// <summary>Sets the amount of water taken up by this plant (mm).</summary>
        /// <remarks>The model can only handle one root zone at present.</remarks>
        /// <param name="zones">Water uptake from each layer (mm), by zone</param>
        public void SetSWUptake(List<ZoneWaterAndN> zones)
        {
            // Get the zone this plant is in
            ZoneWaterAndN MyZone = new ZoneWaterAndN();
            Zone parentZone = Apsim.Parent(this, typeof (Zone)) as Zone;
            foreach (ZoneWaterAndN Z in zones)
                if (Z.Name == parentZone.Name)
                    MyZone = Z;

            // Get the water uptake from each layer
            for (int layer = 0; layer < nLayers; layer++)
                mySoilWaterUptake[layer] = MyZone.Water[layer];
        }
예제 #33
0
        /// <summary>Estimates the amount of plant available water in each soil layer of the root zone.</summary>
        /// <remarks>This is the default APSIM method, with kl representing the daily rate for water extraction</remarks>
        /// <param name="myZone">Soil information</param>
        /// <returns>Amount of available water (mm)</returns>
        private double[] PlantAvailableSoilWaterDefault(ZoneWaterAndN myZone)
        {
            double[] result = new double[nLayers];
            SoilCrop soilCropData = (SoilCrop)mySoil.Crop(Name);
            for (int layer = 0; layer <= roots.BottomLayer; layer++)
            {
                result[layer] = Math.Max(0.0, myZone.Water[layer] - (soilCropData.LL[layer] * mySoil.Thickness[layer]));
                result[layer] *= FractionLayerWithRoots(layer) * soilCropData.KL[layer];
            }

            return result;
        }
예제 #34
0
        /// <summary>Performs the nitrogen uptake calculations.</summary>
        internal void DoNitrogenCalculations()
        {
            if (MyNitrogenUptakeSource == "species")
            {
                // this module will compute nitrogen uptake

                // Pack the soil information
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                myZone.Name = this.Parent.Name;
                myZone.Water = mySoil.Water;
                myZone.NO3N = mySoil.NO3N;
                myZone.NH4N = mySoil.NH4N;

                // Get the N amount available in the soil
                EvaluateSoilNitrogenAvailable(myZone);

                // Get the N amount fixed through symbiosis
                EvaluateNitrogenFixation();

                // Evaluate the use of N remobilised and get N amount demanded from soil
                EvaluateSoilNitrogenDemand();

                // Get N amount take up from the soil
                EvaluateSoilNitrogenUptake();

                // Evaluate whether remobilisation of luxury N is needed
                EvaluateNLuxuryRemobilisation();

                // Send delta N to the soil model
                DoSoilNitrogenUptake();
            }
            else if (MyNitrogenUptakeSource == "SoilArbitrator")
            {
                // Nitrogen uptake was computed by the resource arbitrator

                // Evaluate whether remobilisation of luxury N is needed
                EvaluateNLuxuryRemobilisation();

                // Send delta N to the soil model
                DoSoilNitrogenUptake();
            }
            else if (MyNitrogenUptakeSource == "Arbitrator")
            {
                // Nitrogen uptake was computed by the resource arbitrator

                // gather the uptake values
                if (MyNitrogenUptakeSource == "Arbitrator")
                {
                    for (int layer = 0; layer <= roots.BottomLayer; layer++)
                    {
                        mySoilNH4Uptake[layer] = uptakeNitrogen[layer] * (1.0 - uptakeNitrogenPropNO3[layer]);
                        mySoilNO3Uptake[layer] = uptakeNitrogen[layer] * uptakeNitrogenPropNO3[layer];
                    }
                }

                // Evaluate whether remobilisation of luxury N is needed
                EvaluateNLuxuryRemobilisation();
            }
            else
            {
                // N uptake is computed by another module (e.g. SWIM) and supplied by OnNitrogenUptakesCalculated
                throw new NotImplementedException();
            }
        }
예제 #35
0
파일: Plant15.cs 프로젝트: hol353/ApsimX
        /// <summary>Placeholder for SoilArbitrator</summary>
        /// <param name="soilstate">Soil state</param>
        /// <returns></returns>
        public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate)
        {
            if (IsAlive)
            {
                List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();
                ZoneWaterAndN Uptake = new ZoneWaterAndN();

                ZoneWaterAndN MyZone = new ZoneWaterAndN();
                foreach (ZoneWaterAndN Z in soilstate.Zones)
                    if (Z.Name == this.Parent.Name)
                        MyZone = Z;

                double[] SW = MyZone.Water;
                OnPrepare(null, null);  //DEAN!!!

                Uptake.Name = this.Parent.Name;
                Uptake.Water = Root.CalculateWaterUptake(TopsSWDemand, SW);
                Uptake.NO3N = new double[SW.Length];
                Uptake.NH4N = new double[SW.Length];
                Uptakes.Add(Uptake);
                return Uptakes;
            }
            else
                return null;
        }
예제 #36
0
        /// <summary>Performs the water uptake calculations.</summary>
        internal void DoWaterCalculations()
        {
            if (MyWaterUptakeSource == "species")
            {
                // this module will compute water uptake

                // Pack the soil information
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                myZone.Name = this.Parent.Name;
                myZone.Water = mySoil.Water;
                myZone.NO3N = mySoil.NO3N;
                myZone.NH4N = mySoil.NH4N;

                // Get the amount of soil available water
                EvaluateSoilWaterAvailable(myZone);

                // Get the amount of water taken up
                EvaluateSoilWaterUptake();

                // Send the delta water to soil water module
                DoSoilWaterUptake();
            }
            else if ((MyWaterUptakeSource == "SoilArbitrator") || (MyWaterUptakeSource == "Arbitrator"))
            {
                // water uptake has been calculated by a resource arbitrator
                DoSoilWaterUptake();
            }
            else
            {
                // water uptake is computed by another module (e.g. SWIM) and supplied by OnWaterUptakesCalculated
                throw new NotImplementedException();
            }
        }
예제 #37
0
        /// <summary>
        /// Calculate the potential sw uptake for today
        /// </summary>
        public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate)
        {
            if (Plant.IsAlive)
            {
                // Get all water supplies.
                double waterSupply = 0;
                List<double[]> supplies = new List<double[]>();
                List<string> zoneNames = new List<string>();
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    foreach (IArbitration o in Organs)
                    {
                        double[] organSupply = o.WaterSupply(zone);
                        if (organSupply != null)
                        {
                            supplies.Add(organSupply);
                            zoneNames.Add(zone.Name);
                            waterSupply += MathUtilities.Sum(organSupply);
                        }
                    }
                }

                // Calculate total water demand.
                double waterDemand = 0;
                foreach (IArbitration o in Organs)
                    waterDemand += o.WaterDemand;

                // Calculate demand / supply ratio.
                double fractionUsed = 0;
                if (waterSupply > 0)
                    fractionUsed = Math.Min(1.0, waterDemand / waterSupply);

                // Apply demand supply ratio to each zone and create a ZoneWaterAndN structure
                // to return to caller.
                List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>();
                for (int i = 0; i < supplies.Count; i++)
                {
                    // Just send uptake from my zone
                    ZoneWaterAndN uptake = new ZoneWaterAndN();
                    uptake.Name = zoneNames[i];
                    uptake.Water = MathUtilities.Multiply_Value(supplies[i], fractionUsed);
                    uptake.NO3N = new double[uptake.Water.Length];
                    uptake.NH4N = new double[uptake.Water.Length];
                    zones.Add(uptake);
                }

                return zones;
            }
            else
                return null;
        }
예제 #38
0
 /// <summary>Finds out the amount of plant available nitrogen (NH4 and NO3) in the soil.</summary>
 /// <param name="myZone">Soil information</param>
 internal void EvaluateSoilNitrogenAvailable(ZoneWaterAndN myZone)
 {
     if (myNitrogenAvailableMethod == PlantAvailableNitrogenMethod.BasicAgPasture)
         PlantAvailableSoilNBasicAgPasture(myZone);
     else if (myNitrogenAvailableMethod == PlantAvailableNitrogenMethod.DefaultAPSIM)
         PlantAvailableSoilNDefaultAPSIM(myZone);
     else if (myNitrogenAvailableMethod == PlantAvailableNitrogenMethod.AlternativeRLD)
         PlantAvailableSoilNAlternativeRLD(myZone);
     else if (myNitrogenAvailableMethod == PlantAvailableNitrogenMethod.AlternativeWup)
         PlantAvailableSoilNAlternativeWup(myZone);
 }
예제 #39
0
        /// <summary>Gets the potential plant N uptake for each layer (mm).</summary>
        /// <remarks>The model can only handle one root zone at present.</remarks>
        /// <param name="soilstate">Soil state (current N contents)</param>
        /// <returns>Potential N uptake (kg/ha)</returns>
        public List<ZoneWaterAndN> GetNUptakes(SoilState soilstate)
        {
            if (IsAlive)
            {
                // Get the zone this plant is in
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                Zone parentZone = Apsim.Parent(this, typeof (Zone)) as Zone;
                foreach (ZoneWaterAndN Z in soilstate.Zones)
                    if (Z.Name == parentZone.Name)
                        myZone = Z;

                // Get the N amount available in the soil
                EvaluateSoilNitrogenAvailable(myZone);

                // Get the N amount fixed through symbiosis
                EvaluateNitrogenFixation();

                // Evaluate the use of N remobilised and get N amount demanded from soil
                EvaluateSoilNitrogenDemand();

                // Get N amount take up from the soil
                EvaluateSoilNitrogenUptake();

                //Pack results into uptake structure
                ZoneWaterAndN myUptakeDemand = new ZoneWaterAndN();
                myUptakeDemand.Name = myZone.Name;
                myUptakeDemand.NH4N = mySoilNH4Uptake;
                myUptakeDemand.NO3N = mySoilNO3Uptake;
                myUptakeDemand.Water = new double[nLayers];

                List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>();
                zones.Add(myUptakeDemand);
                return zones;
            }
            else
                return null;
        }
예제 #40
0
 /// <summary>Finds out the amount of plant available water in the soil.</summary>
 /// <param name="myZone">Soil information</param>
 internal void EvaluateSoilWaterAvailable(ZoneWaterAndN myZone)
 {
     if (myWaterAvailableMethod == PlantAvailableWaterMethod.Default)
         mySoilWaterAvailable = PlantAvailableSoilWaterDefault(myZone);
     else if (myWaterAvailableMethod == PlantAvailableWaterMethod.AlternativeKL)
         mySoilWaterAvailable = PlantAvailableSoilWaterAlternativeKL(myZone);
     else if (myWaterAvailableMethod == PlantAvailableWaterMethod.AlternativeKS)
         mySoilWaterAvailable = PlantAvailableSoilWaterAlternativeKS(myZone);
 }
예제 #41
0
        /// <summary>
        /// Returns soil water uptake from each zone by the static tree model
        /// </summary>
        /// <param name="soilstate"></param>
        /// <returns></returns>
        public List<Soils.Arbitrator.ZoneWaterAndN> GetSWUptakes(Soils.Arbitrator.SoilState soilstate)
        {
            double SWDemand = 0;  // Tree water demand (L)
            double PotSWSupply = 0; // Total water supply (L)

            foreach (ZoneInfo ZI in ZoneInfoList)
            {
                Soils.SoilWater S = Apsim.Find(ZI.zone, typeof(Soils.SoilWater)) as Soils.SoilWater;
                SWDemand += S.Eo * (1 / (1 - ZI.Shade / 100) - 1) * ZI.zone.Area * 10000;
            }

            List<ZoneWaterAndN> Uptakes = new List<ZoneWaterAndN>();

            foreach (ZoneWaterAndN Z in soilstate.Zones)
            {
                foreach (ZoneInfo ZI in ZoneInfoList)
                {
                    if (Z.Name == ZI.zone.Name)
                    {
                        ZoneWaterAndN Uptake = new ZoneWaterAndN();
                        //Find the soil for this zone
                        Zone ThisZone = new Zone();
                        Soils.Soil ThisSoil = new Soils.Soil();

                        foreach (Zone SearchZ in Apsim.ChildrenRecursively(Parent, typeof(Zone)))
                            if (SearchZ.Name == Z.Name)
                                ThisSoil = Apsim.Find(SearchZ, typeof(Soils.Soil)) as Soils.Soil;

                        Uptake.Name = Z.Name;
                        double[] SW = Z.Water;
                        Uptake.NO3N = new double[SW.Length];
                        Uptake.NH4N = new double[SW.Length];
                        Uptake.Water = new double[SW.Length];
                        for (int i = 0; i <= SW.Length - 1; i++)
                        {
                            double[] LL15mm = MathUtilities.Multiply(ThisSoil.LL15,ThisSoil.Thickness);
                            Uptake.Water[i] = (SW[i] - LL15mm[i]) * ZI.RLD[i];
                            PotSWSupply += Uptake.Water[i] * ZI.zone.Area * 10000;
                        }
                        Uptakes.Add(Uptake);
                    }
                }
            }
            // Now scale back uptakes if supply > demand
            double F = 0;  // Uptake scaling factor
            if (PotSWSupply > 0)
            {
                F = SWDemand / PotSWSupply;
                if (F > 1)
                    F = 1;
            }
            else
                F = 1;

            foreach (ZoneWaterAndN Z in Uptakes)
                Z.Water = MathUtilities.Multiply_Value(Z.Water, F);
            return Uptakes;
        }
예제 #42
0
        /// <summary>Gets the potential plant water uptake for each layer (mm).</summary>
        /// <remarks>The model can only handle one root zone at present.</remarks>
        /// <param name="soilstate">Soil state (current water content)</param>
        /// <returns>Potential water uptake (mm)</returns>
        public List<ZoneWaterAndN> GetSWUptakes(SoilState soilstate)
        {
            if (IsAlive)
            {
                // Get the zone this plant is in
                ZoneWaterAndN myZone = new ZoneWaterAndN();
                Zone parentZone = Apsim.Parent(this, typeof (Zone)) as Zone;
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                    if (zone.Name == parentZone.Name)
                        myZone = zone;

                // Get the amount of water available for this plant
                EvaluateSoilWaterAvailable(myZone);

                // Get the amount of water potentially taken up by this plant
                EvaluateSoilWaterUptake();

                // Pack potential uptake data for this plant
                ZoneWaterAndN myUptakeDemand = new ZoneWaterAndN();
                myUptakeDemand.Name = myZone.Name;
                myUptakeDemand.Water = mySoilWaterUptake;
                myUptakeDemand.NO3N = new double[nLayers];
                myUptakeDemand.NH4N = new double[nLayers];

                List<ZoneWaterAndN> zones = new List<ZoneWaterAndN>();
                zones.Add(myUptakeDemand);
                return zones;
            }
            else
                return null;
        }