Beispiel #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NormalSurface"/> class.
 /// </summary>
 /// <param name="SoilObject">The soil object.</param>
 /// <param name="Clock">The clock.</param>
 public NormalSurface(SoilWaterSoil SoilObject, IClock Clock)
 {
     SurfaceType    = Surfaces.NormalSurface;
     base.constants = SoilObject.Constants;
     runoff         = new NormalRunoff(SoilObject); //Soil is needed to initialise the cn2bare, etc.
     evap           = new NormalEvaporation(SoilObject, Clock);
 }
Beispiel #2
0
        //Constructor

        public NormalEvaporation(SoilWaterSoil SoilObject, IClock Clock)
        {
            cons = SoilObject.Constants;

            salb = SoilObject.Salb;

            summerCona = SoilObject.SummerCona;
            summerU    = SoilObject.SummerU;
            summerDate = SoilObject.SummerDate;

            winterCona = SoilObject.WinterCona;
            winterU    = SoilObject.WinterU;
            winterDate = SoilObject.WinterDate;


            // soilwat2_soil_property_param()

            //u - can either use (one value for summer and winter) or two different values.
            //    (must also take into consideration where they enter two values [one for summer and one for winter] but they make them both the same)


            if ((Double.IsNaN(summerU) || (Double.IsNaN(winterU))))
            {
                throw new Exception("A single value for u OR BOTH values for summeru and winteru must be specified");
            }
            //if they entered two values but they made them the same
            if (summerU == winterU)
            {
                u = summerU;      //u is now no longer null. As if the user had entered a value for u.
            }



            //cona - can either use (one value for summer and winter) or two different values.
            //       (must also take into consideration where they enter two values [one for summer and one for winter] but they make them both the same)

            if ((Double.IsNaN(summerCona)) || (Double.IsNaN(winterCona)))
            {
                throw new Exception("A single value for cona OR BOTH values for summercona and wintercona must be specified");
            }
            //if they entered two values but they made them the same.
            if (summerCona == winterCona)
            {
                cona = summerCona;   //cona is now no longer null. As if the user had entered a value for cona.
            }


            //summer and winter default dates.
            if (summerDate == "not_read")
            {
                summerDate = "1-oct";
            }

            if (winterDate == "not_read")
            {
                winterDate = "1-apr";
            }

            InitialiseAccumulatingVars(SoilObject, Clock);
        }
Beispiel #3
0
        /// <summary>
        /// Adds the backed up water to surface.
        /// </summary>
        /// <param name="BackedUp">The backed up.</param>
        /// <param name="SoilObject">The soil object.</param>
        public override void AddBackedUpWaterToSurface(double BackedUp, ref SoilWaterSoil SoilObject)
        {
            //do normal surface add backup to surface
            base.AddBackedUpWaterToSurface(BackedUp, ref SoilObject);

            //Any extra_runoff then it becomes a pond.
            pond = Math.Min(base.Runoff, SoilObject.max_pond);

            //If there is too much for the pond handle then add the excess to normal runoff.
            base.Runoff = base.Runoff - pond;
        }
Beispiel #4
0
        public void CalcRunoff(double WaterForRunoff, SoilWaterSoil SoilObject)
        {
            //private void soilwat2_runoff(double Rain, double Runon, double TotalInterception, ref double Runoff)
            //{

            Runoff = 0.0;  //zero the return parameter

            if (WaterForRunoff > 0.0)
            {
                CalcRunoff_USDA_SoilConservationService(WaterForRunoff, SoilObject);

                cumWaterSinceTillage = cumWaterSinceTillage + WaterForRunoff;
                ShouldIStopTillageCNReduction();  //! NB. this needs to be done _after_ cn calculation.
            }
        }
Beispiel #5
0
        /// <summary>
        /// Gets the surface.
        /// </summary>
        /// <param name="SoilObject">The soil object.</param>
        /// <param name="Clock">The clock.</param>
        /// <returns></returns>
        public Surface GetSurface(SoilWaterSoil SoilObject, IClock Clock)
        {
            Surface surface;

            if (SoilObject.max_pond <= 0.0)
            {
                surface = new NormalSurface(SoilObject, Clock);
            }
            else
            {
                surface = new PondSurface(SoilObject, Clock);
            }

            return(surface);
        }
Beispiel #6
0
        private void soilwat2_runoff_depth_factor(SoilWaterSoil SoilObject, ref double[] runoff_wf)
        {
            //runoff_wf -> ! (OUTPUT) weighting factor for runoff

            //*+  Purpose
            //*      Calculate the weighting factor hydraulic effectiveness used
            //*      to weight the effect of soil moisture on runoff.

            //*+  Mission Statement
            //*      Calculate soil moisture effect on runoff


            double cum_depth;                    //! cumulative depth (mm)
            double hydrol_effective_depth_local; //! hydrologically effective depth for runoff (mm) - for when erosion turned on
            int    hydrol_effective_layer;       //! layer number that the effective depth occurs in ()

            double scale_fact;                   //! scaling factor for wf function to sum to 1
            double wf_tot;                       //! total of wf ()
            double wx;                           //! depth weighting factor for current total depth. intermediate variable for deriving wf (total wfs to current layer)
            double xx;                           //! intermediate variable for deriving wf total wfs to previous layer

            xx        = 0.0;
            cum_depth = 0.0;
            wf_tot    = 0.0;


            //! check if hydro_effective_depth applies for eroded profile.
            hydrol_effective_depth_local = Math.Min(cons.hydrol_effective_depth, SoilObject.DepthTotal);

            scale_fact             = 1.0 / (1.0 - Math.Exp(-4.16));
            hydrol_effective_layer = SoilObject.FindLayerNo(hydrol_effective_depth_local);

            foreach (Layer lyr in SoilObject.TopToX(hydrol_effective_layer))
            {
                cum_depth = cum_depth + lyr.dlayer;
                cum_depth = Math.Min(cum_depth, hydrol_effective_depth_local);

                //! assume water content to c%hydrol_effective_depth affects runoff
                //! sum of wf should = 1 - may need to be bounded? <dms 7-7-95>
                wx = scale_fact * (1.0 - Math.Exp(-4.16 * MathUtilities.Divide(cum_depth, hydrol_effective_depth_local, 0.0)));
                runoff_wf[lyr.number - 1] = wx - xx;  //zero based array
                xx = wx;

                wf_tot = wf_tot + runoff_wf[lyr.number - 1]; //zero based array.
            }

            cons.bound_check_real_var(wf_tot, 0.9999, 1.0001, "wf_tot");
        }
Beispiel #7
0
        //Constructor

        public NormalRunoff(SoilWaterSoil SoilObject)
        {
            cons = SoilObject.Constants;

            _cn2_bare  = SoilObject.cn2_bare;
            coverCnRed = SoilObject.cn_red;
            coverCnCov = SoilObject.cn_cov;


            //soilwat2_soil_property_param()

            if (coverCnRed >= _cn2_bare)
            {
                coverCnRed = _cn2_bare - 0.00009;
            }
        }
Beispiel #8
0
        /// <summary>
        /// Adds the backed up water to surface.
        /// </summary>
        /// <param name="BackedUp">The backed up.</param>
        /// <param name="SoilObject">The soil object.</param>
        public override void AddBackedUpWaterToSurface(double BackedUp, ref SoilWaterSoil SoilObject)
        {
            //If Infiltration was more water that the top layer of soil had empty then the extra water had no choice but to back up.
            //In this case turn the backed up water into runoff and reduce the infiltration to only what the top layer could take before backing up.
            //The amount the top layer can take must be equal to the infiltration - backedup amount.

            //nb. What if lateral inflow caused it to back up? We are assuming only source of water into top layer is infiltration from surface.


            //remove backed up amount from the top layer of the soil. (All of the infiltration did not infiltrate)
            Layer top = SoilObject.GetTopLayer();

            top.sw_dep = top.sw_dep - BackedUp;

            //now reduce the infiltration amount by what backed up.
            base.Infiltration = base.Infiltration - BackedUp;

            //turn the proportion of the infiltration that backed up into runoff.
            base.Runoff = base.Runoff + BackedUp;
        }
Beispiel #9
0
 /// <summary>
 /// Removes the evaporation from soil.
 /// </summary>
 /// <param name="SoilObject">The soil object.</param>
 public virtual void RemoveEvaporationFromSoil(ref SoilWaterSoil SoilObject)
 {
 }
Beispiel #10
0
 //nb. Use the methods below rather then just using a SoilObject method to add infiltration or remove water,
 //    because we might want to create Surfaces such as cracking clays that adds infiltration to not just
 //    the top layer but multiple layers. Also these surfaces might want to remove evaporation from
 //    multiple layers and not just the top layer. They will need logic to decide what fractions of
 //    infiltration or evaporation that they want to remove from which layers.
 /// <summary>
 /// Adds the infiltration to soil.
 /// </summary>
 /// <param name="SoilOject">The soil oject.</param>
 public virtual void AddInfiltrationToSoil(ref SoilWaterSoil SoilOject)
 {
 }
Beispiel #11
0
        //Initialise the Accumulating Variables

        public void InitialiseAccumulatingVars(SoilWaterSoil SoilObject, IClock Clock)
        {
            //reset the accumulated Evap variables (sumes1, sumes2, t)
            //nb. sumes1 -> is sum of es during stage1
            //used in the SoilWater Init, Reset event



            // soilwat2_soil_property_param()

            //assign u and cona to either sumer or winter values
            // Need to add 12 hours to move from "midnight" to "noon", or this won't work as expected
            if (DateUtilities.WithinDates(winterDate, Clock.Today, summerDate))
            {
                cona = winterCona;
                u    = winterU;
            }
            else
            {
                cona = summerCona;
                u    = summerU;
            }



            //private void soilwat2_evap_init()
            //    {

            //##################
            //Evap Init   --> soilwat2_evap_init (), soilwat2_ritchie_init()
            //##################


            //soilwat2_ritchie_init();
            //*+  Mission Statement
            //*       Initialise ritchie evaporation model

            double swr_top;       //! stage 2 evaporation occurs ratio available sw potentially available sw in top layer

            Layer top = SoilObject.GetTopLayer();

            //! set up evaporation stage
            swr_top = MathUtilities.Divide((top.sw_dep - top.ll15_dep), (top.dul_dep - top.ll15_dep), 0.0);
            swr_top = cons.bound(swr_top, 0.0, 1.0);

            //! are we in stage1 or stage2 evap?
            if (swr_top < cons.sw_top_crit)
            {
                //! stage 2 evap
                sumes2 = cons.sumes2_max - (cons.sumes2_max * MathUtilities.Divide(swr_top, cons.sw_top_crit, 0.0));
                sumes1 = u;
                t      = MathUtilities.Sqr(MathUtilities.Divide(sumes2, cona, 0.0));
            }
            else
            {
                //! stage 1 evap
                sumes2 = 0.0;
                sumes1 = cons.sumes1_max - (cons.sumes1_max * swr_top);
                t      = 0.0;
            }
        }
Beispiel #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PondSurface"/> class.
 /// </summary>
 /// <param name="SoilObject">The soil object.</param>
 /// <param name="Clock">The clock.</param>
 public PondSurface(SoilWaterSoil SoilObject, IClock Clock) : base(SoilObject, Clock)
 {
     base.SurfaceType = Surfaces.PondSurface;
     pond             = 0.0;
     pond_evap        = 0.0;
 }
Beispiel #13
0
        /// <summary>
        /// Removes the evaporation from soil.
        /// </summary>
        /// <param name="SoilObject">The soil object.</param>
        public override void RemoveEvaporationFromSoil(ref SoilWaterSoil SoilObject)
        {
            Layer top = SoilObject.GetTopLayer();

            top.sw_dep = top.sw_dep - Es;
        }
Beispiel #14
0
        /// <summary>
        /// Adds the infiltration to soil.
        /// </summary>
        /// <param name="SoilObject">The soil object.</param>
        public override void AddInfiltrationToSoil(ref SoilWaterSoil SoilObject)
        {
            Layer top = SoilObject.GetTopLayer();

            top.sw_dep = top.sw_dep + Infiltration;
        }
Beispiel #15
0
        private void CalcRunoff_USDA_SoilConservationService(double WaterForRunoff, SoilWaterSoil SoilObject)
        {
            //private void soilwat2_scs_runoff(double Rain, double Runon, double TotalInterception, ref double Runoff)
            //    {
            //cn2_new (output)
            //Runoff  (output)

            double cn;                                 //! scs curve number
            double cn1;                                //! curve no. for dry soil (antecedant) moisture
            double cn3;                                //! curve no. for wet soil (antecedant) moisture
            double cnpd;                               //! cn proportional in dry range (dul to ll15)

            double s;                                  //! potential max retention (surface ponding + infiltration)
            double xpb;                                //! intermedite variable for deriving runof

            double[] runoff_wf;                        //! weighting factor for depth for each layer
            double   dul_fraction;                     // if between (0-1) not above dul, if (1-infinity) above dul


            double cover_fract;                        //! proportion of maximum cover effect on runoff (0-1)
            double cover_reduction = 0.0;

            double tillage_fract;
            double tillage_reduction = 0.0;            //! reduction in cn due to tillage


            runoff_wf = new double[SoilObject.num_layers];

            soilwat2_runoff_depth_factor(SoilObject, ref runoff_wf);

            cnpd = 0.0;
            foreach (Layer lyr in SoilObject)
            {
                dul_fraction = MathUtilities.Divide((lyr.sw_dep - lyr.ll15_dep), (lyr.dul_dep - lyr.ll15_dep), 0.0);
                cnpd         = cnpd + dul_fraction * runoff_wf[lyr.number - 1]; //zero based array.
            }
            cnpd = cons.bound(cnpd, 0.0, 1.0);


            //reduce cn2 for the day due to the cover effect
            //nb. cover_surface_runoff should really be a parameter to this function
            cover_fract     = MathUtilities.Divide(cover_surface_runoff, coverCnCov, 0.0);
            cover_fract     = cons.bound(cover_fract, 0.0, 1.0);
            cover_reduction = coverCnRed * cover_fract;
            cn2_new         = _cn2_bare - cover_reduction;


            //tillage reduction on cn
            //nb. tillage_cn_red, tillage_cn_rain, and tillage_rain_sum, should really be parameters to this function
            if (tillageCnCumWater > 0.0)
            {
                //We minus 1 because we want the opposite fraction.
                //Tillage Reduction is biggest (CnRed value) straight after Tillage and gets smaller and becomes 0 when reaches CumWater.
                //unlike the Cover Reduction, where the reduction starts out smallest (0) and gets bigger and becomes (CnRed value) when you hit CnCover.
                tillage_fract     = MathUtilities.Divide(cumWaterSinceTillage, tillageCnCumWater, 0.0) - 1.0;
                tillage_reduction = tillageCnRed * tillage_fract;
                cn2_new           = cn2_new + tillage_reduction;
            }
            else
            {
                //nothing
            }


            //! cut off response to cover at high covers if p%cn_red < 100.
            cn2_new = cons.bound(cn2_new, 0.0, 100.0);

            cn1 = MathUtilities.Divide(cn2_new, (2.334 - 0.01334 * cn2_new), 0.0);
            cn3 = MathUtilities.Divide(cn2_new, (0.4036 + 0.005964 * cn2_new), 0.0);
            cn  = cn1 + (cn3 - cn1) * cnpd;

            // ! curve number will be decided from scs curve number table ??dms
            s   = 254.0 * (MathUtilities.Divide(100.0, cn, 1000000.0) - 1.0);
            xpb = WaterForRunoff - 0.2 * s;
            xpb = Math.Max(xpb, 0.0);

            //assign the output variable
            Runoff = MathUtilities.Divide(xpb * xpb, (WaterForRunoff + 0.8 * s), 0.0);

            //sv- I added these output variables
            cn_red_cov  = cover_reduction;
            cn_red_till = tillage_reduction;


            //bound check the ouput variable
            cons.bound_check_real_var(Runoff, 0.0, WaterForRunoff, "runoff");
        }
Beispiel #16
0
        public void CalcEs_RitchieEq_LimitedBySW(double Eo, SoilWaterSoil SoilObject, IClock Clock, double Infiltration)
        {
            //private void soilwat2_ritchie_evaporation()
            //    {
            //es          -> ! (output) actual evaporation (mm)
            //eos         -> ! (input) potential rate of evaporation (mm/day)
            //avail_sw_top -> ! (input) upper limit of soil evaporation (mm/day)  !sv- now calculated in here, not passed in as a argument.

            //*+  Purpose
            //*          ****** calculate actual evaporation from soil surface (es) ******
            //*          most es takes place in two stages: the constant rate stage
            //*          and the falling rate stage (philip, 1957).  in the constant
            //*          rate stage (stage 1), the soil is sufficiently wet for water
            //*          be transported to the surface at a rate at least equal to the
            //*          evaporation potential (eos).
            //*          in the falling rate stage (stage 2), the surface soil water
            //*          content has decreased below a threshold value, so that es
            //*          depends on the flux of water through the upper layer of soil
            //*          to the evaporating site near the surface.

            //*+  Notes
            //*       This changes globals - sumes1/2 and t.

            Es = 0.0;  //Zero the return value.


            double avail_sw_top;    //! available soil water in top layer for actual soil evaporation (mm)


            //2. get available soil water for evaporation

            Layer top = SoilObject.GetTopLayer();

            avail_sw_top = top.sw_dep - top.air_dry_dep;
            avail_sw_top = cons.bound(avail_sw_top, 0.0, Eo);



            //3. get actual soil water evaporation


            double esoil1;     //! actual soil evap in stage 1
            double esoil2;     //! actual soil evap in stage 2
            double sumes1_max; //! upper limit of sumes1
            double w_inf;      //! infiltration into top layer (mm)



            // Need to add 12 hours to move from "midnight" to "noon", or this won't work as expected
            if (DateUtilities.WithinDates(winterDate, Clock.Today, summerDate))
            {
                cona = winterCona;
                u    = winterU;
            }
            else
            {
                cona = summerCona;
                u    = summerU;
            }

            sumes1_max = u;
            w_inf      = Infiltration;

            //! if infiltration, reset sumes1
            //! reset sumes2 if infil exceeds sumes1
            if (w_inf > 0.0)
            {
                sumes2 = Math.Max(0.0, (sumes2 - Math.Max(0.0, w_inf - sumes1)));
                sumes1 = Math.Max(0.0, sumes1 - w_inf);

                //! update t (incase sumes2 changed)
                t = MathUtilities.Sqr(MathUtilities.Divide(sumes2, cona, 0.0));
            }
            else
            {
                //! no infiltration, no re-set.
            }

            //! are we in stage1 ?
            if (sumes1 < sumes1_max)
            {
                //! we are in stage1
                //! set esoil1 = potential, or limited by u.
                esoil1 = Math.Min(Eos, sumes1_max - sumes1);

                if ((Eos > esoil1) && (esoil1 < avail_sw_top))
                {
                    //*           !  eos not satisfied by 1st stage drying,
                    //*           !  & there is evaporative sw excess to air_dry, allowing for esoil1.
                    //*           !  need to calc. some stage 2 drying(esoil2).

                    //*  if g%sumes2.gt.0.0 then esoil2 =f(sqrt(time),p%cona,g%sumes2,g%eos-esoil1).
                    //*  if g%sumes2 is zero, then use ritchie's empirical transition constant (0.6).

                    if (sumes2 > 0.0)
                    {
                        t      = t + 1.0;
                        esoil2 = Math.Min((Eos - esoil1), (cona * Math.Pow(t, 0.5) - sumes2));
                    }
                    else
                    {
                        esoil2 = 0.6 * (Eos - esoil1);
                    }
                }
                else
                {
                    //! no deficit (or esoil1.eq.eos_max,) no esoil2 on this day
                    esoil2 = 0.0;
                }

                //! check any esoil2 with lower limit of evaporative sw.
                esoil2 = Math.Min(esoil2, avail_sw_top - esoil1);


                //!  update 1st and 2nd stage soil evaporation.
                sumes1 = sumes1 + esoil1;
                sumes2 = sumes2 + esoil2;
                t      = MathUtilities.Sqr(MathUtilities.Divide(sumes2, cona, 0.0));
            }
            else
            {
                //! no 1st stage drying. calc. 2nd stage
                esoil1 = 0.0;

                t      = t + 1.0;
                esoil2 = Math.Min(Eos, (cona * Math.Pow(t, 0.5) - sumes2));

                //! check with lower limit of evaporative sw.
                esoil2 = Math.Min(esoil2, avail_sw_top);

                //!   update 2nd stage soil evaporation.
                sumes2 = sumes2 + esoil2;
            }

            Es = esoil1 + esoil2;

            //! make sure we are within bounds
            Es = cons.bound(Es, 0.0, Eos);
            Es = cons.bound(Es, 0.0, avail_sw_top);
        }
Beispiel #17
0
 /// <summary>
 /// Adds the backed up water to surface.
 /// </summary>
 /// <param name="BackedUp">The backed up.</param>
 /// <param name="SoilObject">The soil object.</param>
 public virtual void AddBackedUpWaterToSurface(double BackedUp, ref SoilWaterSoil SoilObject)
 {
 }