Skip to content

Commit

Permalink
Merge pull request #931 from SciML/serialization_updates
Browse files Browse the repository at this point in the history
`ReactionSystem` serialisation update
  • Loading branch information
TorkelE committed Jun 9, 2024
2 parents 59294a5 + e575fb5 commit 8fbdc46
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/reactionsystem_serialisation/serialisation_support.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ end
function make_strip_call_dict(syms)
return Dict([sym => strip_call(Symbolics.unwrap(sym)) for sym in syms])
end

# If the input is a `ReactionSystem`, extracts the unknowns (i.e. syms depending on another variable).
function make_strip_call_dict(rn::ReactionSystem)
return make_strip_call_dict(get_unknowns(rn))
end
Expand Down
23 changes: 22 additions & 1 deletion src/reactionsystem_serialisation/serialise_fields.jl
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ EQUATIONS_FS = (seri_has_equations, get_equations_string, get_equations_annotati

# Checks if the reaction system has any observables.
function seri_has_observed(rn::ReactionSystem)
return !isempty(observed(rn))
return !isempty(get_observed(rn))
end

# Extract a string which declares the system's observables.
Expand Down Expand Up @@ -354,6 +354,27 @@ end
# Combines the 3 -related functions in a constant tuple.
OBSERVED_FS = (seri_has_observed, get_observed_string, get_observed_annotation)

### Handles Observables ###

# Checks if the reaction system has any defaults.
function seri_has_defaults(rn::ReactionSystem)
return !isempty(get_defaults(rn))
end

# Extract a string which declares the system's defaults.
function get_defaults_string(rn::ReactionSystem)
defaults_string = "defaults = " * x_2_string(get_defaults(rn))
return defaults_string
end

# Creates an annotation for the system's defaults.
function get_defaults_annotation(rn::ReactionSystem)
return "Defaults:"
end

# Combines the 3 defaults-related functions in a constant tuple.
DEFAULTS_FS = (seri_has_defaults, get_defaults_string, get_defaults_annotation)

### Handles Continuous Events ###

# Checks if the reaction system have has continuous events.
Expand Down
19 changes: 13 additions & 6 deletions src/reactionsystem_serialisation/serialise_reactionsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ Notes:
"""
function save_reactionsystem(filename::String, rn::ReactionSystem;
annotate = true, safety_check = true)
# Error and warning checks.
reactionsystem_uptodate_check()
if !isempty(get_networkproperties(rn))
@warn "The serialised network has cached network properties (e.g. computed conservation laws). This will not be saved as part of the network, and must be recomputed when it is loaded."
end

# Write model to file and performs a safety check.
open(filename, "w") do file
write(file, get_full_system_string(rn, annotate, true))
end
Expand Down Expand Up @@ -65,6 +71,7 @@ function get_full_system_string(rn::ReactionSystem, annotate::Bool, top_level::B
file_text, has_reactions = push_field(file_text, rn, annotate, top_level, REACTIONS_FS)
file_text, has_equations = push_field(file_text, rn, annotate, top_level, EQUATIONS_FS)
file_text, has_observed = push_field(file_text, rn, annotate, top_level, OBSERVED_FS)
file_text, has_defaults = push_field(file_text, rn, annotate, top_level, DEFAULTS_FS)
file_text, has_continuous_events = push_field(file_text, rn, annotate,
top_level, CONTINUOUS_EVENTS_FS)
file_text, has_discrete_events = push_field(file_text, rn, annotate,
Expand All @@ -78,7 +85,7 @@ function get_full_system_string(rn::ReactionSystem, annotate::Bool, top_level::B
rs_creation_code = make_reaction_system_call(
rn, annotate, top_level, has_sivs, has_species,
has_variables, has_parameters, has_reactions,
has_equations, has_observed, has_continuous_events,
has_equations, has_observed, has_defaults, has_continuous_events,
has_discrete_events, has_systems, has_connection_type)
annotate || (@string_prepend! "\n" file_text)
@string_prepend! "let" file_text
Expand All @@ -89,11 +96,10 @@ end

# Creates a ReactionSystem call for creating the model. Adds all the correct inputs to it. The input
# `has_` `Bool`s described which inputs are used. If the model is `complete`, this is handled here.
function make_reaction_system_call(
rs::ReactionSystem, annotate, top_level, has_sivs, has_species,
has_variables, has_parameters, has_reactions, has_equations,
has_observed, has_continuous_events, has_discrete_events,
has_systems, has_connection_type)
function make_reaction_system_call(rs::ReactionSystem, annotate, top_level, has_sivs,
has_species, has_variables, has_parameters, has_reactions, has_equations,
has_observed, has_defaults, has_continuous_events, has_discrete_events, has_systems,
has_connection_type)

# Gets the independent variable input.
iv = x_2_string(get_iv(rs))
Expand Down Expand Up @@ -141,6 +147,7 @@ function make_reaction_system_call(
# Goes through various fields that might exists, and if so, adds them to the string.
has_sivs && (@string_append! reaction_system_string ", spatial_ivs")
has_observed && (@string_append! reaction_system_string ", observed")
has_defaults && (@string_append! reaction_system_string ", defaults")
has_continuous_events && (@string_append! reaction_system_string ", continuous_events")
has_discrete_events && (@string_append! reaction_system_string ", discrete_events")
has_systems && (@string_append! reaction_system_string ", systems")
Expand Down
Empty file removed test/failed_serialisation.jl
Empty file.
25 changes: 25 additions & 0 deletions test/miscellaneous_tests/reactionsystem_serialisation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,30 @@ end

### Other Tests ###

# Checks that systems with cached network properties yields a warning.
# Checks that default values as saved properly (even if they have different types).
let
# Prepares model inputs.
@species X1(t) X2(t)
@parameters k1 k2::Int64
rxs = [
Reaction(k1, [X1], [X2]),
Reaction(k2, [X2], [X1])
]
defaults = Dict((X1 => 1.0, k2 => 2))

# Creates model and computes conservation laws.
@named rs = ReactionSystem(rxs, t; defaults)
conservationlaws(rs)

# Serialises model and then loads and checks it.
@test_logs (:warn, ) match_mode=:any save_reactionsystem("serialised_rs.jl", rs)
rs_loaded = include("../serialised_rs.jl")
@test rs == rs_loaded
@test ModelingToolkit.get_defaults(rs) == ModelingToolkit.get_defaults(rs_loaded)
rm("serialised_rs.jl")
end

# Tests that an error is generated when non-`ReactionSystem` subs-systems are used.
let
@variables V(t)
Expand All @@ -415,6 +439,7 @@ let
@named osys = ODESystem([eq], t)
@named rs = ReactionSystem(rxs, t; systems = [osys])
@test_throws Exception save_reactionsystem("failed_serialisation.jl", rs)
rm("failed_serialisation.jl")
end

# Checks that completeness is recorded correctly.
Expand Down

0 comments on commit 8fbdc46

Please sign in to comment.