コード例 #1
0
        private void StoreWaterVariablesForNitrogenUptake(ZoneWaterAndN zoneWater)
        {
            ZoneState myZone = root.Zones.Find(z => z.Name == zoneWater.Zone.Name);

            if (myZone != null)
            {
                //store Water variables for N Uptake calculation
                //Old sorghum doesn't do actualUptake of Water until end of day
                myZone.StartWater           = new double[myZone.soil.Thickness.Length];
                myZone.AvailableSW          = new double[myZone.soil.Thickness.Length];
                myZone.PotentialAvailableSW = new double[myZone.soil.Thickness.Length];
                myZone.Supply = new double[myZone.soil.Thickness.Length];

                var      soilCrop = Soil.Crop(Plant.Name);
                double[] kl       = soilCrop.KL;

                if (root.Depth != myZone.Depth)
                {
                    myZone.Depth += 0;
                }

                var currentLayer           = myZone.soil.LayerIndexOfDepth(myZone.Depth);
                var currentLayerProportion = myZone.soil.ProportionThroughLayer(currentLayer, myZone.Depth);
                for (int layer = 0; layer <= currentLayer; ++layer)
                {
                    myZone.StartWater[layer] = myZone.soil.Water[layer];

                    myZone.AvailableSW[layer]          = Math.Max(myZone.soil.Water[layer] - myZone.soil.LL15mm[layer], 0);
                    myZone.PotentialAvailableSW[layer] = myZone.soil.DULmm[layer] - myZone.soil.LL15mm[layer];

                    if (layer == currentLayer)
                    {
                        myZone.AvailableSW[layer]          *= currentLayerProportion;
                        myZone.PotentialAvailableSW[layer] *= currentLayerProportion;
                    }

                    var proportion = root.rootProportionInLayer(layer, myZone);
                    myZone.Supply[layer] = Math.Max(myZone.AvailableSW[layer] * kl[layer] * proportion, 0.0);
                }
                var totalAvail    = myZone.AvailableSW.Sum();
                var totalAvailPot = myZone.PotentialAvailableSW.Sum();
                var totalSupply   = myZone.Supply.Sum();
                WatSupply = totalSupply;

                // Set reporting variables.
                Avail         = myZone.AvailableSW;
                PotAvail      = myZone.PotentialAvailableSW;
                TotalAvail    = myZone.AvailableSW.Sum();
                TotalPotAvail = myZone.PotentialAvailableSW.Sum();

                //used for SWDef PhenologyStress table lookup
                SWAvailRatio = MathUtilities.Bound(MathUtilities.Divide(totalAvail, totalAvailPot, 1.0), 0.0, 10.0);

                //used for SWDef ExpansionStress table lookup
                SDRatio = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 10);

                //used for SwDefPhoto Stress
                PhotoStress = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 1.0);
            }
        }
コード例 #2
0
ファイル: Root.cs プロジェクト: oseledets/ApsimX
        /// <summary>Gets the nitrogen supply from the specified zone.</summary>
        /// <param name="zone">The zone.</param>
        /// <param name="NO3Supply">The returned NO3 supply</param>
        /// <param name="NH4Supply">The returned NH4 supply</param>
        public void CalculateNitrogenSupply(ZoneWaterAndN zone, ref double[] NO3Supply, ref double[] NH4Supply)
        {
            ZoneState myZone = Zones.Find(z => z.Name == zone.Zone.Name);

            if (myZone != null)
            {
                if (RWC == null || RWC.Length != myZone.soil.Thickness.Length)
                {
                    RWC = new double[myZone.soil.Thickness.Length];
                }
                double NO3Uptake = 0;
                double NH4Uptake = 0;
                for (int layer = 0; layer < myZone.soil.Thickness.Length; layer++)
                {
                    if (myZone.LayerLive[layer].Wt > 0)
                    {
                        RWC[layer] = (myZone.soil.Water[layer] - myZone.soil.SoilWater.LL15mm[layer]) / (myZone.soil.SoilWater.DULmm[layer] - myZone.soil.SoilWater.LL15mm[layer]);
                        RWC[layer] = Math.Max(0.0, Math.Min(RWC[layer], 1.0));
                        double SWAF = NUptakeSWFactor.Value(layer);

                        double kno3   = KNO3.Value(layer);
                        double NO3ppm = zone.NO3N[layer] * (100.0 / (myZone.soil.BD[layer] * myZone.soil.Thickness[layer]));
                        NO3Supply[layer] = Math.Min(zone.NO3N[layer] * kno3 * NO3ppm * SWAF, (MaxDailyNUptake.Value() - NO3Uptake));
                        NO3Uptake       += NO3Supply[layer];

                        double knh4   = KNH4.Value(layer);
                        double NH4ppm = zone.NH4N[layer] * (100.0 / (myZone.soil.BD[layer] * myZone.soil.Thickness[layer]));
                        NH4Supply[layer] = Math.Min(zone.NH4N[layer] * knh4 * NH4ppm * SWAF, (MaxDailyNUptake.Value() - NH4Uptake));
                        NH4Uptake       += NH4Supply[layer];
                    }
                }
            }
        }
コード例 #3
0
        private void CalculateNitrogenSupply(ZoneState myZone, ZoneWaterAndN zone)
        {
            myZone.MassFlow = new double[myZone.soil.Thickness.Length];
            myZone.Diffusion = new double[myZone.soil.Thickness.Length];

            int currentLayer = Soils.Soil.LayerIndexOfDepth(myZone.Depth, myZone.soil.Thickness);
            for (int layer = 0; layer <= currentLayer; layer++)
            {
                var swdep = myZone.StartWater[layer]; //mm
                var flow = myZone.WaterUptake[layer];
                
                //NO3N is in kg/ha - old sorghum used g/m^2
                var no3conc = zone.NO3N[layer] * kgha2gsm / swdep;
                var no3massFlow = no3conc * (-flow);
                myZone.MassFlow[layer] = no3massFlow;

                //diffusion
                var swAvailFrac = myZone.AvailableSW[layer] / myZone.PotentialAvailableSW[layer];
                //old sorghum stores N03 in g/ms not kg/ha
                var no3Diffusion = MathUtilities.Bound(swAvailFrac, 0.0, 1.0) * (zone.NO3N[layer] * kgha2gsm);

                if (layer == currentLayer)
                {
                    var proportion = Soils.Soil.ProportionThroughLayer(currentLayer, myZone.Depth, myZone.soil.Thickness);
                    no3Diffusion *= proportion;
                }

                myZone.Diffusion[layer] = no3Diffusion;

                //NH4Supply[layer] = no3massFlow;
                //onyl 2 fields passed in for returning data. 
                //actual uptake needs to distinguish between massflow and diffusion
                //sorghum calcs don't use nh4 - so using that temporarily
            }
        }
コード例 #4
0
ファイル: Root.cs プロジェクト: m8harrison/ApsimX-1
        /// <summary>Gets or sets the water supply.</summary>
        /// <param name="zone">The zone.</param>
        public double[] CalculateWaterSupply(ZoneWaterAndN zone)
        {
            ZoneState myZone = Zones.Find(z => z.Name == zone.Zone.Name);

            if (myZone == null)
            {
                return(null);
            }

            if (myZone.soil.Weirdo != null)
            {
                return(new double[myZone.soil.Thickness.Length]); //With Weirdo, water extraction is not done through the arbitrator because the time step is different.
            }
            else
            {
                double[] kl = myZone.soil.KL(Plant.Name);
                double[] ll = myZone.soil.LL(Plant.Name);

                double[] supply = new double[myZone.soil.Thickness.Length];
                LayerMidPointDepth = Soil.ToMidPoints(myZone.soil.Thickness);
                for (int layer = 0; layer < myZone.soil.Thickness.Length; layer++)
                {
                    if (layer <= Soil.LayerIndexOfDepth(myZone.Depth, myZone.soil.Thickness))
                    {
                        supply[layer] = Math.Max(0.0, kl[layer] * klModifier.Value(layer) *
                                                 (zone.Water[layer] - ll[layer] * myZone.soil.Thickness[layer]) * Soil.ProportionThroughLayer(layer, myZone.Depth, myZone.soil.Thickness));
                    }
                }
                return(supply);
            }
        }
コード例 #5
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">The soil information</param>
        /// <returns>The amount of available water in each layer (mm)</returns>
        internal double[] PlantAvailableSoilWaterAlternativeKS(ZoneWaterAndN myZone)
        {
            double[] result       = new double[nLayers];
            SoilCrop soilCropData = (SoilCrop)mySoil.Crop(mySpeciesName);

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                double condFac = 1.0 - Math.Pow(10.0, -mySoil.KS[layer] / myReferenceKSuptake);
                double rldFac  = 1.0 - Math.Pow(10.0, -RootLengthDensity[layer] / myReferenceRLD);
                double swFac;
                if (mySoil.SoilWater.SWmm[layer] >= mySoil.DULmm[layer])
                {
                    swFac = 1.0;
                }
                else if (mySoil.SoilWater.SWmm[layer] <= mySoil.LL15mm[layer])
                {
                    swFac = 0.0;
                }
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.LL15mm[layer]) /
                                        (mySoil.DULmm[layer] - mySoil.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, myExponentSoilMoisture);
                }

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

                // Actual plant available water
                result[layer] *= FractionLayerWithRoots(layer) * Math.Min(1.0, rldFac * condFac * swFac);
            }

            return(result);
        }
コード例 #6
0
        private void CalculateNitrogenSupply(ZoneState myZone, ZoneWaterAndN zone)
        {
            myZone.MassFlow  = new double[myZone.soil.Thickness.Length];
            myZone.Diffusion = new double[myZone.soil.Thickness.Length];

            int currentLayer = myZone.soil.LayerIndexOfDepth(myZone.Depth);

            for (int layer = 0; layer <= currentLayer; layer++)
            {
                var swdep    = myZone.StartWater[layer]; //mm
                var dltSwdep = myZone.WaterUptake[layer];

                //NO3N is in kg/ha - old sorghum used g/m^2
                var no3conc     = MathUtilities.Divide(zone.NO3N[layer] * kgha2gsm, swdep, 0);
                var no3massFlow = no3conc * (-dltSwdep);
                myZone.MassFlow[layer] = Math.Min(no3massFlow, zone.NO3N[layer] * kgha2gsm);

                //diffusion
                var swAvailFrac = MathUtilities.Divide(myZone.AvailableSW[layer], myZone.PotentialAvailableSW[layer], 0);
                //old sorghum stores N03 in g/ms not kg/ha
                var no3Diffusion = MathUtilities.Bound(swAvailFrac, 0.0, 1.0) * (zone.NO3N[layer] * kgha2gsm);

                myZone.Diffusion[layer] = Math.Min(no3Diffusion, zone.NO3N[layer] * kgha2gsm) * myZone.RootProportions[layer];

                //NH4Supply[layer] = no3massFlow;
                //onyl 2 fields passed in for returning data.
                //actual uptake needs to distinguish between massflow and diffusion
            }
        }
コード例 #7
0
        private void StoreWaterVariablesForNitrogenUptake(ZoneWaterAndN zoneWater)
        {
            ZoneState myZone = root.Zones.Find(z => z.Name == zoneWater.Zone.Name);

            if (myZone != null)
            {
                var soilPhysical = myZone.Soil.FindChild <Soils.IPhysical>();
                var waterBalance = myZone.Soil.FindChild <ISoilWater>();

                //store Water variables for N Uptake calculation
                //Old sorghum doesn't do actualUptake of Water until end of day
                myZone.StartWater           = new double[soilPhysical.Thickness.Length];
                myZone.AvailableSW          = new double[soilPhysical.Thickness.Length];
                myZone.PotentialAvailableSW = new double[soilPhysical.Thickness.Length];
                myZone.Supply = new double[soilPhysical.Thickness.Length];

                var soilCrop = Soil.FindDescendant <SoilCrop>(plant.Name + "Soil");
                if (soilCrop == null)
                {
                    throw new Exception($"Cannot find a soil crop parameterisation called {plant.Name + "Soil"}");
                }

                double[] kl = soilCrop.KL;

                double[] llDep = MathUtilities.Multiply(soilCrop.LL, soilPhysical.Thickness);

                if (root.Depth != myZone.Depth)
                {
                    myZone.Depth += 0; // wtf??
                }
                var currentLayer = SoilUtilities.LayerIndexOfDepth(myZone.Physical.Thickness, myZone.Depth);
                for (int layer = 0; layer <= currentLayer; ++layer)
                {
                    myZone.StartWater[layer] = waterBalance.SWmm[layer];

                    myZone.AvailableSW[layer]          = Math.Max(waterBalance.SWmm[layer] - llDep[layer] * myZone.LLModifier[layer], 0) * myZone.RootProportions[layer];
                    myZone.PotentialAvailableSW[layer] = Math.Max(soilPhysical.DULmm[layer] - llDep[layer] * myZone.LLModifier[layer], 0) * myZone.RootProportions[layer];

                    var proportion = myZone.RootProportions[layer];
                    myZone.Supply[layer] = Math.Max(myZone.AvailableSW[layer] * kl[layer] * proportion, 0.0);
                }
                var totalAvail    = myZone.AvailableSW.Sum();
                var totalAvailPot = myZone.PotentialAvailableSW.Sum();
                var totalSupply   = myZone.Supply.Sum();
                WatSupply = totalSupply;

                // Set reporting variables.
                //Avail = myZone.AvailableSW;
                //PotAvail = myZone.PotentialAvailableSW;

                //used for SWDef PhenologyStress table lookup
                SWAvailRatio = MathUtilities.Bound(MathUtilities.Divide(totalAvail, totalAvailPot, 1.0), 0.0, 10.0);

                //used for SWDef ExpansionStress table lookup
                SDRatio = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 10);

                //used for SwDefPhoto Stress
                //PhotoStress = MathUtilities.Bound(MathUtilities.Divide(totalSupply, WDemand, 1.0), 0.0, 1.0);
            }
        }
コード例 #8
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">The soil information</param>
        /// <param name="mySoilWaterUptake">Soil water uptake</param>
        private void PlantAvailableSoilNAlternativeWup(ZoneWaterAndN myZone, double[] mySoilWaterUptake)
        {
            double layerFrac;     // the fraction of layer within the root zone
            double potAvailableN; // potential available N

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                double swuFac = MathUtilities.Divide(mySoilWaterUptake[layer], myZone.Water[layer], 0.0);

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

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

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > myMaximumNUptake)
            {
                double upFraction = myMaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
コード例 #9
0
 /// <summary>Finds out the amount of plant available water in the soil.</summary>
 /// <param name="myZone">The soil information</param>
 internal void EvaluateSoilWaterAvailability(ZoneWaterAndN myZone)
 {
     for (int layer = 0; layer <= BottomLayer; layer++)
     {
         mySoilWaterAvailable[layer]  = Math.Max(0.0, myZone.Water[layer] - soilCropData.LLmm[layer]);
         mySoilWaterAvailable[layer] *= FractionLayerWithRoots(layer) * soilCropData.KL[layer] * KLModiferDueToDamage(layer);
     }
 }
コード例 #10
0
        /// <summary>Finds out the amount of plant available nitrogen (NH4 and NO3) in the soil.</summary>
        /// <param name="myZone">The soil information</param>
        /// <param name="mySoilWaterUptake">Soil water uptake</param>
        internal void EvaluateSoilNitrogenAvailable(ZoneWaterAndN myZone, double[] mySoilWaterUptake)
        {
            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
            var    thickness         = soilPhysical.Thickness;
            var    bd                = soilPhysical.BD;
            var    water             = myZone.Water;
            var    nh4               = myZone.NH4N;
            var    no3               = myZone.NO3N;
            double depthOfTopOfLayer = 0;

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                layerFrac = (Depth - depthOfTopOfLayer) / thickness[layer];
                layerFrac = Math.Min(1.0, Math.Max(0.0, layerFrac));

                bdFac = 100.0 / (thickness[layer] * bd[layer]);
                if (water[layer] >= dulMM[layer])
                {
                    swFac = 1.0;
                }
                else if (water[layer] <= ll15MM[layer])
                {
                    swFac = 0.0;
                }
                else
                {
                    double waterRatio = (water[layer] - ll15MM[layer]) /
                                        (dulMM[layer] - ll15MM[layer]);
                    waterRatio = MathUtilities.Bound(waterRatio, 0.0, 1.0);
                    swFac      = 1.0 - Math.Pow(1.0 - waterRatio, ExponentSoilMoisture);
                }

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

                // get NO3 available
                potAvailableN             = no3[layer] * layerFrac * swFac * bdFac * KNO3;
                mySoilNO3Available[layer] = Math.Min(no3[layer] * layerFrac, potAvailableN);

                depthOfTopOfLayer += thickness[layer];
            }

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > MaximumNUptake)
            {
                double upFraction = MaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
コード例 #11
0
        /// <summary>The method used to arbitrate N allocations</summary>
        public List <ZoneWaterAndN> GetUptakeEstimates(SoilState soilstate, IArbitration[] Organs)
        {
            // Get all water supplies.
            double waterSupply = 0;  //NOTE: This is in L, not mm, to arbitrate water demands for spatial simulations.

            List <double[]>      supplies = new List <double[]>();
            List <ZoneWaterAndN> zones    = new List <ZoneWaterAndN>();

            foreach (ZoneWaterAndN zone in soilstate.Zones)
            {
                foreach (IOrgan o in Organs)
                {
                    if (o is IWaterNitrogenUptake)
                    {
                        double[] organSupply = (o as IWaterNitrogenUptake).CalculateWaterSupply(zone);
                        if (organSupply != null)
                        {
                            supplies.Add(organSupply);
                            zones.Add(zone);
                            waterSupply += MathUtilities.Sum(organSupply) * zone.Zone.Area;
                        }
                    }
                }
            }

            // Calculate total water demand.
            double waterDemand = 0; //NOTE: This is in L, not mm, to arbitrate water demands for spatial simulations.

            foreach (IHasWaterDemand WD in WaterDemands)
            {
                waterDemand += WD.CalculateWaterDemand() * plant.Zone.Area;
            }

            // 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> ZWNs = new List <ZoneWaterAndN>();

            for (int i = 0; i < supplies.Count; i++)
            {
                // Just send uptake from my zone
                ZoneWaterAndN uptake = new ZoneWaterAndN(zones[i]);
                uptake.Water = MathUtilities.Multiply_Value(supplies[i], fractionUsed);
                uptake.NO3N  = new double[uptake.Water.Length];
                uptake.NH4N  = new double[uptake.Water.Length];
                uptake.PlantAvailableNO3N = new double[uptake.Water.Length];
                uptake.PlantAvailableNH4N = new double[uptake.Water.Length];
                ZWNs.Add(uptake);
            }
            return(ZWNs);
        }
コード例 #12
0
        /// <summary>Calculate Nitrogen UptakeEstimates</summary>
        public List <ZoneWaterAndN> GetUptakeEstimates(SoilState soilstate, IArbitration[] Organs)
        {
            var    N       = Arbitrator.N;
            double NSupply = 0;//NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

            for (int i = 0; i < Organs.Count(); i++)
            {
                N.UptakeSupply[i] = 0;
            }

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

            foreach (ZoneWaterAndN zone in soilstate.Zones)
            {
                ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(zone);

                UptakeDemands.NO3N  = new double[zone.NO3N.Length];
                UptakeDemands.NH4N  = new double[zone.NH4N.Length];
                UptakeDemands.Water = new double[UptakeDemands.NO3N.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.Count(); i++)
                {
                    if (Organs[i] is IWaterNitrogenUptake)
                    {
                        double[] organNO3Supply = new double[zone.NO3N.Length];
                        double[] organNH4Supply = new double[zone.NH4N.Length];
                        (Organs[i] as IWaterNitrogenUptake).CalculateNitrogenSupply(zone, ref organNO3Supply, ref organNH4Supply);
                        UptakeDemands.NO3N = MathUtilities.Add(UptakeDemands.NO3N, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator
                        UptakeDemands.NH4N = MathUtilities.Add(UptakeDemands.NH4N, organNH4Supply);
                        double organSupply = organNH4Supply.Sum() + organNO3Supply.Sum();
                        N.UptakeSupply[i] += organSupply * kgha2gsm * zone.Zone.Area / this.zone.Area;
                        NSupply           += organSupply * zone.Zone.Area;
                    }
                }
                zones.Add(UptakeDemands);
            }

            double NDemand = (N.TotalPlantDemand - N.TotalReallocation) / kgha2gsm * zone.Area; //NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

            if (NDemand < 0)
            {
                NDemand = 0;               //NSupply should be zero if Reallocation can meet all demand (including small rounding errors which can make this -ve)
            }
            if (NSupply > NDemand)
            {
                //Reduce the PotentialUptakes that we pass to the soil arbitrator
                double ratio = Math.Min(1.0, NDemand / NSupply);
                foreach (ZoneWaterAndN UptakeDemands in zones)
                {
                    UptakeDemands.NO3N = MathUtilities.Multiply_Value(UptakeDemands.NO3N, ratio);
                    UptakeDemands.NH4N = MathUtilities.Multiply_Value(UptakeDemands.NH4N, ratio);
                }
            }
            return(zones);
        }
コード例 #13
0
        /// <summary>
        /// Calculate the potential N uptake for today. Should return null if crop is not in the ground.
        /// </summary>
        public virtual List <Soils.Arbitrator.ZoneWaterAndN> GetNitrogenUptakeEstimates(SoilState soilstate)
        {
            if (Plant.IsEmerged)
            {
                double NSupply = 0;//NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

                for (int i = 0; i < Organs.Count; i++)
                {
                    N.UptakeSupply[i] = 0;
                }

                List <ZoneWaterAndN> zones = new List <ZoneWaterAndN>();
                foreach (ZoneWaterAndN zone in soilstate.Zones)
                {
                    ZoneWaterAndN UptakeDemands = new ZoneWaterAndN(zone);

                    UptakeDemands.NO3N = new double[zone.NO3N.Length];
                    UptakeDemands.NH4N = new double[zone.NH4N.Length];
                    UptakeDemands.PlantAvailableNO3N = new double[zone.NO3N.Length];
                    UptakeDemands.PlantAvailableNH4N = new double[zone.NO3N.Length];
                    UptakeDemands.Water = new double[UptakeDemands.NO3N.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.Count; i++)
                    {
                        if (Organs[i] is IWaterNitrogenUptake)
                        {
                            double[] organNO3Supply = new double[zone.NO3N.Length];
                            double[] organNH4Supply = new double[zone.NH4N.Length];
                            (Organs[i] as IWaterNitrogenUptake).CalculateNitrogenSupply(zone, ref organNO3Supply, ref organNH4Supply);
                            UptakeDemands.NO3N = MathUtilities.Add(UptakeDemands.NO3N, organNO3Supply); //Add uptake supply from each organ to the plants total to tell the Soil arbitrator
                            UptakeDemands.NH4N = MathUtilities.Add(UptakeDemands.NH4N, organNH4Supply);
                            N.UptakeSupply[i] += (MathUtilities.Sum(organNH4Supply) + MathUtilities.Sum(organNO3Supply)) * kgha2gsm * zone.Zone.Area / Plant.Zone.Area;
                            NSupply           += (MathUtilities.Sum(organNH4Supply) + MathUtilities.Sum(organNO3Supply)) * zone.Zone.Area;
                        }
                    }
                    zones.Add(UptakeDemands);
                }

                double NDemand = (N.TotalPlantDemand - N.TotalReallocation) / kgha2gsm * Plant.Zone.Area; //NOTE: This is in kg, not kg/ha, to arbitrate N demands for spatial simulations.

                if (NSupply > NDemand)
                {
                    //Reduce the PotentialUptakes that we pass to the soil arbitrator
                    double ratio = Math.Min(1.0, NDemand / NSupply);
                    foreach (ZoneWaterAndN UptakeDemands in zones)
                    {
                        UptakeDemands.NO3N = MathUtilities.Multiply_Value(UptakeDemands.NO3N, ratio);
                        UptakeDemands.NH4N = MathUtilities.Multiply_Value(UptakeDemands.NH4N, ratio);
                    }
                }
                return(zones);
            }
            return(null);
        }
コード例 #14
0
        /// <summary>Finds out the amount of plant available water in the soil.</summary>
        /// <param name="myZone">The soil information</param>
        internal double[] EvaluateSoilWaterAvailable(ZoneWaterAndN myZone)
        {
            double[] result = new double[nLayers];
            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                result[layer]  = Math.Max(0.0, myZone.Water[layer] - (soilCropData.LL[layer] * soilPhysical.Thickness[layer]));
                result[layer] *= FractionLayerWithRoots(layer) * soilCropData.KL[layer] * KLModiferDueToDamage(layer);
            }

            return(result);
        }
コード例 #15
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">The soil information</param>
        private void PlantAvailableSoilNBasicAgPasture(ZoneWaterAndN myZone)
        {
            double layerFrac; // the fraction of layer within the root zone

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                mySoilNH4Available[layer] = myZone.PlantAvailableNH4N[layer] * layerFrac;
                mySoilNO3Available[layer] = myZone.PlantAvailableNO3N[layer] * layerFrac;
            }
        }
コード例 #16
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">The soil information</param>
        /// <returns>The amount of available water in each layer (mm)</returns>
        internal double[] PlantAvailableSoilWaterDefault(ZoneWaterAndN myZone)
        {
            double[] result       = new double[nLayers];
            SoilCrop soilCropData = (SoilCrop)mySoil.Crop(mySpeciesName);

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                result[layer]  = Math.Max(0.0, myZone.Water[layer] - (soilCropData.LL[layer] * mySoil.Thickness[layer]));
                result[layer] *= FractionLayerWithRoots(layer) * soilCropData.KL[layer] * KLModiferDueToDamage(layer);
            }

            return(result);
        }
コード例 #17
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">The 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 <= BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                bdFac     = 100.0 / (mySoil.Thickness[layer] * mySoil.BD[layer]);
                if (myZone.Water[layer] >= mySoil.DULmm[layer])
                {
                    swFac = 1.0;
                }
                else if (myZone.Water[layer] <= mySoil.LL15mm[layer])
                {
                    swFac = 0.0;
                }
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.LL15mm[layer]) /
                                        (mySoil.DULmm[layer] - mySoil.LL15mm[layer]);
                    waterRatio = MathUtilities.Bound(waterRatio, 0.0, 1.0);
                    swFac      = 1.0 - Math.Pow(1.0 - waterRatio, myExponentSoilMoisture);
                }

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

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

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > myMaximumNUptake)
            {
                double upFraction = myMaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
コード例 #18
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 status 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">The 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 <= BottomLayer; layer++)
            {
                layerFrac = FractionLayerWithRoots(layer);
                rldFac    = Math.Min(1.0, MathUtilities.Divide(RootLengthDensity[layer], myReferenceRLD, 1.0));
                if (myZone.Water[layer] >= mySoil.DULmm[layer])
                {
                    swFac = 1.0;
                }
                else if (myZone.Water[layer] <= mySoil.LL15mm[layer])
                {
                    swFac = 0.0;
                }
                else
                {
                    double waterRatio = (myZone.Water[layer] - mySoil.LL15mm[layer]) /
                                        (mySoil.DULmm[layer] - mySoil.LL15mm[layer]);
                    swFac = 1.0 - Math.Pow(1.0 - waterRatio, myExponentSoilMoisture);
                }

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

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

            // check for maximum uptake
            potAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();
            if (potAvailableN > myMaximumNUptake)
            {
                double upFraction = myMaximumNUptake / potAvailableN;
                for (int layer = 0; layer <= BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
コード例 #19
0
        /// <summary>Finds out the amount of plant available nitrogen (NH4 and NO3) in the soil.</summary>
        /// <remarks>
        ///  N availability is considered only within the root zone, and is affected by moisture (dry soils
        ///   having less N available) and N concentration (low concentration leads to reduced availability).
        ///  The effect of soil moisture is a curve starting at LL, where it is zero, reaching one at DUL.
        ///  An exponent bends the pattern between these two values, making it concave if the exponent is
        ///   greater than one, with the derivative being zero at DUL;
        ///  The effect of concentration is a simple linear function starting at zero when there is no N in
        ///   the soil, and reaching its maximum (one) at a concentration defined by the 'kNxx' parameter.
        ///   This (1/kNxx) represents the critical concentration (in ppm), below which N availability is
        ///   limited (e.g. a KNO3 = 0.02 means no limitations if the NO3 concentration is above 50 ppm).
        /// </remarks>
        /// <param name="myZone">The soil information from the zone that contains the roots.</param>
        internal void EvaluateSoilNitrogenAvailability(ZoneWaterAndN myZone)
        {
            var    thickness         = soilPhysical.Thickness;
            var    bd                = soilPhysical.BD;
            var    dulMM             = soilPhysical.DULmm;
            var    llMM              = soilCropData.LLmm;
            var    swMM              = myZone.Water;
            var    nh4               = myZone.NH4N;
            var    no3               = myZone.NO3N;
            double depthAtTopOfLayer = 0;

            for (int layer = 0; layer <= BottomLayer; layer++)
            {
                // get the fraction of this layer that is within the root zone
                double layerFraction = MathUtilities.Bound((Depth - depthAtTopOfLayer) / thickness[layer], 0.0, 1.0);

                // get the soil moisture factor (less N available in drier soil)
                double rwc            = MathUtilities.Bound((swMM[layer] - llMM[layer]) / (dulMM[layer] - llMM[layer]), 0.0, 1.0);
                double moistureFactor = 1.0 - Math.Pow(1.0 - rwc, ExponentSoilMoisture);

                // get NH4 available
                double nh4ppm = nh4[layer] * 100.0 / (thickness[layer] * bd[layer]);
                double concentrationFactor = Math.Min(1.0, nh4ppm * KNH4);
                mySoilNH4Available[layer] = nh4[layer] * layerFraction *Math.Min(0.999999, moistureFactor *concentrationFactor);

                // get NO3 available
                double no3ppm = no3[layer] * 100.0 / (thickness[layer] * bd[layer]);
                concentrationFactor       = Math.Min(1.0, no3ppm * KNO3);
                mySoilNO3Available[layer] = no3[layer] * layerFraction *Math.Min(0.999999, moistureFactor *concentrationFactor);

                depthAtTopOfLayer += thickness[layer];
            }

            // check totals, reduce available N if greater than maximum uptake
            double potentialAvailableN = mySoilNH4Available.Sum() + mySoilNO3Available.Sum();

            if (potentialAvailableN > MaximumNUptake)
            {
                double upFraction = MaximumNUptake / potentialAvailableN;
                for (int layer = 0; layer <= BottomLayer; layer++)
                {
                    mySoilNH4Available[layer] *= upFraction;
                    mySoilNO3Available[layer] *= upFraction;
                }
            }
        }
コード例 #20
0
ファイル: Root.cs プロジェクト: m8harrison/ApsimX-1
        /// <summary>Gets the nitrogen supply from the specified zone.</summary>
        /// <param name="zone">The zone.</param>
        /// <param name="NO3Supply">The returned NO3 supply</param>
        /// <param name="NH4Supply">The returned NH4 supply</param>
        public void CalculateNitrogenSupply(ZoneWaterAndN zone, ref double[] NO3Supply, ref double[] NH4Supply)
        {
            ZoneState myZone = Zones.Find(z => z.Name == zone.Zone.Name);

            if (myZone != null)
            {
                if (RWC == null || RWC.Length != myZone.soil.Thickness.Length)
                {
                    RWC = new double[myZone.soil.Thickness.Length];
                }
                double NO3Uptake = 0;
                double NH4Uptake = 0;

                double[] thickness = myZone.soil.Thickness;
                double[] water     = myZone.soil.Water;
                double[] ll15mm    = myZone.soil.LL15mm;
                double[] dulmm     = myZone.soil.DULmm;
                double[] bd        = myZone.soil.BD;

                double accuDepth = 0;

                for (int layer = 0; layer < thickness.Length; layer++)
                {
                    accuDepth += thickness[layer];
                    if (myZone.LayerLive[layer].Wt > 0)
                    {
                        double factorRootDepth = Math.Max(0, Math.Min(1, 1 - (accuDepth - Depth) / thickness[layer]));
                        RWC[layer] = (water[layer] - ll15mm[layer]) / (dulmm[layer] - ll15mm[layer]);
                        RWC[layer] = Math.Max(0.0, Math.Min(RWC[layer], 1.0));
                        double SWAF = nUptakeSWFactor.Value(layer);

                        double kno3   = this.kno3.Value(layer);
                        double NO3ppm = zone.NO3N[layer] * (100.0 / (bd[layer] * thickness[layer]));
                        NO3Supply[layer] = Math.Min(zone.NO3N[layer] * kno3 * NO3ppm * SWAF * factorRootDepth, (maxDailyNUptake.Value() - NO3Uptake));
                        NO3Uptake       += NO3Supply[layer];

                        double knh4   = this.knh4.Value(layer);
                        double NH4ppm = zone.NH4N[layer] * (100.0 / (bd[layer] * thickness[layer]));
                        NH4Supply[layer] = Math.Min(zone.NH4N[layer] * knh4 * NH4ppm * SWAF * factorRootDepth, (maxDailyNUptake.Value() - NH4Uptake));
                        NH4Uptake       += NH4Supply[layer];
                    }
                }
            }
        }
コード例 #21
0
 /// <summary>Finds out the amount of plant available water in the soil.</summary>
 /// <param name="myZone">The soil information</param>
 internal double[] EvaluateSoilWaterAvailable(ZoneWaterAndN myZone)
 {
     if (myWaterAvailableMethod == PastureSpecies.PlantAvailableWaterMethod.DefaultAPSIM)
     {
         return(PlantAvailableSoilWaterDefault(myZone));
     }
     else if (myWaterAvailableMethod == PastureSpecies.PlantAvailableWaterMethod.AlternativeKL)
     {
         return(PlantAvailableSoilWaterAlternativeKL(myZone));
     }
     else if (myWaterAvailableMethod == PastureSpecies.PlantAvailableWaterMethod.AlternativeKS)
     {
         return(PlantAvailableSoilWaterAlternativeKS(myZone));
     }
     else
     {
         throw new Exception("Invalid water uptake method found");
     }
 }
コード例 #22
0
 /// <summary>Finds out the amount of plant available nitrogen (NH4 and NO3) in the soil.</summary>
 /// <param name="myZone">The soil information</param>
 /// <param name="mySoilWaterUptake">Soil water uptake</param>
 internal void EvaluateSoilNitrogenAvailable(ZoneWaterAndN myZone, double[] mySoilWaterUptake)
 {
     if (myNitrogenAvailableMethod == PastureSpecies.PlantAvailableNitrogenMethod.BasicAgPasture)
     {
         PlantAvailableSoilNBasicAgPasture(myZone);
     }
     else if (myNitrogenAvailableMethod == PastureSpecies.PlantAvailableNitrogenMethod.DefaultAPSIM)
     {
         PlantAvailableSoilNDefaultAPSIM(myZone);
     }
     else if (myNitrogenAvailableMethod == PastureSpecies.PlantAvailableNitrogenMethod.AlternativeRLD)
     {
         PlantAvailableSoilNAlternativeRLD(myZone);
     }
     else if (myNitrogenAvailableMethod == PastureSpecies.PlantAvailableNitrogenMethod.AlternativeWup)
     {
         PlantAvailableSoilNAlternativeWup(myZone, mySoilWaterUptake);
     }
 }
コード例 #23
0
ファイル: SimpleTree.cs プロジェクト: Scicrop/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> GetWaterUptakeEstimates(SoilState soilstate)
        {
            ZoneWaterAndN MyZone = new ZoneWaterAndN(this.Parent as Zone);

            foreach (ZoneWaterAndN Z in soilstate.Zones)
            {
                if (Z.Zone.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.LL15mm.Length; j++)
            {
                PotSWUptake[j] = Math.Max(0.0, RootProportion(j, RootDepth) * soilCrop.KL[j] * (MyZone.Water[j] - Soil.LL15mm[j]));
            }

            double TotPotSWUptake = MathUtilities.Sum(PotSWUptake);

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

            List <ZoneWaterAndN> Uptakes = new List <ZoneWaterAndN>();
            ZoneWaterAndN        Uptake  = new ZoneWaterAndN(this.Parent as Zone);

            Uptake.Water = SWUptake;
            Uptake.NO3N  = new double[SWUptake.Length];
            Uptake.NH4N  = new double[SWUptake.Length];
            Uptake.NH4N  = new double[SWUptake.Length];
            Uptake.PlantAvailableNO3N = new double[SWUptake.Length];
            Uptake.PlantAvailableNH4N = new double[SWUptake.Length];
            Uptakes.Add(Uptake);
            return(Uptakes);
        }
コード例 #24
0
ファイル: SimpleTree.cs プロジェクト: Scicrop/ApsimX
        /// <summary>Placeholder for SoilArbitrator</summary>
        /// <param name="soilstate">soil state</param>
        /// <returns></returns>
        public List <ZoneWaterAndN> GetNitrogenUptakeEstimates(SoilState soilstate)
        {
            ZoneWaterAndN MyZone = new ZoneWaterAndN(this.Parent as Zone);

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

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

            var soilCrop = Soil.Crop(Name);

            for (int j = 0; j < Soil.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 < MyZone.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(this.Parent as Zone);

            Uptake.NO3N = NO3Uptake;
            Uptake.NH4N = NH4Uptake;
            Uptake.PlantAvailableNO3N = new double[NO3Uptake.Length];
            Uptake.PlantAvailableNH4N = new double[NO3Uptake.Length];
            Uptake.Water = new double[NO3Uptake.Length];
            Uptakes.Add(Uptake);
            return(Uptakes);
        }
コード例 #25
0
        private void StoreWaterVariablesForNitrogenUptake(ZoneWaterAndN zoneWater)
        {
            ZoneState myZone = root.Zones.Find(z => z.Name == zoneWater.Zone.Name);
            if (myZone != null)
            {

                //store Water variables for N Uptake calculation
                //Old sorghum doesn't do actualUptake of Water until end of day
                myZone.StartWater = new double[myZone.soil.Thickness.Length];
                myZone.AvailableSW = new double[myZone.soil.Thickness.Length];
                myZone.PotentialAvailableSW = new double[myZone.soil.Thickness.Length];

                for(int layer = 0; layer < myZone.soil.Thickness.Length; ++layer)
                {
                    myZone.StartWater[layer] = myZone.soil.Water[layer];

                    myZone.AvailableSW[layer] = myZone.soil.Water[layer] - myZone.soil.LL15mm[layer];
                    myZone.PotentialAvailableSW[layer] = myZone.soil.DULmm[layer] - myZone.soil.LL15mm[layer];
                }
            }
        }
コード例 #26
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);
        }
コード例 #27
0
ファイル: Root.cs プロジェクト: debunge/ApsimX
        /// <summary>Gets or sets the water supply.</summary>
        /// <param name="zone">The zone.</param>
        public double[] CalculateWaterSupply(ZoneWaterAndN zone)
        {
            ZoneState myZone = Zones.Find(z => z.Name == zone.Zone.Name);

            if (myZone == null)
            {
                return(null);
            }

            SoilCrop crop = myZone.soil.Crop(Plant.Name) as SoilCrop;

            double[] supply         = new double[myZone.soil.Thickness.Length];
            double[] layerMidPoints = Soil.ToMidPoints(myZone.soil.Thickness);
            for (int layer = 0; layer < myZone.soil.Thickness.Length; layer++)
            {
                if (layer <= Soil.LayerIndexOfDepth(myZone.Depth, myZone.soil.Thickness))
                {
                    supply[layer] = Math.Max(0.0, crop.KL[layer] * KLModifier.ValueForX(layerMidPoints[layer]) *
                                             (zone.Water[layer] - crop.LL[layer] * myZone.soil.Thickness[layer]) * Soil.ProportionThroughLayer(layer, myZone.Depth, myZone.soil.Thickness));
                }
            }

            return(supply);
        }
コード例 #28
0
ファイル: TreeProxy.cs プロジェクト: peter-devoil/ApsimX
        /// <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> GetNitrogenUptakeEstimates(Soils.Arbitrator.SoilState soilstate)
        {
            Zone treeZone = ZoneList.FirstOrDefault() as Zone;

            List <ZoneWaterAndN> Uptakes = new List <ZoneWaterAndN>();
            double PotNO3Supply          = 0; // Total N supply (kg)

            double NDemandkg = GetNDemandToday() * 10 * treeZone.Area;

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

                        foreach (Zone SearchZ in forestryZones)
                        {
                            if (SearchZ.Name == Z.Zone.Name)
                            {
                                ThisSoil     = SearchZ.FindInScope <Soils.Soil>();
                                soilPhysical = ThisSoil.FindChild <Soils.IPhysical>();
                                break;
                            }
                        }

                        double[] SW = Z.Water;

                        Uptake.NO3N  = new double[SW.Length];
                        Uptake.NH4N  = new double[SW.Length];
                        Uptake.Water = new double[SW.Length];
                        double[] LL15mm = MathUtilities.Multiply(soilPhysical.LL15, soilPhysical.Thickness);
                        double[] BD     = soilPhysical.BD;
                        double[] RLD    = GetRLD(ZI);

                        for (int i = 0; i <= SW.Length - 1; i++)
                        {
                            Uptake.NO3N[i]  = PotentialNO3Uptake(soilPhysical.Thickness[i], Z.NO3N[i], Z.Water[i], RLD[i], RootRadius, BD[i], Kd);
                            Uptake.NO3N[i] *= 10; // convert from g/m2 to kg/ha
                            PotNO3Supply   += Uptake.NO3N[i] * ZI.Area;
                        }
                        Uptakes.Add(Uptake);
                        break;
                    }
                }
            }
            // Now scale back uptakes if demand > supply
            double F = 0;  // Uptake scaling factor

            if (PotNO3Supply > 0)
            {
                F = NDemandkg / PotNO3Supply;
                if (F > 1)
                {
                    F = 1;
                }
            }
            else
            {
                F = 1;
            }
            NStress = Math.Min(1, Math.Max(0, PotNO3Supply / NDemandkg));

            List <double> uptakeList = new List <double>();

            foreach (ZoneWaterAndN Z in Uptakes)
            {
                Z.NO3N = MathUtilities.Multiply_Value(Z.NO3N, F);
                uptakeList.Add(Z.TotalNO3N);
            }

            NUptake = uptakeList.ToArray();
            return(Uptakes);
        }
コード例 #29
0
ファイル: TreeProxy.cs プロジェクト: peter-devoil/ApsimX
        /// <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> GetWaterUptakeEstimates(Soils.Arbitrator.SoilState soilstate)
        {
            double Etz = treeZoneWater.Eo; //Eo of Tree Zone

            SWDemand = 0;
            foreach (Zone ZI in ZoneList)
            {
                SWDemand += Etz * (GetShade(ZI) / 100) * (ZI.Area * 10000);    // 100 converts from %, 10000 converts from ha to m2
            }
            IndividualTreeWaterDemand = SWDemand / NumberOfTrees;

            List <ZoneWaterAndN> Uptakes = new List <ZoneWaterAndN>();
            double PotSWSupply           = 0; // Total water supply (L)

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

                        foreach (Zone SearchZ in forestryZones)
                        {
                            if (SearchZ.Name == Z.Zone.Name)
                            {
                                ThisSoil     = SearchZ.FindInScope <Soils.Soil>();
                                soilPhysical = ThisSoil.FindChild <Soils.IPhysical>();
                                break;
                            }
                        }

                        double[] SW = Z.Water;
                        Uptake.NO3N  = new double[SW.Length];
                        Uptake.NH4N  = new double[SW.Length];
                        Uptake.Water = new double[SW.Length];
                        double[] LL15mm = MathUtilities.Multiply(soilPhysical.LL15, soilPhysical.Thickness);
                        double[] RLD    = GetRLD(ZI);

                        for (int i = 0; i <= SW.Length - 1; i++)
                        {
                            Uptake.Water[i] = Math.Max(SW[i] - LL15mm[i], 0.0) * BaseKL * RLD[i];
                            PotSWSupply    += Uptake.Water[i] * ZI.Area * 10000;
                        }
                        Uptakes.Add(Uptake);
                        break;
                    }
                }
            }
            // 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;
            }
            WaterStress = Math.Min(1, Math.Max(0, PotSWSupply / SWDemand));

            List <double> uptakeList = new List <double>();

            foreach (ZoneWaterAndN Z in Uptakes)
            {
                Z.Water = MathUtilities.Multiply_Value(Z.Water, F);
                uptakeList.Add(Z.TotalWater);
            }

            WaterUptake = uptakeList.ToArray();
            return(Uptakes);
        }
コード例 #30
0
ファイル: PerennialLeaf.cs プロジェクト: her123/ApsimX
 /// <summary>Gets the nitrogen supply from the specified zone.</summary>
 /// <param name="zone">The zone.</param>
 /// <param name="NO3Supply">The returned NO3 supply</param>
 /// <param name="NH4Supply">The returned NH4 supply</param>
 public void CalcNSupply(ZoneWaterAndN zone, out double[] NO3Supply, out double[] NH4Supply)
 {
     NO3Supply = null;
     NH4Supply = null;
 }