@@ -628,70 +628,77 @@ function ReactionSystem(eqs, iv, unknowns, ps;
628
628
continuous_events = nothing ,
629
629
discrete_events = nothing ,
630
630
metadata = nothing )
631
-
632
- name === nothing &&
631
+
632
+ # Error checks
633
+ if name === nothing &&
633
634
throw (ArgumentError (" The `name` keyword must be provided. Please consider using the `@named` macro" ))
635
+ end
634
636
sysnames = nameof .(systems)
635
- (length (unique (sysnames)) == length (sysnames)) ||
636
- throw (ArgumentError (" System names must be unique." ))
637
+ (length (unique (sysnames)) == length (sysnames)) || throw (ArgumentError (" System names must be unique." ))
637
638
639
+ # Handle defaults values provided via optional arguments.
638
640
if ! (isempty (default_u0) && isempty (default_p))
639
- Base. depwarn (" `default_u0` and `default_p` are deprecated. Use `defaults` instead." ,
640
- :ReactionSystem , force = true )
641
+ Base. depwarn (" `default_u0` and `default_p` are deprecated. Use `defaults` instead." , :ReactionSystem , force = true )
641
642
end
642
643
defaults = MT. todict (defaults)
643
644
defaults = Dict {Any, Any} (value (k) => value (v) for (k, v) in pairs (defaults))
644
645
646
+ # Extracts independent variables (iv and sivs), dependent variables (species and variables)
647
+ # and parameters. Sorts so that species comes before variables in unknowns vector.
645
648
iv′ = value (iv)
646
649
sivs′ = if spatial_ivs === nothing
647
650
Vector {typeof(iv′)} ()
648
651
else
649
652
value .(MT. scalarize (spatial_ivs))
650
653
end
651
- unknowns′ = sort! (value .(MT. scalarize (unknowns)), by = ! isspecies) # species come first
654
+ unknowns′ = sort! (value .(MT. scalarize (unknowns)), by = ! isspecies)
652
655
spcs = filter (isspecies, unknowns′)
653
656
ps′ = value .(MT. scalarize (ps))
654
657
658
+ # Checks that no (by Catalyst) forbidden symbols are used.
655
659
allsyms = Iterators. flatten ((ps′, unknowns′))
656
- all (sym -> getname (sym) ∉ forbidden_symbols_error, allsyms) ||
660
+ if ! all (sym -> getname (sym) ∉ forbidden_symbols_error, allsyms)
657
661
error (" Catalyst reserves the symbols $forbidden_symbols_error for internal use. Please do not use these symbols as parameters or unknowns/species." )
662
+ end
658
663
659
- # sort Reactions before Equations
664
+ # Handles reactions and equations. Sorts so that reactions are before equaions in the equations vector.
660
665
eqs′ = CatalystEqType[eq for eq in eqs]
661
666
sort! (eqs′; by = eqsortby)
662
667
rxs = Reaction[rx for rx in eqs if rx isa Reaction]
663
668
669
+ # Additional error checks.
664
670
if any (MT. isparameter, unknowns′)
665
671
psts = filter (MT. isparameter, unknowns′)
666
672
throw (ArgumentError (" Found one or more parameters among the unknowns; this is not allowed. Move: $psts to be parameters." ))
667
673
end
668
-
669
674
if any (isconstant, unknowns′)
670
675
csts = filter (isconstant, unknowns′)
671
676
throw (ArgumentError (" Found one or more constant species among the unknowns; this is not allowed. Move: $csts to be parameters." ))
672
677
end
673
-
674
- # if there are BC species, check they are balanced in their reactions
678
+ # If there are BC species, check they are balanced in their reactions.
675
679
if balanced_bc_check && any (isbc, unknowns′)
676
680
for rx in eqs
677
- if rx isa Reaction
678
- isbcbalanced (rx) ||
679
- throw (ErrorException (" BC species must be balanced, appearing as a substrate and product with the same stoichiometry. Please fix reaction: $rx " ))
681
+ if (rx isa Reaction) && ! isbcbalanced (rx)
682
+ throw (ErrorException (" BC species must be balanced, appearing as a substrate and product with the same stoichiometry. Please fix reaction: $rx " ))
680
683
end
681
684
end
682
685
end
683
686
687
+ # Adds all unknowns/parameters to the `var_to_name` vector.
688
+ # Adds their (potential) default values to the defaults vector.
684
689
var_to_name = Dict ()
685
690
MT. process_variables! (var_to_name, defaults, unknowns′)
686
691
MT. process_variables! (var_to_name, defaults, ps′)
687
692
MT. collect_var_to_name! (var_to_name, eq. lhs for eq in observed)
688
693
689
- nps = if networkproperties === nothing
690
- NetworkProperties {Int, get_speciestype(iv′, unknowns′, systems)} ()
694
+ # Computes network properties.
695
+ if networkproperties === nothing
696
+ nps = NetworkProperties {Int, get_speciestype(iv′, unknowns′, systems)} ()
691
697
else
692
- networkproperties
698
+ nps = networkproperties
693
699
end
694
700
701
+ # Creates the continious and discrete callbacks.
695
702
ccallbacks = MT. SymbolicContinuousCallbacks (continuous_events)
696
703
dcallbacks = MT. SymbolicDiscreteCallbacks (discrete_events)
697
704
@@ -705,77 +712,125 @@ function ReactionSystem(rxs::Vector, iv = Catalyst.DEFAULT_IV; kwargs...)
705
712
end
706
713
707
714
# search the symbolic expression for parameters or unknowns
708
- # and save in ps and sts respectively. vars is used to cache results
709
- function findvars! (ps, sts , exprtosearch, ivs, vars)
715
+ # and save in ps and us respectively. vars is used to cache results
716
+ function findvars! (ps, us , exprtosearch, ivs, vars)
710
717
MT. get_variables! (vars, exprtosearch)
711
718
for var in vars
712
719
(var ∈ ivs) && continue
713
720
if MT. isparameter (var)
714
721
push! (ps, var)
715
722
else
716
- push! (sts , var)
723
+ push! (us , var)
717
724
end
718
725
end
719
726
empty! (vars)
720
727
end
721
728
722
- # Only used internally by the @reaction_network macro. Permits giving an initial order to
723
- # the parameters, and then adds additional ones found in the reaction. Name could be
724
- # changed.
725
- function make_ReactionSystem_internal (rxs_and_eqs:: Vector , iv, sts_in, ps_in;
726
- spatial_ivs = nothing , kwargs... )
729
+ # Called internally (whether DSL-based or programmtic model creation is used).
730
+ # Creates a sorted reactions + equations vector, also ensuring reaction is first in this vector.
731
+ # Extracts potential species, variables, and parameters from the input (if not provided as part of
732
+ # the model creation) and creates the corresponding vectors.
733
+ # While species are ordered before variables in the unknowns vector, this ordering is not imposed here,
734
+ # but carried out at a later stage.
735
+ function make_ReactionSystem_internal (rxs_and_eqs:: Vector , iv, us_in, ps_in; spatial_ivs = nothing ,
736
+ continuous_events = [], discrete_events = [], kwargs... )
737
+
738
+ # Creates a combined iv vector (iv and sivs). This is used later in the function (so that
739
+ # independent variables can be exluded when encountered quantities are added to `us` and `ps`).
727
740
t = value (iv)
728
741
ivs = Set ([t])
729
742
if (spatial_ivs != = nothing )
730
743
for siv in (MT. scalarize (spatial_ivs))
731
744
push! (ivs, value (siv))
732
745
end
733
746
end
734
- sts = OrderedSet {eltype(sts_in)} (sts_in)
747
+
748
+ # Initialises the new unknowns and parameter vectors.
749
+ # Preallocates the `vars` set, which is used by `findvars!`
750
+ us = OrderedSet {eltype(us_in)} (us_in)
735
751
ps = OrderedSet {eltype(ps_in)} (ps_in)
736
752
vars = OrderedSet ()
737
753
754
+ # Extracts the reactions and equations from the combined reactions + equations input vector.
738
755
all (eq -> eq isa Union{Reaction, Equation}, rxs_and_eqs)
739
756
rxs = Reaction[eq for eq in rxs_and_eqs if eq isa Reaction]
740
757
eqs = Equation[eq for eq in rxs_and_eqs if eq isa Equation]
741
758
742
- # add species / parameters that are substrates / products first
743
- for rx in rxs, reactants in (rx. substrates, rx. products)
744
- for spec in reactants
745
- MT. isparameter (spec) ? push! (ps, spec) : push! (sts, spec)
746
- end
747
- end
748
-
759
+ # Loops through all reactions, adding encountered quantities to the unknown and parameter vectors.
749
760
for rx in rxs
750
- findvars! (ps, sts, rx . rate, ivs, vars)
751
- for s in rx. substoich
752
- (s isa Symbolic) && findvars ! (ps, sts, s, ivs, vars )
761
+ # Loops through all reaction substrates and products, extracting these.
762
+ for reactants in ( rx. substrates, rx . products), spec in reactants
763
+ MT . isparameter (spec) ? push ! (ps, spec) : push! (us, spec )
753
764
end
754
- for p in rx. prodstoich
755
- (p isa Symbolic) && findvars! (ps, sts, p, ivs, vars)
765
+
766
+ # Adds all quantitites encountered in the reaction's rate.
767
+ findvars! (ps, us, rx. rate, ivs, vars)
768
+
769
+ # Extracts all quantitites encountered within stoichiometries.
770
+ for stoichiometry in (rx. substoich, rx. prodstoich), sym in stoichiometry
771
+ (sym isa Symbolic) && findvars! (ps, us, sym, ivs, vars)
756
772
end
757
- end
758
773
759
- stsv = collect (sts)
760
- psv = collect (ps)
774
+ # Will appear here: add stuff from nosie scaling.
775
+ end
761
776
777
+ # Extracts any species, variables, and parameters that occur in (non-reaction) equations.
778
+ # Creates the new reactions + equations vector, `fulleqs` (sorted reactions first, equations next).
762
779
if ! isempty (eqs)
763
780
osys = ODESystem (eqs, iv; name = gensym ())
764
781
fulleqs = CatalystEqType[rxs; equations (osys)]
765
- union! (stsv , unknowns (osys))
766
- union! (psv , parameters (osys))
782
+ union! (us , unknowns (osys))
783
+ union! (ps , parameters (osys))
767
784
else
768
785
fulleqs = rxs
769
- end
786
+ end
770
787
771
- ReactionSystem (fulleqs, t, stsv, psv; spatial_ivs, kwargs... )
788
+ # Loops through all events, adding encountered quantities to the unknwon and parameter vectors.
789
+ find_event_vars! (ps, us, continuous_events, ivs, vars)
790
+ find_event_vars! (ps, us, discrete_events, ivs, vars)
791
+
792
+ # Converts the found unknowns and parameters to vectors.
793
+ usv = collect (us)
794
+ psv = collect (ps)
795
+
796
+ # Passes the processed input into the next `ReactionSystem` call.
797
+ ReactionSystem (fulleqs, t, usv, psv; spatial_ivs, continuous_events, discrete_events, kwargs... )
772
798
end
773
799
774
800
function ReactionSystem (iv; kwargs... )
775
801
ReactionSystem (Reaction[], iv, [], []; kwargs... )
776
802
end
777
803
778
-
804
+ # Loops through all events in an supplied event vector, adding all unknowns and parameters found in
805
+ # its condition and affect functions to their respective vectors (`ps` and `us`).
806
+ function find_event_vars! (ps, us, events:: Vector , ivs, vars)
807
+ foreach (event -> find_event_vars! (ps, us, event, ivs, vars), events)
808
+ end
809
+ # For a single event, adds quantitites from its condition and affect expression(s) to `ps` and `us`.
810
+ function find_event_vars! (ps, us, event, ivs, vars)
811
+ conds, affects = event
812
+ # For discrete events, the condition can be a single value (for periodic events).
813
+ # If not, it is a vector of conditions and we must check each.
814
+ if conds isa Vector
815
+ for cond in conds
816
+ # For continious events the conditions are equations (with lhs and rhs).
817
+ # For discrete events, they are single expressions.
818
+ if cond isa Equation
819
+ findvars! (ps, us, cond. lhs, ivs, vars)
820
+ findvars! (ps, us, cond. rhs, ivs, vars)
821
+ else
822
+ findvars! (ps, us, cond, ivs, vars)
823
+ end
824
+ end
825
+ else
826
+ findvars! (ps, us, conds, ivs, vars)
827
+ end
828
+ # The affects is always a vector of equations. Here, we handle the lhs and rhs separately.
829
+ for affect in affects
830
+ findvars! (ps, us, affect. lhs, ivs, vars)
831
+ findvars! (ps, us, affect. rhs, ivs, vars)
832
+ end
833
+ end
779
834
"""
780
835
remake_ReactionSystem_internal(rs::ReactionSystem;
781
836
default_reaction_metadata::Vector{Pair{Symbol, T}} = Vector{Pair{Symbol, Any}}()) where {T}
0 commit comments