/
modularBondGraph.py
361 lines (296 loc) · 12.2 KB
/
modularBondGraph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
""" Tools for building modular bond graphs.
"""
import BondGraphTools as bgt
import sympy as sp
import copy
#import RE
def setStr():
""" Create component strings
"""
junStr = ("\n## Junction {1}:{0}\n"
"{0} = bgt.new('{1}',name='{0}')\n"
"bgt.add(model,{0})\n"
)
CeStr = ("\n## Component Ce:{0}\n"
"K_{0} = sp.symbols('K_{0}')\n"
"RT = sp.symbols('RT')\n"
"{0} = bgt.new('Ce',name='{0}',value={{'k':K_{0},'R':RT,'T':1}},library='BioChem')\n"
"bgt.add(model,{0})\n"
)
ReStr = ("\n### Re:{0}\n"
"\n## Component Re:{0}\n"
"kappa_{0} = sp.symbols('kappa_{0}')\n"
"RT = sp.symbols('RT')\n"
"{0} = bgt.new('Re',name='{0}',value={{'r':kappa_{0},'R':RT,'T':1}},library='BioChem')\n"
"bgt.add(model,{0})\n"
)
bondStr = "bgt.connect({0},{1})\n"
return junStr, CeStr, bondStr, ReStr
def findAttached(module,name):
""" Find name of component attached to component:name in module """
nameAttached = None
for bond in module.bonds:
if bond.head.component.name is name:
nameAttached = bond.tail.component.name
if bond.tail.component.name is name:
nameAttached = bond.head.component.name
return nameAttached
def unify(model,common=[],metamodel="C",quiet=False):
""" Unify C components (species) listed in common
"""
## Setup strings
junStr, CeStr, bondStr, ReStr = setStr()
if not quiet:
print("Unifying components in:", model.name)
## Create the common components at this level
for Name in common:
junName = Name+'_jun'
if not quiet:
print("Creating:", "Ce:"+Name, "and", "0:"+junName, "in", model.name)
exec(CeStr.format(Name))
exec(junStr.format(junName,'0'))
exec(bondStr.format(junName,Name))
## Replace common components in subsystems by ports
for subsystem in model.components:
#print(subsystem.metamodel,subsystem.name)
if subsystem.metamodel in ["BG"]:
for comp in subsystem.components:
if comp.metamodel in ["BG"]:
if not quiet:
print("unify:",comp.name)
#unify(comp,common=common,metamodel=metamodel)
if ((comp.metamodel in [metamodel]) and
(comp.name in common)):
#out = compPort(subsystem,comp)
#print("Replacing", subsystem.name,":",comp.name,
# "with a port.")
## Expose as port
bgt.expose(comp,comp.name)
## Connect port to junction
port = (subsystem,comp.name)
junName = comp.name+'_jun'
for com in model.components:
if com.name in [junName]:
jun = com
bgt.connect(port,jun)
if not quiet:
print("Exposing:","Ce:"+comp.name,"in",subsystem.name, "and connecting to", "0:"+jun.name)
def create(name,comp,chain,quiet=False):
if not quiet:
print("Creating", name, "from", comp.name, "within", chain.name)
exec(name+" = copy.deepcopy(comp)")
exec(name+".name = '"+name+"'")
exec("chain.add("+name+")")
def rename_instance(model,i,inport,outport,quiet=False):
"""Rename all non-port components in an instance indexed by i
"""
comps = []
for comp in model.components:
if comp.metamodel in ['C','R']:
name = comp.name
comps.append(name)
#print(comps)
renames = {}
for comp in comps:
renames[comp] = comp+'_'+str(i)
#print(renames)
rename(model,renames,quiet=quiet)
def chain(model,inport='in',outport='out',N=2,quiet=False):
""" Concatenate N instances of model via ports inport and outport
The ports are represented in model as Ce components
Ce:in in the first link of the chain and Ce:out in the last link remain as Ce components
The method unifies Ce:out of link i and Ce:in of link i+1 by replacing them by ports
and connecting them to a new Ce component with associated zero junction.
"""
intname = "IS"
name = model.name+"Chain"
## Turn chemostats into ports
compIn = copy.deepcopy(model / inport) # Clone component at inport
compOut = copy.deepcopy(model / outport) # Clone component at outport
nameFirst = model.name+"0"
nameLast = model.name+str(N-1)
nameIn = compIn.name
nameOut = compOut.name
IS = model / inport # Intermediate Ce
if not quiet:
print("Exposing",inport, "and", outport)
bgt.expose(model / inport, "in") # Create in port
bgt.expose(model / outport, "out") # Create outport
## Create the chain
if not quiet:
print("Creating",name)
chain = bgt.new(name=name)
zero = bgt.new('0')
for i in range(N):
## Create the components
cname = model.name+str(i)
Model = copy.deepcopy(model)
rename_instance(Model,i,inport,outport,quiet=quiet)
create(cname,Model,chain,quiet=quiet)
if i>0:
## Create the intermediate species
ISname = intname+str(i)
zeroname = "j"+ISname
zero = bgt.new('0')
create(ISname,IS,chain,quiet=quiet)
create(zeroname,zero,chain,quiet=quiet)
## And connect
previous = model.name+str(i-1)
bgt.connect(chain / zeroname,chain / ISname)
bgt.connect(chain / zeroname,(chain / cname,"in"))
bgt.connect((chain / previous,'out'),chain / zeroname)
## Set up the two ends
jnameIn = "j"+nameIn
create(nameIn,IS,chain,quiet=quiet)
create(jnameIn,zero,chain,quiet=quiet)
bgt.connect(chain / jnameIn, chain / nameIn)
bgt.connect(chain / jnameIn, (chain / nameFirst, "in"))
jnameOut = "j"+nameOut
create(nameOut,IS,chain,quiet=quiet)
create(jnameOut,zero,chain,quiet=quiet)
bgt.connect(chain / jnameOut, chain / nameOut)
bgt.connect((chain / nameLast, "out"), chain / jnameOut)
return chain
def split(model,quiet=False):
""" Split reactions into two and joined by complex
"""
## Setup strings
junStr, CeStr, bondStr, ReStr = setStr()
if not quiet:
print("Splitting reactions in:", model.name)
components = copy.copy(model.components)
for component in components:
if component.metamodel in ["R"]:
if not quiet:
Name = component.name
junName = Name+'_jun'
cName = "C"+Name
rName = Name+Name
print("Splitting", component.name)
exec(CeStr.format(cName))
exec(junStr.format(junName,"0"))
exec(ReStr.format(rName))
exec(bondStr.format(junName,cName))
exec(bondStr.format(junName,rName))
for bond in model.bonds:
if bond.tail.component.name is Name:
bgt.disconnect(bond.tail,bond.head)
bgt.connect(bond.tail.component,model / junName)
bgt.connect((model / rName,1), bond.head.component)
def setValue(module,names,quiet=False):
""" Resets value of components within module according to dict names
"""
if not quiet:
print("Renaming components within", module.name)
for key,value in names.items():
if not quiet:
print("Setting parameter", value[0], "of", key, "to", value[1])
#print((module/key).params)
def rename(module,names,quiet=False):
""" Renames components within module according to dict names
"""
if not quiet:
print("Renaming components within", module.name)
## Find list of all names in this module
nameList = []
for comp in module.components:
if not comp.metamodel in ["0","1"]:
#print(comp.metamodel,comp.name)
nameList.append(comp.name)
for key, name in names.items():
if not name in nameList:
if not quiet:
print("\tRenaming",key,"to",name)
(module / key).name = name
else:
print("\t"+name, "exists in", module.name+": connecting")
## Find what current components called key and name are attached to
for bond in module.bonds:
if bond.head.component.name is name:
nameJun = bond.tail.component
if bond.head.component.name is key:
keyJun = bond.tail.component
keyComp = module / key
bgt.connect(keyJun,nameJun)
bgt.disconnect(keyJun,keyComp)
module.remove(keyComp)
def renameSub(module,portList=[],quiet=True):
""" Rename all non-port components in module to moduleName_compName"""
modName = module.name
if not quiet:
print("Renaming components in:",modName)
renames = {}
for comp in module.components:
if comp.metamodel in ['R','C']:
compName = comp.name
if compName not in portList:
if not quiet:
print("Renaming component:",compName,'('+comp.metamodel+')')
renames[compName] = modName+'_'+compName
rename(module,renames,quiet=quiet)
def changeStoich(module,names,quiet=False):
""" Changes Ce stoichiometry within module according to dict names
"""
if not quiet:
print("Changing stoichiometry components within", module.name)
## Find list of all names in this module
TFlist = []
for comp in module.components:
if comp.metamodel in ["TF"]:
TFlist.append(comp.name)
CeList = []
if comp.metamodel in ["C"]:
CeList.append(comp.name)
for key, val in names.items():
TFname = key+"_TF"
if TFname in TFlist:
if not quiet:
print("\tChanging stoichiometry of",key,"to",val)
(module/TFname).params['r'] = val
else:
if key in CeList:
print('Component Ce:'+key, 'does not have variable stoichiometry, missing :?')
else:
print('Component Ce:'+key, 'does not exist within', module.name)
def sink(model,names=[]):
""" Connect the Ces listed in names to a zero sink """
## Set up strings
junStr, CeStr, bondStr, ReStr = setStr()
## Create the sink: Ce + Re + 0 junction
zeroName = "Zero"
zeroJunName = zeroName+"Jun"
exec(CeStr.format(zeroName))
exec(junStr.format(zeroJunName,"0"))
bgt.connect(model/zeroJunName,model/zeroName)
## Connect the components listed in names via Re component
for name in names:
zeroReName = name+zeroName+"Re"
junName = findAttached(model,name)
exec(ReStr.format(zeroReName))
bgt.connect(model/junName,model/zeroReName)
bgt.connect(model/zeroReName,model/zeroJunName)
# def ReRE(model,quiet=True):
# """ Replace Re components by enzyme catalysed reaction RE """
# components = copy.copy(model.components)
# for comp in components:
# if comp.metamodel in ["R"]:
# name = comp.name
# if not quiet:
# print("Converting reaction", name)
# re = RE.model()
# re.name = name
# rename(re,{'E':name+'ase'},quiet=quiet)
# rename(re,{'AE':name+'cmp'},quiet=quiet)
# rename(re,{'r1':name+'1'},quiet=quiet)
# rename(re,{'r2':name+'2'},quiet=quiet)
# model.add(re)
# bgt.expose(re / 'A','A')
# bgt.expose(re / 'B','B')
# for bond in model.bonds:
# if comp is bond.head.component:
# bgt.disconnect(bond.tail, bond.head)
# bgt.connect(bond.tail,(re,'A'))
# if comp is bond.tail.component:
# bgt.disconnect(bond.tail, bond.head)
# bgt.connect((re,'B'),bond.head)
# model.remove(comp)