public void Solute() { int nt = 2; int ns = 2; SolProps sp = new SolProps(nt, ns); double[] bd = new double[nt + 1]; double[] dis = new double[nt + 1]; string[] isotype = { "", "Fr", "La" }; double[,] isopar = { { 0, 0, 0 }, { 0, 1.0, 1.0 }, { 0, 0.5, 0.01 } }; Array.Copy(new [] { 0, 1.3, 1.3 }, bd, 3); Array.Copy(new [] { 0, 20.0, 20.0 }, dis, 3); for (int j = 1; j <= nt; j++) { sp.Solpar(j, bd[j], dis[j]); sp.Setiso(j, 2, isotype[j], Extensions.GetRowCol(isopar, j, true)); } int n = 10; int nex = 0; double ti = 0; double tf = 0.421148079; double[] thi = { 0, 8.32952248067425E-02, 8.32952248067425E-02, 8.32952248067425E-02, 8.32952248067425E-02, 4.18896102493218E-01, 4.18896102493218E-01, 4.18896102493218E-01, 4.18896102493218E-01, 4.18896102493218E-01, 4.18896102493218E-01 }; double[] thf = { 0, 1.23293862599989E-01, 8.33055911391525E-02, 8.32952276559487E-02, 8.33189852482353E-02, 4.18882017281567E-01, 4.18896097739775E-01, 4.18896102481653E-01, 4.18896102470398E-01, 4.18896050247009E-01, 4.18896158171224E-01}; double[,] dwexs = new double[nex, n]; double win = 0.400090675; double[] cin = { 0, 0, 0 }; double[] dx = { 0, 10, 10, 10, 10, 20, 20, 20, 20, 40, 40 }; int[] jt = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 }; int dsmmax = 10; double[,] sm = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; double[] sdrn = { 0, 0, 0 }; int[] nssteps = { 0, 0, 0 }; double[,] c = new double[ns + 1, n + 1]; double[,,] sex = new double[0, 0, 0]; double[,] smOUT = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 9.9976219E+01, 2.3781371E-02, 2.2604628E-08, 2.0517180E-14, 1.2161602E-18, 4.8670606E-24, 1.9519348E-29, 7.8282825E-35, 1.2209528E-40, 1.7083828E-46}, {0, 9.9983728E+01, 1.6271857E-02, 9.8469378E-11, 5.6908331E-19, 2.1476414E-25, 2.0945763E-31, 2.0471666E-37, 2.0008407E-43, 7.6050509E-50, 2.5932571E-56} }; double[] sdrnOUT = { 0, 9.10749016E-51, 3.36911468E-61 }; int[] nsstepsOUT = { 0, 1, 1 }; double[,] cOUT = { {0, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0, 1.20054901384821E+03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0, 7.68024454834764E+02, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00} }; List<object> res = Flow.TestSolute(ti, tf, thi, thf, dwexs, win, cin, n, ns, nex, dx, jt, dsmmax, sm, sdrn, nssteps, c, sex, false, sp); double[,] smRes = res[0] as double[,]; for (int i = 1; i < smOUT.GetLength(0); i++) for (int j = 1; j < smOUT.GetLength(1); j++) Assert.AreEqual(smOUT[i, j], smRes[i, j], Math.Abs(smOUT[i, 1] * 1E-5)); //variations in sm at E-40... I don't think we really care at that point. Also probably outside of float range double[] sdrnRes = res[1] as double[]; for (int i = 1; i < sdrnOUT.Length; i++) Assert.AreEqual(sdrnOUT[i], sdrnRes[i], 1E-10); //same as above. We're working with -60 exponents here. No bearing to reality. int[] nsstepsRes = res[2] as int[]; for (int i = 1; i < nsstepsOUT.Length; i++) Assert.AreEqual(nsstepsOUT[i], nsstepsRes[i]); double[,] cRes = res[3] as double[,]; for (int i = 1; i < cOUT.GetLength(0); i++) for (int j = 1; j < cOUT.GetLength(1); j++) Assert.AreEqual(cOUT[i, j], cRes[i, j], Math.Abs(cOUT[i,j] * 1E-7)); }
static double[,] isopar; //2 params (nt,2) //public static void Setup() public static void Main(string[] args) { Soil.SoilProperties = new Dictionary <string, SoilProps>(); Fluxes.FluxTables = new Dictionary <string, FluxTable>(); Program.GenerateFlux(); c0 = new double[ns + 1]; cin = new double[ns + 1]; h = new double[n + 1]; S = new double[n + 1]; isotype = new string[nt + 1]; isopar = new double[nt + 1, 2 + 1]; soff = new double[ns + 1]; sdrn = new double[ns + 1]; sinfil = new double[ns + 1]; SoilData sd = new SoilData(); Flow.sink = new SinkDripperDrain(); //set the type of sink to use jt = new int[n + 1]; nssteps = new int[ns + 1]; sidx = new int[n + 1]; sm = new double[ns + 1, n + 1]; //set a list of soil layers(cm). x = new double[] { 0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 120.0, 160.0, 200.0 }; for (int c = 1; c <= n; c++) { sidx[c] = c < 5 ? 103 : 109; //soil ident of layers } //set required soil hydraulic params sd.GetTables(n, sidx, x); SolProps solProps = new SolProps(nt, ns); bd = new double[] { 0, 1.3, 1.3 }; dis = new double[] { 0, 20.0, 20.0 }; //set isotherm type and params for solute 2 here isotype[1] = "Fr"; isotype[2] = "La"; isopar[1, 1] = 1.0; isopar[1, 2] = 1.0; isopar[2, 1] = 0.5; isopar[2, 2] = 0.01; Matrix <double> isoparM = Matrix <double> .Build.DenseOfArray(isopar); for (j = 1; j <= nt; j++) //set params { solProps.Solpar(j, bd[j], dis[j]); //set isotherm type and params solProps.Setiso(j, 2, isotype[j], isoparM.Column(j).ToArray()); } //initialise for run ts = 0.0; //start time //dSmax controls time step.Use 0.05 for a fast but fairly accurate solution. //Use 0.001 to get many steps to test execution time per step. Flow.dSmax = 0.01; //0.01 ensures very good accuracy for (int c = 1; c <= n; c++) { jt[c] = c < 5 ? 1 : 2; //!4 layers of type 1, rest of type2 } h0 = 0.0; //pond depth initially zero h1 = -1000.0; h2 = -400.0; //initial matric heads double Sh = 0; //not used for this call but required as C# does not have 'present' operator sd.Sofh(h1, 1, out S1, out Sh); //solve uses degree of satn sd.Sofh(h2, 5, out S2, out Sh); for (int c = 1; c <= n; c++) { S[c] = c < 5 ? S1 : S2; } wpi = MathUtilities.Sum(MathUtilities.Multiply(MathUtilities.Multiply(sd.ths, S), sd.dx)); //water in profile initially nsteps = 0; //no.of time steps for water soln(cumulative) win = 0.0; //water input(total precip) evap = 0.0; runoff = 0.0; infil = 0.0; drn = 0.0; for (int col = 1; col < sm.GetLength(0); col++) { sm[col, 1] = 1000.0 / sd.dx[1]; } //initial solute concn(mass units per cc of soil) //solute in profile initially spi = new [] { 1000.0, 1000.0 }; Flow.dsmmax = 0.1 * sm[1, 1]; //solute stepsize control param Flow.nwsteps = 10; MathUtilities.Zero(c0); MathUtilities.Zero(cin); //no solute input nssteps.Populate(0); //no.of time steps for solute soln(cumulative) MathUtilities.Zero(soff); MathUtilities.Zero(sinfil); MathUtilities.Zero(sdrn); qprec = 1.0; //precip at 1 cm / h for first 24 h ti = ts; qevap = 0.05; // potential evap rate from soil surface double[,] wex = new double[1, 1]; //unused option params in FORTRAN... must be a better way of doing this double[,,] sex = new double[1, 1, 1]; //timer here in FORTRAN, this basically runs the solution for 100 days for (j = 1; j <= 100; j++) { tf = ti + 24.0; Flow.Solve(solProps, sd, ti, tf, qprec, qevap, ns, Flow.sink.nex, ref h0, ref S, ref evap, ref runoff, ref infil, ref drn, ref nsteps, jt, cin, ref c0, ref sm, ref soff, ref sinfil, ref sdrn, ref nssteps, ref wex, ref sex); win = win + qprec * (tf - ti); if (j == 1) { ti = tf; } qprec = 0.0; } win = win + qprec * (tf - ti); wp = MathUtilities.Sum(MathUtilities.Multiply(MathUtilities.Multiply(sd.ths, S), sd.dx)); //!water in profile double hS = 0; //hS is not used used here, but is a required parameter for (j = 1; j <= n; j++) { sd.hofS(S[j], j, out h[j], out hS); } }
static double[,] sm; //(n, ns) #endregion Fields #region Methods //public static void Setup() public static void Main(string[] args) { Soil.SoilProperties = new Dictionary<string, SoilProps>(); Fluxes.FluxTables = new Dictionary<string, FluxTable>(); Program.GenerateFlux(); c0 = new double[ns + 1]; cin = new double[ns + 1]; h = new double[n + 1]; S = new double[n + 1]; isotype = new string[nt + 1]; isopar = new double[nt + 1, 2 + 1]; soff = new double[ns + 1]; sdrn = new double[ns + 1]; sinfil = new double[ns + 1]; SoilData sd = new SoilData(); Flow.sink = new SinkDripperDrain(); //set the type of sink to use jt = new int[n+1]; nssteps = new int[ns + 1]; sidx = new int[n+1]; sm = new double[ns + 1, n + 1]; //set a list of soil layers(cm). x = new double[] { 0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 120.0, 160.0, 200.0 }; for (int c = 1; c <= n; c++) sidx[c] = c < 5 ? 103 : 109; //soil ident of layers //set required soil hydraulic params sd.GetTables(n, sidx, x); SolProps solProps = new SolProps(nt, ns); bd = new double[] {0, 1.3, 1.3 }; dis = new double[] {0, 20.0, 20.0 }; //set isotherm type and params for solute 2 here isotype[1] = "Fr"; isotype[2] = "La"; isopar[1, 1] = 1.0; isopar[1, 2] = 1.0; isopar[2, 1] = 0.5; isopar[2, 2] = 0.01; Matrix<double> isoparM = Matrix<double>.Build.DenseOfArray(isopar); for (j = 1; j <= nt; j++) //set params { solProps.Solpar(j, bd[j], dis[j]); //set isotherm type and params solProps.Setiso(j, 2, isotype[j], isoparM.Column(j).ToArray()); } //initialise for run ts = 0.0; //start time //dSmax controls time step.Use 0.05 for a fast but fairly accurate solution. //Use 0.001 to get many steps to test execution time per step. Flow.dSmax = 0.01; //0.01 ensures very good accuracy for (int c = 1; c <= n; c++) jt[c] = c < 5 ? 1 : 2; //!4 layers of type 1, rest of type2 h0 = 0.0; //pond depth initially zero h1 = -1000.0; h2 = -400.0; //initial matric heads double Sh = 0; //not used for this call but required as C# does not have 'present' operator sd.Sofh(h1, 1, out S1, out Sh); //solve uses degree of satn sd.Sofh(h2, 5, out S2, out Sh); for (int c = 1; c <= n; c++) S[c] = c < 5 ? S1 : S2; wpi = MathUtilities.Sum(MathUtilities.Multiply(MathUtilities.Multiply(sd.ths, S), sd.dx)); //water in profile initially nsteps = 0; //no.of time steps for water soln(cumulative) win = 0.0; //water input(total precip) evap = 0.0; runoff = 0.0; infil = 0.0; drn = 0.0; for (int col = 1; col < sm.GetLength(0); col++) sm[col, 1] = 1000.0 / sd.dx[1]; //initial solute concn(mass units per cc of soil) //solute in profile initially spi = new []{1000.0, 1000.0}; Flow.dsmmax = 0.1 * sm[1, 1]; //solute stepsize control param Flow.nwsteps = 10; MathUtilities.Zero(c0); MathUtilities.Zero(cin); //no solute input nssteps.Populate(0); //no.of time steps for solute soln(cumulative) MathUtilities.Zero(soff); MathUtilities.Zero(sinfil); MathUtilities.Zero(sdrn); qprec = 1.0; //precip at 1 cm / h for first 24 h ti = ts; qevap = 0.05;// potential evap rate from soil surface double[,] wex = new double[1,1]; //unused option params in FORTRAN... must be a better way of doing this double[,,] sex=new double[1,1,1]; //timer here in FORTRAN, this basically runs the solution for 100 days for (j = 1; j <= 100; j++) { tf = ti + 24.0; Flow.Solve(solProps, sd, ti, tf, qprec, qevap, ns, Flow.sink.nex, ref h0, ref S, ref evap, ref runoff, ref infil, ref drn, ref nsteps, jt, cin, ref c0, ref sm, ref soff, ref sinfil, ref sdrn, ref nssteps, ref wex,ref sex); win = win + qprec * (tf - ti); if (j == 1) ti = tf; qprec = 0.0; } win = win + qprec * (tf - ti); wp = MathUtilities.Sum(MathUtilities.Multiply(MathUtilities.Multiply(sd.ths,S), sd.dx)); //!water in profile double hS = 0; //hS is not used used here, but is a required parameter for (j = 1; j <= n; j++) sd.hofS(S[j], j, out h[j], out hS); }