@@ -39,6 +39,7 @@ def __init__(self, base_variables, base_variables_casadi, solution, warn=True):
39
39
40
40
self .all_ts = solution .all_ts
41
41
self .all_ys = solution .all_ys
42
+ self .all_inputs = solution .all_inputs
42
43
self .all_inputs_casadi = solution .all_inputs_casadi
43
44
44
45
self .mesh = base_variables [0 ].mesh
@@ -51,8 +52,8 @@ def __init__(self, base_variables, base_variables_casadi, solution, warn=True):
51
52
self .u_sol = solution .y
52
53
53
54
# Sensitivity starts off uninitialized, only set when called
54
- self ._sensitivity = None
55
- self .all_sensitivities = solution .all_sensitivities
55
+ self ._sensitivities = None
56
+ self .solution_sensitivities = solution .sensitivities
56
57
57
58
# Set timescale
58
59
self .timescale = solution .timescale_eval
@@ -488,52 +489,44 @@ def data(self):
488
489
"""Same as entries, but different name"""
489
490
return self .entries
490
491
491
-
492
- class Interpolant0D :
493
- def __init__ (self , entries ):
494
- self .entries = entries
495
-
496
- def __call__ (self , t ):
497
- return self .entries
498
-
499
492
@property
500
- def sensitivity (self ):
493
+ def sensitivities (self ):
501
494
"""
502
- Returns a dictionary of sensitivity for each input parameter.
495
+ Returns a dictionary of sensitivities for each input parameter.
503
496
The keys are the input parameters, and the value is a matrix of size
504
497
(n_x * n_t, n_p), where n_x is the number of states, n_t is the number of time
505
498
points, and n_p is the size of the input parameter
506
499
"""
507
- # No sensitivity if there are no inputs
508
- if len (self .inputs ) == 0 :
500
+ # No sensitivities if there are no inputs
501
+ if len (self .all_inputs [ 0 ] ) == 0 :
509
502
return {}
510
- # Otherwise initialise and return sensitivity
511
- if self ._sensitivity is None :
512
- if self .solution_sensitivity != {}:
503
+ # Otherwise initialise and return sensitivities
504
+ if self ._sensitivities is None :
505
+ if self .solution_sensitivities != {}:
513
506
self .initialise_sensitivity_explicit_forward ()
514
507
else :
515
508
raise ValueError (
516
- "Cannot compute sensitivities. The 'sensitivity ' argument of the "
517
- "solver should be changed from 'None' to allow sensitivity "
509
+ "Cannot compute sensitivities. The 'sensitivities ' argument of the "
510
+ "solver.solve should be changed from 'None' to allow sensitivities "
518
511
"calculations. Check solver documentation for details."
519
512
)
520
- return self ._sensitivity
513
+ return self ._sensitivities
521
514
522
515
def initialise_sensitivity_explicit_forward (self ):
523
516
"Set up the sensitivity dictionary"
524
- inputs_stacked = casadi . vertcat ( * [ p for p in self .inputs . values ()])
517
+ inputs_stacked = self .all_inputs_casadi [ 0 ]
525
518
526
519
# Set up symbolic variables
527
520
t_casadi = casadi .MX .sym ("t" )
528
521
y_casadi = casadi .MX .sym ("y" , self .u_sol .shape [0 ])
529
522
p_casadi = {
530
523
name : casadi .MX .sym (name , value .shape [0 ])
531
- for name , value in self .inputs .items ()
524
+ for name , value in self .all_inputs [ 0 ] .items ()
532
525
}
533
526
p_casadi_stacked = casadi .vertcat (* [p for p in p_casadi .values ()])
534
527
535
528
# Convert variable to casadi format for differentiating
536
- var_casadi = self .base_variable .to_casadi (t_casadi , y_casadi , inputs = p_casadi )
529
+ var_casadi = self .base_variables [ 0 ] .to_casadi (t_casadi , y_casadi , inputs = p_casadi )
537
530
dvar_dy = casadi .jacobian (var_casadi , y_casadi )
538
531
dvar_dp = casadi .jacobian (var_casadi , p_casadi_stacked )
539
532
@@ -544,8 +537,8 @@ def initialise_sensitivity_explicit_forward(self):
544
537
dvar_dp_func = casadi .Function (
545
538
"dvar_dp" , [t_casadi , y_casadi , p_casadi_stacked ], [dvar_dp ]
546
539
)
547
- for idx in range (len (self .t_sol )):
548
- t = self .t_sol [idx ]
540
+ for idx in range (len (self .all_ts [ 0 ] )):
541
+ t = self .all_ts [ 0 ] [idx ]
549
542
u = self .u_sol [:, idx ]
550
543
inp = inputs_stacked [:, idx ]
551
544
next_dvar_dy_eval = dvar_dy_func (t , u , inp )
@@ -558,20 +551,29 @@ def initialise_sensitivity_explicit_forward(self):
558
551
dvar_dp_eval = casadi .vertcat (dvar_dp_eval , next_dvar_dp_eval )
559
552
560
553
# Compute sensitivity
561
- dy_dp = self .solution_sensitivity ["all" ]
554
+ dy_dp = self .solution_sensitivities ["all" ]
562
555
S_var = dvar_dy_eval @ dy_dp + dvar_dp_eval
563
556
564
- sensitivity = {"all" : S_var }
557
+ sensitivities = {"all" : S_var }
565
558
566
559
# Add the individual sensitivity
567
560
start = 0
568
- for name , inp in self .inputs .items ():
561
+ for name , inp in self .all_inputs [ 0 ] .items ():
569
562
end = start + inp .shape [0 ]
570
- sensitivity [name ] = S_var [:, start :end ]
563
+ sensitivities [name ] = S_var [:, start :end ]
571
564
start = end
572
565
573
566
# Save attribute
574
- self ._sensitivity = sensitivity
567
+ self ._sensitivities = sensitivities
568
+
569
+
570
+ class Interpolant0D :
571
+ def __init__ (self , entries ):
572
+ self .entries = entries
573
+
574
+ def __call__ (self , t ):
575
+ return self .entries
576
+
575
577
576
578
class Interpolant1D :
577
579
def __init__ (self , pts_for_interp , entries_for_interp ):
0 commit comments