Skip to content

Commit

Permalink
fixup! docs: update documentation with new parameter indexing API and…
Browse files Browse the repository at this point in the history
… semantics
  • Loading branch information
AayushSabharwal committed May 15, 2024
1 parent 25fe115 commit f021b84
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 34 deletions.
11 changes: 6 additions & 5 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ If a solution object saves a timeseries of parameter values that are updated dur
simulation (such as by callbacks), it must implement the following methods to ensure
correct functioning of [`getu`](@ref) and [`getp`](@ref).

Parameter timeseries support requires that the value provider store the different
timeseries in a [`ParameterTimeseriesCollection`](@ref).

```@docs
is_parameter_timeseries
parameter_timeseries
parameter_values_at_time
parameter_values_at_state_time
parameter_timeseries_at_state_time
get_parameter_timeseries_collection
ParameterTimeseriesCollection
with_updated_parameter_timeseries_values
```

### Batched Queries and Updates
Expand Down Expand Up @@ -118,5 +120,4 @@ symbolic_evaluate
```@docs
SymbolCache
ProblemState
ParameterTimeseriesCollection
```
57 changes: 28 additions & 29 deletions docs/src/complete_sii.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,28 @@ correct implementation of these functions and the indexing syntax they enable.
```@example param_timeseries
using SymbolicIndexingInterface
# First, we must implement a parameter object that knows where the parameters in
# each parameter timeseries are stored
struct MyParameterObject
p::Vector{Float64}
disc_idxs::Vector{Vector{Int}}
end
# To be able to access parameter values
SymbolicIndexingInterface.parameter_values(mpo::MyParameterObject) = mpo.p
# Update the parameter object with new values
function SymbolicIndexingInterface.with_updated_parameter_timeseries_values(mpo::MyParameterObject, args::Pair...)
for (ts_idx, val) in args
mpo.p[mpo.disc_idxs[ts_idx]] = val
end
return mpo
end
struct ExampleSolution2
sys::SymbolCache
u::Vector{Vector{Float64}}
t::Vector{Float64}
p::Vector{Float64} # the parameter object. Only some parameters are timeseries params
p_idxs::Vector{Vector{Int}}
p::MyParameterObject # the parameter object. Only some parameters are timeseries params
p_ts::ParameterTimeseriesCollection
end
Expand All @@ -344,30 +360,7 @@ SymbolicIndexingInterface.state_values(fs::ExampleSolution2) = fs.u
SymbolicIndexingInterface.current_time(fs::ExampleSolution2) = fs.t
# By default, `parameter_values` refers to the last value
SymbolicIndexingInterface.parameter_values(fs::ExampleSolution2) = fs.p
SymbolicIndexingInterface.parameter_values(fs::ExampleSolution2, i) = fs.p[i]
function SymbolicIndexingInterface.parameter_values(fs::ExampleSolution2, i::ParameterTimeseriesIndex, j)
return fs.p_ts[i, j]
end
# Index into the parameter timeseries vector
function SymbolicIndexingInterface.parameter_values_at_time(fs::ExampleSolution2, t)
newp = copy(fs.p)
# iterating over `ParameterTimeseriesCollection` iterates over the contained timeseries
# objects
for (idxs, timeseries) in zip(fs.p_idxs, fs.p_ts)
# find the index of the last point in time the parameter values were saved
# before the requested time `t`
index_in_timeseries = searchsortedlast(current_time(timeseries), t)
# obtain the required values
timeseries_values = state_values(timeseries, index_in_timeseries)
# update parameter vector
newp[idxs] = timeseries_values
end
return newp
end
function SymbolicIndexingInterface.parameter_timeseries(fs::ExampleSolution2, i)
# `ParameterTimeseriesCollection` implements this for us
return parameter_timeseries(fs.p_ts, i)
end
SymbolicIndexingInterface.get_parameter_timeseries_collection(fs::FakeSolution) = fs.p_ts
# Mark the object as a timeseries object
SymbolicIndexingInterface.is_timeseries(::Type{ExampleSolution2}) = Timeseries()
# Mark the object as a parameter timeseries object
Expand All @@ -391,7 +384,9 @@ SymbolicIndexingInterface.state_values(a::MyDiffEqArray) = a.u
```

Now we can create an example object and observe the new functionality. Note that
`sol.ps[sym, args...]` is identical to `getp(sol, sym)(sol, args...)`.
`sol.ps[sym, args...]` is identical to `getp(sol, sym)(sol, args...)`. In a real
application, the solution object will be populated during the solve process. We manually
construct the object here for demonstration.

```@example param_timeseries
sys = SymbolCache(
Expand All @@ -412,12 +407,16 @@ d_timeseries = MyDiffEqArray(
collect(0.0:0.2:1.0),
[[0.17i] for i in 1:6]
)
p = MyParameterObject(
# parameter values at the final time
[4.2, b_c_timeseries.u[end]..., d_timeseries.u[end]...],
[[2, 3], 4]
)
sol = ExampleSolution2(
sys,
[i * ones(3) for i in 1:5], # u
collect(0.0:0.25:1.0), # t
[4.2, b_c_timeseries.u[end]..., d_timeseries.u[end]...], # p must contain final values
[[2, 3], 4], # p_idxs
p,
ParameterTimeseriesCollection([b_c_timeseries, d_timeseries]) # p_ts
)
sol.ps[:a] # returns the value of non-timeseries parameter
Expand Down

0 comments on commit f021b84

Please sign in to comment.