@@ -233,8 +233,9 @@ function make_affect(affect::Vector{Equation}; iv = nothing, algeeqs = Equation[
233
233
dvs = OrderedSet ()
234
234
params = OrderedSet ()
235
235
for eq in affect
236
- ! haspre (eq) &&
236
+ if ! haspre (eq) && ! ( symbolic_type (eq . rhs) === NotSymbolic ())
237
237
@warn " Affect equation $eq has no `Pre` operator. As such it will be interpreted as an algebraic equation to be satisfied after the callback. If you intended to use the value of a variable x before the affect, use Pre(x)."
238
+ end
238
239
collect_vars! (dvs, params, eq, iv; op = Pre)
239
240
end
240
241
for eq in algeeqs
@@ -299,19 +300,19 @@ function SymbolicContinuousCallbacks(events; algeeqs::Vector{Equation} = Equatio
299
300
callbacks
300
301
end
301
302
302
- function Base. show (io:: IO , cb:: SymbolicContinuousCallback )
303
+ function Base. show (io:: IO , cb:: AbstractCallback )
303
304
indent = get (io, :indent , 0 )
304
305
iio = IOContext (io, :indent => indent + 1 )
305
- print (io, " SymbolicContinuousCallback(" )
306
- print (iio, " Equations :" )
306
+ is_discrete (cb) ? print (io, " SymbolicDiscreteCallback( " ) : print (io, " SymbolicContinuousCallback(" )
307
+ print (iio, " Conditions :" )
307
308
show (iio, equations (cb))
308
309
print (iio, " ; " )
309
310
if affects (cb) != nothing
310
311
print (iio, " Affect:" )
311
312
show (iio, affects (cb))
312
313
print (iio, " , " )
313
314
end
314
- if affect_negs (cb) != nothing
315
+ if ! is_discrete (cb) && affect_negs (cb) != nothing
315
316
print (iio, " Negative-edge affect:" )
316
317
show (iio, affect_negs (cb))
317
318
print (iio, " , " )
@@ -328,19 +329,19 @@ function Base.show(io::IO, cb::SymbolicContinuousCallback)
328
329
print (iio, " )" )
329
330
end
330
331
331
- function Base. show (io:: IO , mime:: MIME"text/plain" , cb:: SymbolicContinuousCallback )
332
+ function Base. show (io:: IO , mime:: MIME"text/plain" , cb:: AbstractCallback )
332
333
indent = get (io, :indent , 0 )
333
334
iio = IOContext (io, :indent => indent + 1 )
334
- println (io, " SymbolicContinuousCallback:" )
335
- println (iio, " Equations :" )
335
+ is_discrete (cb) ? println (io, " SymbolicDiscreteCallback: " ) : println (io, " SymbolicContinuousCallback:" )
336
+ println (iio, " Conditions :" )
336
337
show (iio, mime, equations (cb))
337
338
print (iio, " \n " )
338
339
if affects (cb) != nothing
339
340
println (iio, " Affect:" )
340
341
show (iio, mime, affects (cb))
341
342
print (iio, " \n " )
342
343
end
343
- if affect_negs (cb) != nothing
344
+ if ! is_discrete (cb) && affect_negs (cb) != nothing
344
345
print (iio, " Negative-edge affect:\n " )
345
346
show (iio, mime, affect_negs (cb))
346
347
print (iio, " \n " )
@@ -394,8 +395,8 @@ Arguments:
394
395
- algeeqs: Algebraic equations of the system that must be satisfied after the callback occurs.
395
396
"""
396
397
struct SymbolicDiscreteCallback <: AbstractCallback
397
- conditions:: Any
398
- affect:: Affect
398
+ conditions:: Union{Real, Vector{<:Real}, Vector{Equation}}
399
+ affect:: Union{ Affect, Nothing}
399
400
initialize:: Union{Affect, Nothing}
400
401
finalize:: Union{Affect, Nothing}
401
402
@@ -409,6 +410,9 @@ struct SymbolicDiscreteCallback <: AbstractCallback
409
410
end # Default affect to nothing
410
411
end
411
412
413
+ SymbolicDiscreteCallback (p:: Pair , args... ; kwargs... ) = SymbolicDiscreteCallback (p[1 ], p[2 ])
414
+ SymbolicDiscreteCallback (cb:: SymbolicDiscreteCallback , args... ; kwargs... ) = cb
415
+
412
416
"""
413
417
Generate discrete callbacks.
414
418
"""
@@ -438,29 +442,6 @@ function is_timed_condition(condition::T) where {T}
438
442
end
439
443
end
440
444
441
- function Base. show (io:: IO , db:: SymbolicDiscreteCallback )
442
- indent = get (io, :indent , 0 )
443
- iio = IOContext (io, :indent => indent + 1 )
444
- println (io, " SymbolicDiscreteCallback:" )
445
- println (iio, " Conditions:" )
446
- print (iio, " ; " )
447
- if affects (db) != nothing
448
- print (iio, " Affect:" )
449
- show (iio, affects (db))
450
- print (iio, " , " )
451
- end
452
- if initialize_affects (db) != nothing
453
- print (iio, " Initialization affect:" )
454
- show (iio, initialize_affects (db))
455
- print (iio, " , " )
456
- end
457
- if finalize_affects (db) != nothing
458
- print (iio, " Finalization affect:" )
459
- show (iio, finalize_affects (db))
460
- end
461
- print (iio, " )" )
462
- end
463
-
464
445
function vars! (vars, cb:: SymbolicDiscreteCallback ; op = Differential)
465
446
if symbolic_type (conditions (cb)) == NotSymbolic
466
447
if conditions (cb) isa AbstractArray
@@ -529,7 +510,7 @@ function namespace_callback(cb::SymbolicDiscreteCallback, s)::SymbolicDiscreteCa
529
510
end
530
511
531
512
function Base. hash (cb:: SymbolicContinuousCallback , s:: UInt )
532
- s = foldr (hash, cb. eqs , init = s)
513
+ s = foldr (hash, cb. conditions , init = s)
533
514
s = hash (cb. affect, s)
534
515
s = hash (cb. affect_neg, s)
535
516
s = hash (cb. initialize, s)
@@ -538,8 +519,8 @@ function Base.hash(cb::SymbolicContinuousCallback, s::UInt)
538
519
end
539
520
540
521
function Base. hash (cb:: SymbolicDiscreteCallback , s:: UInt )
541
- s = hash ( cb. condition, s)
542
- s = hash (cb. affects , s)
522
+ s = foldr (hash, cb. conditions, init = s)
523
+ s = hash (cb. affect , s)
543
524
s = hash (cb. initialize, s)
544
525
hash (cb. finalize, s)
545
526
end
649
630
"""
650
631
Compile user-defined functional affect.
651
632
"""
652
- function compile_functional_affect (affect:: FunctionalAffect , cb, sys, dvs, ps; kwargs... )
633
+ function compile_functional_affect (affect:: FunctionalAffect , cb, sys; kwargs... )
634
+ dvs = unknowns (sys)
635
+ ps = parameters (sys)
653
636
dvs_ind = Dict (reverse (en) for en in enumerate (dvs))
654
637
v_inds = map (sym -> dvs_ind[sym], unknowns (affect))
655
638
@@ -686,7 +669,18 @@ is_discrete(cb::Vector{<:AbstractCallback}) = eltype(cb) isa SymbolicDiscreteCal
686
669
function generate_continuous_callbacks (sys:: AbstractSystem , dvs = unknowns (sys), ps = parameters (sys; initial_parameters = true ); kwargs... )
687
670
cbs = continuous_events (sys)
688
671
isempty (cbs) && return nothing
689
- generate_callback (cbs, sys; kwargs... )
672
+ cb_classes = Dict {SciMLBase.RootfindOpt, Vector{SymbolicContinuousCallback}} ()
673
+ for cb in cbs
674
+ _cbs = get! (() -> SymbolicContinuousCallback[], cb_classes, cb. rootfind)
675
+ push! (_cbs, cb)
676
+ end
677
+ cb_classes = sort! (OrderedDict (cb_classes))
678
+ compiled_callbacks = [generate_callback (cb, sys; kwargs... ) for (rf, cb) in cb_classes]
679
+ if length (compiled_callbacks) == 1
680
+ return only (compiled_callbacks)
681
+ else
682
+ return CallbackSet (compiled_callbacks... )
683
+ end
690
684
end
691
685
692
686
function generate_discrete_callbacks (sys:: AbstractSystem , dvs = unknowns (sys), ps = parameters (sys; initial_parameters = true ); kwargs... )
@@ -716,9 +710,9 @@ function generate_callback(cbs::Vector{SymbolicContinuousCallback}, sys; kwargs.
716
710
finals = []
717
711
for cb in cbs
718
712
affect = compile_affect (cb. affect, cb, sys, default = (args... ) -> ())
719
-
720
713
push! (affects, affect)
721
- push! (affect_negs, compile_affect (cb. affect_neg, cb, sys, default = affect))
714
+ affect_neg = (cb. affect_neg === cb. affect) ? affect : compile_affect (cb. affect_neg, cb, sys, default = (args... ) -> ())
715
+ push! (affect_negs, affect_neg)
722
716
push! (inits, compile_affect (cb. initialize, cb, sys, default = nothing ))
723
717
push! (finals, compile_affect (cb. finalize, cb, sys, default = nothing ))
724
718
end
@@ -728,8 +722,6 @@ function generate_callback(cbs::Vector{SymbolicContinuousCallback}, sys; kwargs.
728
722
eq2affect = reduce (vcat,
729
723
[fill (i, num_eqs[i]) for i in eachindex (affects)])
730
724
eqs = reduce (vcat, eqs)
731
- @assert length (eq2affect) == length (eqs)
732
- @assert maximum (eq2affect) == length (affects)
733
725
734
726
affect = function (integ, idx)
735
727
affects[eq2affect[idx]](integ)
@@ -744,7 +736,7 @@ function generate_callback(cbs::Vector{SymbolicContinuousCallback}, sys; kwargs.
744
736
745
737
return VectorContinuousCallback (
746
738
trigger, affect, affect_neg, length (eqs); initialize, finalize,
747
- rootfind = cbs[1 ]. rootfind, initializealg = SciMLBase. NoInit)
739
+ rootfind = cbs[1 ]. rootfind, initializealg = SciMLBase. NoInit () )
748
740
end
749
741
750
742
function generate_callback (cb, sys; kwargs... )
@@ -762,16 +754,16 @@ function generate_callback(cb, sys; kwargs...)
762
754
if is_discrete (cb)
763
755
if is_timed && conditions (cb) isa AbstractVector
764
756
return PresetTimeCallback (trigger, affect; initialize,
765
- finalize, initializealg = SciMLBase. NoInit)
757
+ finalize, initializealg = SciMLBase. NoInit () )
766
758
elseif is_timed
767
759
return PeriodicCallback (affect, trigger; initialize, finalize)
768
760
else
769
761
return DiscreteCallback (trigger, affect; initialize,
770
- finalize, initializealg = SciMLBase. NoInit)
762
+ finalize, initializealg = SciMLBase. NoInit () )
771
763
end
772
764
else
773
765
return ContinuousCallback (trigger, affect, affect_neg; initialize, finalize,
774
- rootfind = cb. rootfind, initializealg = SciMLBase. NoInit)
766
+ rootfind = cb. rootfind, initializealg = SciMLBase. NoInit () )
775
767
end
776
768
end
777
769
@@ -793,27 +785,25 @@ Notes
793
785
"""
794
786
function compile_affect (
795
787
aff:: Union{Nothing, Affect} , cb:: AbstractCallback , sys:: AbstractSystem ; default = nothing , kwargs... )
788
+ isnothing (aff) && return default
789
+
796
790
save_idxs = if ! (has_index_cache (sys) && (ic = get_index_cache (sys)) != = nothing )
797
791
Int[]
798
792
else
799
793
get (ic. callback_to_clocks, cb, Int[])
800
794
end
801
795
802
- isnothing (aff) && return default
803
-
804
- ps = parameters (aff)
805
- dvs = unknowns (aff)
806
- dvs_to_modify = setdiff (dvs, getfield .(observed (sys), :lhs ))
807
-
808
796
if aff isa AffectSystem
809
797
affsys = system (aff)
810
798
aff_map = aff_to_sys (aff)
811
799
sys_map = Dict ([v => k for (k, v) in aff_map])
812
800
reinit = has_alg_eqs (sys)
801
+ ps_to_modify = discretes (aff)
802
+ dvs_to_modify = setdiff (unknowns (aff), getfield .(observed (sys), :lhs ))
813
803
814
804
function affect! (integrator)
815
805
pmap = Pair[]
816
- for pre_p in previous_vals (aff )
806
+ for pre_p in parameters (affsys )
817
807
p = only (arguments (unwrap (pre_p)))
818
808
pval = isparameter (p) ? integrator. ps[p] : integrator[p]
819
809
push! (pmap, pre_p => pval)
@@ -825,17 +815,17 @@ function compile_affect(
825
815
for u in dvs_to_modify
826
816
integrator[u] = affsol[sys_map[u]]
827
817
end
828
- for p in discretes (aff)
818
+ for p in ps_to_modify
829
819
integrator. ps[p] = affsol[sys_map[p]]
830
820
end
831
821
for idx in save_idxs
832
- SciMLBase. save_discretes! (integ , idx)
822
+ SciMLBase. save_discretes! (integrator , idx)
833
823
end
834
824
835
825
sys isa JumpSystem && reset_aggregated_jumps! (integrator)
836
826
end
837
827
elseif aff isa FunctionalAffect || aff isa ImperativeAffect
838
- compile_functional_affect (aff, cb, sys, dvs, ps ; kwargs... )
828
+ compile_functional_affect (aff, cb, sys; kwargs... )
839
829
end
840
830
end
841
831
0 commit comments