Skip to content

Commit bc1833d

Browse files
committed
save progress
1 parent 51d1dc7 commit bc1833d

File tree

3 files changed

+87
-33
lines changed

3 files changed

+87
-33
lines changed

src/reactionsystem_serialisation/serialisation_support.jl

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ macro string_prepend!(input1, input2, string)
2121
return esc(:($string = $rhs))
2222
end
2323

24+
# Gets the character at a specific index.
25+
get_char(str, idx) = collect(str)[idx]
26+
get_char_end(str, offset) = collect(str)[end - offset]
27+
# Gets a substring (which is robust to unicode characters like η).
28+
get_substring(str, idx1, idx2) = String(collect(str)[idx1, idx2])
29+
get_substring_end(str, idx1, offset) = String(collect(str)[idx1, end - offset])
30+
2431

2532
### Field Serialisation Support Functions ###
2633

@@ -72,7 +79,7 @@ end
7279
# any calls (e.g. X(t) becomes X). E.g. a species vector [X, Y, Z] is converted to "[X, Y, Z]".
7380
function syms_2_strings(syms)
7481
strip_called_syms = [strip_call(Symbolics.unwrap(sym)) for sym in syms]
75-
return "$(convert(Vector{Any}, strip_called_syms))"[4:end]
82+
return get_substring("$(convert(Vector{Any}, strip_called_syms))", 4)
7683
end
7784

7885
# Converts a vector of symbolics (e.g. the species or parameter vectors) to a string corresponding to
@@ -100,10 +107,10 @@ function sym_2_declaration_string(sym; multiline_format = false)
100107
# to ensure that this is the case.
101108
if !(sym isa SymbolicUtils.BasicSymbolic{Real})
102109
sym_type = String(Symbol(typeof(Symbolics.unwrap(sym))))
103-
if (sym_type[1:28] != "SymbolicUtils.BasicSymbolic{") || (sym_type[end] != '}')
110+
if (get_substring(sym_type, 1, 28) != "SymbolicUtils.BasicSymbolic{") || (get_char_end(sym_type, 0) != '}')
104111
error("Encountered symbolic of unexpected type: $sym_type.")
105112
end
106-
@string_append! dec_string "::" sym_type[29:end-1]
113+
@string_append! dec_string "::" get_substring_end(sym_type, 29, -1)
107114
end
108115

109116
# If there is a default value, adds this to the declaration.
@@ -120,7 +127,7 @@ function sym_2_declaration_string(sym; multiline_format = false)
120127
for metadata in metadata_to_declare
121128
@string_append! metadata_string metadata_2_string(sym, metadata) ", "
122129
end
123-
@string_append! dec_string metadata_string[1:end-2] "]"
130+
@string_append! dec_string $(get_substring_end(metadata_string, 1, -2)) "]"
124131
end
125132

126133
# Returns the declaration entry for the symbol.
@@ -145,31 +152,31 @@ function x_2_string(x::Vector)
145152
for val in x
146153
@string_append! output x_2_string(val) ", "
147154
end
148-
return output[1:end-2] * "]"
155+
return get_substring_end(output, 1, -2) * "]"
149156
end
150157
function x_2_string(x::Tuple)
151158
output = "("
152159
for val in x
153160
@string_append! output x_2_string(val) ", "
154161
end
155-
return output[1:end-2] * ")"
162+
return get_substring_end(output, 1, -2) * ")"
156163
end
157164
function x_2_string(x::Dict)
158165
output = "Dict(["
159166
for key in keys(x)
160167
@string_append! output x_2_string(key) " => " x_2_string(x[key]) ", "
161168
end
162-
return output[1:end-2] * "])"
169+
return get_substring_end(output, 1, -2) * "])"
163170
end
164171
function x_2_string(x::Union{Matrix, Symbolics.Arr{Any, 2}})
165172
output = "["
166173
for j = 1:size(x)[1]
167174
for i = 1:size(x)[2]
168175
@string_append! output x_2_string(x[j,i]) " "
169176
end
170-
output = output[1:end-1] * "; "
177+
output = get_substring_end(output, 1, -1) * "; "
171178
end
172-
return output[1:end-2] *"]"
179+
return get_substring_end(output, 1, -2) *"]"
173180
end
174181

175182

src/reactionsystem_serialisation/serialise_fields.jl

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function handle_us_n_ps(file_text::String, rn::ReactionSystem, annotate::Bool, t
8787
p_deps && (@string_append! us_n_ps_string "parameters, ")
8888
sp_deps && (@string_append! us_n_ps_string "species, ")
8989
var_deps && (@string_append! us_n_ps_string "variables, ")
90-
us_n_ps_string = us_n_ps_string[1:end-2]
90+
us_n_ps_string = get_substring_end(us_n_ps_string, 1, -2)
9191
@string_append! us_n_ps_string " depends on the declaration of other parameters, species, and/or variables.\n# These are specially handled here.\n"
9292
end
9393

@@ -117,7 +117,7 @@ function handle_us_n_ps(file_text::String, rn::ReactionSystem, annotate::Bool, t
117117
p_deps && (@string_append! us_n_ps_string "ps = " syms_2_strings(ps_all) "\n")
118118
sp_deps && (@string_append! us_n_ps_string "sps = " syms_2_strings(sps_all) "\n")
119119
var_deps && (@string_append! us_n_ps_string "vars = " syms_2_strings(vars_all) "\n")
120-
us_n_ps_string = us_n_ps_string[1:end-1]
120+
us_n_ps_string = get_substring_end(us_n_ps_string, 1, -1)
121121
end
122122

123123
# If this is not a top-level system, `local ` must be added to all declarations.
@@ -217,7 +217,9 @@ function get_reactions_string(rn::ReactionSystem)
217217
strip_call_dict = make_strip_call_dict(rn)
218218

219219
# Handles the case with one reaction separately. Only effect is nicer formatting.
220-
(length(get_rxs(rn)) == 1) && (return "rxs = [$(reaction_string(rx, strip_call_dict))]")
220+
if length(get_rxs(rn)) == 1
221+
return "rxs = [$(reaction_string(get_rxs(rn)[1], strip_call_dict))]"
222+
end
221223

222224
# Creates the string corresponding to the code which generates the system's reactions.
223225
rxs_string = "rxs = ["
@@ -226,7 +228,7 @@ function get_reactions_string(rn::ReactionSystem)
226228
end
227229

228230
# Updates the string (including removing the last `,`) and returns it.
229-
return rxs_string[1:end-1] * "\n]"
231+
return get_substring_end(rxs_string, 1, -1) * "\n]"
230232
end
231233

232234
# Creates a string that corresponds to the declaration of a single `Reaction`.
@@ -251,7 +253,7 @@ function reaction_string(rx::Reaction, strip_call_dict)
251253
metadata_entry = "$(x_2_string(entry)), "
252254
@string_append! rx_string metadata_entry
253255
end
254-
rx_string = rx_string[1:end-2] * "]"
256+
rx_string = get_substring_end(rx_string, 1, -2) * "]"
255257
end
256258

257259
# Returns the Reaction string.
@@ -291,7 +293,7 @@ function get_equations_string(rn::ReactionSystem)
291293
end
292294

293295
# Updates the string (including removing the last `,`) and returns it.
294-
return eqs_string[1:end-1] * "\n]"
296+
return get_substring_end(eqs_string, 1, -1) * "\n]"
295297
end
296298

297299
# Creates an annotation for the system's equations.
@@ -378,7 +380,7 @@ function get_continuous_events_string(rn::ReactionSystem)
378380
end
379381

380382
# Updates the string (including removing the last `,`) and returns it.
381-
return continuous_events_string[1:end-1] * "\n]"
383+
return get_substring_end(continuous_events_string, 1, -1) * "\n]"
382384
end
383385

384386
# Creates a string that corresponds to the declaration of a single continuous event.
@@ -388,7 +390,7 @@ function continuous_event_string(continuous_event, strip_call_dict)
388390
for eq in continuous_event.eqs
389391
@string_append! eqs_string expression_2_string(eq; strip_call_dict) ", "
390392
end
391-
eqs_string = eqs_string[1:end-2] * "]"
393+
eqs_string = get_substring_end(eqs_string, 1, -2) * "]"
392394

393395
# Creates the string corresponding to the affects.
394396
# Continuous events' `affect` field should probably be called `affects`. Likely the `s` was
@@ -397,7 +399,7 @@ function continuous_event_string(continuous_event, strip_call_dict)
397399
for affect in continuous_event.affect
398400
@string_append! affects_string expression_2_string(affect; strip_call_dict) ", "
399401
end
400-
affects_string = affects_string[1:end-2] * "]"
402+
affects_string = get_substring_end(affects_string, 1, -2) * "]"
401403

402404
return eqs_string * " => " * affects_string
403405
end
@@ -435,7 +437,7 @@ function get_discrete_events_string(rn::ReactionSystem)
435437
end
436438

437439
# Updates the string (including removing the last `,`) and returns it.
438-
return discrete_events_string[1:end-1] * "\n]"
440+
return get_substring_end(discrete_events_string, 1, -1) * "\n]"
439441
end
440442

441443
# Creates a string that corresponds to the declaration of a single discrete event.
@@ -453,7 +455,7 @@ function discrete_event_string(discrete_event, strip_call_dict)
453455
for affect in discrete_event.affects
454456
@string_append! affects_string expression_2_string(affect; strip_call_dict) ", "
455457
end
456-
affects_string = affects_string[1:end-2] * "]"
458+
affects_string = get_substring_end(affects_string, 1, -2) * "]"
457459

458460
return condition_string * " => " * affects_string
459461
end
@@ -504,7 +506,7 @@ function get_systems_string(rn::ReactionSystem, annotate::Bool)
504506
# Manipulates the subsystem declaration to make it nicer.
505507
subsystem_string = get_full_system_string(system, annotate, false)
506508
subsystem_string = replace(subsystem_string, "\n" => "\n\t")
507-
subsystem_string = "let\n" * subsystem_string[7:end-6] * "end"
509+
subsystem_string = "let\n" * get_substring_end(subsystem_string, 7, -6) * "end"
508510
@string_append! systems_string "\nsystems[$idx] = " subsystem_string
509511
end
510512

test/miscellaneous_tests/reactionsystem_serialisation.jl

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Fetch packages.
44
using Catalyst
5+
using Catalyst: get_rxs
56
using ModelingToolkit: getdefault, getdescription, get_metadata
67

78
# Creates missing getters for MTK metadata (can be removed once added to MTK).
@@ -20,21 +21,63 @@ D = default_time_deriv()
2021
# Checks annotated and non-annotated files against manually written ones.
2122
let
2223
# Creates and serialises the model.
23-
rn = @reaction_system begin
24+
rn = @reaction_network rn begin
2425
@observables X2 ~ 2X
2526
@equations D(V) ~ 1 - V
26-
(p,d), 0 <--> X
27+
d, X --> 0
2728
end
2829
save_reaction_network("test_serialisation_annotated.jl", rn; safety_check = false)
2930
save_reaction_network("test_serialisation.jl", rn; annotate = false, safety_check = false)
3031

3132
# Checks equivalence.
3233
file_string_annotated = read("test_serialisation_annotated.jl", String)
3334
file_string = read("test_serialisation.jl", String)
34-
file_string_annotated_real = ""
35-
file_string_real = ""
35+
file_string_annotated_real = """let
36+
37+
# Independent variable:
38+
@variables t
39+
40+
# Parameters:
41+
ps = @parameters d
42+
43+
# Species:
44+
sps = @species X(t)
45+
46+
# Variables:
47+
vars = @variables V(t)
48+
49+
# Reactions:
50+
rxs = [Reaction(d, [X], nothing, [1], nothing)]
51+
52+
# Equations:
53+
eqs = [Differential(t)(V) ~ 1 - V]
54+
55+
# Observables:
56+
@variables X2(t)
57+
observed = [X2 ~ 2X]
58+
59+
# Declares ReactionSystem model:
60+
rs = ReactionSystem([rxs; eqs], t, [sps; vars], ps; name = :rn, observed)
61+
complete(rs)
62+
63+
end"""
64+
file_string_real = """let
65+
66+
@variables t
67+
ps = @parameters d
68+
sps = @species X(t)
69+
vars = @variables V(t)
70+
rxs = [Reaction(d, [X], nothing, [1], nothing)]
71+
eqs = [Differential(t)(V) ~ 1 - V]
72+
@variables X2(t)
73+
observed = [X2 ~ 2X]
74+
75+
rs = ReactionSystem([rxs; eqs], t, [sps; vars], ps; name = :rn, observed)
76+
complete(rs)
77+
78+
end"""
3679
@test file_string_annotated == file_string_annotated_real
37-
@test file == file_string_real
80+
@test file_string == file_string_real
3881

3982
# Deletes the files.
4083
rm("test_serialisation_annotated.jl")
@@ -95,8 +138,10 @@ let
95138
end
96139

97140
# Creates the hierarchical model. Adds metadata to both reactions and the systems.
141+
# First reaction has `+ s + r` as that is easier than manually listing all symbolics.
142+
# (These needs to be part of the system somehow, as they are only added through the `misc` metadata)
98143
rxs1 = [
99-
Reaction(a + A, [X], [], metadata = [:misc => bool_md])
144+
Reaction(a + A + s + r, [X], [], metadata = [:misc => bool_md])
100145
Reaction(b + B, [Y], [], metadata = [:misc => int_md])
101146
Reaction(c + C, [Z], [], metadata = [:misc => sym_md])
102147
Reaction(d1 + D1, [V1], [], metadata = [:misc => str_md])
@@ -329,15 +374,15 @@ let
329374
X3 ~ 3*X
330375
end
331376
@continuous_events begin
332-
X2 < 5.0 => [X ~ X + 1.0]
333-
X3 > 20.0 => [X ~ X - 1.0]
377+
[X ~ 5.0] => [X ~ X + 1.0]
378+
[X ~ 20.0] => [X ~ X - 1.0]
334379
end
335-
@discrete_events [5.0 => d ~ d/2]
380+
@discrete_events 5.0 => [d ~ d/2]
336381
d, X --> 0
337382
end
338383

339384
# Checks that serialisation works.
340-
save_reaction_network("serialised_rs", rs; safety_check = false)
385+
save_reaction_network("serialised_rs.jl", rs; safety_check = false)
341386
@test isequal(rs, include("serialised_rs.jl"))
342387
rm("serialised_rs.jl")
343388
end
@@ -371,7 +416,7 @@ let
371416
save_reaction_network("serialised_rs_complete.jl", rs_complete)
372417
rs_complete_loaded = include("serialised_rs_complete.jl")
373418
@test ModelingToolkit.iscomplete(rs_complete_loaded)
374-
rn("serialised_rs_complete.jl")
419+
rm("serialised_rs_complete.jl")
375420

376421
# Checks for non-complete system.
377422
rs_incomplete = @network_component begin
@@ -380,5 +425,5 @@ let
380425
save_reaction_network("serialised_rs_incomplete.jl", rs_incomplete)
381426
rs_incomplete_loaded = include("serialised_rs_incomplete.jl")
382427
@test !ModelingToolkit.iscomplete(rs_incomplete_loaded)
383-
rn("serialised_rs_incomplete.jl")
428+
rm("serialised_rs_incomplete.jl")
384429
end

0 commit comments

Comments
 (0)