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 }
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 }