Coverage for pySDC/tutorial/step_2/C_using_pySDCs_frontend.py: 100%
35 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
1# ---
2# jupyter:
3# jupytext:
4# formats: py:percent
5# kernelspec:
6# display_name: Python 3
7# name: python3
8# ---
10# %% [markdown]
11# # Part C: Using pySDC's frontend
12#
13# Finally, the user-friendliest interface pySDC has to offer: a **controller** does the whole iteration logic of
14# [Part B](B_my_first_sweeper) for us. We use `controller_nonMPI`, the default controller. It needs no `mpi4py`, and
15# depending on the description it can do SDC, multilevel SDC, multistep SDC and PFASST (more on this in the next
16# steps).
17#
18# The description is the same as in Part B. New are the **controller parameters**, here used to also write the
19# log to a file.
21# %%
22from pathlib import Path
24import matplotlib.pyplot as plt
25import numpy as np
27from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
28from pySDC.implementations.problem_classes.HeatEquation_ND_FD import heatNd_forced
29from pySDC.implementations.sweeper_classes.imex_1st_order import imex_1st_order
31# initialize level parameters
32level_params = {'restol': 1e-10, 'dt': 0.1}
34# initialize sweeper parameters
35sweeper_params = {'quad_type': 'RADAU-RIGHT', 'num_nodes': 3}
37# initialize problem parameters
38problem_params = {
39 'nu': 0.1, # diffusion coefficient
40 'freq': 4, # frequency for the test value
41 'nvars': 1023, # number of degrees of freedom
42 'bc': 'dirichlet-zero', # boundary conditions
43}
45# initialize step parameters
46step_params = {'maxiter': 20}
48# initialize controller parameters
49controller_params = {
50 'log_to_file': True,
51 'fname': 'data/step_2_C_out.txt',
52}
54# Fill description dictionary for easy hierarchy creation
55description = {
56 'problem_class': heatNd_forced,
57 'problem_params': problem_params,
58 'sweeper_class': imex_1st_order,
59 'sweeper_params': sweeper_params,
60 'level_params': level_params,
61 'step_params': step_params,
62}
64Path("data").mkdir(parents=True, exist_ok=True)
66# %% [markdown]
67# ## Instantiating the controller
68#
69# When the controller is created, it prints the full setup. Everything marked with `-->` was set by us, `->` marks
70# what follows from that, and the rest are defaults. This is the place to check what a run actually used. Set the
71# controller parameter `dump_setup` to `False` to switch it off.
73# %% tags=["scroll-output"]
74# instantiate the controller
75controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
77# %% [markdown]
78# ## Running
79#
80# We ask for the time interval $[0.1, 0.3]$, which with `dt = 0.1` means two time steps. The initial value comes
81# from the problem class, which the controller has created inside its step, just like in Part A.
83# %%
84# set time parameters
85t0 = 0.1
86Tend = 0.3 # note that we are requesting 2 time steps here (dt is 0.1)
88# get initial values on finest level
89P = controller.MS[0].levels[0].prob
90uinit = P.u_exact(t0)
92# call main function to get things done...
93uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
95# compute exact solution and compare
96uex = P.u_exact(Tend)
97err = abs(uex - uend)
98print(f'Error after SDC iterations: {err:8.6e}')
100# %% [markdown]
101# That is the whole program a user writes: a description, some pre- and some post-processing. The controller also
102# wrote its log to the file we named; here are its last lines:
104# %%
105print(''.join(Path(controller_params['fname']).read_text().splitlines(True)[-3:]))
107# %% tags=["hide-input"]
108x = np.array([(i + 1) * P.dx for i in range(P.nvars[0])])
109fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3))
110ax1.plot(x, uinit, label=f'$t = {t0}$')
111ax1.plot(x, uend, label=f'$t = {Tend}$, SDC')
112ax1.plot(x[::40], uex[::40], 'k.', label=f'$t = {Tend}$, exact')
113ax1.set_xlabel('$x$')
114ax1.legend(frameon=False, fontsize=8)
115ax2.plot(x, np.abs(uend - uex))
116ax2.set_xlabel('$x$')
117ax2.set_title('error at $t = 0.3$', fontsize=10)
118fig.tight_layout()
120# %% [markdown]
121# :::{admonition} Important things to note
122# - The description is all a user needs to steer pySDC; most of the logic and the data structures stay hidden.
123# This part is the prototype for working with pySDC.
124# - Unlike in Part B, we have no direct access to the residuals or the iteration counts yet: they are in `stats`,
125# which [Step 3](../step_3) is about.
126# :::
127#
128# The check the tests run:
130# %%
131assert err <= 2e-5, f"ERROR: controller doing IMEX SDC iteration did not reduce the error enough, got {err}"