2929import argparse
3030
3131
32- def run (n , backend , benchmark_mode ):
32+ def run (n , backend , benchmark_mode , correctness_test ):
3333 if backend == "ddpt" :
3434 import ddptensor as np
3535 from ddptensor .numpy import fromfunction
3636 from ddptensor import init , fini , sync
37+
3738 all_axes = [0 , 1 ]
39+ init (False )
40+
41+ try :
42+ import mpi4py
43+
44+ mpi4py .rc .finalize = False
45+ from mpi4py import MPI
46+
47+ comm_rank = MPI .COMM_WORLD .Get_rank ()
48+ except ImportError :
49+ comm_rank = 0
50+
3851 elif backend == "numpy" :
3952 import numpy as np
4053 from numpy import fromfunction
41- init = fini = sync = lambda x = None : None
54+
55+ fini = sync = lambda x = None : None
4256 all_axes = None
57+ comm_rank = 0
4358 else :
4459 raise ValueError (f'Unknown backend: "{ backend } "' )
4560
46- print (f'Using backend: { backend } ' )
47- init (False )
61+ def info (s ):
62+ if comm_rank == 0 :
63+ print (s )
64+
65+ info (f"Using backend: { backend } " )
66+
67+ if correctness_test :
68+ n = 10
4869
4970 # constants
5071 h = 1.0
@@ -63,31 +84,33 @@ def run(n, backend, benchmark_mode):
6384 nx = n
6485 ny = n
6586 # grid spacing
66- dx = lx / nx
67- dy = lx / ny
87+ dx = lx / nx
88+ dy = lx / ny
6889
6990 # export interval
7091 t_export = 0.02
7192 t_end = 1.0
7293
7394 # coordinate arrays
7495 x_t_2d = fromfunction (
75- lambda i , j : xmin + i * dx + dx / 2 , (nx , ny ), dtype = np .float64 )
96+ lambda i , j : xmin + i * dx + dx / 2 , (nx , ny ), dtype = np .float64
97+ )
7698 y_t_2d = fromfunction (
77- lambda i , j : ymin + j * dy + dy / 2 , (nx , ny ), dtype = np .float64 )
99+ lambda i , j : ymin + j * dy + dy / 2 , (nx , ny ), dtype = np .float64
100+ )
78101
79102 T_shape = (nx , ny )
80103 U_shape = (nx + 1 , ny )
81- V_shape = (nx , ny + 1 )
104+ V_shape = (nx , ny + 1 )
82105
83106 dofs_T = int (numpy .prod (numpy .asarray (T_shape )))
84107 dofs_U = int (numpy .prod (numpy .asarray (U_shape )))
85108 dofs_V = int (numpy .prod (numpy .asarray (V_shape )))
86109
87- print ( f' Grid size: { nx } x { ny } ' )
88- print ( f' Elevation DOFs: { dofs_T } ' )
89- print ( f' Velocity DOFs: { dofs_U + dofs_V } ' )
90- print ( f' Total DOFs: { dofs_T + dofs_U + dofs_V } ' )
110+ info ( f" Grid size: { nx } x { ny } " )
111+ info ( f" Elevation DOFs: { dofs_T } " )
112+ info ( f" Velocity DOFs: { dofs_U + dofs_V } " )
113+ info ( f" Total DOFs: { dofs_T + dofs_U + dofs_V } " )
91114
92115 # prognostic variables: elevation, (u, v) velocity
93116 e = np .full (T_shape , 0.0 , np .float64 )
@@ -115,7 +138,7 @@ def exact_elev(t, x_t_2d, y_t_2d, lx, ly):
115138 sol_x = np .cos (2 * n * math .pi * x_t_2d / lx )
116139 m = 1
117140 sol_y = np .cos (2 * m * math .pi * y_t_2d / ly )
118- omega = c * math .pi * ((n / lx )** 2 + (m / ly )** 2 ) ** 0.5
141+ omega = c * math .pi * ((n / lx ) ** 2 + (m / ly ) ** 2 ) ** 0.5
119142 # NOTE ddpt fails with scalar computation
120143 sol_t = numpy .cos (2 * omega * t )
121144 return amp * sol_x * sol_y * sol_t
@@ -132,10 +155,14 @@ def exact_elev(t, x_t_2d, y_t_2d, lx, ly):
132155 if benchmark_mode :
133156 dt = 1e-5
134157 nt = 100
135- t_export = dt * 25
158+ t_export = dt * 25
159+ if correctness_test :
160+ dt = 0.02
161+ nt = 10
162+ t_export = dt * 2
136163
137- print ( f' Time step: { dt } s' )
138- print ( f' Total run time: { t_end } s, { nt } time steps' )
164+ info ( f" Time step: { dt } s" )
165+ info ( f" Total run time: { t_end } s, { nt } time steps" )
139166
140167 sync ()
141168
@@ -146,12 +173,14 @@ def rhs(u, v, e):
146173 # sign convention: positive on rhs
147174
148175 # pressure gradient -g grad(elev)
149- dudt = - g * (e [1 :nx , 0 :ny ] - e [0 : nx - 1 , 0 :ny ]) / dx
150- dvdt = - g * (e [0 :nx , 1 :ny ] - e [0 :nx , 0 : ny - 1 ]) / dy
176+ dudt = - g * (e [1 :nx , 0 :ny ] - e [0 : nx - 1 , 0 :ny ]) / dx
177+ dvdt = - g * (e [0 :nx , 1 :ny ] - e [0 :nx , 0 : ny - 1 ]) / dy
151178
152179 # velocity divergence -h div(u)
153- dedt = - h * ((u [1 :nx + 1 , 0 :ny ] - u [0 :nx , 0 :ny ]) / dx +
154- (v [0 :nx , 1 :ny + 1 ] - v [0 :nx , 0 :ny ]) / dy )
180+ dedt = - h * (
181+ (u [1 : nx + 1 , 0 :ny ] - u [0 :nx , 0 :ny ]) / dx
182+ + (v [0 :nx , 1 : ny + 1 ] - v [0 :nx , 0 :ny ]) / dy
183+ )
155184
156185 return dudt , dvdt , dedt
157186
@@ -165,23 +194,23 @@ def step(u, v, e, u1, v1, e1, u2, v2, e2):
165194 e1 [0 :nx , 0 :ny ] = e [0 :nx , 0 :ny ] + dt * dedt
166195
167196 dudt , dvdt , dedt = rhs (u1 , v1 , e1 )
168- u2 [1 :nx , 0 :ny ] = 0.75 * u [1 :nx , 0 :ny ] + 0.25 * (u1 [1 :nx , 0 :ny ] + dt * dudt )
169- v2 [0 :nx , 1 :ny ] = 0.75 * v [0 :nx , 1 :ny ] + 0.25 * (v1 [0 :nx , 1 :ny ] + dt * dvdt )
170- e2 [0 :nx , 0 :ny ] = 0.75 * e [0 :nx , 0 :ny ] + 0.25 * (e1 [0 :nx , 0 :ny ] + dt * dedt )
197+ u2 [1 :nx , 0 :ny ] = 0.75 * u [1 :nx , 0 :ny ] + 0.25 * (u1 [1 :nx , 0 :ny ] + dt * dudt )
198+ v2 [0 :nx , 1 :ny ] = 0.75 * v [0 :nx , 1 :ny ] + 0.25 * (v1 [0 :nx , 1 :ny ] + dt * dvdt )
199+ e2 [0 :nx , 0 :ny ] = 0.75 * e [0 :nx , 0 :ny ] + 0.25 * (e1 [0 :nx , 0 :ny ] + dt * dedt )
171200
172201 dudt , dvdt , dedt = rhs (u2 , v2 , e2 )
173- u [1 :nx , 0 :ny ] = u [1 :nx , 0 :ny ]/ 3.0 + 2.0 / 3.0 * (u2 [1 :nx , 0 :ny ] + dt * dudt )
174- v [0 :nx , 1 :ny ] = v [0 :nx , 1 :ny ]/ 3.0 + 2.0 / 3.0 * (v2 [0 :nx , 1 :ny ] + dt * dvdt )
175- e [0 :nx , 0 :ny ] = e [0 :nx , 0 :ny ]/ 3.0 + 2.0 / 3.0 * (e2 [0 :nx , 0 :ny ] + dt * dedt )
202+ u [1 :nx , 0 :ny ] = u [1 :nx , 0 :ny ] / 3.0 + 2.0 / 3.0 * (u2 [1 :nx , 0 :ny ] + dt * dudt )
203+ v [0 :nx , 1 :ny ] = v [0 :nx , 1 :ny ] / 3.0 + 2.0 / 3.0 * (v2 [0 :nx , 1 :ny ] + dt * dvdt )
204+ e [0 :nx , 0 :ny ] = e [0 :nx , 0 :ny ] / 3.0 + 2.0 / 3.0 * (e2 [0 :nx , 0 :ny ] + dt * dedt )
176205
177206 t = 0
178207 i_export = 0
179208 next_t_export = 0
180209 initial_v = None
181210 tic = time_mod .perf_counter ()
182- for i in range (nt + 1 ):
211+ for i in range (nt + 1 ):
183212 sync ()
184- t = i * dt
213+ t = i * dt
185214
186215 if t >= next_t_export - 1e-8 :
187216 elev_max = float (np .max (e , all_axes ))
@@ -192,10 +221,12 @@ def step(u, v, e, u1, v1, e1, u2, v2, e2):
192221 initial_v = total_v
193222 diff_v = total_v - initial_v
194223
195- print (f'{ i_export :2d} { i :4d} { t :.3f} elev={ elev_max :7.5f} '
196- f'u={ u_max :7.5f} dV={ diff_v : 6.3e} ' )
224+ info (
225+ f"{ i_export :2d} { i :4d} { t :.3f} elev={ elev_max :7.5f} "
226+ f"u={ u_max :7.5f} dV={ diff_v : 6.3e} "
227+ )
197228 if elev_max > 1e3 or not math .isfinite (elev_max ):
198- print ( f' Invalid elevation value: { elev_max } ' )
229+ info ( f" Invalid elevation value: { elev_max } " )
199230 break
200231 i_export += 1
201232 next_t_export = i_export * t_export
@@ -206,31 +237,55 @@ def step(u, v, e, u1, v1, e1, u2, v2, e2):
206237 sync ()
207238
208239 duration = time_mod .perf_counter () - tic
209- print ( f' Duration: { duration :.2f} s' )
240+ info ( f" Duration: { duration :.2f} s" )
210241
211242 e_exact = exact_elev (t , x_t_2d , y_t_2d , lx , ly )
212243 err2 = (e_exact - e ) * (e_exact - e ) * dx * dy / lx / ly
213244 err_L2 = math .sqrt (float (np .sum (err2 , all_axes )))
214- print ( f' L2 error: { err_L2 :7.5e} ' )
245+ info ( f" L2 error: { err_L2 :7.5e} " )
215246
216247 if nx == 128 and ny == 128 and not benchmark_mode :
217- assert numpy .allclose (err_L2 , 7.22407e-03 )
218- print ('SUCCESS' )
248+ assert numpy .allclose (err_L2 , 7.224068445111e-03 )
249+ info ("SUCCESS" )
250+
251+ if correctness_test :
252+ assert numpy .allclose (err_L2 , 1.317066179876e-02 )
253+ info ("SUCCESS" )
219254
220255 fini ()
221256
222257
223258if __name__ == "__main__" :
224259 parser = argparse .ArgumentParser (
225- description = ' Run wave equation benchmark' ,
260+ description = " Run wave equation benchmark" ,
226261 formatter_class = argparse .ArgumentDefaultsHelpFormatter ,
227262 )
228- parser .add_argument ('-n' , '--resolution' , type = int , default = 128 ,
229- help = 'Number of grid cells in x and y direction.' )
230- parser .add_argument ('-t' , '--benchmark-mode' , action = 'store_true' ,
231- help = 'Run a fixed number of time steps.' )
232- parser .add_argument ('-b' , '--backend' , type = str , default = 'ddpt' ,
233- choices = ['ddpt' , 'numpy' ],
234- help = 'Backend to use.' )
263+ parser .add_argument (
264+ "-n" ,
265+ "--resolution" ,
266+ type = int ,
267+ default = 128 ,
268+ help = "Number of grid cells in x and y direction." ,
269+ )
270+ parser .add_argument (
271+ "-t" ,
272+ "--benchmark-mode" ,
273+ action = "store_true" ,
274+ help = "Run a fixed number of time steps." ,
275+ )
276+ parser .add_argument (
277+ "-ct" ,
278+ "--correctness-test" ,
279+ action = "store_true" ,
280+ help = "Run a minimal correctness test." ,
281+ )
282+ parser .add_argument (
283+ "-b" ,
284+ "--backend" ,
285+ type = str ,
286+ default = "ddpt" ,
287+ choices = ["ddpt" , "numpy" ],
288+ help = "Backend to use." ,
289+ )
235290 args = parser .parse_args ()
236- run (args .resolution , args .backend , args .benchmark_mode )
291+ run (args .resolution , args .backend , args .benchmark_mode , args . correctness_test )
0 commit comments