Beispiel #1
0
        public static void FluxTable(double dz, SoilProps sp)
        {
            // Generates a flux table for use by other programs.
            // Assumes soil props available in sp of module soil.
            // dz - path length.


            //diags - timer start here

            nu   = sp.nc;
            ah   = sp.hc; aK = sp.Kc; aphi = sp.phic; aS = sp.Sc;
            aKco = sp.Kco; aphico = sp.phico;
            he   = sp.he; Ks = sp.ks;

            // Get K values for Simpson's integration rule in subroutine odef.
            for (i = 0; i < nu - 2; i++)
            {
                x      = 0.5 * (aphi[i + 1] - aphi[i]);
                hpK[i] = aK[i] + x * (aKco[0, i] + x * (aKco[1, i] + x * aKco[2, i]));
            }

            // Get fluxes aq(1,:) for values aphi[i] at bottom (wet), aphi(1) at top (dry).
            // These are used to select suitable phi values for flux table.
            nit      = 0;
            aq[1, 1] = aK[1];                            // q=K here because dphi/dz=0
            dh       = 2.0;                              // for getting phi in saturated region
            q1       = (aphi[1] - aphi[2]) / dz;         // q1 is initial estimate
            aq[1, 2] = ssflux(1, 2, dz, q1, 0.1 * rerr); // get accurate flux
            for (j = 2; j < nu + 20; j++)                // 20*dh should be far enough for small curvature in (phi,q)
            {
                if (j > nu)                              // part satn - set h, K and phi
                {
                    ah[j]   = ah[j - 1] + dh * (j - nu);
                    aK[j]   = Ks;
                    aphi[j] = aphi[j - 1] + Ks * dh * (j - nu);
                }
            }

            // get approx q from linear extrapolation
            q1       = aq[1, j - 1] + (aphi[j] - aphi[j - 1]) * (aq[1, j - 1] - aq[1, j - 2]) / (aphi[j - 1] - aphi[j - 2]);
            aq[1, j] = ssflux(1, j, dz, q1, 0.1 * rerr); // get accurate q
            nt       = j;
            ns       = nt - nu;
            if (j > nu)
            {
                if (-(aphi[j] - aphi[j - 1]) / (aq[1, j] - aq[1, j - 1]) < (1 + rerr) * dz)
                {
                    Environment.Exit(0);
                }
            }

            // Get phi values phif for flux table using curvature of q vs phi.
            // rerr and cfac determine spacings of phif.
            Vector <double> aphiV = Vector <double> .Build.DenseOfArray(aphi);

            Matrix <double> aqM = Matrix <double> .Build.DenseOfArray(aq);

            i  = nonlin(nu, aphiV.SubVector(0, nu).ToArray(), aqM.Column(0).SubVector(0, nu).ToArray(), rerr);
            re = curv(nu, aphiV.SubVector(0, nu).ToArray(), aqM.Column(0).SubVector(0, nu).ToArray());// for unsat phi
            indices(nu - 2, re.Take(nu - 3).Reverse().ToArray(), 1 + nu - i, cfac, out nphif, ref iphif);
            int[] iphifReverse = iphif.Take(nphif).Reverse().ToArray();
            for (int idx = 0; idx < nphif; idx++)
            {
                iphif[idx] = 1 + nu - iphifReverse[idx];                                                               // locations of phif in aphi
            }
            aphiV = Vector <double> .Build.DenseOfArray(aphi);                                                         //may not need to do this; haevn't check in aphi has changed since last use.

            aqM = Matrix <double> .Build.DenseOfArray(aq);                                                             //as above

            re = curv(1 + ns, aphiV.SubVector(nu, nt - nu).ToArray(), aqM.Column(1).SubVector(nu, nt - nu).ToArray()); // for sat phi
            indices(ns - 1, re, ns, cfac, out nfs, ref ifs);

            for (int idx = nphif; i < nphif + nfs - 2; idx++)
            {
                iphif[idx] = nu - 1 + ifs[idx];
            }
            nfu   = nphif; // no. of unsat phif
            nphif = nphif + nfs - 1;
            for (int idx = 0; i < nphif; idx++)
            {
                phif[idx]  = aphi[iphif[idx]];
                qf[0, idx] = aq[0, iphif[idx]];
            }
            // Get rest of fluxes
            // First for lower end wetter
            for (j = 1; j < nphif; j++)
            {
                for (i = 1; i < j; i++)
                {
                    q1 = qf[i - 1, j];
                    if (ah[iphif[j]] - dz < ah[iphif[i]])
                    {
                        q1 = 0.0; // improve?
                    }
                    qf[i, j] = ssflux(iphif[i], iphif[j], dz, q1, 0.1 * rerr);
                }
            }
            // Then for upper end wetter
            for (i = 1; i < nphif; i++)
            {
                for (j = i - 1; j > 1; j--)
                {
                    q1 = qf[i, j + 1];
                    if (j + 1 == i)
                    {
                        q1 = q1 + (aphi[iphif[i]] - aphi[iphif[j]]) / dz;
                    }
                    qf[i, j] = ssflux(iphif[i], iphif[j], dz, q1, 0.1 * rerr);
                }
            }
            // Use of flux table involves only linear interpolation, so gain accuracy
            // by providing fluxes in between using quadratic interpolation.
            ni = nphif - 1;
            for (int idx = 0; idx < ni; idx++)
            {
                phii[idx] = 0.5 * (phif[idx] + phif[idx + 1]);
            }

            Matrix <double> qi1M = Matrix <double> .Build.DenseOfArray(qi1);

            Matrix <double> qfM = Matrix <double> .Build.DenseOfArray(qf);

            double[] qi1Return;
            double[] qi2Return;
            double[] qi3Return;

            for (i = 0; i < nphif; i++)
            {
                qi1Return = quadinterp(phif, qfM.Row(i).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi1Return.Length; idx++)
                {
                    qi1[i, idx] = qi1Return[idx];
                }
            }

            for (j = 0; j < nphif; j++)
            {
                qi2Return = quadinterp(phif, qfM.Column(j).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi2Return.Length; idx++)
                {
                    qi2[idx, i] = qi2Return[idx];
                }
            }

            for (j = 0; j < ni; j++)
            {
                qi1M = Matrix <double> .Build.DenseOfArray(qi1);

                qi3Return = quadinterp(phif, qi1M.Column(j).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi3Return.Length; idx++)
                {
                    qi3[idx, i] = qi3Return[idx];
                }
            }

            // Put all the fluxes together.
            i = nphif + ni;
            for (int iidx = 0; iidx < i; i += 2)
            {
                for (int npidx = 0; npidx < nphif; npidx++)
                {
                    for (int niidx = 0; niidx < ni; niidx++)
                    {
                        qi5[iidx, iidx]         = qf[npidx, npidx];
                        qi5[iidx, iidx + 1]     = qi1[npidx, niidx];
                        qi5[iidx + 1, iidx]     = qi2[niidx, npidx];
                        qi5[iidx + 1, iidx + 1] = qi3[niidx, niidx];
                    }
                }
            }

            // Get accurate qi5(j,j)=Kofphi(phii(ip))
            ip = 0;
            for (j = 1; j < i; j += 2)
            {
                ip = ip + 1;
                ii = iphif[ip + 1] - 1;
                for (int idx = 0; idx < aphi.Length; idx++) // Search down to locate phii position for cubic.
                {
                    if (aphi[ii] <= phii[ip])
                    {
                        break;
                    }
                    ii = ii - 1;
                }
                x         = phii[ip] - aphi[ii];
                qi5[j, j] = aK[ii] + x * (aKco[1, ii] + x * (aKco[2, ii] + x * aKco[3, ii]));
            }

            for (int idx = 0; idx < i; i++)
            {
                phii5[idx * 2]     = phif[idx];
                phii5[idx * 2 + 1] = phii[idx];
            }

            // diags - end timer here


            // Assemble flux table
            j = 2 * nfu - 1;
            for (ie = 0; ie < 2; ie++)
            {
                pe      = ft.fend[ie];
                pe.phif = new double[phif.Length];
                pe.sid  = sp.sid;
                pe.nfu  = j;
                pe.nft  = i;
                pe.dz   = dz;
                pe.phif = phii5; //(1:i) assume it's the whole array
            }
            ft.ftable = qi5;     // (1:i,1:i) as above
        }
Beispiel #2
0
        public static void FluxTable(double dz, SoilProps sp)
        {
            // Generates a flux table for use by other programs.
            // Assumes soil props available in sp of module soil.
            // dz - path length.

            //diags - timer start here

            nu = sp.nc;
            ah = sp.hc; aK = sp.Kc; aphi = sp.phic; aS = sp.Sc;
            aKco = sp.Kco; aphico = sp.phico;
            he = sp.he; Ks = sp.ks;

            // Get K values for Simpson's integration rule in subroutine odef.
            for (i = 0; i < nu - 2; i++)
            {
                x = 0.5 * (aphi[i + 1] - aphi[i]);
                hpK[i] = aK[i] + x * (aKco[0, i] + x * (aKco[1, i] + x * aKco[2, i]));
            }

            // Get fluxes aq(1,:) for values aphi[i] at bottom (wet), aphi(1) at top (dry).
            // These are used to select suitable phi values for flux table.
            nit = 0;
            aq[1, 1] = aK[1]; // q=K here because dphi/dz=0
            dh = 2.0; // for getting phi in saturated region
            q1 = (aphi[1] - aphi[2]) / dz; // q1 is initial estimate
            aq[1, 2] = ssflux(1, 2, dz, q1, 0.1 * rerr); // get accurate flux
            for (j = 2; j < nu + 20; j++) // 20*dh should be far enough for small curvature in (phi,q)
                if (j > nu) // part satn - set h, K and phi
                {
                    ah[j] = ah[j - 1] + dh * (j - nu);
                    aK[j] = Ks;
                    aphi[j] = aphi[j - 1] + Ks * dh * (j - nu);
                }

            // get approx q from linear extrapolation
            q1 = aq[1, j - 1] + (aphi[j] - aphi[j - 1]) * (aq[1, j - 1] - aq[1, j - 2]) / (aphi[j - 1] - aphi[j - 2]);
            aq[1, j] = ssflux(1, j, dz, q1, 0.1 * rerr); // get accurate q
            nt = j;
            ns = nt - nu;
            if (j > nu)
                if (-(aphi[j] - aphi[j - 1]) / (aq[1, j] - aq[1, j - 1]) < (1 + rerr) * dz)
                    Environment.Exit(0);

            // Get phi values phif for flux table using curvature of q vs phi.
            // rerr and cfac determine spacings of phif.
            Vector<double> aphiV = Vector<double>.Build.DenseOfArray(aphi);
            Matrix<double> aqM = Matrix<double>.Build.DenseOfArray(aq);
            i = nonlin(nu, aphiV.SubVector(0, nu).ToArray(), aqM.Column(0).SubVector(0, nu).ToArray(), rerr);
            re = curv(nu, aphiV.SubVector(0, nu).ToArray(), aqM.Column(0).SubVector(0, nu).ToArray());// for unsat phi
            indices(nu - 2, re.Take(nu - 3).Reverse().ToArray(), 1 + nu - i, cfac, out nphif, ref iphif);
            int[] iphifReverse = iphif.Take(nphif).Reverse().ToArray();
            for (int idx = 0; idx < nphif; idx++)
                iphif[idx] = 1 + nu - iphifReverse[idx]; // locations of phif in aphi
            aphiV = Vector<double>.Build.DenseOfArray(aphi); //may not need to do this; haevn't check in aphi has changed since last use.
            aqM = Matrix<double>.Build.DenseOfArray(aq); //as above
            re = curv(1 + ns, aphiV.SubVector(nu, nt - nu).ToArray(), aqM.Column(1).SubVector(nu, nt - nu).ToArray()); // for sat phi
            indices(ns - 1, re, ns, cfac, out nfs, ref ifs);

            for (int idx = nphif; i < nphif + nfs - 2; idx++)
                iphif[idx] = nu - 1 + ifs[idx];
            nfu = nphif; // no. of unsat phif
            nphif = nphif + nfs - 1;
            for (int idx = 0; i < nphif; idx++)
            {
                phif[idx] = aphi[iphif[idx]];
                qf[0, idx] = aq[0, iphif[idx]];
            }
            // Get rest of fluxes
            // First for lower end wetter
            for (j = 1; j < nphif; j++)
                for (i = 1; i < j; i++)
                {
                    q1 = qf[i - 1, j];
                    if (ah[iphif[j]] - dz < ah[iphif[i]])
                        q1 = 0.0; // improve?
                    qf[i, j] = ssflux(iphif[i], iphif[j], dz, q1, 0.1 * rerr);
                }
            // Then for upper end wetter
            for (i = 1; i < nphif; i++)
                for (j = i - 1; j > 1; j--)
                {
                    q1 = qf[i, j + 1];
                    if (j + 1 == i)
                        q1 = q1 + (aphi[iphif[i]] - aphi[iphif[j]]) / dz;
                    qf[i, j] = ssflux(iphif[i], iphif[j], dz, q1, 0.1 * rerr);
                }
            // Use of flux table involves only linear interpolation, so gain accuracy
            // by providing fluxes in between using quadratic interpolation.
            ni = nphif - 1;
            for (int idx = 0; idx < ni; idx++)
                phii[idx] = 0.5 * (phif[idx] + phif[idx + 1]);

            Matrix<double> qi1M = Matrix<double>.Build.DenseOfArray(qi1);
            Matrix<double> qfM = Matrix<double>.Build.DenseOfArray(qf);
            double[] qi1Return;
            double[] qi2Return;
            double[] qi3Return;

            for (i = 0; i < nphif; i++)
            {
                qi1Return = quadinterp(phif, qfM.Row(i).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi1Return.Length; idx++)
                    qi1[i, idx] = qi1Return[idx];
            }

            for (j = 0; j < nphif; j++)
            {
                qi2Return = quadinterp(phif, qfM.Column(j).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi2Return.Length; idx++)
                    qi2[idx, i] = qi2Return[idx];
            }

            for (j = 0; j < ni; j++)
            {
                qi1M = Matrix<double>.Build.DenseOfArray(qi1);
                qi3Return = quadinterp(phif, qi1M.Column(j).ToArray(), nphif, phii);
                for (int idx = 0; idx < qi3Return.Length; idx++)
                    qi3[idx, i] = qi3Return[idx];
            }

            // Put all the fluxes together.
            i = nphif + ni;
            for (int iidx = 0; iidx < i; i += 2)
                for (int npidx = 0; npidx < nphif; npidx++)
                    for (int niidx = 0; niidx < ni; niidx++)
                    {
                        qi5[iidx, iidx] = qf[npidx, npidx];
                        qi5[iidx, iidx + 1] = qi1[npidx, niidx];
                        qi5[iidx + 1, iidx] = qi2[niidx, npidx];
                        qi5[iidx + 1, iidx + 1] = qi3[niidx, niidx];
                    }

            // Get accurate qi5(j,j)=Kofphi(phii(ip))
            ip = 0;
            for (j = 1; j < i; j += 2)
            {
                ip = ip + 1;
                ii = iphif[ip + 1] - 1;
                for (int idx = 0; idx < aphi.Length; idx++) // Search down to locate phii position for cubic.
                {
                    if (aphi[ii] <= phii[ip])
                        break;
                    ii = ii - 1;
                }
                x = phii[ip] - aphi[ii];
                qi5[j, j] = aK[ii] + x * (aKco[1, ii] + x * (aKco[2, ii] + x * aKco[3, ii]));
            }

            for (int idx = 0; idx < i; i++)
            {
                phii5[idx * 2] = phif[idx];
                phii5[idx * 2 + 1] = phii[idx];
            }

            // diags - end timer here

            // Assemble flux table
            j = 2 * nfu - 1;
            for (ie = 0; ie < 2; ie++)
            {
                pe = ft.fend[ie];
                pe.phif = new double[phif.Length];
                pe.sid = sp.sid;
                pe.nfu = j;
                pe.nft = i;
                pe.dz = dz;
                pe.phif = phii5; //(1:i) assume it's the whole array
            }
            ft.ftable = qi5; // (1:i,1:i) as above
        }