@@ -15,6 +15,56 @@ parameter_values(arr::AbstractArray) = arr
1515parameter_values (arr:: AbstractArray , i) = arr[i]
1616parameter_values (prob, i) = parameter_values (parameter_values (prob), i)
1717
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+
1868"""
1969 set_parameter!(sys, val, idx)
2070
@@ -47,6 +97,13 @@ solution from which the values are obtained.
4797Requires that the integrator or solution implement [`parameter_values`](@ref). This function
4898typically does not need to be implemented, and has a default implementation relying on
4999[`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.
50107"""
51108function getp (sys, p)
52109 symtype = symbolic_type (p)
@@ -55,18 +112,42 @@ function getp(sys, p)
55112end
56113
57114function _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
60143 end
61144end
62145
63146function _getp (sys, :: ScalarSymbolic , :: SymbolicTypeTrait , p)
64147 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)
70151end
71152
72153for (t1, t2) in [
@@ -78,15 +159,57 @@ for (t1, t2) in [
78159 getters = getp .((sys,), p)
79160
80161 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)
83164 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)
87178 end
88179 buffer
89180 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
90213 end
91214 end
92215end
0 commit comments