Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReactionSystem serialisation update #931

Merged
merged 2 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading