Skip to content

Commit b9b3702

Browse files
author
Thomas Baumann
committed
Added a test for counting Newton iterations
1 parent 6c6efff commit b9b3702

File tree

5 files changed

+25
-153
lines changed

5 files changed

+25
-153
lines changed

pySDC/implementations/hooks/log_work.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pySDC.core.Hooks import hooks
22

3+
34
class LogWork(hooks):
45
"""
56
Log the increment of all work counters in the problem between steps
@@ -18,7 +19,8 @@ def pre_step(self, step, level_number):
1819
"""
1920
if level_number == 0:
2021
self.__work_last_step = [
21-
{key: step.levels[i].prob.work_counters[key].niter for key in step.levels[i].prob.work_counters.keys()} for i in range(len(step.levels))
22+
{key: step.levels[i].prob.work_counters[key].niter for key in step.levels[i].prob.work_counters.keys()}
23+
for i in range(len(step.levels))
2224
]
2325

2426
def post_step(self, step, level_number):

pySDC/implementations/problem_classes/Van_der_Pol_implicit.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def __init__(self, problem_params, dtype_u=mesh, dtype_f=mesh):
3939
super(vanderpol, self).__init__(
4040
(problem_params['nvars'], None, np.dtype('float64')), dtype_u, dtype_f, problem_params
4141
)
42-
self.total_newton_iter = 0 # access this from the hooks to make stats
4342

4443
def u_exact(self, t, u_init=None, t_init=None):
4544
"""
@@ -129,7 +128,6 @@ def solve_system(self, rhs, dt, u0, t):
129128
x1 = u[0]
130129
x2 = u[1]
131130
n += 1
132-
self.total_newton_iter += n
133131

134132
if np.isnan(res) and self.params.stop_at_nan:
135133
raise ProblemError('Newton got nan after %i iterations, aborting...' % n)

pySDC/projects/Resilience/fault_stats.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
import pySDC.helpers.plot_helper as plot_helper
1010
from pySDC.helpers.stats_helper import get_sorted
1111

12-
from pySDC.projects.Resilience.hook import hook_collection, LogUAllIter, LogData, LogNewtonIter
12+
from pySDC.projects.Resilience.hook import hook_collection, LogUAllIter, LogData
1313
from pySDC.projects.Resilience.fault_injection import get_fault_injector_hook
1414
from pySDC.implementations.convergence_controller_classes.hotrod import HotRod
1515
from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1616
from pySDC.implementations.convergence_controller_classes.basic_restarting import BasicRestartingNonMPI
1717
from pySDC.implementations.hooks.log_errors import LogLocalErrorPostStep
18+
from pySDC.implementations.hooks.log_work import LogWork
1819

1920
# these problems are available for testing
2021
from pySDC.projects.Resilience.advection import run_advection
@@ -620,7 +621,7 @@ def generate_stats(self, strategy=None, runs=1000, reload=True, faults=True, com
620621
else:
621622
error = self.get_error(u, t, controller, strategy)
622623
total_iteration = sum([k[1] for k in get_sorted(stats, type='k')])
623-
total_newton_iteration = sum([k[1] for k in get_sorted(stats, type='newton_iter')])
624+
total_newton_iteration = sum([k[1] for k in get_sorted(stats, type='work_newton')])
624625

625626
# record the new data point
626627
if faults:
@@ -694,7 +695,7 @@ def single_run(self, strategy, run=0, faults=False, force_params=None, hook_clas
694695
pySDC.Controller: The controller of the run
695696
float: The time the problem should have run to
696697
'''
697-
hook_class = hook_collection + [LogNewtonIter] + ([LogData] if hook_class is None else hook_class)
698+
hook_class = hook_collection + [LogWork] + ([LogData] if hook_class is None else hook_class)
698699
force_params = {} if force_params is None else force_params
699700

700701
# build the custom description
@@ -870,7 +871,7 @@ def scrutinize(self, strategy, run, faults=True):
870871
)
871872
print(f'k: sum: {np.sum(k)}, min: {np.min(k)}, max: {np.max(k)}, mean: {np.mean(k):.2f},')
872873

873-
_newton_iter = get_sorted(stats, type='newton_iter')
874+
_newton_iter = get_sorted(stats, type='work_newton')
874875
if len(_newton_iter) > 0:
875876
newton_iter = [me[1] for me in _newton_iter]
876877
print(

pySDC/projects/Resilience/hook.py

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,56 +8,6 @@
88
hook_collection = [LogSolution, LogEmbeddedErrorEstimate, LogExtrapolationErrorEstimate, LogStepSize]
99

1010

11-
class LogSpaceIter(hooks):
12-
"""
13-
Log the number of iterations from the space solver e.g. CG or GMRES after each step
14-
"""
15-
16-
def pre_step(self, step, level_number):
17-
if level_number == 0:
18-
if 'space_iter_counter' in step.levels[0].prob.__dict__.keys():
19-
self.__space_iter_last_step = [
20-
step.levels[i].prob.space_iter_counter.niter for i in range(len(step.levels))
21-
]
22-
23-
def post_step(self, step, level_number):
24-
L = step.levels[level_number]
25-
if 'space_iter_counter' in L.prob.__dict__.keys():
26-
self.add_to_stats(
27-
process=step.status.slot,
28-
time=L.time + L.dt,
29-
level=L.level_index,
30-
iter=step.status.iter,
31-
sweep=L.status.sweep,
32-
type='space_iter',
33-
value=L.prob.space_iter_counter.niter - self.__space_iter_last_step[level_number],
34-
)
35-
36-
37-
class LogNewtonIter(hooks):
38-
"""
39-
Log the number of Newton iterations required for each step
40-
"""
41-
42-
def pre_step(self, step, level_number):
43-
if level_number == 0:
44-
self.__newton_iter_last_step = [
45-
step.levels[i].prob.__dict__.get('total_newton_iter', 0) for i in range(len(step.levels))
46-
]
47-
48-
def post_step(self, step, level_number):
49-
L = step.levels[level_number]
50-
self.add_to_stats(
51-
process=step.status.slot,
52-
time=L.time + L.dt,
53-
level=L.level_index,
54-
iter=step.status.iter,
55-
sweep=L.status.sweep,
56-
type='newton_iter',
57-
value=L.prob.__dict__.get('total_newton_iter', 0) - self.__newton_iter_last_step[level_number],
58-
)
59-
60-
6111
class LogData(hooks):
6212
"""
6313
Record data required for analysis of problems in the resilience project

pySDC/projects/Resilience/leaky_superconductor.py

Lines changed: 17 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,23 @@ def compare_imex_full(plotting=False):
202202
plotting (bool): Plot the solution or not
203203
"""
204204
from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
205+
from pySDC.implementations.hooks.log_work import LogWork
206+
207+
maxiter = 5
208+
num_nodes = 3
209+
newton_iter_max = 20
205210

206211
res = {}
207212

208213
custom_description = {}
209214
custom_description['problem_params'] = {
210215
'newton_tol': 1e-10,
211-
'newton_iter': 20,
216+
'newton_iter': newton_iter_max,
212217
'nvars': 2**9,
213218
}
219+
custom_description['step_params'] = {'maxiter': maxiter}
220+
custom_description['sweeper_params'] = {'num_nodes': num_nodes}
221+
214222
custom_controller_params = {'logger_level': 30}
215223
for imex in [False, True]:
216224
custom_description['convergence_controllers'] = {Adaptivity: {'e_tol': 1e-6, 'dt_max': 1e2}}
@@ -219,9 +227,16 @@ def compare_imex_full(plotting=False):
219227
custom_controller_params=custom_controller_params,
220228
imex=imex,
221229
Tend=5e2,
230+
hook_class=LogWork,
222231
)
223232

224233
res[imex] = get_sorted(stats, type='u')[-1][1]
234+
newton_iter = [me[1] for me in get_sorted(stats, type='work_newton')]
235+
236+
if imex:
237+
assert all([me == 0 for me in newton_iter]), f"IMEX is not supposed to do Newton iterations!"
238+
else:
239+
assert max(newton_iter)/num_nodes/maxiter <= newton_iter_max, "Took more Newton iterations than allowed!"
225240
if plotting: # pragma no cover
226241
plot_solution(stats, controller)
227242

@@ -236,100 +251,6 @@ def compare_imex_full(plotting=False):
236251
), f"Expected runaway to happen, but maximum temperature is {max(res[True]):.2e} < u_max={prob.params.u_max:.2e}!"
237252

238253

239-
def compare_dirk():
240-
from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity, AdaptivityRK
241-
from pySDC.implementations.sweeper_classes.Runge_Kutta import DIRK34
242-
from pySDC.projects.Resilience.hook import hook_collection, LogNewtonIter, LogData, LogSpaceIter
243-
from pySDC.helpers.plot_helper import figsize_by_journal, setup_mpl
244-
from pySDC.implementations.hooks.log_work import LogWork
245-
246-
setup_mpl(reset=True)
247-
fig, axs = plt.subplots(2, 2, figsize=figsize_by_journal('Springer_Numerical_Algorithms', 1, 0.82), sharex=True)
248-
249-
problem_params = {}
250-
problem_params['direct_solver'] = False
251-
252-
description = {}
253-
description['step_params'] = {'maxiter': 4}
254-
description['convergence_controllers'] = {Adaptivity: {'e_tol': 1e-5, 'dt_max': 50.0}}
255-
256-
description_RK = {}
257-
description_RK['convergence_controllers'] = {AdaptivityRK: {'e_tol': 1e-5, 'dt_max': 5e1, 'update_order': 4}}
258-
description_RK['sweeper_class'] = DIRK34
259-
description_RK['step_params'] = {'maxiter': 1}
260-
261-
description_res = {}
262-
description_res['step_params'] = {'maxiter': 99}
263-
description_res['level_params'] = {'restol': 1e-10}
264-
265-
controller_params = {}
266-
controller_params['hook_class'] = hook_collection + [LogNewtonIter, LogData, LogSpaceIter, LogWork]
267-
controller_params['logger_level'] = 30
268-
Tend = 500
269-
270-
stats_fixed, _, _ = run_leaky_superconductor(
271-
custom_description=description_res,
272-
imex=False,
273-
Tend=Tend,
274-
custom_controller_params=controller_params,
275-
custom_problem_params=problem_params,
276-
)
277-
stats, _, _ = run_leaky_superconductor(
278-
custom_description=description,
279-
imex=False,
280-
Tend=Tend,
281-
custom_controller_params=controller_params,
282-
custom_problem_params=problem_params,
283-
)
284-
stats_RK, _, _ = run_leaky_superconductor(
285-
custom_description=description_RK,
286-
imex=False,
287-
Tend=Tend,
288-
custom_controller_params=controller_params,
289-
custom_problem_params=problem_params,
290-
)
291-
292-
labels = {
293-
0: 'SDC+adaptivity',
294-
1: 'DIRK4(3)',
295-
2: 'SDC',
296-
}
297-
ls = {
298-
0: '-',
299-
1: '--',
300-
2: ':',
301-
}
302-
S = [stats, stats_RK, stats_fixed]
303-
for i in range(len(S)):
304-
newton_iter = get_sorted(S[i], type='work_newton')
305-
axs[0, 0].plot(
306-
[me[0] for me in newton_iter], np.cumsum([me[1] for me in newton_iter]), label=labels[i], ls=ls[i]
307-
)
308-
309-
space_iter = get_sorted(S[i], type='work_linear')
310-
axs[1, 1].plot([me[0] for me in space_iter], np.cumsum([me[1] for me in space_iter]), ls=ls[i])
311-
312-
dt = get_sorted(S[i], type='dt')
313-
axs[0, 1].plot([me[0] for me in dt], [me[1] for me in dt], ls=ls[i])
314-
315-
# u = get_sorted(S[i], type='u', recomputed=False)
316-
# axs[1,1].plot([me[0] for me in u], [max(me[1]) for me in u], ls=ls[i])
317-
318-
k = get_sorted(S[i], type='sweeps', recomputed=None)
319-
axs[1, 0].plot([me[0] for me in k], np.cumsum([me[1] for me in k]), ls=ls[i])
320-
axs[0, 0].set_yscale('log')
321-
axs[1, 1].set_yscale('log')
322-
axs[0, 0].legend(frameon=False)
323-
axs[0, 0].set_ylabel('cumulative Newton iterations')
324-
axs[1, 0].set_ylabel('cumulative SDC iterations')
325-
axs[1, 0].set_xlabel('$t$')
326-
axs[0, 1].set_ylabel(r'$\Delta t$')
327-
axs[1, 1].set_ylabel('cumulative GMRES iterations')
328-
fig.tight_layout()
329-
fig.savefig('data/quench_newton.pdf')
330-
331-
332254
if __name__ == '__main__':
333-
compare_dirk()
334-
# compare_imex_full(plotting=True)
255+
compare_imex_full(plotting=True)
335256
plt.show()

0 commit comments

Comments
 (0)