Skip to content

Commit 0db6bf3

Browse files
committed
basic nameswapping utility for SimBiology
1 parent 9499c47 commit 0db6bf3

File tree

6 files changed

+128
-0
lines changed

6 files changed

+128
-0
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.1.19"
77
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
88
MathML = "abcecc63-2b08-419c-80c4-c63dca6fa478"
99
SBML = "e5567a89-2604-4b09-9718-f5f78e97c3bb"
10+
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
1011
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
1112

1213
[compat]

src/SBMLToolkit.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ module SBMLToolkit
33
using Catalyst
44
using SBML
55
using SymbolicUtils
6+
using Setfield
67

78
include("systems.jl")
89
include("reactions.jl")
910
include("rules.jl")
1011
include("events.jl")
1112
include("utils.jl")
13+
include("nameswap.jl")
1214

1315
export ReactionSystem, ODESystem
1416
export readSBML, readSBMLFromString, set_level_and_version, convert_simplify_math

src/nameswap.jl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
function swap_id_name(k, v; prop = :name)
2+
new_prop = getproperty(v, prop)
3+
@set! v.$prop = k
4+
new_prop, v
5+
end
6+
7+
function replace_math_ident(id_name_dict, node)
8+
if typeof(node) == SBML.MathIdent
9+
return SBML.MathIdent(id_name_dict[node.id])
10+
elseif typeof(node) == SBML.MathApply
11+
return SBML.MathApply(node.fn, replace_math_ident(id_name_dict, node.args))
12+
elseif isa(node, AbstractArray)
13+
return map(x -> replace_math_ident(id_name_dict, x), node)
14+
else
15+
return node
16+
end
17+
end
18+
19+
"SimBiology makes the names of everything a hashed ID, but keeps the ID in the name"
20+
function fix_simbio_names(m::SBML.Model)
21+
cid_name_d = Dict(keys(m.compartments) .=> getproperty.(values(m.compartments), :name))
22+
pid_name_d = Dict(keys(m.parameters) .=> getproperty.(values(m.parameters), :name))
23+
rid_name_d = Dict(keys(m.reactions) .=> getproperty.(values(m.reactions), :name))
24+
25+
for prop in [:compartments, :parameters, :reactions]
26+
xs = getproperty(m, prop)
27+
new_xs = Dict()
28+
for (k, v) in xs
29+
nk, nv = swap_id_name(k, v)
30+
new_xs[nk] = nv
31+
end
32+
@set! m.$prop = new_xs
33+
end
34+
35+
new_ss = Dict()
36+
for (k, v) in m.species
37+
nk, nv = swap_id_name(k, v)
38+
cname = cid_name_d[v.compartment]
39+
# for species, we want to concat the name and compartment name like in simbiology and MTK
40+
sname = string(cname, "", nk)
41+
@set! nv.compartment = cname
42+
new_ss[sname] = nv
43+
end
44+
@set! m.species = new_ss
45+
46+
sid_name_d = Dict(reverse.(keys(new_ss) .=> getproperty.(values(new_ss), :name)))
47+
48+
ds = [cid_name_d, pid_name_d, rid_name_d, sid_name_d]
49+
slen = sum(length.(ds))
50+
id_name_dict = merge(ds...)
51+
@assert slen == length(id_name_dict)
52+
53+
for (k, v) in m.reactions
54+
for (i, sr) in enumerate(v.reactants)
55+
@set! sr.species = id_name_dict[sr.species]
56+
m.reactions[k].reactants[i] = sr
57+
end
58+
for (i, sr) in enumerate(v.products)
59+
@set! sr.species = id_name_dict[sr.species]
60+
m.reactions[k].products[i] = sr
61+
end
62+
@set! m.reactions[k].kinetic_math = replace_math_ident(id_name_dict, v.kinetic_math)
63+
end
64+
65+
for (i, r) in enumerate(m.rules)
66+
@set! m.rules[i].variable = id_name_dict[r.variable]
67+
new_tree = replace_math_ident(id_name_dict, r.math)
68+
@set! m.rules[i].math = new_tree
69+
end
70+
71+
m
72+
end

test/data/simpleModel.sbml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<sbml xmlns="http://www.sbml.org/sbml/level2/version4" level="2" version="4">
3+
<annotation>
4+
<SimBiology xmlns="http://www.mathworks.com">
5+
<Version Major="6" Minor="4" Point="0"/>
6+
</SimBiology>
7+
</annotation>
8+
<model id="mw97c68eca_aecf_484b_b128_48c812a0c25c" name="simpleModel">
9+
<listOfCompartments>
10+
<compartment id="mwfb3bbd58_15e9_4f26_9be2_0c1221191847" name="unnamed" size="1" constant="true"/>
11+
</listOfCompartments>
12+
<listOfSpecies>
13+
<species id="mw31016a43_49a9_41bf_8a3f_346484470a6e" name="A" compartment="mwfb3bbd58_15e9_4f26_9be2_0c1221191847" initialConcentration="10" boundaryCondition="false" constant="false"/>
14+
<species id="mw6966d9de_9719_43d5_8fbe_40a117eee9c7" name="B" compartment="mwfb3bbd58_15e9_4f26_9be2_0c1221191847" initialConcentration="0" boundaryCondition="false" constant="false"/>
15+
</listOfSpecies>
16+
<listOfReactions>
17+
<reaction id="mw8998ca1f_76ee_4090_948e_b455153beda5" name="Reaction_1" reversible="false">
18+
<listOfReactants>
19+
<speciesReference species="mw31016a43_49a9_41bf_8a3f_346484470a6e" stoichiometry="1"/>
20+
</listOfReactants>
21+
<listOfProducts>
22+
<speciesReference species="mw6966d9de_9719_43d5_8fbe_40a117eee9c7" stoichiometry="1"/>
23+
</listOfProducts>
24+
<kineticLaw>
25+
<math xmlns="http://www.w3.org/1998/Math/MathML">
26+
<apply>
27+
<times/>
28+
<ci> mwbb21d5b0_5b44_4d2f_8d51_1aaff3f8bf6d </ci>
29+
<ci> mw31016a43_49a9_41bf_8a3f_346484470a6e </ci>
30+
</apply>
31+
</math>
32+
<listOfParameters>
33+
<parameter id="mwbb21d5b0_5b44_4d2f_8d51_1aaff3f8bf6d" name="k" value="0.5" constant="true"/>
34+
</listOfParameters>
35+
</kineticLaw>
36+
</reaction>
37+
</listOfReactions>
38+
</model>
39+
</sbml>

test/nameswap.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using SBML
2+
3+
sbml_fn = joinpath(@__DIR__, "data/simpleModel.sbml")
4+
5+
m_ = readSBML(sbml_fn, doc -> begin
6+
set_level_and_version(3, 2)(doc)
7+
convert_simplify_math(doc)
8+
end)
9+
10+
m = deepcopy(m_)
11+
m2 = SBML.fix_simbio_names(m)
12+
13+
@test keys(m2.species) == Set(["unnamed₊A", "unnamed₊B"])

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ using SafeTestsets, Test
88
@safetestset "Utils" begin include("utils.jl") end
99
@safetestset "Simulation results" begin include("simresults.jl") end
1010
@safetestset "Wuschel" begin include("wuschel.jl") end
11+
@safetestset "Nameswap" begin include("nameswap.jl") end
1112
end

0 commit comments

Comments
 (0)