Skip to content

Commit 18989d3

Browse files
authored
TIME-X Test Hackathon @ TUD: Test for SwitchEstimator (#404)
* Added piecewise linear interpolation to SwitchEstimator * Started with test for SwitchEstimator [WIP] * Test to proof sum_restarts when event occuring at boundary * Started with test to check adapt_interpolation_info [WIP] * Added test for SE.adapt_interpolation_info() * Update linear interpolation + logging + changing tolerances * Test for linear interpolation + update of other test * Correction for finite difference + adaption tolerance * Added test for DAE case for SE * Choice of FD seems to be important for performance of SE * Removed attributes from dummy probs (since the parent classes have it) * Test for dummy problems + using functions from battery_model.py * Moved standard params for test to function * Updated hardcoded solutions for battery models * Updated hardcoded solutions for DiscontinuousTestODE * Updated docu in SE for FDs * Lagrange Interpolation works better with baclward FD and alpha=0.9 * Added test for state function + global error * Updated LogEvent hooks * Updated hardcoded solutions again * Adapted test_problems.py * Minor changes * Updated tests * Speed-up test for buck converter * Black.. * Use msg about convergence info in Newton in SE * Moved dummy problem to file * Speed up loop using mask * Removed loop
1 parent b02181b commit 18989d3

File tree

10 files changed

+686
-179
lines changed

10 files changed

+686
-179
lines changed

pySDC/implementations/problem_classes/DiscontinuousTestODE.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,72 @@ def get_switching_info(self, u, t):
214214
m_guess = m - 1
215215
break
216216

217-
state_function = [u[m][0] - 5 for m in range(len(u))] if switch_detected else []
217+
state_function = [u[m][0] - 5 for m in range(len(u))]
218218
return switch_detected, m_guess, state_function
219219

220220
def count_switches(self):
221221
"""
222222
Setter to update the number of switches if one is found.
223223
"""
224224
self.nswitches += 1
225+
226+
227+
class ExactDiscontinuousTestODE(DiscontinuousTestODE):
228+
r"""
229+
Dummy ODE problem for testing the ``SwitchEstimator`` class. The problem contains the exact dynamics
230+
of the problem class ``DiscontinuousTestODE``.
231+
"""
232+
233+
def __init__(self, newton_maxiter=100, newton_tol=1e-8):
234+
"""Initialization routine"""
235+
super().__init__(newton_maxiter, newton_tol)
236+
237+
def eval_f(self, u, t):
238+
"""
239+
Derivative.
240+
241+
Parameters
242+
----------
243+
u : dtype_u
244+
Exact value of u.
245+
t : float
246+
Time :math:`t`.
247+
248+
Returns
249+
-------
250+
f : dtype_f
251+
Derivative.
252+
"""
253+
254+
f = self.dtype_f(self.init)
255+
256+
t_switch = np.inf if self.t_switch is None else self.t_switch
257+
h = u[0] - 5
258+
if h >= 0 or t >= t_switch:
259+
f[:] = 1
260+
else:
261+
f[:] = np.exp(t)
262+
return f
263+
264+
def solve_system(self, rhs, factor, u0, t):
265+
"""
266+
Just return the exact solution...
267+
268+
Parameters
269+
----------
270+
rhs : dtype_f
271+
Right-hand side for the linear system.
272+
factor : float
273+
Abbrev. for the local stepsize (or any other factor required).
274+
u0 : dtype_u
275+
Initial guess for the iterative solver.
276+
t : float
277+
Current time (e.g. for time-dependent BCs).
278+
279+
Returns
280+
-------
281+
me : dtype_u
282+
The solution as mesh.
283+
"""
284+
285+
return self.u_exact(t)

pySDC/projects/PinTSimE/battery_model.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,13 @@ def generateDescription(
167167
'convergence_controllers': convergence_controllers,
168168
}
169169

170-
return description, controller_params
170+
# instantiate controller
171+
controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
172+
173+
return description, controller_params, controller
171174

172175

173-
def controllerRun(description, controller_params, t0, Tend, exact_event_time_avail=False):
176+
def controllerRun(description, controller_params, controller, t0, Tend, exact_event_time_avail=False):
174177
"""
175178
Executes a controller run for a problem defined in the description.
176179
@@ -180,6 +183,8 @@ def controllerRun(description, controller_params, t0, Tend, exact_event_time_ava
180183
Contains all information for a controller run.
181184
controller_params : dict
182185
Parameters needed for a controller run.
186+
controller : pySDC.core.Controller
187+
Controller to do the stuff.
183188
t0 : float
184189
Starting time of simulation.
185190
Tend : float
@@ -193,9 +198,6 @@ def controllerRun(description, controller_params, t0, Tend, exact_event_time_ava
193198
Raw statistics from a controller run.
194199
"""
195200

196-
# instantiate controller
197-
controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
198-
199201
# get initial values on finest level
200202
P = controller.MS[0].levels[0].prob
201203
uinit = P.u_exact(t0)
@@ -233,7 +235,7 @@ def main():
233235
'max_restarts': 50,
234236
'recomputed': False,
235237
'tol_event': 1e-10,
236-
'alpha': 1.0,
238+
'alpha': 0.96,
237239
'exact_event_time_avail': None,
238240
}
239241

@@ -244,8 +246,8 @@ def main():
244246

245247
hook_class = [LogSolution, LogEventBattery, LogEmbeddedErrorEstimate, LogStepSize]
246248

247-
use_detection = [True]
248-
use_adaptivity = [True]
249+
use_detection = [True, False]
250+
use_adaptivity = [True, False]
249251

250252
for problem, sweeper in zip([battery, battery_implicit], [imex_1st_order, generic_implicit]):
251253
for defaults in [False, True]:
@@ -360,7 +362,7 @@ def runSimulation(problem, sweeper, all_params, use_adaptivity, use_detection, h
360362

361363
restol = -1 if use_A else handling_params['restol']
362364

363-
description, controller_params = generateDescription(
365+
description, controller_params, controller = generateDescription(
364366
dt=dt,
365367
problem=problem,
366368
sweeper=sweeper,
@@ -381,6 +383,7 @@ def runSimulation(problem, sweeper, all_params, use_adaptivity, use_detection, h
381383
stats, t_switch_exact = controllerRun(
382384
description=description,
383385
controller_params=controller_params,
386+
controller=controller,
384387
t0=interval[0],
385388
Tend=interval[-1],
386389
exact_event_time_avail=handling_params['exact_event_time_avail'],

pySDC/projects/PinTSimE/buck_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def main():
5555
use_adaptivity=use_adaptivity,
5656
use_detection=use_detection,
5757
hook_class=hook_class,
58-
interval=(0.0, 2e-2),
58+
interval=(0.0, 1e-2),
5959
dt_list=[1e-5, 2e-5],
6060
nnodes=[M_fix],
6161
)

pySDC/projects/PinTSimE/discontinuous_test_ODE.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ def main():
6868
'max_restarts': 50,
6969
'recomputed': False,
7070
'tol_event': 1e-12,
71-
'alpha': 1.0,
71+
'alpha': 0.96,
7272
'exact_event_time_avail': True,
73+
'typeFD': 'backward',
7374
}
7475

7576
# ---- all parameters are stored in this dictionary ----

pySDC/projects/PinTSimE/estimation_check.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def run_estimation_check():
4545
'max_restarts': 50,
4646
'recomputed': False,
4747
'tol_event': 1e-10,
48-
'alpha': 1.0,
48+
'alpha': 0.96,
4949
'exact_event_time_avail': None,
5050
}
5151

@@ -114,7 +114,7 @@ def run_estimation_check():
114114

115115
plotAccuracyCheck(u_num, prob_cls_name, M_fix)
116116

117-
plotStateFunctionAroundEvent(u_num, prob_cls_name, M_fix)
117+
# plotStateFunctionAroundEvent(u_num, prob_cls_name, M_fix)
118118

119119
plotStateFunctionOverTime(u_num, prob_cls_name, M_fix)
120120

@@ -187,6 +187,9 @@ def plotStateFunctionAroundEvent(u_num, prob_cls_name, M_fix): # pragma: no cov
187187
Routine that plots the state function at time before the event, exactly at the event, and after the event. Note
188188
that this routine does make sense only for a state function that remains constant after the event.
189189
190+
TODO: Function still does not work as expected. Every time when the switch estimator is adapted, the tolerances
191+
does not suit anymore!
192+
190193
Parameters
191194
----------
192195
u_num : dict
@@ -239,15 +242,18 @@ def plotStateFunctionAroundEvent(u_num, prob_cls_name, M_fix): # pragma: no cov
239242

240243
if use_SE:
241244
t_switches = [u_num[dt][M_fix][use_SE][use_A]['t_switches'] for dt in dt_list]
242-
t_switch = [t_event[i] for t_event in t_switches]
245+
for t_switch_item in t_switches:
246+
mask = np.append([True], np.abs(t_switch_item[1:] - t_switch_item[:-1]) > 1e-10)
247+
t_switch_item = t_switch_item[mask]
243248

249+
t_switch = [t_event[i] for t_event in t_switches]
244250
ax[0, ind].plot(
245251
dt_list,
246252
[
247253
h_item[m]
248254
for (t_item, h_item, t_switch_item) in zip(t, h, t_switch)
249255
for m in range(len(t_item))
250-
if abs(t_item[m] - t_switch_item) <= 1e-14
256+
if abs(t_item[m] - t_switch_item) <= 2.7961188919789493e-11
251257
],
252258
color='limegreen',
253259
marker='s',

0 commit comments

Comments
 (0)