// The above parameters can be varied, but the defaults should usually be ok. //subroutine to generate the property values. public static SoilProps gensptbl(double dzmin, SoilParam sPar, bool Kgiven) { int nlimax = 220; int i, j, nli1, nc, nld; double[] h = new double[nlimax + 3]; double[] lhr = new double[nlimax + 3]; double[] K = new double[nlimax + 3]; double[] phi = new double[nlimax + 3]; double[] S = new double[nlimax + 3]; double[] cco = new double[4]; //diags - timing starts here SoilProps sp = new SoilProps(); sp.sid = sPar.sid; sp.ths = sPar.ths; sp.ks = sPar.ks; sp.he = sPar.he; sp.phie = phie; sp.S = S; sp.n = sPar.layers; // Find start of significant fluxes. hdry = sPar.hd; // normally -1e7 cm phidry = 0.0; hwet = Math.Min(sPar.he, -1.0); // h/hwet used for log spacing if (Kgiven) { dlh = Math.Log(10.0) / 3.0; // three points per decade x = Math.Exp(-dlh); // x*x*x=0.1 h[0] = hdry; K[0] = MVG.Kofh(h[0]); phi[0] = 0.0; for (i = 1; i < nlimax; i++) // should exit well before nlimax { h[i] = x * h[i - 1]; K[i] = MVG.Kofh(h[i]); // Get approx. phi by integration using dln(-h). phi[i] = phi[i - 1] - 0.5 * (K[i] * h[i] - K[i - 1] * h[i - 1]) * dlh; if (phi[i] > qsmall * dzmin) { break; // max flux is approx (phi-0)/dzmin } } if (i > nlimax) { Console.WriteLine("gensptbl: start of significant fluxes not found"); Environment.Exit(1); } hdry = h[i - 1]; phidry = phi[i - 1]; } else { // Calculate K and find start of significant fluxes. Props(ref sp, hdry, phidry, lhr, h, Kgiven); for (i = 2; i < sp.n; i++) { if (phi[i] > qsmall * dzmin) { break; } } if (i > sp.n) { Console.WriteLine("gensptbl: start of significant fluxes not found"); Environment.Exit(1); } i = i - 1; hdry = h[i]; phidry = phi[i]; } // hdry and phidry are values where significant fluxes start. // Get props. sp.Kc = new double[sp.n]; Props(ref sp, hdry, phidry, lhr, h, Kgiven); // Get ln(-h) and S values from dryness to approx -10000 cm. // These needed for vapour flux (rel humidity > 0.99 at -10000 cm). // To have complete S(h) coverage, bridge any gap between -10000 and h[1]. x = Math.Log(-Math.Max(vhmax, h[0])); lhd = Math.Log(-sPar.hd); dlh = Math.Log(10.0) / nhpd; // nhpd points per decade nli1 = (int)Math.Round((lhd - x) / dlh, 0); nld = nli1 + 1; nc = 1 + sp.n / 3; // n-1 has been made divisible by 3 // fill out the rest of the structure. sp.nld = nld; sp.nc = nc; sp.h = h; sp.lnh = new double[nld + 1]; sp.Sd = new double[nld + 1]; sp.Kco = new double[3 + 1, nc + 1]; sp.phico = new double[3 + 1, nc + 1]; sp.Sco = new double[3 + 1, nc + 1]; // Store Sd and lnh in sp. sp.lnh[1] = lhd; for (j = 2; j <= nld; j++) { sp.lnh[j] = lhd - dlh * (j - 1); } if (Kgiven) { sp.Sd[1] = MVG.Sofh(sPar.hd); for (j = 2; j <= nld; j++) { x = sp.lnh[j]; sp.Sd[j] = MVG.Sofh(-Math.Exp(x)); } } else { MVG.Sdofh(sPar.hd, out x, out dSdh); sp.Sd[1] = x; for (j = 2; j <= nld; j++) { x = sp.lnh[j]; MVG.Sdofh(-Math.Exp(x), out x, out dSdh); sp.Sd[j] = x; } } // Get polynomial coefficients. j = 0; sp.Sc = new double[sp.n + 1]; sp.hc = new double[sp.n + 1]; sp.phic = new double[sp.n + 1]; Matrix <double> KcoM = Matrix <double> .Build.DenseOfArray(sp.Kco); Matrix <double> phicoM = Matrix <double> .Build.DenseOfArray(sp.phico); Matrix <double> ScoM = Matrix <double> .Build.DenseOfArray(sp.Sco); for (i = 1; i <= sp.n; i += 3) { j = j + 1; sp.Sc[j] = S[i]; sp.hc[j] = h[i]; sp.Kc[j] = sp.K[i]; sp.phic[j] = sp.phi[i]; if (i == sp.n) { break; } cco = Cuco(sp.phi.Slice(i, i + 3), sp.K.Slice(i, i + 3)); KcoM.SetColumn(j, cco.Slice(2, 4).ToArray()); cco = Cuco(sp.S.Slice(i, i + 3), sp.phi.Slice(i, i + 3)); phicoM.SetColumn(j, cco.Slice(2, 4).ToArray()); cco = Cuco(sp.phi.Slice(i, i + 3), sp.S.Slice(i, i + 3)); ScoM.SetColumn(j, cco.Slice(2, 4).ToArray()); } sp.Kco = KcoM.ToArray(); sp.phico = phicoM.ToArray(); sp.Sco = ScoM.ToArray(); return(sp); }
private static void Props(ref SoilProps sp, double hdry, double phidry, double[] lhr, double[] h, bool Kgiven) { int i, j, nli; double[] g = new double[201]; double[] dSdhg = new double[201]; j = 2 * (nliapprox / 6); // an even number nli = 3 * j; //nli divisible by 2 (for integrations) and 3 (for cubic coeffs) if (sp.he > hwet) { nli = 3 * (j + 1) - 1; // to allow for extra points } dlhr = -Math.Log(hdry / hwet) / nli; // even spacing in log(-h) // lhr(1:nli + 1) = (/ (-i * dlhr,i = nli,0,-1)/) double[] slice = lhr.Slice(1, nli + 1); for (int idx = nli; idx > 0; idx--) { slice[idx] = -idx * dlhr; } Array.Reverse(slice); Array.Copy(slice, 0, lhr, 0, slice.Length); for (int idx = 1; idx <= nli + 1; idx++) { h[idx] = hwet * Math.Exp(lhr[idx]); } if (sp.he > hwet) // add extra points { sp.n = nli + 3; h[sp.n - 1] = 0.5 * (sp.he + hwet); h[sp.n] = sp.he; } else { sp.n = nli + 1; } sp.K = new double[sp.n + 1]; sp.Kc = new double[sp.n + 1]; sp.phi = new double[sp.n + 1]; if (Kgiven) { for (i = 1; i <= sp.n; i++) { sp.S[i] = MVG.Sofh(h[i]); sp.K[i] = MVG.KofhS(h[i], sp.S[i]); } sp.S[sp.n] = MVG.Sofh(h[sp.n]); } else // calculate relative K by integration using dln(-h) { for (i = 1; i <= sp.n; i++) { MVG.Sdofh(h[i], out sp.S[i], out dSdhg[i]); } g[1] = 0; for (i = 2; i <= nli; i += 2) // integrate using Simpson's rule { g[i + 1] = g[i - 1] + dlhr * (dSdhg[i - 1] + 4.0 * dSdhg[i] + dSdhg[i + 1]) / 3.0; } g[2] = 0.5 * (g[0] + g[2]); for (i = 3; i <= nli - 1; i += 2) { g[i + 1] = g[i - 1] + dlhr * (dSdhg[i - 1] + 4.0 * dSdhg[i] + dSdhg[i + 1]) / 3.0; } if (sp.he > hwet) { g[sp.n] = g[sp.n - 2] + (h[sp.n] - h[sp.n - 1]) * (dSdhg[sp.n - 2] / h[sp.n - 2] + 4.0 * dSdhg[sp.n - 1] / h[sp.n - 1]) / 3.0; g[sp.n - 1] = g[sp.n]; // not accurate, but K[sp.n-1] will be discarded } for (i = 1; i <= sp.n; i++) { sp.K[i] = sp.ks * Math.Pow(sp.S[i], MVG.GetP()) * Math.Pow(g[i] / g[sp.n], 2); } } // Calculate phi by integration using dln(-h). sp.phi[1] = phidry; for (i = 2; i <= nli; i += 2) // integrate using Simpson's rule { sp.phi[i + 1] = sp.phi[i - 1] + dlhr * (sp.K[i - 1] * h[i - 1] + 4.0 * sp.K[i] * h[i] + sp.K[i + 1] * h[i + 1]) / 3.0; } sp.phi[2] = 0.5 * (sp.phi[1] + sp.phi[3]); for (i = 3; i <= nli - 1; i += 2) { sp.phi[i + 1] = sp.phi[i - 1] + dlhr * (sp.K[i - 1] * h[i - 1] + 4.0 * sp.K[i] * h[i] + sp.K[i + 1] * h[i + 1]) / 3.0; } if (sp.he > hwet) // drop unwanted point { sp.phi[sp.n - 1] = sp.phi[sp.n - 2] + (h[sp.n] - h[sp.n - 1]) * (sp.K[sp.n - 2] + 4.0 * sp.K[sp.n - 1] + sp.K[sp.n]) / 3.0; h[sp.n - 1] = h[sp.n]; sp.S[sp.n - 1] = sp.S[sp.n]; sp.K[sp.n - 1] = sp.K[sp.n]; sp.n = sp.n - 1; } phie = sp.phi[sp.n]; sp.phie = phie; }