Beispiel #1
0
        /// <summary>
        /// Reads tables and sets up data
        /// </summary>
        /// <param name="nin">Number of layers.</param>
        /// <param name="sid">Soil ID of layers.</param>
        /// <param name="xin">Depth to bottoms of layers.</param>
        public void GetTables(int nin, int[] sid, double[] xin)
        {
            double small = 1E-5;
            string id, mm, sfile;

            string[] ftname = new string[2 + 1];
            int      i, j, ns, np, nc, i1;

            int[] isoil = new int[nin + 1];
            int[,] isid = new int[2 + 1, nin + 1 + 1];
            int[] jt = new int[nin + 2];            //0-based FORTRAN array. +2 as first and last elements will be copied twice
            double[,] dz = new double[2 + 1, nin + 1 + 1];
            double[] hdx = new double[nin + 1 + 1]; //0-based FORTRAN array
            double   x1;

            n       = nin;
            x       = xin;
            soilloc = new int[n + 1];
            pathloc = new int[n + 1];        //0 based in FORTRAN
            philoc  = new int[2 + 1, n + 1]; //0 based in FORTRAN
            dx      = MathUtilities.Subtract(x.Slice(2, n), x.Slice(1, n - 1));

            //  Set up locations in soil, path, S and phi arrays.
            philoc.Populate2D(1);

            // Get ns different soil idents in array isoil.
            isoil = sid.Skip(1).Distinct().ToArray();
            ns    = isoil.Length;
            for (int count = 1; count < soilloc.Length; count++)
            {
                soilloc[count] = Array.IndexOf(isoil, sid[count]);
            }

            // Get soil idents in array isid and lengths in array dz for the np paths.
            dx = MathUtilities.Subtract(x, x.Skip(x.Length - 1).Concat(x.Take(x.Length - 1)).ToArray());
            Array.Copy(dx, 1, x, 1, dx.Length / 2);

            //hdx=(/0.0,0.5*dx,0.0/) ! half delta x
            for (int a = 0; a < hdx.Length; a++)
            {
                if (a == 0 || a == hdx.Length - 1)
                {
                    hdx[a] = 0;
                }
                else
                {
                    hdx[a] = dx[a] / 2;
                }
            }

            Array.Copy(sid, 1, jt, 1, sid.Length - 1);
            jt[0]             = sid[1];
            jt[jt.Length - 1] = sid[n];
            np = 0; //no.of different paths out of possible n + 1
            for (i = 0; i <= n; i++)
            {
                isid[1, np + 1] = jt[i];
                isid[2, np + 1] = jt[i + 1];
                if (jt[i] == jt[i + 1]) //no interface between types
                {
                    dz[1, np + 1] = hdx[i] + hdx[i + 1];
                    dz[2, np + 1] = 0;
                }
                else
                {
                    dz[1, np + 1] = hdx[i];
                    dz[2, np + 1] = hdx[i + 1];
                }

                //Increment np if this path is new.
                for (j = 1; j <= np; j++)
                {
                    if (isid[1, j] != isid[1, np + 1] || isid[2, j] != isid[2, np + 1])
                    {
                        continue;
                    }

                    double[] absdz = new double[dz.GetLength(0)];
                    for (int a = 0; a < absdz.Length; a++)
                    {
                        absdz[a] = Math.Abs(dz[a, j] - dz[a, np + 1]);
                    }

                    if (MathUtilities.Sum(absdz) < small)
                    {
                        break;
                    }
                }
                if (j > np)
                {
                    np++;
                }
                pathloc[i] = j; //store path location
            }

            // Read soil properties
            nsp = ns;
            sp  = new SoilProps[nsp + 1];
            for (i = 1; i <= ns; i++)
            {
                sp[i] = Soil.ReadProps("soil" + isoil[i - 1]);
            }

            //Set ths and he
            ths = new double[n + 1];
            he  = new double[n + 1];

            for (i = 1; i <= n; i++)
            {
                ths[i] = sp[soilloc[i] + 1].ths;
                he[i]  = sp[soilloc[i] + 1].he;
            }

            //Set up S and phi arrays to get phi from S.
            S      = new double[ns + 1, nphi + 1];
            rdS    = new double[ns + 1];
            phi    = new double[ns + 1, nphi + 1];
            dphidS = new double[ns + 1, nphi - 1 + 1];
            K      = new double[ns + 1, nphi + 1];
            dKdS   = new double[ns + 1, nphi - 1 + 1];
            for (i = 1; i <= ns; i++)
            {
                nc = sp[i].nc;

                //S(:,i)=sp(i)%Sc(1)+(/(j,j=0,nphi-1)/)*(sp(i)%Sc(nc)-sp(i)%Sc(1))/(nphi-1)
                for (int a = 0; a < nphi; a++)
                {
                    S[i, a + 1] = sp[i].Sc[1] + a * (sp[i].Sc[nc] - sp[i].Sc[1]) / (nphi - 1);
                }
                phi[i, 1]    = sp[i].phic[1];
                phi[i, nphi] = sp[i].phic[nc];
                j            = 1;
                for (i1 = 2; i1 <= nphi - 1; i1++)
                {
                    while (true)
                    {
                        if (S[i, i1] < sp[i].Sc[j + 1])
                        {
                            break;
                        }
                        j++;
                    }
                    x1         = S[i, i1] - sp[i].Sc[j];
                    phi[i, i1] = sp[i].phic[j] + x1 * (sp[i].phico[1, j] + x1 * (sp[i].phico[2, j] + x1 * sp[i].phico[3, j]));
                    x1         = phi[i, i1] - sp[i].phic[j];
                    K[i, i1]   = sp[i].Kc[j] + x1 * (sp[i].Kco[1, j] + x1 * (sp[i].Kco[2, j] + x1 * sp[i].Kco[3, j]));
                }

                rdS[i] = 1.0 / (S[i, 2] - S[i, 1]);

                for (int a = 2; a <= nphi; a++)
                {
                    dphidS[i, a - 1] = rdS[i] * (phi[i, a] - phi[i, a - 1]);
                    dKdS[i, a - 1]   = rdS[i] * (K[i, a] - K[i, a - 1]);
                }
            }

            // Read flux tables and form flux paths.
            ft    = new FluxTable[np + 1];
            fpath = new FluxPath[np + 1];
            nft   = np;
            for (i = 1; i <= np; i++)
            {
                for (j = 1; j <= 2; j++)
                {
                    id = isid[j, i].ToString();
                    mm = Math.Round(10.0 * dz[j, i]).ToString();
                    Console.WriteLine(id);
                    Console.WriteLine(mm);
                    ftname[j] = "soil" + id + "dz" + mm;
                }
                if (isid[1, i] == isid[2, i])
                {
                    sfile = ftname[1];
                }
                else
                {
                    sfile = ftname[1] + "_" + ftname[2];
                }
                ft[i] = Fluxes.ReadFluxTable(sfile);

                // Set up flux path data.
                j           = jsp(ft[i].fend[0].sid, ns, isoil);
                pe1.nfu     = ft[i].fend[0].nfu;
                pe1.nft     = ft[i].fend[0].nft;
                pe1.nld     = sp[j].nld;
                pe1.ths     = sp[j].ths;
                pe1.rdS     = rdS[j];
                pe1.Ks      = sp[j].ks;
                pe1.S       = Extensions.GetRowCol(S, j, false);
                pe1.phi     = Extensions.GetRowCol(phi, j, false);
                pe1.dphidS  = Extensions.GetRowCol(dphidS, j, false);
                pe1.K       = Extensions.GetRowCol(K, j, false);
                pe1.dKdS    = Extensions.GetRowCol(dKdS, j, false);
                pe1.Sd      = sp[j].Sd;
                pe1.lnh     = sp[j].lnh;
                pe1.phif    = ft[i].fend[0].phif;
                fpath[i].dz = ft[i].fend[0].dz;
                if (ft[i].fend[1].sid == ft[i].fend[0].sid)
                {
                    pe2 = pe1;
                }
                else //composite path
                {
                    j           = jsp(ft[i].fend[1].sid, ns, isoil);
                    pe2.nfu     = ft[i].fend[1].nfu;
                    pe2.nft     = ft[i].fend[1].nft;
                    pe2.nld     = sp[j].nld;
                    pe2.ths     = sp[j].ths;
                    pe2.rdS     = rdS[j];
                    pe2.Ks      = sp[j].ks;
                    pe2.S       = Extensions.GetRowCol(S, j, false);
                    pe2.phi     = Extensions.GetRowCol(phi, j, false);
                    pe2.dphidS  = Extensions.GetRowCol(dphidS, j, false);
                    pe2.K       = Extensions.GetRowCol(K, j, false);
                    pe2.dKdS    = Extensions.GetRowCol(dKdS, j, false);
                    pe2.Sd      = sp[j].Sd;
                    pe2.lnh     = sp[j].lnh;
                    pe2.phif    = ft[i].fend[1].phif;
                    fpath[i].dz = fpath[i].dz + ft[i].fend[1].dz;
                }
                fpath[i].pend    = new PathEnd[3];
                fpath[i].pend[1] = pe1;
                fpath[i].pend[2] = pe2;
                fpath[i].ftable  = ft[i].ftable;
            }
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
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);
        }