Exemple #1
0
        // The above parameters can be varied, but the defaults should usually be ok.

        //subroutine to generate the property values.
        public static SoilProps gensptbl(double dzmin, SoilParam sPar, bool Kgiven)
        {
            int nlimax = 220;
            int i, j, nli1, nc, nld;

            double[] h   = new double[nlimax + 3];
            double[] lhr = new double[nlimax + 3];
            double[] K   = new double[nlimax + 3];
            double[] phi = new double[nlimax + 3];
            double[] S   = new double[nlimax + 3];
            double[] cco = new double[4];

            //diags - timing starts here

            SoilProps sp = new SoilProps();

            sp.sid = sPar.sid; sp.ths = sPar.ths; sp.ks = sPar.ks;
            sp.he  = sPar.he; sp.phie = phie; sp.S = S; sp.n = sPar.layers;

            // Find start of significant fluxes.
            hdry   = sPar.hd;                 // normally -1e7 cm
            phidry = 0.0;
            hwet   = Math.Min(sPar.he, -1.0); // h/hwet used for log spacing

            if (Kgiven)
            {
                dlh    = Math.Log(10.0) / 3.0; // three points per decade
                x      = Math.Exp(-dlh);       // x*x*x=0.1
                h[0]   = hdry;
                K[0]   = MVG.Kofh(h[0]);
                phi[0] = 0.0;
                for (i = 1; i < nlimax; i++) // should exit well before nlimax
                {
                    h[i] = x * h[i - 1];
                    K[i] = MVG.Kofh(h[i]);
                    // Get approx. phi by integration using dln(-h).
                    phi[i] = phi[i - 1] - 0.5 * (K[i] * h[i] - K[i - 1] * h[i - 1]) * dlh;
                    if (phi[i] > qsmall * dzmin)
                    {
                        break; // max flux is approx (phi-0)/dzmin
                    }
                }
                if (i > nlimax)
                {
                    Console.WriteLine("gensptbl: start of significant fluxes not found");
                    Environment.Exit(1);
                }
                hdry   = h[i - 1];
                phidry = phi[i - 1];
            }
            else
            {
                // Calculate K and find start of significant fluxes.
                Props(ref sp, hdry, phidry, lhr, h, Kgiven);
                for (i = 2; i < sp.n; i++)
                {
                    if (phi[i] > qsmall * dzmin)
                    {
                        break;
                    }
                }
                if (i > sp.n)
                {
                    Console.WriteLine("gensptbl: start of significant fluxes not found");
                    Environment.Exit(1);
                }
                i      = i - 1;
                hdry   = h[i];
                phidry = phi[i];
            }

            // hdry and phidry are values where significant fluxes start.
            // Get props.
            sp.Kc = new double[sp.n];
            Props(ref sp, hdry, phidry, lhr, h, Kgiven);
            // Get ln(-h) and S values from dryness to approx -10000 cm.
            // These needed for vapour flux (rel humidity > 0.99 at -10000 cm).
            // To have complete S(h) coverage, bridge any gap between -10000 and h[1].
            x    = Math.Log(-Math.Max(vhmax, h[0]));
            lhd  = Math.Log(-sPar.hd);
            dlh  = Math.Log(10.0) / nhpd; // nhpd points per decade
            nli1 = (int)Math.Round((lhd - x) / dlh, 0);
            nld  = nli1 + 1;
            nc   = 1 + sp.n / 3; // n-1 has been made divisible by 3
            // fill out the rest of the structure.
            sp.nld   = nld; sp.nc = nc;
            sp.h     = h;
            sp.lnh   = new double[nld + 1];
            sp.Sd    = new double[nld + 1];
            sp.Kco   = new double[3 + 1, nc + 1];
            sp.phico = new double[3 + 1, nc + 1];
            sp.Sco   = new double[3 + 1, nc + 1];
            // Store Sd and lnh in sp.
            sp.lnh[1] = lhd;
            for (j = 2; j <= nld; j++)
            {
                sp.lnh[j] = lhd - dlh * (j - 1);
            }

            if (Kgiven)
            {
                sp.Sd[1] = MVG.Sofh(sPar.hd);
                for (j = 2; j <= nld; j++)
                {
                    x        = sp.lnh[j];
                    sp.Sd[j] = MVG.Sofh(-Math.Exp(x));
                }
            }
            else
            {
                MVG.Sdofh(sPar.hd, out x, out dSdh);
                sp.Sd[1] = x;
                for (j = 2; j <= nld; j++)
                {
                    x = sp.lnh[j];
                    MVG.Sdofh(-Math.Exp(x), out x, out dSdh);
                    sp.Sd[j] = x;
                }
            }

            // Get polynomial coefficients.
            j       = 0;
            sp.Sc   = new double[sp.n + 1];
            sp.hc   = new double[sp.n + 1];
            sp.phic = new double[sp.n + 1];
            Matrix <double> KcoM = Matrix <double> .Build.DenseOfArray(sp.Kco);

            Matrix <double> phicoM = Matrix <double> .Build.DenseOfArray(sp.phico);

            Matrix <double> ScoM = Matrix <double> .Build.DenseOfArray(sp.Sco);

            for (i = 1; i <= sp.n; i += 3)
            {
                j          = j + 1;
                sp.Sc[j]   = S[i];
                sp.hc[j]   = h[i];
                sp.Kc[j]   = sp.K[i];
                sp.phic[j] = sp.phi[i];
                if (i == sp.n)
                {
                    break;
                }

                cco = Cuco(sp.phi.Slice(i, i + 3), sp.K.Slice(i, i + 3));
                KcoM.SetColumn(j, cco.Slice(2, 4).ToArray());

                cco = Cuco(sp.S.Slice(i, i + 3), sp.phi.Slice(i, i + 3));
                phicoM.SetColumn(j, cco.Slice(2, 4).ToArray());

                cco = Cuco(sp.phi.Slice(i, i + 3), sp.S.Slice(i, i + 3));
                ScoM.SetColumn(j, cco.Slice(2, 4).ToArray());
            }
            sp.Kco   = KcoM.ToArray();
            sp.phico = phicoM.ToArray();
            sp.Sco   = ScoM.ToArray();
            return(sp);
        }
Exemple #2
0
        private static void Props(ref SoilProps sp, double hdry, double phidry, double[] lhr, double[] h, bool Kgiven)
        {
            int i, j, nli;

            double[] g     = new double[201];
            double[] dSdhg = new double[201];

            j   = 2 * (nliapprox / 6); // an even number
            nli = 3 * j;               //nli divisible by 2 (for integrations) and 3 (for cubic coeffs)
            if (sp.he > hwet)
            {
                nli = 3 * (j + 1) - 1;           // to allow for extra points
            }
            dlhr = -Math.Log(hdry / hwet) / nli; // even spacing in log(-h)

            // lhr(1:nli + 1) = (/ (-i * dlhr,i = nli,0,-1)/)
            double[] slice = lhr.Slice(1, nli + 1);
            for (int idx = nli; idx > 0; idx--)
            {
                slice[idx] = -idx * dlhr;
            }
            Array.Reverse(slice);
            Array.Copy(slice, 0, lhr, 0, slice.Length);
            for (int idx = 1; idx <= nli + 1; idx++)
            {
                h[idx] = hwet * Math.Exp(lhr[idx]);
            }

            if (sp.he > hwet)  // add extra points
            {
                sp.n        = nli + 3;
                h[sp.n - 1] = 0.5 * (sp.he + hwet);
                h[sp.n]     = sp.he;
            }
            else
            {
                sp.n = nli + 1;
            }

            sp.K   = new double[sp.n + 1];
            sp.Kc  = new double[sp.n + 1];
            sp.phi = new double[sp.n + 1];

            if (Kgiven)
            {
                for (i = 1; i <= sp.n; i++)
                {
                    sp.S[i] = MVG.Sofh(h[i]);
                    sp.K[i] = MVG.KofhS(h[i], sp.S[i]);
                }
                sp.S[sp.n] = MVG.Sofh(h[sp.n]);
            }
            else // calculate relative K by integration using dln(-h)
            {
                for (i = 1; i <= sp.n; i++)
                {
                    MVG.Sdofh(h[i], out sp.S[i], out dSdhg[i]);
                }

                g[1] = 0;

                for (i = 2; i <= nli; i += 2)  // integrate using Simpson's rule
                {
                    g[i + 1] = g[i - 1] + dlhr * (dSdhg[i - 1] + 4.0 * dSdhg[i] + dSdhg[i + 1]) / 3.0;
                }

                g[2] = 0.5 * (g[0] + g[2]);

                for (i = 3; i <= nli - 1; i += 2)
                {
                    g[i + 1] = g[i - 1] + dlhr * (dSdhg[i - 1] + 4.0 * dSdhg[i] + dSdhg[i + 1]) / 3.0;
                }

                if (sp.he > hwet)
                {
                    g[sp.n]     = g[sp.n - 2] + (h[sp.n] - h[sp.n - 1]) * (dSdhg[sp.n - 2] / h[sp.n - 2] + 4.0 * dSdhg[sp.n - 1] / h[sp.n - 1]) / 3.0;
                    g[sp.n - 1] = g[sp.n]; // not accurate, but K[sp.n-1] will be discarded
                }

                for (i = 1; i <= sp.n; i++)
                {
                    sp.K[i] = sp.ks * Math.Pow(sp.S[i], MVG.GetP()) * Math.Pow(g[i] / g[sp.n], 2);
                }
            }

            // Calculate phi by integration using dln(-h).
            sp.phi[1] = phidry;

            for (i = 2; i <= nli; i += 2) // integrate using Simpson's rule
            {
                sp.phi[i + 1] = sp.phi[i - 1] + dlhr * (sp.K[i - 1] * h[i - 1] + 4.0 * sp.K[i] * h[i] + sp.K[i + 1] * h[i + 1]) / 3.0;
            }

            sp.phi[2] = 0.5 * (sp.phi[1] + sp.phi[3]);

            for (i = 3; i <= nli - 1; i += 2)
            {
                sp.phi[i + 1] = sp.phi[i - 1] + dlhr * (sp.K[i - 1] * h[i - 1] + 4.0 * sp.K[i] * h[i] + sp.K[i + 1] * h[i + 1]) / 3.0;
            }

            if (sp.he > hwet)  // drop unwanted point
            {
                sp.phi[sp.n - 1] = sp.phi[sp.n - 2] + (h[sp.n] - h[sp.n - 1]) * (sp.K[sp.n - 2] + 4.0 * sp.K[sp.n - 1] + sp.K[sp.n]) / 3.0;
                h[sp.n - 1]      = h[sp.n];
                sp.S[sp.n - 1]   = sp.S[sp.n];
                sp.K[sp.n - 1]   = sp.K[sp.n];
                sp.n             = sp.n - 1;
            }
            phie    = sp.phi[sp.n];
            sp.phie = phie;
        }