Skip to content

Commit 8d32788

Browse files
committed
Final touches
1 parent 382ae2f commit 8d32788

File tree

4 files changed

+84
-88
lines changed

4 files changed

+84
-88
lines changed

pySDC/playgrounds/PinT_Workshop_2025/0_pySDC.ipynb

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
],
4949
"source": [
5050
"from qmat import genQCoeffs\n",
51-
"nodes, _, Q = genQCoeffs(\n",
52-
" \"Collocation\", nNodes=3, nodeType=\"LEGENDRE\", quadType=\"RADAU-RIGHT\")\n",
51+
"\n",
52+
"nodes, _, Q = genQCoeffs(\"Collocation\", nNodes=3, nodeType=\"LEGENDRE\", quadType=\"RADAU-RIGHT\")\n",
5353
"print(f'{Q=}')"
5454
]
5555
},
@@ -188,7 +188,7 @@
188188
"Controller: <class 'pySDC.implementations.controller_classes.controller_nonMPI.controller_nonMPI'>\n",
189189
" all_to_done = False\n",
190190
" dump_setup = True\n",
191-
" fname = run_pid77603.log\n",
191+
" fname = run_pid94048.log\n",
192192
"--> hook_class = [<class 'pySDC.implementations.hooks.default_hook.DefaultHooks'>, <class 'pySDC.implementations.hooks.log_timings.CPUTimings'>, <class 'pySDC.implementations.hooks.log_solution.LogSolution'>]\n",
193193
" log_to_file = False\n",
194194
"--> logger_level = 15\n",
@@ -297,7 +297,7 @@
297297
"sweeper_params['num_nodes'] = [2, 4]\n",
298298
"sweeper_params['QI'] = ['LU', 'MIN-SR-S']\n",
299299
"\n",
300-
"problem_params = {'nvars': [(128,)*2, (64,)*2], 'newton_maxiter': [5, 99]}\n",
300+
"problem_params = {'nvars': [(128,) * 2, (64,) * 2], 'newton_maxiter': [5, 99]}\n",
301301
"\n",
302302
"convergence_controllers = {}\n",
303303
"# convergence_controllers[Adaptivity] = {'e_tol': 1e-4} # for instance\n",
@@ -320,7 +320,7 @@
320320
"controller_params['mssdc_jac'] = False\n",
321321
"\n",
322322
"# setup controller\n",
323-
"controller = controller_nonMPI(controller_params=controller_params, description=description, num_procs=2) "
323+
"controller = controller_nonMPI(controller_params=controller_params, description=description, num_procs=2)"
324324
]
325325
},
326326
{
@@ -388,8 +388,8 @@
388388
"hooks - INFO: Process 1 on time 0.010000 at stage IT_COARSE: Level: 1 -- Iteration: 9 -- Sweep: 1 -- residual: 1.45034263e-03\n",
389389
"hooks - INFO: Process 0 on time 0.000000 at stage IT_FINE: Level: 0 -- Iteration: 9 -- Sweep: 1 -- residual: 2.00115081e-04\n",
390390
"hooks - INFO: Process 1 on time 0.010000 at stage IT_FINE: Level: 0 -- Iteration: 9 -- Sweep: 1 -- residual: 8.62214360e-04\n",
391-
"hooks - INFO: Finished run after 1.31e+00s\n",
392-
"hooks - INFO: Finished run after 1.31e+00s\n"
391+
"hooks - INFO: Finished run after 1.32e+00s\n",
392+
"hooks - INFO: Finished run after 1.32e+00s\n"
393393
]
394394
}
395395
],
@@ -440,7 +440,7 @@
440440
"Controller: <class 'pySDC.implementations.controller_classes.controller_nonMPI.controller_nonMPI'>\n",
441441
" all_to_done = False\n",
442442
" dump_setup = True\n",
443-
" fname = run_pid77603.log\n",
443+
" fname = run_pid94048.log\n",
444444
"--> hook_class = [<class 'pySDC.implementations.hooks.default_hook.DefaultHooks'>, <class 'pySDC.implementations.hooks.log_timings.CPUTimings'>, <class 'pySDC.implementations.hooks.default_hook.DefaultHooks'>, <class 'pySDC.implementations.hooks.log_timings.CPUTimings'>, <class 'pySDC.implementations.hooks.log_solution.LogSolution'>]\n",
445445
" log_to_file = False\n",
446446
"--> logger_level = 15\n",
@@ -542,15 +542,15 @@
542542
"hooks - INFO: Process 1 on time 0.010000 at stage IT_FINE: Level: 0 -- Iteration: 4 -- Sweep: 1 -- residual: 3.97339053e-05\n",
543543
"hooks - INFO: Process 1 on time 0.010000 at stage IT_COARSE: Level: 1 -- Iteration: 5 -- Sweep: 1 -- residual: 7.79394248e-08\n",
544544
"hooks - INFO: Process 1 on time 0.010000 at stage IT_FINE: Level: 0 -- Iteration: 5 -- Sweep: 1 -- residual: 2.63545359e-07\n",
545-
"hooks - INFO: Finished run after 5.81e-01s\n",
546-
"hooks - INFO: Finished run after 5.81e-01s\n"
545+
"hooks - INFO: Finished run after 6.12e-01s\n",
546+
"hooks - INFO: Finished run after 6.12e-01s\n"
547547
]
548548
}
549549
],
550550
"source": [
551551
"sweeper_params['QI'] = 'LU'\n",
552552
"sweeper_params['num_nodes'] = 2\n",
553-
"controller = controller_nonMPI(controller_params=controller_params, description=description, num_procs=2) \n",
553+
"controller = controller_nonMPI(controller_params=controller_params, description=description, num_procs=2)\n",
554554
"uend, stats = controller.run(u0=uinit, t0=0, Tend=2e-2)"
555555
]
556556
},
@@ -563,6 +563,8 @@
563563
"Feel free to experiment further with the parameters to achieve even faster convergence.\n",
564564
"\n",
565565
"## Some projects with pySDC\n",
566+
"We will now look at a few representative projects done with pySDC\n",
567+
"\n",
566568
"3D runs of Rayleigh-Benard convection and Gray-Scott\n",
567569
"\n",
568570
"<img src=\"figs/3D_RBC_3.pdf\" style=\"width:10cm;\"/> <img src=\"figs/GS3D_000040.png\" style=\"width:20cm;\"/>\n",
@@ -571,9 +573,9 @@
571573
"\n",
572574
"<img src=\"figs/scaling_GS3D_time.pdf\" style=\"width:20cm;\"/>\n",
573575
"\n",
574-
"Compare run time of various SDC configurations\n",
576+
"Compare run time of various SDC configurations and compare preconditioner performance\n",
575577
"\n",
576-
"<img src=\"figs/timings_SDC_variants_GrayScott.pdf\" style=\"width:10cm;\"/>\n",
578+
"<img src=\"figs/timings_SDC_variants_GrayScott.pdf\" style=\"width:10cm;\"/> <img src=\"figs/parallelSDC_preconditioner_vanderpol.pdf\" style=\"width:10cm;\"/>\n",
577579
"\n",
578580
"Compare wall time of SDC against reference RK method\n",
579581
"\n",

pySDC/playgrounds/PinT_Workshop_2025/1_Add_problem_class.ipynb

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,16 @@
4949
"N = 128\n",
5050
"\n",
5151
"# setup grid\n",
52-
"dx, grid = get_1d_grid(size=N, bc='periodic', left_boundary=0, right_boundary=2*np.pi)\n",
52+
"dx, grid = get_1d_grid(size=N, bc='periodic', left_boundary=0, right_boundary=2 * np.pi)\n",
5353
"\n",
5454
"# setup finite difference matrices\n",
5555
"fd_params = {'order': 4, 'stencil_type': 'center', 'dx': dx, 'size': N, 'dim': 1, 'bc': 'periodic'}\n",
5656
"advection, _ = get_finite_difference_matrix(derivative=1, **fd_params)\n",
5757
"diffusion, _ = get_finite_difference_matrix(derivative=2, **fd_params)\n",
5858
"\n",
59+
"\n",
5960
"def eval_f(u):\n",
60-
" return (c*advection + nu*diffusion) @ u"
61+
" return (c * advection + nu * diffusion) @ u"
6162
]
6263
},
6364
{
@@ -76,9 +77,9 @@
7677
"outputs": [],
7778
"source": [
7879
"u = np.sin(grid)\n",
79-
"assert np.allclose(diffusion@u, -np.sin(grid)) # check diffusion part\n",
80-
"assert np.allclose(advection@u, np.cos(grid)) # check advection part\n",
81-
"assert np.allclose(eval_f(u), -nu*np.sin(grid)+c*np.cos(grid)) # check f evaluation"
80+
"assert np.allclose(diffusion @ u, -np.sin(grid)) # check diffusion part\n",
81+
"assert np.allclose(advection @ u, np.cos(grid)) # check advection part\n",
82+
"assert np.allclose(eval_f(u), -nu * np.sin(grid) + c * np.cos(grid)) # check f evaluation"
8283
]
8384
},
8485
{
@@ -101,8 +102,9 @@
101102
"from scipy.sparse.linalg import spsolve\n",
102103
"from scipy.sparse import eye\n",
103104
"\n",
105+
"\n",
104106
"def implicit_euler(rhs, dt):\n",
105-
" A = eye(N) - dt*(c*advection + nu*diffusion)\n",
107+
" A = eye(N) - dt * (c * advection + nu * diffusion)\n",
106108
" return spsolve(A, rhs)"
107109
]
108110
},
@@ -127,12 +129,12 @@
127129
"# check advection\n",
128130
"nu = 0\n",
129131
"c = 1e-1\n",
130-
"assert np.allclose(implicit_euler(u, dt), np.sin(grid+c*dt))\n",
132+
"assert np.allclose(implicit_euler(u, dt), np.sin(grid + c * dt))\n",
131133
"\n",
132134
"# check diffusion\n",
133135
"nu = 1e-1\n",
134136
"c = 0\n",
135-
"assert np.allclose(implicit_euler(u, dt), np.sin(grid)*np.exp(-nu*dt))"
137+
"assert np.allclose(implicit_euler(u, dt), np.sin(grid) * np.exp(-nu * dt))"
136138
]
137139
},
138140
{
@@ -161,16 +163,17 @@
161163
"import scipy.sparse as sp\n",
162164
"import numpy as np\n",
163165
"\n",
166+
"\n",
164167
"class AdvectionDiffusion(Problem):\n",
165168
" dtype_u = mesh # wraps numpy ndarray\n",
166169
" dtype_f = mesh\n",
167-
" \n",
170+
"\n",
168171
" def __init__(self, N, c, nu):\n",
169172
" init = (N, None, np.dtype('float64')) # describes how to initialize data\n",
170173
" super().__init__(init=init)\n",
171-
" \n",
174+
"\n",
172175
" # setup grid\n",
173-
" dx, self.grid = get_1d_grid(size=N, bc='periodic', left_boundary=0, right_boundary=2*np.pi)\n",
176+
" dx, self.grid = get_1d_grid(size=N, bc='periodic', left_boundary=0, right_boundary=2 * np.pi)\n",
174177
"\n",
175178
" # setup finite difference matrices\n",
176179
" fd_params = {'order': 4, 'stencil_type': 'center', 'dx': dx, 'size': N, 'dim': 1, 'bc': 'periodic'}\n",
@@ -201,8 +204,10 @@
201204
" # prepare a new work counter for this factor / step size. Seems weird now, but bear with me.\n",
202205
" key = f'gmres-{dt:.2e}'\n",
203206
" self.work_counters[f'gmres-{dt:.2e}'] = self.work_counters.get(key, WorkCounter())\n",
204-
" \n",
205-
" me[...], _ = sp.linalg.gmres(self.Id - dt*self.A, rhs, x0=u0, callback=self.work_counters[key], rtol=1e-10, callback_type='pr_norm')\n",
207+
"\n",
208+
" me[...], _ = sp.linalg.gmres(\n",
209+
" self.Id - dt * self.A, rhs, x0=u0, callback=self.work_counters[key], rtol=1e-10, callback_type='pr_norm'\n",
210+
" )\n",
206211
" return me\n",
207212
"\n",
208213
" def u0(self):\n",
@@ -229,16 +234,18 @@
229234
"source": [
230235
"prob = AdvectionDiffusion(128, 1e-1, 1e-3)\n",
231236
"u = prob.u0()\n",
232-
"assert np.allclose(prob.eval_f(u, 0), -prob.nu*np.sin(prob.grid)+prob.c*np.cos(prob.grid))\n",
237+
"assert np.allclose(prob.eval_f(u, 0), -prob.nu * np.sin(prob.grid) + prob.c * np.cos(prob.grid))\n",
233238
"\n",
234239
"dt = 1e-2\n",
235240
"advection_prob = AdvectionDiffusion(N=128, c=1e-1, nu=0)\n",
236241
"u = advection_prob.u0()\n",
237-
"assert abs(advection_prob.solve_system(u, dt, u, 0)- np.sin(advection_prob.grid+advection_prob.c*dt)) < 1e-6\n",
242+
"assert abs(advection_prob.solve_system(u, dt, u, 0) - np.sin(advection_prob.grid + advection_prob.c * dt)) < 1e-6\n",
238243
"\n",
239244
"diffusion_prob = AdvectionDiffusion(N=128, c=0, nu=1e-1)\n",
240245
"u = diffusion_prob.u0()\n",
241-
"assert abs(diffusion_prob.solve_system(u, dt, u, 0)- np.sin(diffusion_prob.grid)*np.exp(-diffusion_prob.nu*dt)) < 1e-6"
246+
"assert (\n",
247+
" abs(diffusion_prob.solve_system(u, dt, u, 0) - np.sin(diffusion_prob.grid) * np.exp(-diffusion_prob.nu * dt)) < 1e-6\n",
248+
")"
242249
]
243250
},
244251
{
@@ -283,7 +290,7 @@
283290
"Controller: <class 'pySDC.implementations.controller_classes.controller_nonMPI.controller_nonMPI'>\n",
284291
" all_to_done = False\n",
285292
" dump_setup = True\n",
286-
" fname = run_pid77606.log\n",
293+
" fname = run_pid94051.log\n",
287294
"--> hook_class = [<class 'pySDC.implementations.hooks.default_hook.DefaultHooks'>, <class 'pySDC.implementations.hooks.log_timings.CPUTimings'>, <class 'pySDC.implementations.hooks.log_solution.LogSolution'>, <class 'pySDC.implementations.hooks.log_work.LogWork'>]\n",
288295
" log_to_file = False\n",
289296
"--> logger_level = 15\n",
@@ -349,7 +356,11 @@
349356
"sweeper_params['num_nodes'] = 3\n",
350357
"sweeper_params['QI'] = 'MIN-SR-S'\n",
351358
"\n",
352-
"problem_params = {'N': 128, 'c': 8e-1, 'nu':1e-1,}\n",
359+
"problem_params = {\n",
360+
" 'N': 128,\n",
361+
" 'c': 8e-1,\n",
362+
" 'nu': 1e-1,\n",
363+
"}\n",
353364
"\n",
354365
"# gather all parameters in one dictionary and add problem and sweeper class\n",
355366
"description = {}\n",
@@ -430,7 +441,7 @@
430441
"hooks - INFO: Process 0 on time 0.900000 at stage IT_FINE: Level: 0 -- Iteration: 2 -- Sweep: 1 -- residual: 5.78007793e-06\n",
431442
"hooks - INFO: Process 0 on time 0.900000 at stage IT_FINE: Level: 0 -- Iteration: 3 -- Sweep: 1 -- residual: 1.36492229e-07\n",
432443
"hooks - INFO: Process 0 on time 0.900000 at stage IT_FINE: Level: 0 -- Iteration: 4 -- Sweep: 1 -- residual: 3.15861094e-09\n",
433-
"hooks - INFO: Finished run after 8.13e-02s\n"
444+
"hooks - INFO: Finished run after 8.51e-02s\n"
434445
]
435446
}
436447
],
@@ -563,7 +574,7 @@
563574
"source": [
564575
"# get values on the diagonal of the preconditioner\n",
565576
"sweeper = controller.MS[0].levels[0].sweep\n",
566-
"diag_vals = [sweeper.QI[i+1, i+1] for i in range(sweeper.coll.num_nodes)]\n",
577+
"diag_vals = [sweeper.QI[i + 1, i + 1] for i in range(sweeper.coll.num_nodes)]\n",
567578
"\n",
568579
"# get the keys for gmres iterations at various step sizes from this\n",
569580
"work_keys = [f'work_gmres-{sweeper.level.dt * me:.2e}' for me in diag_vals]\n",
@@ -573,17 +584,20 @@
573584
"total_gmres_iterations = sum(gmres_iter_per_task)\n",
574585
"\n",
575586
"# compute speedup in implicit solves\n",
576-
"max_rel_gmres_per_task = max(gmres_iter_per_task)/total_gmres_iterations\n",
577-
"speedup = 1/max_rel_gmres_per_task\n",
587+
"max_rel_gmres_per_task = max(gmres_iter_per_task) / total_gmres_iterations\n",
588+
"speedup = 1 / max_rel_gmres_per_task\n",
578589
"parallel_efficiency = speedup / sweeper.coll.num_nodes\n",
579590
"\n",
580591
"# visualize and print the results\n",
581592
"import matplotlib.pyplot as plt\n",
593+
"\n",
582594
"plt.bar(np.arange(sweeper.coll.num_nodes), gmres_iter_per_task)\n",
583595
"plt.ylabel('GMRES iterations')\n",
584596
"plt.xlabel('Collocation node / task')\n",
585597
"\n",
586-
"print(f'Performed {max_rel_gmres_per_task*100:.0f}% of GMRES iterations on task {np.argmax(gmres_iter_per_task)}. This translates to speedup of {speedup:.2f} and {parallel_efficiency*100:.0f}% parallel efficiency in the implicit solves.')\n"
598+
"print(\n",
599+
" f'Performed {max_rel_gmres_per_task*100:.0f}% of GMRES iterations on task {np.argmax(gmres_iter_per_task)}. This translates to speedup of {speedup:.2f} and {parallel_efficiency*100:.0f}% parallel efficiency in the implicit solves.'\n",
600+
")"
587601
]
588602
},
589603
{

0 commit comments

Comments
 (0)