Coverage for pySDC/projects/PinTSimE/hardcoded_solutions.py: 99%

133 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2024-11-16 14:51 +0000

1import numpy as np 

2 

3from pySDC.core.errors import ParameterError 

4 

5 

6def testSolution(u_num, prob_cls_name, dt, use_adaptivity, use_detection): 

7 r""" 

8 Test for numerical solution if values satisfy hardcoded values. 

9 

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. 

15 

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``. 

19 

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 """ 

34 

35 unknowns = u_num['unknowns'] 

36 u_num_tmp = {unknown: u_num[unknown][-1] for unknown in unknowns} 

37 

38 got = {} 

39 got = u_num_tmp 

40 

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 ) 

73 

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 ) 

99 

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 ) 

128 

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 ) 

148 

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 ) 

181 

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 ) 

207 

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 ) 

236 

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 ) 

256 

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 ) 

291 

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 ) 

319 

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 ) 

350 

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 ) 

372 

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 ) 

403 

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 ) 

424 

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 ) 

447 

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 ) 

470 

471 else: 

472 raise ParameterError(f"For {prob_cls_name} there is no test implemented here!") 

473 

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