@@ -383,10 +383,81 @@ def test_solve_sensitivity_scalar_var_scalar_input(self):
383
383
],
384
384
)
385
385
386
+ # More complicated model
387
+ # Create model
388
+ model = pybamm .BaseModel ()
389
+ var = pybamm .Variable ("var" )
390
+ p = pybamm .InputParameter ("p" )
391
+ q = pybamm .InputParameter ("q" )
392
+ r = pybamm .InputParameter ("r" )
393
+ s = pybamm .InputParameter ("s" )
394
+ model .rhs = {var : p * q }
395
+ model .initial_conditions = {var : r }
396
+ model .variables = {"var times s" : var * s }
397
+
398
+ # Solve
399
+ # Make sure that passing in extra options works
400
+ solver = pybamm .ScipySolver (
401
+ rtol = 1e-10 , atol = 1e-10 , solve_sensitivity_equations = True
402
+ )
403
+ t_eval = np .linspace (0 , 1 , 80 )
404
+ solution = solver .solve (
405
+ model , t_eval , inputs = {"p" : 0.1 , "q" : 2 , "r" : - 1 , "s" : 0.5 }
406
+ )
407
+ np .testing .assert_allclose (solution .y [0 ], - 1 + 0.2 * solution .t )
408
+ np .testing .assert_allclose (
409
+ solution .sensitivity ["p" ], (2 * solution .t )[:, np .newaxis ],
410
+ )
411
+ np .testing .assert_allclose (
412
+ solution .sensitivity ["q" ], (0.1 * solution .t )[:, np .newaxis ],
413
+ )
414
+ np .testing .assert_allclose (solution .sensitivity ["r" ], 1 )
415
+ np .testing .assert_allclose (solution .sensitivity ["s" ], 0 )
416
+ np .testing .assert_allclose (
417
+ solution .sensitivity ["all" ],
418
+ np .hstack (
419
+ [
420
+ solution .sensitivity ["p" ],
421
+ solution .sensitivity ["q" ],
422
+ solution .sensitivity ["r" ],
423
+ solution .sensitivity ["s" ],
424
+ ]
425
+ ),
426
+ )
427
+ np .testing .assert_allclose (
428
+ solution ["var times s" ].data , 0.5 * (- 1 + 0.2 * solution .t )
429
+ )
430
+ np .testing .assert_allclose (
431
+ solution ["var times s" ].sensitivity ["p" ],
432
+ 0.5 * (2 * solution .t )[:, np .newaxis ],
433
+ )
434
+ np .testing .assert_allclose (
435
+ solution ["var times s" ].sensitivity ["q" ],
436
+ 0.5 * (0.1 * solution .t )[:, np .newaxis ],
437
+ )
438
+ np .testing .assert_allclose (solution ["var times s" ].sensitivity ["r" ], 0.5 )
439
+ np .testing .assert_allclose (
440
+ solution ["var times s" ].sensitivity ["s" ],
441
+ (- 1 + 0.2 * solution .t )[:, np .newaxis ],
442
+ )
443
+ np .testing .assert_allclose (
444
+ solution ["var times s" ].sensitivity ["all" ],
445
+ np .hstack (
446
+ [
447
+ solution ["var times s" ].sensitivity ["p" ],
448
+ solution ["var times s" ].sensitivity ["q" ],
449
+ solution ["var times s" ].sensitivity ["r" ],
450
+ solution ["var times s" ].sensitivity ["s" ],
451
+ ]
452
+ ),
453
+ )
454
+
386
455
@unittest .skip ("" )
387
456
def test_solve_sensitivity_vector_var_scalar_input (self ):
388
457
var = pybamm .Variable ("var" , "negative electrode" )
389
458
model = pybamm .BaseModel ()
459
+ # Set length scales to avoid warning
460
+ model .length_scales = {"negative electrode" : 1 }
390
461
param = pybamm .InputParameter ("param" )
391
462
model .rhs = {var : - param * var }
392
463
model .initial_conditions = {var : 2 }
@@ -410,32 +481,152 @@ def test_solve_sensitivity_vector_var_scalar_input(self):
410
481
decimal = 4 ,
411
482
)
412
483
484
+ # More complicated model
485
+ # Create model
486
+ model = pybamm .BaseModel ()
487
+ # Set length scales to avoid warning
488
+ model .length_scales = {"negative electrode" : 1 }
489
+ var = pybamm .Variable ("var" , "negative electrode" )
490
+ p = pybamm .InputParameter ("p" )
491
+ q = pybamm .InputParameter ("q" )
492
+ r = pybamm .InputParameter ("r" )
493
+ s = pybamm .InputParameter ("s" )
494
+ model .rhs = {var : p * q }
495
+ model .initial_conditions = {var : r }
496
+ model .variables = {"var times s" : var * s }
497
+
498
+ # Discretise
499
+ disc .process_model (model )
500
+
501
+ # Solve
502
+ # Make sure that passing in extra options works
503
+ solver = pybamm .ScipySolver (
504
+ rtol = 1e-10 , atol = 1e-10 , solve_sensitivity_equations = True
505
+ )
506
+ t_eval = np .linspace (0 , 1 , 80 )
507
+ solution = solver .solve (
508
+ model , t_eval , inputs = {"p" : 0.1 , "q" : 2 , "r" : - 1 , "s" : 0.5 }
509
+ )
510
+ np .testing .assert_allclose (solution .y , np .tile (- 1 + 0.2 * solution .t , (n , 1 )))
511
+ np .testing .assert_allclose (
512
+ solution .sensitivity ["p" ], np .repeat (2 * solution .t , n )[:, np .newaxis ],
513
+ )
514
+ np .testing .assert_allclose (
515
+ solution .sensitivity ["q" ], np .repeat (0.1 * solution .t , n )[:, np .newaxis ],
516
+ )
517
+ np .testing .assert_allclose (solution .sensitivity ["r" ], 1 )
518
+ np .testing .assert_allclose (solution .sensitivity ["s" ], 0 )
519
+ np .testing .assert_allclose (
520
+ solution .sensitivity ["all" ],
521
+ np .hstack (
522
+ [
523
+ solution .sensitivity ["p" ],
524
+ solution .sensitivity ["q" ],
525
+ solution .sensitivity ["r" ],
526
+ solution .sensitivity ["s" ],
527
+ ]
528
+ ),
529
+ )
530
+ np .testing .assert_allclose (
531
+ solution ["var times s" ].data , np .tile (0.5 * (- 1 + 0.2 * solution .t ), (n , 1 ))
532
+ )
533
+ np .testing .assert_allclose (
534
+ solution ["var times s" ].sensitivity ["p" ],
535
+ np .repeat (0.5 * (2 * solution .t ), n )[:, np .newaxis ],
536
+ )
537
+ np .testing .assert_allclose (
538
+ solution ["var times s" ].sensitivity ["q" ],
539
+ np .repeat (0.5 * (0.1 * solution .t ), n )[:, np .newaxis ],
540
+ )
541
+ np .testing .assert_allclose (solution ["var times s" ].sensitivity ["r" ], 0.5 )
542
+ np .testing .assert_allclose (
543
+ solution ["var times s" ].sensitivity ["s" ],
544
+ np .repeat (- 1 + 0.2 * solution .t , n )[:, np .newaxis ],
545
+ )
546
+ np .testing .assert_allclose (
547
+ solution ["var times s" ].sensitivity ["all" ],
548
+ np .hstack (
549
+ [
550
+ solution ["var times s" ].sensitivity ["p" ],
551
+ solution ["var times s" ].sensitivity ["q" ],
552
+ solution ["var times s" ].sensitivity ["r" ],
553
+ solution ["var times s" ].sensitivity ["s" ],
554
+ ]
555
+ ),
556
+ )
557
+
413
558
def test_solve_sensitivity_scalar_var_vector_input (self ):
414
559
var = pybamm .Variable ("var" , "negative electrode" )
415
560
model = pybamm .BaseModel ()
561
+ # Set length scales to avoid warning
562
+ model .length_scales = {"negative electrode" : 1 }
563
+
416
564
param = pybamm .InputParameter ("param" , "negative electrode" )
417
565
model .rhs = {var : - param * var }
418
566
model .initial_conditions = {var : 2 }
419
- model .variables = {"x-average of var" : pybamm .x_average (var )}
567
+ model .variables = {
568
+ "var" : var ,
569
+ "integral of var" : pybamm .Integral (var , pybamm .standard_spatial_vars .x_n ),
570
+ }
420
571
421
572
# create discretisation
422
- mesh = get_mesh_for_testing (xpts = 5 )
573
+ mesh = get_mesh_for_testing ()
423
574
spatial_methods = {"macroscale" : pybamm .FiniteVolume ()}
424
575
disc = pybamm .Discretisation (mesh , spatial_methods )
425
576
disc .process_model (model )
426
577
n = disc .mesh ["negative electrode" ].npts
427
578
428
- # Solve - scalar input
429
- solver = pybamm .ScipySolver (solve_sensitivity_equations = True )
430
- t_eval = np .linspace (0 , 1 , 3 )
579
+ # Solve - constant input
580
+ solver = pybamm .ScipySolver (
581
+ rtol = 1e-10 , atol = 1e-10 , solve_sensitivity_equations = True
582
+ )
583
+ t_eval = np .linspace (0 , 1 )
431
584
solution = solver .solve (model , t_eval , inputs = {"param" : 7 * np .ones (n )})
585
+ l_n = mesh ["negative electrode" ].edges [- 1 ]
432
586
np .testing .assert_array_almost_equal (
433
587
solution ["var" ].data , np .tile (2 * np .exp (- 7 * t_eval ), (n , 1 )), decimal = 4 ,
434
588
)
589
+
435
590
np .testing .assert_array_almost_equal (
436
591
solution ["var" ].sensitivity ["param" ],
437
- np .repeat (- 2 * t_eval * np .exp (- 7 * t_eval ), n )[:, np .newaxis ],
438
- decimal = 4 ,
592
+ np .vstack ([np .eye (n ) * - 2 * t * np .exp (- 7 * t ) for t in t_eval ]),
593
+ )
594
+ np .testing .assert_array_almost_equal (
595
+ solution ["integral of var" ].data , 2 * np .exp (- 7 * t_eval ) * l_n , decimal = 4 ,
596
+ )
597
+ np .testing .assert_array_almost_equal (
598
+ solution ["integral of var" ].sensitivity ["param" ],
599
+ np .tile (- 2 * t_eval * np .exp (- 7 * t_eval ) * l_n / 40 , (40 , 1 )).T ,
600
+ )
601
+
602
+ # Solve - linspace input
603
+ solver = pybamm .ScipySolver (
604
+ rtol = 1e-10 , atol = 1e-10 , solve_sensitivity_equations = True
605
+ )
606
+ t_eval = np .linspace (0 , 1 )
607
+ p_eval = np .linspace (1 , 2 , n )
608
+ solution = solver .solve (model , t_eval , inputs = {"param" : p_eval })
609
+ l_n = mesh ["negative electrode" ].edges [- 1 ]
610
+ np .testing .assert_array_almost_equal (
611
+ solution ["var" ].data , 2 * np .exp (- p_eval [:, np .newaxis ] * t_eval ), decimal = 4
612
+ )
613
+ np .testing .assert_array_almost_equal (
614
+ solution ["var" ].sensitivity ["param" ],
615
+ np .vstack ([np .diag (- 2 * t * np .exp (- p_eval * t )) for t in t_eval ]),
616
+ )
617
+
618
+ np .testing .assert_array_almost_equal (
619
+ solution ["integral of var" ].data ,
620
+ np .sum (
621
+ 2
622
+ * np .exp (- p_eval [:, np .newaxis ] * t_eval )
623
+ * mesh ["negative electrode" ].d_edges [:, np .newaxis ],
624
+ axis = 0 ,
625
+ ),
626
+ )
627
+ np .testing .assert_array_almost_equal (
628
+ solution ["integral of var" ].sensitivity ["param" ],
629
+ np .vstack ([- 2 * t * np .exp (- p_eval * t ) * l_n / 40 for t in t_eval ]),
439
630
)
440
631
441
632
0 commit comments