Esempio n. 1
0
        private static void WriteFluxes(BinaryWriter b, FluxTable fluxTable)
        {
            byte[]          bytes;
            BinaryFormatter formatter = new BinaryFormatter();

            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, fluxTable);
                bytes = stream.ToArray();
            }
            b.Write(bytes);
        }
Esempio n. 2
0
 /// <summary>
 /// Only used in unit tests. Resets all static variables
 /// </summary>
 public static void TestReset()
 {
     mx      = 100;
     maxit   = 20;
     i       = j = k = m = ni = id = ip = nco1 = nco2 = ie = ii = jj = 0;
     nft     = new int[2 + 1];
     nfu     = new int[2 + 1];
     n       = new int[2 + 1];
     nfi     = new int[2 + 1];
     rerr    = 1e-3;
     phi1max = dhe = v = vlast = dx = e = f = df = q1 = phialast = v1 = v2 = f1 = f2 = 0;
     he      = new double[2 + 1];
     phie    = new double[2 + 1];
     Ks      = new double[2 + 1];
     co      = new double[4 + 1];
     xval    = new double[mx + 1];
     phico1  = new double[mx + 1];
     phico2  = new double[mx + 1];
     hi      = new double[3 * mx + 1];
     phif    = new double[mx + 1, 2 + 1];
     phifi   = new double[mx + 1, 2 + 1];
     phii5   = new double[mx + 1, 2 + 1];
     coq     = new double[3 * mx + 1, 3 + 1];
     co1     = new double[mx + 1, 4 + 1];
     qp      = new double[mx + 1, mx + 1];
     qi1     = new double[mx + 1, mx + 1];
     qi2     = new double[mx + 1, mx + 1];
     qi3     = new double[mx + 1, mx + 1];
     qi5     = new double[mx + 1, mx + 1];
     h       = new double[3 * mx + 1, 2 + 1];
     phi     = new double[3 * mx + 1, 2 + 1];
     phii    = new double[3 * mx + 1, 2 + 1];
     qf      = new double[mx + 1, mx + 1, 2 + 1];
     co2     = new double[mx + 1, mx + 1, 4 + 1];
     ftwo    = new FluxTable();
     ft      = new FluxTable[] { new FluxTable(), new FluxTable() };
     sp      = new SoilProps[] { new SoilProps(), new SoilProps() };
 }
Esempio n. 3
0
 private static void WriteFluxes(BinaryWriter b, FluxTable fluxTable)
 {
     byte[] bytes;
     BinaryFormatter formatter = new BinaryFormatter();
     using (MemoryStream stream = new MemoryStream())
     {
         formatter.Serialize(stream, fluxTable);
         bytes = stream.ToArray();
     }
     b.Write(bytes);
 }
Esempio n. 4
0
 public static FluxTable TwoTables(FluxTable ft1, SoilProps sp1, FluxTable ft2, SoilProps sp2)
 {
     return(new FluxTable());
 }
Esempio n. 5
0
        public static FluxTable TwoTables(FluxTable ft1, SoilProps sp1, FluxTable ft2, SoilProps sp2)
        {
            /*Generates a composite flux table from two uniform ones.
             * Sets up quadratic interpolation table to get phi at interface for lower path
             * from phi at interface for upper path.
             * Sets up cubic interpolation tables to get fluxes from phi at interface for
             * upper and lower paths.
             * Solves for phi at interface in upper path that gives same fluxes in upper
             * and lower paths, for all phi at upper and lower ends of composite path.
             * Increases no. of fluxes in table by quadratic interpolation.
             * ft1, ft2 - flux tables for upper and lower paths.
             * sp1, sp2 - soil prop tables for upper and lower paths. -PR
             *
             * Note that arrays are one indexed; 0 index is not used.
             * This is done as a number of calculations use the index as an input.
             * Exception to this is flux/soil arrays where array index is not used in calculations. -JF
             */


            // Set up required pointers and data
            if (ft1.fend[0].sid != ft1.fend[1].sid || ft2.fend[0].sid != ft2.fend[1].sid)
            {
                Console.WriteLine("Flux table not for uniform soil.");
                Environment.Exit(1);
            }
            ft1.ftable = Matrix <double> .Build.DenseOfArray(ft1.ftable).Transpose().ToArray();

            ft2.ftable = Matrix <double> .Build.DenseOfArray(ft2.ftable).Transpose().ToArray();

            ft[0] = ft1;
            ft[1] = ft2;
            sp[0] = sp1;
            sp[1] = sp2;
            for (i = 1; i <= 2; i++)
            {
                n[i]    = sp[i - 1].n;
                he[i]   = sp[i - 1].he;
                phie[i] = sp[i - 1].phie;
                Ks[i]   = sp[i - 1].ks;
                for (int x = 1; x <= n[i]; x++)
                {
                    h[x, i]   = sp[i - 1].h[x];
                    phi[x, i] = sp[i - 1].phi[x];
                }
            }

            // Discard unwanted input - use original uninterpolated values only.
            for (i = 1; i <= 2; i++)
            {
                m = ft[i - 1].fend[0].nft; //should be odd
                j = 1 + m / 2;
                double[] tempPhif = new double[j + 1];
                Array.Copy(ft[i - 1].fend[0].phif.Where((x, it) => it % 2 == 1).ToArray(), 0, tempPhif, 1, j);
                for (int x = 1; x <= j; x++)
                {
                    phif[x, i] = tempPhif[x]; //discard every second
                }
                nft[i] = j;
                nfu[i] = 1 + ft[i - 1].fend[1].nfu / 2; //ft[i].fend[1].nfu should be odd


                double[,] tempFt = new double[m + 1, m + 1];
                for (int a = 1; a <= m; a += 2)
                {
                    for (int b = 1; b <= m; b += 2)
                    {
                        tempFt[a / 2 + 1, b / 2 + 1] = ft[i - 1].ftable[a, b];
                    }
                }

                for (int a = 1; a <= m; a++)
                {
                    for (int b = 1; b <= m; b++)
                    {
                        qf[b, a, i] = tempFt[a, b];
                    }
                }
            }

            // Extend phi2 and h2 if he1>he2, or vice-versa.
            dhe = Math.Abs(he[1] - he[2]);
            if (dhe > 0.001)
            {
                if (he[1] > he[2])
                {
                    i = 1;
                    j = 2;
                }
                else
                {
                    i = 2;
                    j = 1;
                }
                double[] hFind = new double[n[i] + 1];
                for (int x = 1; x <= n[i] + 1; x++)
                {
                    hFind[x - n[i] + 1] = h[i, x];
                }
                ii = Find(he[j], hFind);
                for (k = 1; k <= n[i] - ii; k++)
                {
                    h[j, n[j] + k]   = h[i, ii + k];//test these
                    phi[j, n[j] + k] = phie[j] + Ks[j] * (h[i, ii + k] - he[j]);
                }
                n[j] = n[j] + n[i] - ii;
            }
            phi1max = phi[n[1], 1];

            // Get phi for same h.
            if (h[1, 1] > h[1, 2])
            {
                i = 1;
                j = 2;
            }
            else
            {
                i = 2;
                j = 1;
            }

            Matrix <double> hm = Matrix <double> .Build.DenseOfArray(h); //test

            double[] absh = hm.Column(j).ToArray();
            absh = absh.Slice(1, n[j]);
            absh = MathUtilities.Subtract_Value(absh, h[1, i]);
            for (int x = 0; x < absh.Length; x++)
            {
                absh[x] = Math.Abs(absh[x]);
            }
            id = MinLoc(absh);
            if (h[id, j] >= h[1, 1])
            {
                id--;
            }

            //phii(j,:) for soil j will match h(i,:) from soil i and h(j, 1:id) from soil j.
            //phii(i,:) for soil i will match h(i,:) and fill in for h(j, 1:id).
            for (int iid = 1; iid <= id; iid++)
            {
                phii[iid, j] = phi[iid, j]; // keep these values
            }
            // But interpolate to match values that start at greater h.
            jj = id + 1;                       //h(j,id+1) to be checked first
            phii[id + n[i], j] = phi[n[j], j]; // last h values match
            for (ii = 1; ii <= n[i] - 1; ii++)
            {
                while (true) //get place of h(i,ii) in h array for soil j
                {
                    if (jj > n[j])
                    {
                        Console.WriteLine("twotbls: h[j,n[j]] <= h[i,ii]; i, j, ii, n[j] = " + i + " " + j + " " + ii + " " + n[j]);
                        Environment.Exit(1);
                    }

                    if (h[jj, j] > h[ii, i])
                    {
                        break;
                    }
                    jj += 1;
                }

                k = jj - 1; //first point for cubic interp
                if (jj + 2 > n[j])
                {
                    k = n[j] - 3;
                }

                double[] hCuco   = new double[5];
                double[] phiCuco = new double[5];
                for (int x = k; x <= k + 3; x++)
                {
                    hCuco[x - k + 1]   = h[x, j];
                    phiCuco[x - k + 1] = phi[x, j];
                }

                co = Soil.Cuco(hCuco, phiCuco); // get cubic coeffs
                v  = h[ii, i] - h[k, j];
                phii[id + ii, j] = co[1] + v * (co[2] + v * (co[3] + v * co[4]));
            }
            ni = id + n[i];

            // Generate sensible missing values using quadratic extrapolation.
            co = Fluxes.Quadco(new double[4] {
                0, phii[1, j], phii[id + 1, j], phii[id + 2, j]
            }, new double[4] {
                0, 0, phi[1, i], phi[2, i]
            });
            if (co[2] > 0) // +ve slope at zero - ok
            {
                for (int x = 1; x <= id; x++)
                {
                    xval[x]    = phii[x, j] - phii[1, j];
                    phii[x, i] = co[i] + xval[x] * (co[2] + xval[x] * co[3]);
                }
            }
            else // -ve slope at zero, use quadratic with zero slope at zero
            {
                co[3] = phi[1, i] / Math.Pow(phii[id + 1, j], 2);
                for (int x = 1; x <= id; x++)
                {
                    phii[x, i] = co[3] * Math.Pow(phii[x, j], 2);
                }
            }

            // phii(i,id+1:ni)=phi(i,1:n(i))
            double[] phin = new double[ni - id + 1];
            for (int x = 1; x <= n[i]; x++)
            {
                phin[x] = phi[x, i];
            }
            for (int x = id + 1; x <= ni; x++)
            {
                phii[x, i] = phin[x - (id + 1) + 1];
            }

            //hi(1:id) = h(j, 1:id)
            for (int x = 1; x <= id; x++)
            {
                hi[x] = h[x, j];
            }

            // hi(id+1:ni)=h(i,1:n(i))
            for (int x = 1; x <= n[i]; x++)
            {
                hi[id + x] = h[x, i];
            }

            /* hi(1:ni) are h values for the interface tables.
             * phii(1,1:ni) are corresponding interface phi values for upper layer.
             * phii(2,1:ni) are corresponding interface phi values for lower layer.
             * Set up quadratic interpolation coeffs to get phii2 given phii1.
             */
            Matrix <double> coqM = Matrix <double> .Build.DenseOfArray(coq);

            Vector <double>[] quadcoV = new Vector <double> [ni - 2 + 1];
            double[]          tmpx;
            double[]          tmpy;
            for (i = 1; i <= ni - 2; i++)
            {
                tmpx       = new [] { 0, phii[i, 1], phii[i + 1, 1], phii[i + 2, 1] };
                tmpy       = new [] { 0, phii[i, 2], phii[i + 1, 2], phii[i + 2, 2] };
                quadcoV[i] = Vector <double> .Build.DenseOfArray(Fluxes.Quadco(tmpx, tmpy));

                coqM.SetRow(i, quadcoV[i]);
            }
            Vector <double> lincoV = Vector <double> .Build.DenseOfArray(Linco(new [] { 0, phii[ni - 1, 1], phii[ni, 1] }, new [] { 0, phii[ni - 1, 2], phii[ni, 2] }));

            coqM.SetRow(ni - 1, lincoV);
            coq            = coqM.ToArray();
            coq[ni - 1, 3] = 0;

            double[,] getco = new double[20, 20];

            // Set up cubic coeffs to get fluxes q given phi.
            for (j = 1; j <= nft[2]; j++)
            {
                k  = 1;
                ip = 1;
                while (true)
                {
                    phico2[k] = phif[ip, 2];
                    double[] co2co = Soil.Cuco(new double[5] {
                        0, phif[ip, 2], phif[ip + 1, 2], phif[ip + 2, 2], phif[ip + 3, 2]
                    },
                                               new double[5] {
                        0, qf[j, ip, 2], qf[j, ip + 1, 2], qf[j, ip + 2, 2], qf[j, ip + 3, 2]
                    });
                    for (int x = 1; x < co2co.Length; x++)
                    {
                        co2[j, k, x] = co2co[x];
                    }
                    ip += 3;
                    if (ip == nft[2])
                    {
                        break;
                    }
                    if (ip > nft[2])
                    {
                        ip = nft[2] - 3;
                    }
                    k++;
                }
                for (int x = 1; x < 20; x++)
                {
                    for (int y = 1; y < 20; y++)
                    {
                        getco[y, x] = co2[y, x, 1];
                    }
                }
            }

            nco2 = k;

            // Get fluxes
            for (i = 1; i <= nft[1]; i++) //step through top phis
            {
                vlast = phif[i, 1];
                k     = 1;
                ip    = 1;
                Matrix <double> co1M = Matrix <double> .Build.DenseOfArray(co1);

                while (true)
                {
                    phico1[k] = phif[ip, 1];
                    co1M.SetRow(k, Soil.Cuco(new double[5] {
                        0, phif[ip, 1], phif[ip + 1, 1], phif[ip + 2, 1], phif[ip + 3, 1]
                    },
                                             new double[5] {
                        0, qf[ip, i, 1], qf[ip + 1, i, 1], qf[ip + 2, i, 1], qf[ip + 3, i, 1]
                    }));
                    ip += 3;
                    if (ip == nft[1])
                    {
                        break;
                    }
                    if (ip > nft[1])
                    {
                        ip = nft[1] - 3;
                    }
                    k++;
                }
                co1  = co1M.ToArray();
                nco1 = k;
                for (j = 1; j <= nft[2]; j++) // bottom phis
                {
                    v = vlast;
                    for (k = 1; k <= maxit; k++) // solve for upper interface phi giving same fluxes
                    {
                        fd(v, out f, out df, out q1);
                        dx = f / df; // Newton's method - almost always works
                        v  = Math.Min(10.0 * phif[nft[1], 1], Math.Max(phii[1, 1], v - dx));
                        e  = Math.Abs(f / q1);
                        if (e < rerr)
                        {
                            break;
                        }
                        vlast = v;
                    }
                    if (k > maxit) //failed - bracket q and use bisection
                    {
                        v1 = phii[1, 1];
                        fd(v1, out f1, out df, out q1);
                        if (f1 <= 0.0) // answer is off table - use end value
                        {
                            qp[j, i] = q1;
                            continue;
                        }
                        v2 = phii[ni, 1];
                        fd(v2, out f2, out df, out q1);
                        for (k = 1; k <= maxit; k++)
                        {
                            if (f1 * f2 < 0.0)
                            {
                                break;
                            }
                            v1 = v2;
                            f1 = f2;
                            v2 = 2.0 * v1;
                            fd(v2, out f2, out df, out q1);
                        }
                        if (k > maxit)
                        {
                            Console.WriteLine(v1 + " " + v2 + " " + f1 + " " + f2);
                            v1 = phii[1, 1];
                            fd(v1, out f1, out df, out q1);
                            Console.WriteLine(v1 + " " + f1);
                            Console.WriteLine("twotbls: too many iterations at i, j = " + i + " " + j);
                            Environment.Exit(1);
                        }
                        for (k = 1; k <= maxit; k++)
                        {
                            v = 0.5 * (v1 + v2);
                            fd(v, out f, out df, out q1);
                            e = Math.Abs(f / q1);
                            if (e < rerr)
                            {
                                break;
                            }
                            if (f > 0.0)
                            {
                                v1 = v;
                                f1 = f;
                            }
                            else
                            {
                                v2 = v;
                                f2 = f;
                            }
                        }
                        vlast = v;
                        if (k > maxit)
                        {
                            Console.WriteLine("twotbls: too many iterations at i, j = " + i + " " + j);
                            Environment.Exit(1);
                        }
                    }
                    // Solved
                    qp[j, i] = q1;
                } //end j
            }     //end i

            //interpolate extra fluxes
            for (i = 1; i <= 2; i++)
            {
                nfi[i] = nft[i] - 1;
                for (int x = 1; x <= nfi[i]; x++)
                {
                    phifi[x, i] = 0.5 * (phif[x, i] + phif[x + 1, i]);
                }
            }

            Matrix <double> phifM = Matrix <double> .Build.DenseOfArray(phif);

            Matrix <double> phifiM = Matrix <double> .Build.DenseOfArray(phifi);

            Matrix <double> qpM = Matrix <double> .Build.DenseOfArray(qp);

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

            Matrix <double> qi2M = Matrix <double> .Build.DenseOfArray(qi2);

            Matrix <double> qi3M = Matrix <double> .Build.DenseOfArray(qi3);

            for (i = 1; i <= nft[1]; i++)
            {
                qi1M.SetColumn(i, Fluxes.Quadinterp(phifM.Column(2).ToArray(), qpM.Column(i).ToArray(), nft[2], phifiM.Column(2).ToArray()));
            }
            for (j = 1; j <= nft[2]; j++)
            {
                qi2M.SetRow(j, Fluxes.Quadinterp(phifM.Column(1).ToArray(), qpM.Row(j).ToArray(), nft[1], phifiM.Column(1).ToArray()));
            }
            for (j = 1; j <= nfi[2]; j++)
            {
                qi3M.SetRow(j, Fluxes.Quadinterp(phifM.Column(1).ToArray(), qi1M.Row(j).ToArray(), nft[1], phifiM.Column(1).ToArray()));
            }

            qi1 = qi1M.ToArray();
            qi2 = qi2M.ToArray();
            qi3 = qi3M.ToArray();

            // Put all the fluxes together
            i = nft[1] + nfi[1];
            j = nft[2] + nfi[2];

            // qi5(1:i:2,1:j:2)=qp(1:nft[1],1:nft[2])
            for (int a = 1; a <= mx; a += 2)
            {
                for (int b = 1; b <= mx; b += 2)
                {
                    qi5[b, a] = qp[b / 2 + 1, a / 2 + 1];
                }
            }

            // qi5(1:a: 2, 2:b: 2) = qi1(1:nft[1], 1:nfi[2])
            for (int a = 1; a <= mx; a += 2)
            {
                for (int b = 2; b <= mx; b += 2)
                {
                    qi5[b, a] = qi1[(b - 1) / 2 + 1, a / 2 + 1];
                }
            }

            // qi5(2:a:2,1:b:2)=qi2(1:nfi[1],1:nft[2])
            for (int a = 2; a <= mx; a += 2)
            {
                for (int b = 1; b <= mx; b += 2)
                {
                    qi5[b, a] = qi2[b / 2 + 1, (a - 1) / 2 + 1];
                }
            }

            // qi5(2:a:2,2:b:2)=qi3(1:nfi[1],1:nfi[2])
            for (int a = 2; a <= mx; a += 2)
            {
                for (int b = 2; b <= mx; b += 2)
                {
                    qi5[b, a] = qi3[(b - 1) / 2 + 1, (a - 1) / 2 + 1];
                }
            }

            // phii5(1, 1:a: 2) = phif(1, 1:nft[1])
            for (int a = 1; a <= mx; a += 2)
            {
                phii5[a, 1] = phif[a / 2 + 1, 1];
            }

            // phii5(1,2:a:2)=phifi(1,1:nfi[1])
            for (int a = 2; a < 101; a += 2)
            {
                phii5[a, 1] = phifi[(a - 1) / 2 + 1, 1];
            }

            // phii5(2,1:b:2)=phif(2,1:nft[2])
            for (int a = 1; a <= mx; a += 2)
            {
                phii5[a, 2] = phif[a / 2 + 1, 2];
            }

            // phii5(2,2:b:2)=phifi(2,1:nfi[2])
            for (int a = 2; a <= mx; a += 2)
            {
                phii5[a, 2] = phifi[(a - 1) / 2 + 1, 2];
            }


            // Assemble flux table
            ftwo.fend = new FluxEnd[2];
            for (ie = 0; ie < 2; ie++)
            {
                ftwo.fend[ie].sid  = sp[ie].sid;
                ftwo.fend[ie].nfu  = ft[ie].fend[1].nfu;
                ftwo.fend[ie].nft  = ft[ie].fend[1].nft;
                ftwo.fend[ie].dz   = ft[ie].fend[1].dz;
                ftwo.fend[ie].phif = ft[ie].fend[1].phif;
            }

            double[,] qi5Slice = new double[i + 1, j + 1];
            for (int x = 1; x <= i; x++)
            {
                for (int y = 1; y <= j; y++)
                {
                    qi5Slice[x, y] = qi5[x, y];
                }
            }
            ftwo.ftable = qi5Slice;

            return(ftwo);
        }
Esempio n. 6
0
 public static FluxTable TwoTables(FluxTable ft1, SoilProps sp1, FluxTable ft2, SoilProps sp2)
 {
     return new FluxTable();
 }
Esempio n. 7
0
        static void Main(string[] args)
        {
            string output = string.Empty;

            //define test soils
            SoilParam[] soils = new SoilParam[2];
            soils[0] = new SoilParam(10, 103, 0.4, 2.0, -2.0, -10.0, 1.0 / 3.0, 1.0);
            soils[1] = new SoilParam(10, 109, 0.6, 0.2, -2.0, -40.0, 1.0 / 9.0, 1.0);

            string[] ftname = new string[2];
            int[]    sidx;
            int      i, j;

            int[]  ndz;
            double dzmin;

            double[] x;
            double[,] dz = new double[2, 10]; //only for testing? if not will need to change hardcoded dimensions.
            bool      Kgiven = false;
            SoilProps sp1, sp2;
            FluxTable ft1, ft2;

            //define soil profile
            x     = new double[] { 10, 20, 30, 40, 60, 80, 100, 120, 160, 200 };    //length = num soil layers
            sidx  = new int[] { 103, 103, 103, 103, 109, 109, 109, 109, 109, 109 }; //soil ident of layers
            dzmin = 1.0;                                                            // smallest likely path length
            ndz   = new int[] { 2, 4 };                                             // for the two soil types - gives six flux tables
            //can be done in loops, but clearer this way and will only be used for testing
            dz[0, 0] = 5;
            dz[0, 1] = 10;
            dz[1, 0] = 10;
            dz[1, 1] = 20;
            dz[1, 2] = 30;
            dz[1, 4] = 40;
            for (i = 0; i < 2; i++)
            {
                BinaryWriter b = new BinaryWriter(File.OpenWrite("soil" + soils[i].sid + ".dat"));
                MVG.Params(soils[i].sid, soils[i].ths, soils[i].ks, soils[i].he, soils[i].hd, soils[i].p, soils[i].hg, soils[i].em, soils[i].en);
                soils[i].sp = Soil.gensptbl(dzmin, soils[i], Kgiven);
                b.Write(soils[i].sid);
                WriteProps(b, soils[i].sp);
                b.Close();
                for (j = 0; j < ndz[i]; j++)
                {
                    Fluxes.FluxTable(dz[i, j], soils[i].sp);
                    b = new BinaryWriter(File.OpenWrite("soil" + soils[i].sid + "dz" + dz[i, j] * 10));
                    b.Write(soils[i].sid);
                    WriteFluxes(b, Fluxes.ft);
                    b.Close();
                }
            }

            //generate and write composite flux table for path with two soil types
            sp1 = ReadProps("soil103.dat");
            sp2 = ReadProps("soil109.dat");

            ft1 = ReadFluxes("soil103dz50.dat");
            ft2 = ReadFluxes("soil103dz100.dat");

            FluxTable    ftwo = TwoFluxes.TwoTables(ft1, sp1, ft2, sp2);
            BinaryWriter bw   = new BinaryWriter(File.OpenWrite("soil0103dz0050_soil0109dz0100.dat"));

            WriteFluxes(bw, ftwo);
        }
Esempio n. 8
0
        public static FluxTable TwoTables(FluxTable ft1, SoilProps sp1, FluxTable ft2, SoilProps sp2)
        {
            /*Generates a composite flux table from two uniform ones.
              Sets up quadratic interpolation table to get phi at interface for lower path
              from phi at interface for upper path.
              Sets up cubic interpolation tables to get fluxes from phi at interface for
              upper and lower paths.
              Solves for phi at interface in upper path that gives same fluxes in upper
              and lower paths, for all phi at upper and lower ends of composite path.
              Increases no. of fluxes in table by quadratic interpolation.
              ft1, ft2 - flux tables for upper and lower paths.
              sp1, sp2 - soil prop tables for upper and lower paths. -PR

              Note that arrays are one indexed; 0 index is not used.
              This is done as a number of calculations use the index as an input.
              Exception to this is flux/soil arrays where array index is not used in calculations. -JF
            */

            // Set up required pointers and data
            if (ft1.fend[0].sid != ft1.fend[1].sid || ft2.fend[0].sid != ft2.fend[1].sid)
            {
                Console.WriteLine("Flux table not for uniform soil.");
                Environment.Exit(1);
            }
            ft1.ftable = Matrix<double>.Build.DenseOfArray(ft1.ftable).Transpose().ToArray();
            ft2.ftable = Matrix<double>.Build.DenseOfArray(ft2.ftable).Transpose().ToArray();
            ft[0] = ft1;
            ft[1] = ft2;
            sp[0] = sp1;
            sp[1] = sp2;
            for (i = 1; i <= 2; i++)
            {
                n[i] = sp[i - 1].n;
                he[i] = sp[i - 1].he;
                phie[i] = sp[i - 1].phie;
                Ks[i] = sp[i - 1].ks;
                for (int x = 1; x <= n[i]; x++)
                {
                    h[x, i] = sp[i - 1].h[x];
                    phi[x, i] = sp[i - 1].phi[x];
                }
            }

            // Discard unwanted input - use original uninterpolated values only.
            for (i = 1; i <= 2; i++)
            {
                m = ft[i - 1].fend[0].nft; //should be odd
                j = 1 + m / 2;
                double[] tempPhif = new double[j + 1];
                Array.Copy(ft[i - 1].fend[0].phif.Where((x, it) => it % 2 == 1).ToArray(), 0, tempPhif, 1, j);
                for (int x = 1; x <= j; x++)
                    phif[x, i] = tempPhif[x]; //discard every second
                nft[i] = j;
                nfu[i] = 1 + ft[i - 1].fend[1].nfu / 2; //ft[i].fend[1].nfu should be odd

                double[,] tempFt = new double[m + 1, m + 1];
                for (int a = 1; a <= m; a += 2)
                    for (int b = 1; b <= m; b += 2)
                        tempFt[a / 2 + 1, b / 2 + 1] = ft[i - 1].ftable[a, b];

                for (int a = 1; a <= m; a++)
                    for (int b = 1; b <= m; b++)
                        qf[b, a, i] = tempFt[a, b];
            }

            // Extend phi2 and h2 if he1>he2, or vice-versa.
            dhe = Math.Abs(he[1] - he[2]);
            if (dhe > 0.001)
            {
                if (he[1] > he[2])
                {
                    i = 1;
                    j = 2;
                }
                else
                {
                    i = 2;
                    j = 1;
                }
                double[] hFind = new double[n[i] + 1];
                for (int x = 1; x <= n[i] + 1; x++)
                    hFind[x - n[i] + 1] = h[i, x];
                ii = Find(he[j], hFind);
                for (k = 1; k <= n[i] - ii; k++)
                {
                    h[j, n[j] + k] = h[i, ii + k];//test these
                    phi[j, n[j] + k] = phie[j] + Ks[j] * (h[i, ii + k] - he[j]);
                }
                n[j] = n[j] + n[i] - ii;
            }
            phi1max = phi[n[1], 1];

            // Get phi for same h.
            if (h[1, 1] > h[1, 2])
            {
                i = 1;
                j = 2;
            }
            else
            {
                i = 2;
                j = 1;
            }

            Matrix<double> hm = Matrix<double>.Build.DenseOfArray(h); //test
            double[] absh = hm.Column(j).ToArray();
            absh = absh.Slice(1, n[j]);
            absh = MathUtilities.Subtract_Value(absh, h[1, i]);
            for (int x = 0; x < absh.Length; x++)
                absh[x] = Math.Abs(absh[x]);
            id = MinLoc(absh);
            if (h[id, j] >= h[1, 1])
                id--;

            //phii(j,:) for soil j will match h(i,:) from soil i and h(j, 1:id) from soil j.
            //phii(i,:) for soil i will match h(i,:) and fill in for h(j, 1:id).
            for (int iid = 1; iid <= id; iid++)
                phii[iid, j] = phi[iid, j]; // keep these values

            // But interpolate to match values that start at greater h.
            jj = id + 1; //h(j,id+1) to be checked first
            phii[id + n[i], j] = phi[n[j], j]; // last h values match
            for (ii = 1; ii <= n[i] - 1; ii++)
            {
                while (true) //get place of h(i,ii) in h array for soil j
                {
                    if (jj > n[j])
                    {
                        Console.WriteLine("twotbls: h[j,n[j]] <= h[i,ii]; i, j, ii, n[j] = " + i + " " + j + " " + ii + " " + n[j]);
                        Environment.Exit(1);
                    }

                    if (h[jj, j] > h[ii, i])
                        break;
                    jj += 1;
                }

                k = jj - 1; //first point for cubic interp
                if (jj + 2 > n[j])
                    k = n[j] - 3;

                double[] hCuco = new double[5];
                double[] phiCuco = new double[5];
                for (int x = k; x <= k + 3; x++)
                {
                    hCuco[x - k + 1] = h[x, j];
                    phiCuco[x - k + 1] = phi[x, j];
                }

                co = Soil.Cuco(hCuco, phiCuco); // get cubic coeffs
                v = h[ii, i] - h[k, j];
                phii[id + ii, j] = co[1] + v * (co[2] + v * (co[3] + v * co[4]));
            }
            ni = id + n[i];

            // Generate sensible missing values using quadratic extrapolation.
            co = Fluxes.Quadco(new double[4] { 0, phii[1, j], phii[id + 1, j], phii[id + 2, j] }, new double[4] { 0, 0, phi[1, i], phi[2, i] });
            if (co[2] > 0) // +ve slope at zero - ok
            {
                for (int x = 1; x <= id; x++)
                {
                    xval[x] = phii[x, j] - phii[1, j];
                    phii[x, i] = co[i] + xval[x] * (co[2] + xval[x] * co[3]);
                }
            }
            else // -ve slope at zero, use quadratic with zero slope at zero
            {
                co[3] = phi[1, i] / Math.Pow(phii[id + 1, j], 2);
                for (int x = 1; x <= id; x++)
                    phii[x, i] = co[3] * Math.Pow(phii[x, j], 2);
            }

            // phii(i,id+1:ni)=phi(i,1:n(i))
            double[] phin = new double[ni - id + 1];
            for (int x = 1; x <= n[i]; x++)
                phin[x] = phi[x, i];
            for (int x = id + 1; x <= ni; x++)
                phii[x, i] = phin[x - (id + 1) + 1];

            //hi(1:id) = h(j, 1:id)
            for (int x = 1; x <= id; x++)
                hi[x] = h[x, j];

            // hi(id+1:ni)=h(i,1:n(i))
            for (int x = 1; x <= n[i]; x++)
                hi[id + x] = h[x, i];

            /* hi(1:ni) are h values for the interface tables.
             * phii(1,1:ni) are corresponding interface phi values for upper layer.
             * phii(2,1:ni) are corresponding interface phi values for lower layer.
             * Set up quadratic interpolation coeffs to get phii2 given phii1.
             */
            Matrix<double> coqM = Matrix<double>.Build.DenseOfArray(coq);
            Vector<double>[] quadcoV = new Vector<double>[ni - 2 + 1];
            double[] tmpx;
            double[] tmpy;
            for (i = 1; i <= ni - 2; i++)
            {
                tmpx = new [] { 0, phii[i, 1], phii[i + 1, 1], phii[i + 2, 1] };
                tmpy = new [] { 0, phii[i, 2], phii[i + 1, 2], phii[i + 2, 2] };
                quadcoV[i] = Vector<double>.Build.DenseOfArray(Fluxes.Quadco(tmpx, tmpy));
                coqM.SetRow(i, quadcoV[i]);
            }
            Vector<double> lincoV = Vector<double>.Build.DenseOfArray(Linco(new [] { 0, phii[ni - 1, 1], phii[ni, 1] }, new [] { 0, phii[ni - 1, 2], phii[ni, 2] }));
            coqM.SetRow(ni - 1, lincoV);
            coq = coqM.ToArray();
            coq[ni - 1, 3] = 0;

            double[,] getco = new double[20, 20];

            // Set up cubic coeffs to get fluxes q given phi.
            for (j = 1; j <= nft[2]; j++)
            {
                k = 1;
                ip = 1;
                while (true)
                {
                    phico2[k] = phif[ip, 2];
                    double[] co2co = Soil.Cuco(new double[5] { 0, phif[ip, 2], phif[ip + 1, 2], phif[ip + 2, 2], phif[ip + 3, 2] },
                                               new double[5] { 0, qf[j, ip, 2], qf[j, ip + 1, 2], qf[j, ip + 2, 2], qf[j, ip + 3, 2] });
                    for (int x = 1; x < co2co.Length; x++)
                        co2[j, k, x] = co2co[x];
                    ip += 3;
                    if (ip == nft[2])
                        break;
                    if (ip > nft[2])
                        ip = nft[2] - 3;
                    k++;
                }
                for (int x = 1; x < 20; x++)
                    for (int y = 1; y < 20; y++)
                        getco[y, x] = co2[y, x, 1];
            }

            nco2 = k;

            // Get fluxes
            for (i = 1; i <= nft[1]; i++) //step through top phis
            {
                vlast = phif[i, 1];
                k = 1;
                ip = 1;
                Matrix<double> co1M = Matrix<double>.Build.DenseOfArray(co1);
                while (true)
                {
                    phico1[k] = phif[ip, 1];
                    co1M.SetRow(k, Soil.Cuco(new double[5] { 0, phif[ip, 1], phif[ip + 1, 1], phif[ip + 2, 1], phif[ip + 3, 1] },
                                                new double[5] { 0, qf[ip, i, 1], qf[ip + 1, i, 1], qf[ip + 2, i, 1], qf[ip + 3, i, 1] }));
                    ip += 3;
                    if (ip == nft[1])
                        break;
                    if (ip > nft[1])
                        ip = nft[1] - 3;
                    k++;
                }
                co1 = co1M.ToArray();
                nco1 = k;
                for (j = 1; j <= nft[2]; j++) // bottom phis
                {
                    v = vlast;
                    for (k = 1; k <= maxit; k++) // solve for upper interface phi giving same fluxes
                    {
                        fd(v, out f, out df, out q1);
                        dx = f / df; // Newton's method - almost always works
                        v = Math.Min(10.0 * phif[nft[1], 1], Math.Max(phii[1, 1], v - dx));
                        e = Math.Abs(f / q1);
                        if (e < rerr)
                            break;
                        vlast = v;
                    }
                    if (k > maxit) //failed - bracket q and use bisection
                    {
                        v1 = phii[1, 1];
                        fd(v1, out f1, out df, out q1);
                        if (f1 <= 0.0) // answer is off table - use end value
                        {
                            qp[j, i] = q1;
                            continue;
                        }
                        v2 = phii[ni, 1];
                        fd(v2, out f2, out df, out q1);
                        for (k = 1; k <= maxit; k++)
                        {
                            if (f1 * f2 < 0.0)
                                break;
                            v1 = v2;
                            f1 = f2;
                            v2 = 2.0 * v1;
                            fd(v2, out f2, out df, out q1);
                        }
                        if (k > maxit)
                        {
                            Console.WriteLine(v1 + " " + v2 + " " + f1 + " " + f2);
                            v1 = phii[1, 1];
                            fd(v1, out f1, out df, out q1);
                            Console.WriteLine(v1 + " " + f1);
                            Console.WriteLine("twotbls: too many iterations at i, j = " + i + " " + j);
                            Environment.Exit(1);
                        }
                        for (k = 1; k <= maxit; k++)
                        {
                            v = 0.5 * (v1 + v2);
                            fd(v, out f, out df, out q1);
                            e = Math.Abs(f / q1);
                            if (e < rerr)
                                break;
                            if (f > 0.0)
                            {
                                v1 = v;
                                f1 = f;
                            }
                            else
                            {
                                v2 = v;
                                f2 = f;
                            }
                        }
                        vlast = v;
                        if (k > maxit)
                        {
                            Console.WriteLine("twotbls: too many iterations at i, j = " + i + " " + j);
                            Environment.Exit(1);
                        }
                    }
                    // Solved
                    qp[j, i] = q1;
                } //end j
            } //end i

            //interpolate extra fluxes
            for (i = 1; i <= 2; i++)
            {
                nfi[i] = nft[i] - 1;
                for (int x = 1; x <= nfi[i]; x++)
                    phifi[x, i] = 0.5 * (phif[x, i] + phif[x + 1, i]);
            }

            Matrix<double> phifM = Matrix<double>.Build.DenseOfArray(phif);
            Matrix<double> phifiM = Matrix<double>.Build.DenseOfArray(phifi);
            Matrix<double> qpM = Matrix<double>.Build.DenseOfArray(qp);
            Matrix<double> qi1M = Matrix<double>.Build.DenseOfArray(qi1);
            Matrix<double> qi2M = Matrix<double>.Build.DenseOfArray(qi2);
            Matrix<double> qi3M = Matrix<double>.Build.DenseOfArray(qi3);

            for (i = 1; i <= nft[1]; i++)
            {
                qi1M.SetColumn(i, Fluxes.Quadinterp(phifM.Column(2).ToArray(), qpM.Column(i).ToArray(), nft[2], phifiM.Column(2).ToArray()));
            }
            for (j = 1; j <= nft[2]; j++)
            {
                qi2M.SetRow(j, Fluxes.Quadinterp(phifM.Column(1).ToArray(), qpM.Row(j).ToArray(), nft[1], phifiM.Column(1).ToArray()));
            }
            for (j = 1; j <= nfi[2]; j++)
            {
                qi3M.SetRow(j, Fluxes.Quadinterp(phifM.Column(1).ToArray(), qi1M.Row(j).ToArray(), nft[1], phifiM.Column(1).ToArray()));
            }

            qi1 = qi1M.ToArray();
            qi2 = qi2M.ToArray();
            qi3 = qi3M.ToArray();

            // Put all the fluxes together
            i = nft[1] + nfi[1];
            j = nft[2] + nfi[2];

            // qi5(1:i:2,1:j:2)=qp(1:nft[1],1:nft[2])
            for (int a = 1; a <= mx; a += 2)
                for (int b = 1; b <= mx; b += 2)
                    qi5[b, a] = qp[b / 2 + 1, a / 2 + 1];

            // qi5(1:a: 2, 2:b: 2) = qi1(1:nft[1], 1:nfi[2])
            for (int a = 1; a <= mx; a += 2)
                for (int b = 2; b <= mx; b += 2)
                    qi5[b, a] = qi1[(b-1) / 2 + 1, a / 2 + 1];

            // qi5(2:a:2,1:b:2)=qi2(1:nfi[1],1:nft[2])
            for (int a = 2; a <= mx; a += 2)
                for (int b = 1; b <= mx; b += 2)
                    qi5[b, a] = qi2[b / 2 + 1, (a - 1) / 2 + 1];

            // qi5(2:a:2,2:b:2)=qi3(1:nfi[1],1:nfi[2])
            for (int a = 2; a <= mx; a += 2)
                for (int b = 2; b <= mx; b += 2)
                    qi5[b, a] = qi3[(b - 1) / 2 + 1, (a - 1) / 2 + 1];

            // phii5(1, 1:a: 2) = phif(1, 1:nft[1])
            for (int a = 1; a <= mx; a += 2)
                phii5[a, 1] = phif[a / 2 + 1, 1];

            // phii5(1,2:a:2)=phifi(1,1:nfi[1])
            for (int a = 2; a < 101; a += 2)
                phii5[a, 1] = phifi[(a - 1) / 2 + 1, 1];

            // phii5(2,1:b:2)=phif(2,1:nft[2])
            for (int a = 1; a <= mx; a += 2)
                phii5[a, 2] = phif[a / 2 + 1, 2];

            // phii5(2,2:b:2)=phifi(2,1:nfi[2])
            for (int a = 2; a <= mx; a += 2)
                phii5[a, 2] = phifi[(a-1) / 2 + 1, 2];

            // Assemble flux table
            ftwo.fend = new FluxEnd[2];
            for (ie = 0; ie < 2; ie++)
            {
                ftwo.fend[ie].sid = sp[ie].sid;
                ftwo.fend[ie].nfu = ft[ie].fend[1].nfu;
                ftwo.fend[ie].nft = ft[ie].fend[1].nft;
                ftwo.fend[ie].dz = ft[ie].fend[1].dz;
                ftwo.fend[ie].phif = ft[ie].fend[1].phif;
            }

            double[,] qi5Slice = new double[i + 1, j + 1];
            for (int x = 1; x <= i; x++)
                for (int y = 1; y <= j; y++)
                    qi5Slice[x, y] = qi5[x, y];
            ftwo.ftable = qi5Slice;

            return ftwo;
        }
Esempio n. 9
0
 /// <summary>
 /// Only used in unit tests. Resets all static variables
 /// </summary>
 public static void TestReset()
 {
     mx = 100;
     maxit = 20;
     i = j = k = m = ni = id = ip = nco1 = nco2 = ie = ii = jj = 0;
     nft = new int[2 + 1];
     nfu = new int[2 + 1];
     n = new int[2 + 1];
     nfi = new int[2 + 1];
     rerr = 1e-3;
     phi1max = dhe = v = vlast = dx = e = f = df = q1 = phialast = v1 = v2 = f1 = f2 = 0;
     he = new double[2 + 1];
     phie = new double[2 + 1];
     Ks = new double[2 + 1];
     co = new double[4 + 1];
     xval = new double[mx + 1];
     phico1 = new double[mx + 1];
     phico2 = new double[mx + 1];
     hi = new double[3 * mx + 1];
     phif = new double[mx + 1, 2 + 1];
     phifi = new double[mx + 1, 2 + 1];
     phii5 = new double[mx + 1, 2 + 1];
     coq = new double[3 * mx + 1, 3 + 1];
     co1 = new double[mx + 1, 4 + 1];
     qp = new double[mx + 1, mx + 1];
     qi1 = new double[mx + 1, mx + 1];
     qi2 = new double[mx + 1, mx + 1];
     qi3 = new double[mx + 1, mx + 1];
     qi5 = new double[mx + 1, mx + 1];
     h = new double[3 * mx + 1, 2 + 1];
     phi = new double[3 * mx + 1, 2 + 1];
     phii = new double[3 * mx + 1, 2 + 1];
     qf = new double[mx + 1, mx + 1, 2 + 1];
     co2 = new double[mx + 1, mx + 1, 4 + 1];
     ftwo = new FluxTable();
     ft = new FluxTable[] { new FluxTable(), new FluxTable() };
     sp = new SoilProps[] { new SoilProps(), new SoilProps() };
 }
Esempio n. 10
0
        public static void GenerateFlux()
        {
            MVG.TestParams(103, 9.0, 0.99670220130280185, 9.99999999999998460E-003);
            SoilProps sp = Soil.gensptbl(1.0, new SoilParam(10, 103, 0.4, 2.0, -2.0, -10.0, 1.0 / 3.0, 1.0), true);

            Fluxes.FluxTable(5.0, sp);
            FluxTable ft = Fluxes.ft;

            string output = string.Empty;

            //define test soils
            SoilParam[] soils = new SoilParam[2];
            soils[0] = new SoilParam(10, 103, 0.4, 2.0, -2.0, -10.0, 1.0 / 3.0, 1.0);
            soils[1] = new SoilParam(10, 109, 0.6, 0.2, -2.0, -40.0, 1.0 / 9.0, 1.0);

            string[] ftname = new string[2];
            int[]    sidx;
            int      i, j;

            int[]  ndz;
            double dzmin;

            double[] x;
            double[,] dz = new double[2, 10]; //only for testing? if not will need to change hardcoded dimensions.
            bool Kgiven = true;

            //define soil profile
            x     = new double[] { 10, 20, 30, 40, 60, 80, 100, 120, 160, 200 };    //length = num soil layers
            sidx  = new int[] { 103, 103, 103, 103, 109, 109, 109, 109, 109, 109 }; //soil ident of layers
            dzmin = 1.0;                                                            // smallest likely path length
            ndz   = new int[] { 2, 4 };                                             // for the two soil types - gives six flux tables
            //can be done in loops, but clearer this way and will only be used for testing
            dz[0, 0] = 5;
            dz[0, 1] = 10;
            dz[1, 0] = 10;
            dz[1, 1] = 20;
            dz[1, 2] = 30;
            dz[1, 4] = 40;
            for (i = 0; i < 2; i++)
            {
                MVG.Params(soils[i].sid, soils[i].ths, soils[i].ks, soils[i].he, soils[i].hd, soils[i].p, soils[i].hg, soils[i].em, soils[i].en); //set MVG params
                soils[i].sp = Soil.gensptbl(dzmin, soils[i], Kgiven);                                                                             // generate soil props
                Soil.SoilProperties.Add("soil" + soils[i].sid, soils[i].sp);
                for (j = 0; j <= ndz[i]; j++)
                {
                    Fluxes.FluxTable(dz[i, j], soils[i].sp);     // generate flux tables
                    using (MemoryStream ms = new MemoryStream()) // make copies of the tables or they get overwritten
                    {
                        BinaryFormatter fm = new BinaryFormatter();
                        fm.Serialize(ms, Fluxes.ft);
                        ms.Position = 0;
                        Fluxes.FluxTables.Add("soil" + soils[i].sid + "dz" + (dz[i, j] * 10), (FluxTable)fm.Deserialize(ms));
                    }
                }
            }
            SoilProps sp1  = Soil.ReadProps("soil103");
            SoilProps sp2  = Soil.ReadProps("soil109");
            FluxTable ft1  = Fluxes.ReadFluxTable("soil103dz50");
            FluxTable ft2  = Fluxes.ReadFluxTable("soil109dz100");
            FluxTable ftwo = TwoFluxes.TwoTables(ft1, sp1, ft2, sp2);

            Fluxes.FluxTables.Add("soil103dz50_soil109dz100", ftwo);
        }