@@ -817,6 +817,38 @@ def test_solve_sensitivity_scalar_var_vector_input(self):
817
817
np .vstack ([- 2 * t * np .exp (- p_eval * t ) * l_n / n for t in t_eval ]),
818
818
)
819
819
820
+ def test_solve_sensitivity_then_no_sensitivity (self ):
821
+ # Create model
822
+ model = pybamm .BaseModel ()
823
+ var = pybamm .Variable ("var" )
824
+ p = pybamm .InputParameter ("p" )
825
+ model .rhs = {var : p * var }
826
+ model .initial_conditions = {var : 1 }
827
+ model .variables = {"var squared" : var ** 2 }
828
+
829
+ # Solve
830
+ # Make sure that passing in extra options works
831
+ solver = pybamm .CasadiSolver (
832
+ mode = "fast" , rtol = 1e-10 , atol = 1e-10
833
+ )
834
+ t_eval = np .linspace (0 , 1 , 80 )
835
+ solution = solver .solve (model , t_eval , inputs = {"p" : 0.1 },
836
+ calculate_sensitivities = True )
837
+
838
+ # check sensitivities
839
+ np .testing .assert_allclose (
840
+ solution .sensitivities ["p" ],
841
+ (solution .t * np .exp (0.1 * solution .t ))[:, np .newaxis ],
842
+ )
843
+
844
+ solution = solver .solve (model , t_eval , inputs = {"p" : 0.1 })
845
+
846
+ np .testing .assert_array_equal (solution .t , t_eval )
847
+ np .testing .assert_allclose (solution .y , np .exp (0.1 * solution .t ).reshape (1 , - 1 ))
848
+ np .testing .assert_allclose (
849
+ solution ["var squared" ].data , np .exp (0.1 * solution .t ) ** 2
850
+ )
851
+
820
852
821
853
class TestCasadiSolverDAEsWithForwardSensitivityEquations (unittest .TestCase ):
822
854
def test_solve_sensitivity_scalar_var_scalar_input (self ):
@@ -858,180 +890,33 @@ def test_solve_sensitivity_scalar_var_scalar_input(self):
858
890
atol = 1e-7
859
891
)
860
892
861
- def test_solve_sensitivity_vector_var_scalar_input (self ):
862
- var = pybamm .Variable ("var" , "negative electrode" )
863
- model = pybamm .BaseModel ()
864
- # Set length scales to avoid warning
865
- model .length_scales = {"negative electrode" : 1 }
866
- param = pybamm .InputParameter ("param" )
867
- model .rhs = {var : - param * var }
868
- model .initial_conditions = {var : 2 }
869
- model .variables = {"var" : var }
870
-
871
- # create discretisation
872
- disc = get_discretisation_for_testing ()
873
- disc .process_model (model )
874
- n = disc .mesh ["negative electrode" ].npts
875
-
876
- # Solve - scalar input
877
- solver = pybamm .CasadiSolver ()
878
- t_eval = np .linspace (0 , 1 )
879
- solution = solver .solve (model , t_eval , inputs = {"param" : 7 },
880
- calculate_sensitivities = ["param" ])
881
- np .testing .assert_array_almost_equal (
882
- solution ["var" ].data , np .tile (2 * np .exp (- 7 * t_eval ), (n , 1 )), decimal = 4 ,
883
- )
884
- np .testing .assert_array_almost_equal (
885
- solution ["var" ].sensitivities ["param" ],
886
- np .repeat (- 2 * t_eval * np .exp (- 7 * t_eval ), n )[:, np .newaxis ],
887
- decimal = 4 ,
888
- )
889
-
890
- # More complicated model
893
+ def test_solve_sensitivity_algebraic (self ):
891
894
# Create model
892
895
model = pybamm .BaseModel ()
893
- # Set length scales to avoid warning
894
- model .length_scales = {"negative electrode" : 1 }
895
- var = pybamm .Variable ("var" , "negative electrode" )
896
+ var = pybamm .Variable ("var" )
896
897
p = pybamm .InputParameter ("p" )
897
- q = pybamm .InputParameter ("q" )
898
- r = pybamm .InputParameter ("r" )
899
- s = pybamm .InputParameter ("s" )
900
- model .rhs = {var : p * q }
901
- model .initial_conditions = {var : r }
902
- model .variables = {"var times s" : var * s }
903
-
904
- # Discretise
905
- disc .process_model (model )
898
+ model .algebraic = {var : var - p * pybamm .t }
899
+ model .initial_conditions = {var : 0 }
900
+ model .variables = {"var squared" : var ** 2 }
906
901
907
902
# Solve
908
903
# Make sure that passing in extra options works
909
- solver = pybamm .CasadiSolver (
910
- rtol = 1e-10 , atol = 1e-10 ,
911
- )
904
+ solver = pybamm .CasadiAlgebraicSolver (tol = 1e-10 )
912
905
t_eval = np .linspace (0 , 1 , 80 )
913
- solution = solver .solve (
914
- model , t_eval , inputs = {"p" : 0.1 , "q" : 2 , "r" : - 1 , "s" : 0.5 },
915
- calculate_sensitivities = True ,
916
- )
917
- np .testing .assert_allclose (solution .y , np .tile (- 1 + 0.2 * solution .t , (n , 1 )))
918
- np .testing .assert_allclose (
919
- solution .sensitivities ["p" ], np .repeat (2 * solution .t , n )[:, np .newaxis ],
920
- )
921
- np .testing .assert_allclose (
922
- solution .sensitivities ["q" ], np .repeat (0.1 * solution .t , n )[:, np .newaxis ],
923
- )
924
- np .testing .assert_allclose (solution .sensitivities ["r" ], 1 )
925
- np .testing .assert_allclose (solution .sensitivities ["s" ], 0 )
926
- np .testing .assert_allclose (
927
- solution .sensitivities ["all" ],
928
- np .hstack (
929
- [
930
- solution .sensitivities ["p" ],
931
- solution .sensitivities ["q" ],
932
- solution .sensitivities ["r" ],
933
- solution .sensitivities ["s" ],
934
- ]
935
- ),
936
- )
906
+ solution = solver .solve (model , t_eval , inputs = {"p" : 0.1 },
907
+ calculate_sensitivities = True )
908
+ np .testing .assert_array_equal (solution .t , t_eval )
909
+ np .testing .assert_allclose (solution .y [0 ], 0.1 * solution .t )
937
910
np .testing .assert_allclose (
938
- solution [ "var times s" ]. data , np . tile ( 0.5 * (- 1 + 0.2 * solution . t ), ( n , 1 ))
911
+ solution . sensitivities [ "p" ], solution . t . reshape (- 1 , 1 ), atol = 1e-7
939
912
)
940
913
np .testing .assert_allclose (
941
- solution ["var times s" ].sensitivities ["p" ],
942
- np .repeat (0.5 * (2 * solution .t ), n )[:, np .newaxis ],
914
+ solution ["var squared" ].data , (0.1 * solution .t ) ** 2
943
915
)
944
916
np .testing .assert_allclose (
945
- solution ["var times s" ].sensitivities ["q" ],
946
- np .repeat (0.5 * (0.1 * solution .t ), n )[:, np .newaxis ],
947
- )
948
- np .testing .assert_allclose (solution ["var times s" ].sensitivities ["r" ], 0.5 )
949
- np .testing .assert_allclose (
950
- solution ["var times s" ].sensitivities ["s" ],
951
- np .repeat (- 1 + 0.2 * solution .t , n )[:, np .newaxis ],
952
- )
953
- np .testing .assert_allclose (
954
- solution ["var times s" ].sensitivities ["all" ],
955
- np .hstack (
956
- [
957
- solution ["var times s" ].sensitivities ["p" ],
958
- solution ["var times s" ].sensitivities ["q" ],
959
- solution ["var times s" ].sensitivities ["r" ],
960
- solution ["var times s" ].sensitivities ["s" ],
961
- ]
962
- ),
963
- )
964
-
965
- def test_solve_sensitivity_scalar_var_vector_input (self ):
966
- var = pybamm .Variable ("var" , "negative electrode" )
967
- model = pybamm .BaseModel ()
968
- # Set length scales to avoid warning
969
- model .length_scales = {"negative electrode" : 1 }
970
-
971
- param = pybamm .InputParameter ("param" , "negative electrode" )
972
- model .rhs = {var : - param * var }
973
- model .initial_conditions = {var : 2 }
974
- model .variables = {
975
- "var" : var ,
976
- "integral of var" : pybamm .Integral (var , pybamm .standard_spatial_vars .x_n ),
977
- }
978
-
979
- # create discretisation
980
- mesh = get_mesh_for_testing (xpts = 5 )
981
- spatial_methods = {"macroscale" : pybamm .FiniteVolume ()}
982
- disc = pybamm .Discretisation (mesh , spatial_methods )
983
- disc .process_model (model )
984
- n = disc .mesh ["negative electrode" ].npts
985
-
986
- # Solve - constant input
987
- solver = pybamm .CasadiSolver (
988
- mode = "fast" , rtol = 1e-10 , atol = 1e-10
989
- )
990
- t_eval = np .linspace (0 , 1 )
991
- solution = solver .solve (model , t_eval , inputs = {"param" : 7 * np .ones (n )},
992
- calculate_sensitivities = True )
993
- l_n = mesh ["negative electrode" ].edges [- 1 ]
994
- np .testing .assert_array_almost_equal (
995
- solution ["var" ].data , np .tile (2 * np .exp (- 7 * t_eval ), (n , 1 )), decimal = 4 ,
996
- )
997
-
998
- np .testing .assert_array_almost_equal (
999
- solution ["var" ].sensitivities ["param" ],
1000
- np .vstack ([np .eye (n ) * - 2 * t * np .exp (- 7 * t ) for t in t_eval ]),
1001
- )
1002
- np .testing .assert_array_almost_equal (
1003
- solution ["integral of var" ].data , 2 * np .exp (- 7 * t_eval ) * l_n , decimal = 4 ,
1004
- )
1005
- np .testing .assert_array_almost_equal (
1006
- solution ["integral of var" ].sensitivities ["param" ],
1007
- np .tile (- 2 * t_eval * np .exp (- 7 * t_eval ) * l_n / n , (n , 1 )).T ,
1008
- )
1009
-
1010
- # Solve - linspace input
1011
- p_eval = np .linspace (1 , 2 , n )
1012
- solution = solver .solve (model , t_eval , inputs = {"param" : p_eval },
1013
- calculate_sensitivities = True )
1014
- l_n = mesh ["negative electrode" ].edges [- 1 ]
1015
- np .testing .assert_array_almost_equal (
1016
- solution ["var" ].data , 2 * np .exp (- p_eval [:, np .newaxis ] * t_eval ), decimal = 4
1017
- )
1018
- np .testing .assert_array_almost_equal (
1019
- solution ["var" ].sensitivities ["param" ],
1020
- np .vstack ([np .diag (- 2 * t * np .exp (- p_eval * t )) for t in t_eval ]),
1021
- )
1022
-
1023
- np .testing .assert_array_almost_equal (
1024
- solution ["integral of var" ].data ,
1025
- np .sum (
1026
- 2
1027
- * np .exp (- p_eval [:, np .newaxis ] * t_eval )
1028
- * mesh ["negative electrode" ].d_edges [:, np .newaxis ],
1029
- axis = 0 ,
1030
- ),
1031
- )
1032
- np .testing .assert_array_almost_equal (
1033
- solution ["integral of var" ].sensitivities ["param" ],
1034
- np .vstack ([- 2 * t * np .exp (- p_eval * t ) * l_n / n for t in t_eval ]),
917
+ solution ["var squared" ].sensitivities ["p" ],
918
+ (2 * 0.1 * solution .t ** 2 ).reshape (- 1 , 1 ),
919
+ atol = 1e-7
1035
920
)
1036
921
1037
922
0 commit comments