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); }
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); }
// 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); }
static double vhmax = -10000; // for vapour - rel humidity > 0.99 at vhmax #endregion Fields #region Methods // 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, n, 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; n = sp.n; // 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[1] = 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(sp, hdry, phidry, lhr, h, Kgiven); for (i = 2; i < n; i++) if (phi[i] > qsmall * dzmin) break; if (i > 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(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[1])); 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 + 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.K = K; sp.phi = phi; sp.lnh = new double[nld]; sp.Sd = new double[nld]; sp.Kco = new double[3, nc - 1]; sp.phico = new double[3, nc - 1]; sp.Sco = new double[3, nc - 1]; // Store Sd and lnh in sp. sp.lnh[0] = lhd; for (j = 1; j < nli1; j++) sp.lnh[j] = lhd - dlh * j; if (Kgiven) { sp.Sd[0] = MVG.Sofh(sPar.hd); for (j = 1; 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[0] = x; for (j = 1; 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]; sp.hc = new double[sp.n]; sp.phic = new double[sp.n]; for (i = 0; i < n; i += 3) { j = j + 1; sp.Sc[j] = S[i]; sp.hc[j] = h[i]; sp.Kc[j] = K[i]; sp.phic[j] = phi[i]; if (i == n) break; cco = Cuco(sp.phi.Skip(i).Take(4).ToArray(), sp.K.Skip(i).Take(4).ToArray()); for (int row = 0; row < sp.Kco.GetLength(0); row++) for (int col = 0; col < 2; col++) sp.Kco[row, col] = cco[col + 2]; cco = Cuco(sp.S.Skip(i).Take(4).ToArray(), sp.phi.Skip(i).Take(4).ToArray()); for (int row = 0; row < sp.Kco.GetLength(0); row++) for (int col = 0; col < 2; col++) sp.phico[row, col] = cco[col + 2]; cco = Cuco(sp.phi.Skip(i).Take(4).ToArray(), sp.S.Skip(i).Take(4).ToArray()); for (int row = 0; row < sp.Kco.GetLength(0); row++) for (int col = 0; col < 2; col++) sp.Sco[row, col] = cco[col + 2]; } // diags - end timing return sp; }
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); }