Skip to content

Commit 9128de0

Browse files
Merge pull request #48 from siravan/master
ver 2.4.1
2 parents 1df333b + 763afad commit 9128de0

File tree

5 files changed

+103
-40
lines changed

5 files changed

+103
-40
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "CellMLToolkit"
22
uuid = "03cb29e0-1ef4-4721-aa24-cf58a006576f"
33
authors = ["Shahriar Iravanian <siravan@svtsim.com>"]
4-
version = "2.4.0"
4+
version = "2.4.1"
55

66
[deps]
77
EzXML = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615"

src/accessors.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,20 @@ list_imports(xml) = findall("//x:import", get_model(xml), ["x"=>cellml_ns(xml)])
122122
node: an import node as returned by list_imports
123123
"""
124124
list_import_components(node) = findall("./x:component", nodeof(node), ["x"=>cellml_ns(node)])
125+
126+
function list_encapsulation(doc, comp)
127+
name = string(nameof(comp))
128+
ns = cellml_ns(doc)
129+
groups = parentnode.(findall("//x:group/x:relationship_ref[@relationship='encapsulation']", root(doc), ["x"=>ns]))
130+
if isempty(groups) # CellML ver 2.0
131+
return findall("//x:encapsulation//x:component_ref[@component='$name']//x:component_ref", root(doc), ["x"=>ns])
132+
else # CellML ver 1.0 and 1.1
133+
for g in groups
134+
nodes = findall(".//x:component_ref[@component='$name']//x:component_ref", g, ["x"=>ns])
135+
if !isempty(nodes)
136+
return nodes
137+
end
138+
end
139+
return EzXML.Node[]
140+
end
141+
end

src/components.jl

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,16 @@ end
139139
@memoize function classify_variables(doc::Document)
140140
groups = find_equivalence_groups(doc)
141141
lhs = list_all_lhs(doc)
142-
Dict{Var, Bool}(first(g) => (length(last(g) lhs) == 1) for g in groups)
142+
class = Dict{Var, Bool}()
143+
144+
for g in groups
145+
n = length(last(g) lhs)
146+
if n > 1
147+
error("Equivalence group $g has more than one initial_value: $(last(g) lhs)")
148+
end
149+
class[first(g)] = (n == 1)
150+
end
151+
class
143152
end
144153

145154
"""
@@ -150,7 +159,7 @@ function translate_connections(doc::Document, systems, class)
150159
a = []
151160
for conn in connections(doc)
152161
for (u1,u2) in variables(conn)
153-
if class[u1] && class[u2]
162+
if class[u1] && class[u2]
154163
var1 = getproperty(systems[u1.comp], u1.var)
155164
var2 = getproperty(systems[u2.comp], u2.var)
156165
push!(a, var1 ~ var2)
@@ -250,7 +259,7 @@ end
250259
comp in the name of the component
251260
class is the output of classify_variables
252261
"""
253-
function process_component(doc::Document, comp, class)
262+
function process_component(doc::Document, comp, class)
254263
math = list_component_math(comp)
255264
pre_sub = pre_substitution(doc, comp, class)
256265

@@ -274,13 +283,19 @@ end
274283

275284
function collect_initiated_values(doc::Document)
276285
vars = Dict{Var, Float64}()
286+
syms = Dict{Var, Var}()
277287

278288
for comp in components(doc)
279289
for v in list_initiated_variables(comp)
280-
vars[make_var(to_symbol(comp), v)] = Float64(Meta.parse(v["initial_value"]))
290+
val = Meta.parse(v["initial_value"])
291+
if val isa Symbol
292+
syms[make_var(to_symbol(comp), v)] = make_var(to_symbol(comp), val)
293+
else
294+
vars[make_var(to_symbol(comp), v)] = Float64(val)
295+
end
281296
end
282297
end
283-
vars
298+
vars, syms
284299
end
285300

286301
function split_sym(sym)
@@ -292,21 +307,22 @@ end
292307
find_sys_p(doc::Document, sys) = find_list_value(doc, parameters(sys))
293308
find_sys_u0(doc::Document, sys) = find_list_value(doc, states(sys))
294309

295-
function find_list_value(doc::Document, a)
296-
c = collect_initiated_values(doc)
297-
iv = find_iv(doc)
298-
299-
d = collect(keys(c))
310+
function find_list_value(doc::Document, names)
311+
vars, syms = collect_initiated_values(doc)
312+
varkeys = Set(keys(vars))
300313
groups = find_equivalence_groups(doc)
301314

302-
val = []
303-
for x in a
304-
var = [x for x in groups[split_sym(x)] d]
315+
vals = []
316+
317+
for x in names
318+
u = split_sym(x)
319+
u = haskey(syms,u) ? syms[u] : u
320+
var = groups[u] varkeys
305321
if length(var) == 0
306322
error("value of $x is not found")
307323
end
308-
push!(val, x => c[var[1]])
324+
push!(vals, x => vars[first(var)])
309325

310326
end
311-
return val
327+
return vals
312328
end

src/import.jl

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
using Random
22

3-
component_sym(x) = Symbol(x)
3+
sym(x) = Symbol(x)
4+
5+
function populate_dependency!(doc, comp)
6+
empty!(comp.deps)
7+
for x in list_encapsulation(doc, comp)
8+
push!(comp.deps, sym(x["component"]))
9+
end
10+
end
11+
12+
function add_component!(doc, name, node, populate=true)
13+
comp = Component(name, node, Set{Symbol}())
14+
populate && populate_dependency!(doc, comp)
15+
push!(doc.comps, comp)
16+
comp
17+
end
18+
19+
function add_connection!(doc, c1, c2, vars)
20+
conn = Connection(c1, c2, vars)
21+
push!(doc.conns, conn)
22+
conn
23+
end
424

525
"""
626
load_cellml loads a CellML file and populates a Document structures with
@@ -10,22 +30,20 @@ component_sym(x) = Symbol(x)
1030
"""
1131
function load_cellml(path; resolve=true)
1232
xml = readxml(path)
33+
doc = Document(path, [xml], Component[], Connection[])
1334

14-
comps = [Component(component_sym(c["name"]), c) for c in list_components(xml)]
35+
for c in list_components(xml)
36+
add_component!(doc, sym(c["name"]), c)
37+
end
1538

16-
conns = Connection[]
1739
for conn in list_connections(xml)
18-
c1, c2 = component_sym.(components_of(get_connection_component(conn)))
40+
c1, c2 = sym.(components_of(get_connection_component(conn)))
1941
vars = [make_var(c1,v1) => make_var(c2,v2)
2042
for (v1,v2) in variables_of.(list_connection_variables(conn))]
21-
push!(conns, Connection(c1, c2, vars))
43+
add_connection!(doc, c1, c2, vars)
2244
end
2345

24-
doc = Document(path, [xml], comps, conns)
25-
26-
if resolve
27-
resolve_imports(doc)
28-
end
46+
resolve && resolve_imports!(doc)
2947

3048
return doc
3149
end
@@ -40,44 +58,55 @@ end
4058

4159
find_component(doc::Document, name) = find_component(doc.comps, name)
4260

43-
implicit_name(sym) = Symbol("$(string(sym))_$(randstring(6))")
61+
# implicit_name(sym) = Symbol("$(string(sym))_$(randstring(6))")
62+
implicit_name(sym) = Symbol("$(string(sym))")
4463

4564
"""
4665
resolve_imports recursivelly resolves the imported components of doc.
4766
"""
48-
function resolve_imports(doc::Document)
67+
function resolve_imports!(doc::Document)
4968
for ϵ in list_imports(doc) # εισαγωγή == import
5069
href = ϵ["xlink:href"]
5170
@info "importing $href"
5271
path = joinpath(splitdir(doc.path)[1], href)
5372
child = load_cellml(path)
5473
append!(doc.xmls, child.xmls)
5574

56-
L = Dict{Symbol, Symbol}() # L keeps the import names of components
75+
L = Dict{Symbol, Symbol}() # L keeps the import names of components
76+
D = Set{Symbol}() # D is the set of imported dependencies
77+
C = Set{Symbol}()
5778

5879
# first, import explicitly imported component
5980
for σ in list_import_components(ϵ) # συστατικό == component
60-
name = component_sym(σ["component_ref"])
61-
comp = find_component(child, name)
62-
push!(doc.comps, Component(component_sym(σ["name"]), comp.node))
63-
L[name] = component_sym(σ["name"])
81+
old_name = sym(σ["component_ref"])
82+
new_name = sym(σ["name"])
83+
old_comp = find_component(child, old_name)
84+
85+
add_component!(doc, new_name, old_comp.node)
86+
87+
D = D old_comp.deps
88+
L[old_name] = new_name
89+
push!(C, old_name)
6490
end
6591

6692
# second, import implicitly imported component, as defined by closure
67-
for c in find_closure(child, collect(keys(L)))
68-
comp = find_component(child, c)
69-
name = implicit_name(c) # generates a name with a random suffix to prevent name collision
70-
push!(doc.comps, Component(name, comp.node))
71-
L[c] = name
93+
#for c in find_closure(child, collect(keys(L)))
94+
for old_name in D
95+
if old_name C
96+
old_comp = find_component(child, old_name)
97+
new_name = implicit_name(old_name) # generates a name with a random suffix to prevent name collision
98+
add_component!(doc, new_name, old_comp.node, false)
99+
L[old_name] = new_name
100+
end
72101
end
73102

74103
# third, we also need to import connections from the child CellML file
75104
for conn in connections(child)
76105
c1, c2 = components(conn)
77-
if haskey(L,c1) || haskey(L,c2)
106+
if haskey(L,c1) && haskey(L,c2)
78107
d1, d2 = L[c1], L[c2]
79108
vars = [Var(d1,v1.var) => Var(d2,v2.var) for (v1,v2) in conn.vars]
80-
push!(doc.conns, Connection(d1, d2, vars))
109+
add_connection!(doc, d1, d2, vars)
81110
end
82111
end
83112
end

src/structures.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ end
66
struct Component
77
name::Symbol
88
node::EzXML.Node
9+
deps::Set{Symbol}
910
end
1011

1112
nameof(comp::Component) = comp.name

0 commit comments

Comments
 (0)