@@ -15,6 +15,56 @@ parameter_values(arr::AbstractArray) = arr
15
15
parameter_values (arr:: AbstractArray , i) = arr[i]
16
16
parameter_values (prob, i) = parameter_values (parameter_values (prob), i)
17
17
18
+ """
19
+ parameter_values_at_time(p, i)
20
+
21
+ Return an indexable collection containing the value of all parameters in `p` at time index
22
+ `i`. This is useful when parameter values change during the simulation
23
+ (such as through callbacks) and their values are saved. `i` is the time index in the
24
+ timeseries formed by these changing parameter values, obtained using
25
+ [`parameter_timeseries`](@ref).
26
+
27
+ By default, this function returns `parameter_values(p)` regardless of `i`, and only needs
28
+ to be specialized for timeseries objects where parameter values are not constant at all
29
+ times. The resultant object should be indexable using [`parameter_values`](@ref).
30
+
31
+ If this function is implemented, [`parameter_values_at_state_time`](@ref) must be
32
+ implemented for [`getu`](@ref) to work correctly.
33
+ """
34
+ function parameter_values_at_time end
35
+ parameter_values_at_time (p, i) = parameter_values (p)
36
+
37
+ """
38
+ parameter_values_at_state_time(p, i)
39
+
40
+ Return an indexable collection containing the value of all parameters in `p` at time
41
+ index `i`. This is useful when parameter values change during the simulation (such as
42
+ through callbacks) and their values are saved. `i` is the time index in the timeseries
43
+ formed by dependent variables (as opposed to the timeseries of the parameters, as in
44
+ [`parameter_values_at_time`](@ref)).
45
+
46
+ By default, this function returns `parameter_values(p)` regardless of `i`, and only needs
47
+ to be specialized for timeseries objects where parameter values are not constant at
48
+ all times. The resultant object should be indexable using [`parameter_values`](@ref).
49
+
50
+ If this function is implemented, [`parameter_values_at_time`](@ref) must be implemented for
51
+ [`getp`](@ref) to work correctly.
52
+ """
53
+ function parameter_values_at_state_time end
54
+ parameter_values_at_state_time (p, i) = parameter_values (p)
55
+
56
+ """
57
+ parameter_timeseries(p)
58
+
59
+ Return an iterable of time steps at which the parameter values are saved. This is only
60
+ required for objects where `is_timeseries(p) === Timeseries()` and the parameter values
61
+ change during the simulation (such as through callbacks). By default, this returns `[0]`.
62
+
63
+ See also: [`parameter_values_at_time`](@ref).
64
+ """
65
+ function parameter_timeseries end
66
+ parameter_timeseries (_) = [0 ]
67
+
18
68
"""
19
69
set_parameter!(sys, val, idx)
20
70
@@ -47,6 +97,13 @@ solution from which the values are obtained.
47
97
Requires that the integrator or solution implement [`parameter_values`](@ref). This function
48
98
typically does not need to be implemented, and has a default implementation relying on
49
99
[`parameter_values`](@ref).
100
+
101
+ If the returned function is used on a timeseries object which saves parameter timeseries, it
102
+ can be used to index said timeseries. The timeseries object must implement
103
+ [`parameter_timeseries`](@ref), [`parameter_values_at_time`](@ref) and
104
+ [`parameter_values_at_state_time`](@ref). The function returned from `getp` will can be passed
105
+ `Colon()` (`:`) as the last argument to return the entire parameter timeseries for `p`, or
106
+ any index into the parameter timeseries for a subset of values.
50
107
"""
51
108
function getp (sys, p)
52
109
symtype = symbolic_type (p)
@@ -55,18 +112,42 @@ function getp(sys, p)
55
112
end
56
113
57
114
function _getp (sys, :: NotSymbolic , :: NotSymbolic , p)
58
- return function getter (sol)
59
- return parameter_values (sol, p)
115
+ return let p = p
116
+ function _getter (:: NotTimeseries , prob)
117
+ parameter_values (prob, p)
118
+ end
119
+ function _getter (:: Timeseries , prob)
120
+ parameter_values (prob, p)
121
+ end
122
+ function _getter (:: Timeseries , prob, i:: Union{Int, CartesianIndex} )
123
+ parameter_values (
124
+ parameter_values_at_time (
125
+ prob, only (to_indices (parameter_timeseries (prob), (i,)))),
126
+ p)
127
+ end
128
+ function _getter (:: Timeseries , prob, i:: Union{AbstractArray{Bool}, Colon} )
129
+ parameter_values .(
130
+ parameter_values_at_time .((prob,),
131
+ (j for j in only (to_indices (parameter_timeseries (prob), (i,))))),
132
+ p)
133
+ end
134
+ function _getter (:: Timeseries , prob, i)
135
+ parameter_values .(parameter_values_at_time .((prob,), i), (p,))
136
+ end
137
+ getter = let _getter = _getter
138
+ function getter (prob, args... )
139
+ return _getter (is_timeseries (prob), prob, args... )
140
+ end
141
+ end
142
+ getter
60
143
end
61
144
end
62
145
63
146
function _getp (sys, :: ScalarSymbolic , :: SymbolicTypeTrait , p)
64
147
idx = parameter_index (sys, p)
65
- return let idx = idx
66
- function getter (sol)
67
- return parameter_values (sol, idx)
68
- end
69
- end
148
+ return invoke (_getp, Tuple{Any, NotSymbolic, NotSymbolic, Any},
149
+ sys, NotSymbolic (), NotSymbolic (), idx)
150
+ return _getp (sys, NotSymbolic (), NotSymbolic (), idx)
70
151
end
71
152
72
153
for (t1, t2) in [
@@ -78,15 +159,57 @@ for (t1, t2) in [
78
159
getters = getp .((sys,), p)
79
160
80
161
return let getters = getters
81
- function getter (sol )
82
- map (g -> g (sol ), getters)
162
+ function _getter ( :: NotTimeseries , prob )
163
+ map (g -> g (prob ), getters)
83
164
end
84
- function getter (buffer, sol)
85
- for (i, g) in zip (eachindex (buffer), getters)
86
- buffer[i] = g (sol)
165
+ function _getter (:: Timeseries , prob)
166
+ map (g -> g (prob), getters)
167
+ end
168
+ function _getter (:: Timeseries , prob, i:: Union{Int, CartesianIndex} )
169
+ map (g -> g (prob, i), getters)
170
+ end
171
+ function _getter (:: Timeseries , prob, i)
172
+ [map (g -> g (prob, j), getters)
173
+ for j in only (to_indices (parameter_timeseries (prob), (i,)))]
174
+ end
175
+ function _getter! (buffer, :: NotTimeseries , prob)
176
+ for (g, bufi) in zip (getters, eachindex (buffer))
177
+ buffer[bufi] = g (prob)
87
178
end
88
179
buffer
89
180
end
181
+ function _getter! (buffer, :: Timeseries , prob)
182
+ for (g, bufi) in zip (getters, eachindex (buffer))
183
+ buffer[bufi] = g (prob)
184
+ end
185
+ buffer
186
+ end
187
+ function _getter! (buffer, :: Timeseries , prob, i:: Union{Int, CartesianIndex} )
188
+ for (g, bufi) in zip (getters, eachindex (buffer))
189
+ buffer[bufi] = g (prob, i)
190
+ end
191
+ buffer
192
+ end
193
+ function _getter! (buffer, :: Timeseries , prob, i)
194
+ for (bufi, tsi) in zip (
195
+ eachindex (buffer), only (to_indices (parameter_timeseries (prob), (i,))))
196
+ for (g, bufj) in zip (getters, eachindex (buffer[bufi]))
197
+ buffer[bufi][bufj] = g (prob, tsi)
198
+ end
199
+ end
200
+ buffer
201
+ end
202
+ _getter, _getter!
203
+ getter = let _getter = _getter, _getter! = _getter!
204
+ function getter (prob, i... )
205
+ return _getter (is_timeseries (prob), prob, i... )
206
+ end
207
+ function getter (buffer:: AbstractArray , prob, i... )
208
+ return _getter! (buffer, is_timeseries (prob), prob, i... )
209
+ end
210
+ getter
211
+ end
212
+ getter
90
213
end
91
214
end
92
215
end
0 commit comments