Coverage for pySDC/projects/PinTSimE/hardcoded_solutions.py: 99%
133 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
1import numpy as np
3from pySDC.core.errors import ParameterError
6def testSolution(u_num, prob_cls_name, dt, use_adaptivity, use_detection):
7 r"""
8 Test for numerical solution if values satisfy hardcoded values.
10 Note
11 ----
12 Only the items are tested which does make sense for any problem. For instance, `getDataDict` stores the global error
13 after each step **for each problem class**. Since an exact solution is only available for e.g. ``DiscontinuousTestODE``,
14 a test is only be done for this problem class.
16 Hardcoded solutions are computed for only one collocation node ``M_fix``, which is specified for each problem in the
17 related files, see ``pySDC.projects.PinTSimE.battery_model``, ``pySDC.projects.PinTSimE.estimation_check`` and
18 ``pySDC.projects.PinTSimE.discontinuous_test_ODE``.
20 Parameters
21 ----------
22 u_num : dict
23 Contains the numerical solution together with event time found by event detection, step sizes adjusted
24 via adaptivity and/or switch estimation.
25 prob_cls_name : str
26 Indicates which problem class is tested.
27 dt : float
28 (Initial) step sizes used for the simulation.
29 use_adaptivity : bool
30 Indicates whether adaptivity is used in the simulation or not.
31 use_detection : bool
32 Indicates whether discontinuity handling is used in the simulation or not.
33 """
35 unknowns = u_num['unknowns']
36 u_num_tmp = {unknown: u_num[unknown][-1] for unknown in unknowns}
38 got = {}
39 got = u_num_tmp
41 if prob_cls_name == 'battery':
42 if use_adaptivity and use_detection:
43 msg = f"Error when using switch estimator and adaptivity for {prob_cls_name} for dt={dt:.1e}:"
44 if dt == 1e-2:
45 expected = {
46 'iL': 0.5393867577881641,
47 'vC': 0.9999999999913842,
48 't_switches': [0.1823215567921536, 0.18232155679215356, 0.18232155679173784],
49 'dt': 0.09453745651144455,
50 'e_em': 1.7587042933087105e-12,
51 'sum_restarts': 15.0,
52 'sum_niters': 280.0,
53 }
54 elif dt == 1e-3:
55 expected = {
56 'iL': 0.5393867577223005,
57 'vC': 0.9999999999813279,
58 't_switches': [0.18232155676894835, 0.1823215567897308, 0.18232155678877865],
59 'dt': 0.06467602356229402,
60 'e_em': 1.1468603844377867e-13,
61 'sum_restarts': 17.0,
62 'sum_niters': 368.0,
63 }
64 got.update(
65 {
66 't_switches': u_num['t_switches'],
67 'dt': u_num['dt'][-1, 1],
68 'e_em': u_num['e_em'][-1, 1],
69 'sum_restarts': u_num['sum_restarts'],
70 'sum_niters': u_num['sum_niters'],
71 }
72 )
74 elif not use_adaptivity and use_detection:
75 msg = f"Error when using switch estimator for {prob_cls_name} for dt={dt:.1e}:"
76 if dt == 1e-2:
77 expected = {
78 'iL': 0.5456190026495924,
79 'vC': 0.9991666666670524,
80 't_switches': [0.18232155679395579, 0.18232155679395592, 0.18232155679356965],
81 'sum_restarts': 14.0,
82 'sum_niters': 416.0,
83 }
84 elif dt == 1e-3:
85 expected = {
86 'iL': 0.5403849766797957,
87 'vC': 0.9999166666675774,
88 't_switches': [0.18232155679395004, 0.18232155679303919],
89 'sum_restarts': 11.0,
90 'sum_niters': 2536.0,
91 }
92 got.update(
93 {
94 't_switches': u_num['t_switches'],
95 'sum_restarts': u_num['sum_restarts'],
96 'sum_niters': u_num['sum_niters'],
97 }
98 )
100 if use_adaptivity and not use_detection:
101 msg = f"Error when using adaptivity for {prob_cls_name} for dt={dt:.1e}:"
102 if dt == 1e-2:
103 expected = {
104 'iL': 0.4433805288639916,
105 'vC': 0.90262388393713,
106 'dt': 0.18137307612335937,
107 'e_em': 2.7177844974524135e-09,
108 'sum_restarts': 0.0,
109 'sum_niters': 24.0,
110 }
111 elif dt == 1e-3:
112 expected = {
113 'iL': 0.3994744179584864,
114 'vC': 0.9679037468770668,
115 'dt': 0.1701392217033212,
116 'e_em': 2.0992988458701234e-09,
117 'sum_restarts': 0.0,
118 'sum_niters': 32.0,
119 }
120 got.update(
121 {
122 'dt': u_num['dt'][-1, 1],
123 'e_em': u_num['e_em'][-1, 1],
124 'sum_restarts': u_num['sum_restarts'],
125 'sum_niters': u_num['sum_niters'],
126 }
127 )
129 elif not use_adaptivity and not use_detection:
130 msg = f'Error for {prob_cls_name} for dt={dt:.1e}:'
131 if dt == 1e-2:
132 expected = {
133 'iL': 0.5456625861551172,
134 'vC': 0.9973251377556902,
135 'sum_niters': 240.0,
136 }
137 elif dt == 1e-3:
138 expected = {
139 'iL': 0.538639340748308,
140 'vC': 0.9994050706403905,
141 'sum_niters': 2400.0,
142 }
143 got.update(
144 {
145 'sum_niters': u_num['sum_niters'],
146 }
147 )
149 elif prob_cls_name == 'battery_implicit':
150 if use_adaptivity and use_detection:
151 msg = f"Error when using switch estimator and adaptivity for {prob_cls_name} for dt={dt:.1e}:"
152 if dt == 1e-2:
153 expected = {
154 'iL': 0.5393867577468375,
155 'vC': 0.9999999999980123,
156 't_switches': [0.18232155680038617, 0.1823215568023739],
157 'dt': 0.08896232033732146,
158 'e_em': 2.220446049250313e-16,
159 'sum_restarts': 15.0,
160 'sum_niters': 280.0,
161 }
162 elif dt == 1e-3:
163 expected = {
164 'iL': 0.5393867576415584,
165 'vC': 0.9999999999802239,
166 't_switches': [0.18232155678530526, 0.1823215568066914, 0.1823215568057151],
167 'dt': 0.06333183541149384,
168 'e_em': 2.220446049250313e-16,
169 'sum_restarts': 17.0,
170 'sum_niters': 368.0,
171 }
172 got.update(
173 {
174 't_switches': u_num['t_switches'],
175 'dt': u_num['dt'][-1, 1],
176 'e_em': u_num['e_em'][-1, 1],
177 'sum_restarts': u_num['sum_restarts'],
178 'sum_niters': u_num['sum_niters'],
179 }
180 )
182 elif not use_adaptivity and use_detection:
183 msg = f"Error when using switch estimator for {prob_cls_name} for dt={dt:.1e}:"
184 if dt == 1e-2:
185 expected = {
186 'iL': 0.5490992952561473,
187 'vC': 0.9999999999982524,
188 't_switches': [0.1823215567992934, 0.18232155680104123],
189 'sum_restarts': 14.0,
190 'sum_niters': 416.0,
191 }
192 elif dt == 1e-3:
193 expected = {
194 'iL': 0.5407340516779595,
195 'vC': 0.9999999999936255,
196 't_switches': [0.18232155676519302],
197 'sum_restarts': 10.0,
198 'sum_niters': 2536.0,
199 }
200 got.update(
201 {
202 't_switches': u_num['t_switches'],
203 'sum_restarts': u_num['sum_restarts'],
204 'sum_niters': u_num['sum_niters'],
205 }
206 )
208 if use_adaptivity and not use_detection:
209 msg = f"Error when using adaptivity for {prob_cls_name} for dt={dt:.1e}:"
210 if dt == 1e-2:
211 expected = {
212 'iL': 0.4694087102919169,
213 'vC': 0.9026238839418407,
214 'dt': 0.18137307612335937,
215 'e_em': 2.3469713394952407e-09,
216 'sum_restarts': 0.0,
217 'sum_niters': 24.0,
218 }
219 elif dt == 1e-3:
220 expected = {
221 'iL': 0.39947441811958956,
222 'vC': 0.9679037468856341,
223 'dt': 0.1701392217033212,
224 'e_em': 1.147640815712947e-09,
225 'sum_restarts': 0.0,
226 'sum_niters': 32.0,
227 }
228 got.update(
229 {
230 'dt': u_num['dt'][-1, 1],
231 'e_em': u_num['e_em'][-1, 1],
232 'sum_restarts': u_num['sum_restarts'],
233 'sum_niters': u_num['sum_niters'],
234 }
235 )
237 elif not use_adaptivity and not use_detection:
238 msg = f'Error for {prob_cls_name} for dt={dt:.1e}:'
239 if dt == 1e-2:
240 expected = {
241 'iL': 0.5456915668459889,
242 'vC': 0.9973251377578705,
243 'sum_niters': 240.0,
244 }
245 elif dt == 1e-3:
246 expected = {
247 'iL': 0.5386399890100035,
248 'vC': 0.999405070641239,
249 'sum_niters': 2400.0,
250 }
251 got.update(
252 {
253 'sum_niters': u_num['sum_niters'],
254 }
255 )
257 elif prob_cls_name == 'battery_n_capacitors':
258 if use_adaptivity and use_detection:
259 msg = f"Error when using switch estimator and adaptivity for {prob_cls_name} for dt={dt:.1e}:"
260 if dt == 1e-2:
261 expected = {
262 'iL': 0.6125019898578352,
263 'vC1': 1.0000000000471956,
264 'vC2': 1.0000000000165106,
265 't_switches': [0.18232155678158268, 0.36464311353802376],
266 'dt': 0.0985931246953285,
267 'e_em': 2.295386103412511e-12,
268 'sum_restarts': 24.0,
269 'sum_niters': 552.0,
270 }
271 elif dt == 1e-3:
272 expected = {
273 'iL': 0.6125019901065321,
274 'vC1': 1.0000000000787372,
275 'vC2': 1.000000000028657,
276 't_switches': [0.1823215567907939, 0.3646431134803315],
277 'dt': 0.07154669986159717,
278 'e_em': 2.3381296898605797e-13,
279 'sum_restarts': 22.0,
280 'sum_niters': 472.0,
281 }
282 got.update(
283 {
284 't_switches': u_num['t_switches'],
285 'dt': u_num['dt'][-1, 1],
286 'e_em': u_num['e_em'][-1, 1],
287 'sum_restarts': u_num['sum_restarts'],
288 'sum_niters': u_num['sum_niters'],
289 }
290 )
292 elif not use_adaptivity and use_detection:
293 msg = f"Error when using switch estimator for {prob_cls_name} for dt={dt:.1e}:"
294 if dt == 1e-2:
295 expected = {
296 'iL': 0.6313858468030417,
297 'vC1': 1.0000000002414198,
298 'vC2': 1.0000000000095093,
299 't_switches': [0.18232155679395579, 0.3646431133464922],
300 'sum_restarts': 19.0,
301 'sum_niters': 664.0,
302 }
303 elif dt == 1e-3:
304 expected = {
305 'iL': 0.6151254295045797,
306 'vC1': 1.0000000000227713,
307 'vC2': 1.0000000000329365,
308 't_switches': [0.18232155680153855, 0.3646431135651182],
309 'sum_restarts': 16.0,
310 'sum_niters': 4224.0,
311 }
312 got.update(
313 {
314 't_switches': u_num['t_switches'],
315 'sum_restarts': u_num['sum_restarts'],
316 'sum_niters': u_num['sum_niters'],
317 }
318 )
320 if use_adaptivity and not use_detection:
321 msg = f"Error when using adaptivity for {prob_cls_name} for dt={dt:.1e}:"
322 if dt == 1e-2:
323 expected = {
324 'iL': 0.15890544838473294,
325 'vC1': 0.8806086293336285,
326 'vC2': 0.9915019206727803,
327 'dt': 0.38137307612335936,
328 'e_em': 4.145817911194172e-09,
329 'sum_restarts': 0.0,
330 'sum_niters': 24.0,
331 }
332 elif dt == 1e-3:
333 expected = {
334 'iL': 0.15422467570971707,
335 'vC1': 0.8756872272783145,
336 'vC2': 0.9971015415168025,
337 'dt': 0.3701392217033212,
338 'e_em': 3.6970297934146856e-09,
339 'sum_restarts': 0.0,
340 'sum_niters': 32.0,
341 }
342 got.update(
343 {
344 'dt': u_num['dt'][-1, 1],
345 'e_em': u_num['e_em'][-1, 1],
346 'sum_restarts': u_num['sum_restarts'],
347 'sum_niters': u_num['sum_niters'],
348 }
349 )
351 elif not use_adaptivity and not use_detection:
352 msg = f'Error for {prob_cls_name} for dt={dt:.1e}:'
353 if dt == 1e-2:
354 expected = {
355 'iL': 0.5939796175551723,
356 'vC1': 0.9973251377556902,
357 'vC2': 0.9973251377466236,
358 'sum_niters': 400.0,
359 }
360 elif dt == 1e-3:
361 expected = {
362 'iL': 0.6107051960885036,
363 'vC1': 0.9994050706403905,
364 'vC2': 0.9997382611893499,
365 'sum_niters': 4000.0,
366 }
367 got.update(
368 {
369 'sum_niters': u_num['sum_niters'],
370 }
371 )
373 elif prob_cls_name == 'DiscontinuousTestODE':
374 if not use_adaptivity and use_detection:
375 msg = f"Error when using switch estimator for {prob_cls_name} for dt={dt:.1e}:"
376 if dt == 1e-2:
377 expected = {
378 'u': 5.998326995729771,
379 'e_global': 0.0041911003550794135,
380 't_switches': [1.6094379124660123],
381 'e_event': [3.1912028575220575e-11],
382 'sum_restarts': 22.0,
383 'sum_niters': 675.0,
384 }
385 elif dt == 1e-3:
386 expected = {
387 'u': 5.9721869476933005,
388 'e_global': 0.0004191100622819022,
389 't_switches': [1.6094379124262566, 1.6094379124260099],
390 'e_event': [7.843725668976731e-12],
391 'sum_restarts': 20.0,
392 'sum_niters': 2352.0,
393 }
394 got.update(
395 {
396 't_switches': u_num['t_switches'],
397 'sum_restarts': u_num['sum_restarts'],
398 'sum_niters': u_num['sum_niters'],
399 'e_global': u_num['e_global'][-1, 1],
400 'e_event': u_num['e_event'],
401 }
402 )
404 elif not use_adaptivity and not use_detection:
405 msg = f"Error for {prob_cls_name} for dt={dt:.1e}:"
406 if dt == 1e-2:
407 expected = {
408 'u': 5.9805345175338225,
409 'e_global': 0.009855041056925806,
410 'sum_niters': 527.0,
411 }
412 elif dt == 1e-3:
413 expected = {
414 'u': 5.9737411566014105,
415 'e_global': 0.0005763403865515215,
416 'sum_niters': 2226.0,
417 }
418 got.update(
419 {
420 'sum_niters': u_num['sum_niters'],
421 'e_global': u_num['e_global'][-1, 1],
422 }
423 )
425 elif prob_cls_name == 'piline':
426 if not use_adaptivity and not use_detection:
427 msg = f"Error for {prob_cls_name} for dt={dt:.1e}:"
428 if dt == 5e-2:
429 expected = {
430 'vC1': 83.97535096068474,
431 'vC2': 80.52142367760014,
432 'iLp': 16.096505806313573,
433 'sum_niters': 2045.0,
434 }
435 elif dt == 1e-2:
436 expected = {
437 'vC1': 83.97462422132232,
438 'vC2': 80.52135774600202,
439 'iLp': 16.09884649820726,
440 'sum_niters': 7206.0,
441 }
442 got.update(
443 {
444 'sum_niters': u_num['sum_niters'],
445 }
446 )
448 elif prob_cls_name == 'buck_converter':
449 if not use_adaptivity and not use_detection:
450 msg = f"Error for {prob_cls_name} for dt={dt:.1e}:"
451 if dt == 2e-5:
452 expected = {
453 'vC1': 9.781955920747619,
454 'vC2': 6.396971204930281,
455 'iLp': -1.1056614708409171,
456 'sum_niters': 2519.0,
457 }
458 elif dt == 1e-5:
459 expected = {
460 'vC1': 9.782142840662102,
461 'vC2': 6.388775533709242,
462 'iLp': -1.0994027552202539,
463 'sum_niters': 4242.0,
464 }
465 got.update(
466 {
467 'sum_niters': u_num['sum_niters'],
468 }
469 )
471 else:
472 raise ParameterError(f"For {prob_cls_name} there is no test implemented here!")
474 for key in expected.keys():
475 if key == 't_switches' or key == 'e_event':
476 err_msg = f'{msg} Expected {key}={expected[key]}, got {key}={got[key]}'
477 if len(expected[key]) == got[key]:
478 assert np.allclose(expected[key], got[key], atol=1e-4), err_msg
479 else:
480 assert np.isclose(expected[key][-1], got[key][-1], atol=1e-4), err_msg
481 else:
482 err_msg = f'{msg} Expected {key}={expected[key]:.4e}, got {key}={got[key]:.4e}'
483 assert np.isclose(expected[key], got[key], atol=1e-4), err_msg