@@ -104,9 +104,12 @@ https://docs.sciml.ai/DiffEqDocs/stable/basics/solution/
104
104
successfully, whether it terminated early due to a user-defined callback, or whether it
105
105
exited due to an error. For more details, see
106
106
[the return code documentation](https://docs.sciml.ai/SciMLBase/stable/interfaces/Solutions/#retcodes).
107
+ - `saved_subsystem`: a [`SavedSubsystem`](@ref) representing the subset of variables saved
108
+ in this solution, or `nothing` if all variables are saved. Here "variables" refers to
109
+ both continuous-time state variables and timeseries parameters.
107
110
"""
108
111
struct ODESolution{T, N, uType, uType2, DType, tType, rateType, discType, P, A, IType, S,
109
- AC <: Union{Nothing, Vector{Int}} , R, O} < :
112
+ AC <: Union{Nothing, Vector{Int}} , R, O, V } < :
110
113
AbstractODESolution{T, N, uType}
111
114
u:: uType
112
115
u_analytic:: uType2
@@ -124,6 +127,7 @@ struct ODESolution{T, N, uType, uType2, DType, tType, rateType, discType, P, A,
124
127
retcode:: ReturnCode.T
125
128
resid:: R
126
129
original:: O
130
+ saved_subsystem:: V
127
131
end
128
132
129
133
function ConstructionBase. constructorof (:: Type{O} ) where {T, N, O <: ODESolution{T, N} }
@@ -137,7 +141,7 @@ function ConstructionBase.setproperties(sol::ODESolution, patch::NamedTuple)
137
141
patch = merge (getproperties (sol), patch)
138
142
return ODESolution {T, N} (patch. u, patch. u_analytic, patch. errors, patch. t, patch. k,
139
143
patch. discretes, patch. prob, patch. alg, patch. interp, patch. dense, patch. tslocation, patch. stats,
140
- patch. alg_choice, patch. retcode, patch. resid, patch. original)
144
+ patch. alg_choice, patch. retcode, patch. resid, patch. original, patch . saved_subsystem )
141
145
end
142
146
143
147
Base. @propagate_inbounds function Base. getproperty (x:: AbstractODESolution , s:: Symbol )
@@ -154,12 +158,12 @@ end
154
158
function ODESolution {T, N} (
155
159
u, u_analytic, errors, t, k, discretes, prob, alg, interp, dense,
156
160
tslocation, stats, alg_choice, retcode, resid = nothing ,
157
- original = nothing ) where {T, N}
161
+ original = nothing , saved_subsystem = nothing ) where {T, N}
158
162
return ODESolution{T, N, typeof (u), typeof (u_analytic), typeof (errors), typeof (t),
159
163
typeof (k), typeof (discretes), typeof (prob), typeof (alg), typeof (interp),
160
- typeof (stats), typeof (alg_choice), typeof (resid),
161
- typeof (original )}(u, u_analytic, errors, t, k, discretes, prob, alg, interp,
162
- dense, tslocation, stats, alg_choice, retcode, resid, original)
164
+ typeof (stats), typeof (alg_choice), typeof (resid), typeof (original),
165
+ typeof (saved_subsystem )}(u, u_analytic, errors, t, k, discretes, prob, alg, interp,
166
+ dense, tslocation, stats, alg_choice, retcode, resid, original, saved_subsystem )
163
167
end
164
168
165
169
error_if_observed_derivative (_, _, :: Type{Val{0}} ) = nothing
@@ -409,15 +413,25 @@ const PeriodicDiffEqArray = DiffEqArray{T, N, A, B} where {T, N, A, B <: Abstrac
409
413
# public API, used by MTK
410
414
"""
411
415
get_saveable_values(sys, ps, timeseries_idx)
416
+
417
+ Return the values to be saved in parameter object `ps` for timeseries index `timeseries_idx`. Called by
418
+ `save_discretes!`. If this returns `nothing`, `save_discretes!` will not save anything.
412
419
"""
413
420
function get_saveable_values (sys, ps, timeseries_idx)
414
421
return get_saveable_values (symbolic_container (sys), ps, timeseries_idx)
415
422
end
416
423
424
+ """
425
+ save_discretes!(integ::DEIntegrator, timeseries_idx)
426
+
427
+ Save the parameter timeseries with index `timeseries_idx`. Calls `get_saveable_values` to
428
+ get the values to save. If it returns `nothing`, then the save does not happen.
429
+ """
417
430
function save_discretes! (integ:: DEIntegrator , timeseries_idx)
418
- save_discretes! (integ. sol, current_time (integ),
419
- get_saveable_values (integ, parameter_values (integ), timeseries_idx),
420
- timeseries_idx)
431
+ inner_sol = get_sol (integ)
432
+ vals = get_saveable_values (inner_sol, parameter_values (integ), timeseries_idx)
433
+ vals === nothing && return
434
+ save_discretes! (integ. sol, current_time (integ), vals, timeseries_idx)
421
435
end
422
436
423
437
save_discretes! (args... ) = nothing
@@ -451,6 +465,7 @@ function build_solution(prob::Union{AbstractODEProblem, AbstractDDEProblem},
451
465
interp = LinearInterpolation (t, u),
452
466
retcode = ReturnCode. Default, destats = missing , stats = nothing ,
453
467
resid = nothing , original = nothing ,
468
+ saved_subsystem = nothing ,
454
469
kwargs... )
455
470
T = eltype (eltype (u))
456
471
@@ -482,7 +497,12 @@ function build_solution(prob::Union{AbstractODEProblem, AbstractDDEProblem},
482
497
483
498
ps = parameter_values (prob)
484
499
if has_sys (prob. f)
485
- discretes = create_parameter_timeseries_collection (prob. f. sys, ps, prob. tspan)
500
+ sswf = if saved_subsystem === nothing
501
+ prob. f. sys
502
+ else
503
+ SavedSubsystemWithFallback (saved_subsystem, prob. f. sys)
504
+ end
505
+ discretes = create_parameter_timeseries_collection (sswf, ps, prob. tspan)
486
506
else
487
507
discretes = nothing
488
508
end
@@ -503,7 +523,8 @@ function build_solution(prob::Union{AbstractODEProblem, AbstractDDEProblem},
503
523
alg_choice,
504
524
retcode,
505
525
resid,
506
- original)
526
+ original,
527
+ saved_subsystem)
507
528
if calculate_error
508
529
calculate_solution_errors! (sol; timeseries_errors = timeseries_errors,
509
530
dense_errors = dense_errors)
@@ -524,7 +545,8 @@ function build_solution(prob::Union{AbstractODEProblem, AbstractDDEProblem},
524
545
alg_choice,
525
546
retcode,
526
547
resid,
527
- original)
548
+ original,
549
+ saved_subsystem)
528
550
end
529
551
end
530
552
0 commit comments