cdFBA 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cdfba-0.0.1/LICENSE +21 -0
- cdfba-0.0.1/PKG-INFO +37 -0
- cdfba-0.0.1/README.md +5 -0
- cdfba-0.0.1/cdFBA/__init__.py +71 -0
- cdfba-0.0.1/cdFBA/processes/__init__.py +6 -0
- cdfba-0.0.1/cdFBA/processes/dfba.py +363 -0
- cdfba-0.0.1/cdFBA/utils.py +478 -0
- cdfba-0.0.1/cdFBA.egg-info/PKG-INFO +37 -0
- cdfba-0.0.1/cdFBA.egg-info/SOURCES.txt +12 -0
- cdfba-0.0.1/cdFBA.egg-info/dependency_links.txt +1 -0
- cdfba-0.0.1/cdFBA.egg-info/requires.txt +3 -0
- cdfba-0.0.1/cdFBA.egg-info/top_level.txt +1 -0
- cdfba-0.0.1/setup.cfg +4 -0
- cdfba-0.0.1/setup.py +53 -0
cdfba-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vivarium Collective
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cdfba-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: cdFBA
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Home-page: https://github.com/vivarium-collective/cdFBA
|
|
5
|
+
Author: Tasnif Rahman
|
|
6
|
+
Author-email: trahman@uchc.edu
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: vivarium-interface
|
|
21
|
+
Requires-Dist: cobra
|
|
22
|
+
Requires-Dist: matplotlib
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
|
|
33
|
+
# cdFBA
|
|
34
|
+
Community Dynamic Flux Balance Analysis using process-bigraph.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
#### This project is a work in progress
|
cdfba-0.0.1/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from cdFBA.processes import register_processes
|
|
2
|
+
|
|
3
|
+
def apply_non_negative(schema, current, update, core):
|
|
4
|
+
new_value = current + update
|
|
5
|
+
return max(0, new_value)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def set_update(schema, current, update, core):
|
|
9
|
+
return update
|
|
10
|
+
|
|
11
|
+
def volumetric_update(schema, current, update, core):
|
|
12
|
+
counts = update.get('counts')
|
|
13
|
+
volume = current.get('volume')
|
|
14
|
+
|
|
15
|
+
new_counts = current['counts']
|
|
16
|
+
new_concentrations = current['concentrations']
|
|
17
|
+
if counts:
|
|
18
|
+
for key, value in counts.items():
|
|
19
|
+
new = new_counts[key] + value
|
|
20
|
+
new_counts[key] = new
|
|
21
|
+
new_concentrations[key] = new/volume
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
'counts': new_counts,
|
|
25
|
+
'concentrations': new_concentrations,
|
|
26
|
+
'volume': volume,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
positive_float = {
|
|
30
|
+
'_type': 'positive_float',
|
|
31
|
+
'_inherit': 'float',
|
|
32
|
+
'_apply': apply_non_negative}
|
|
33
|
+
|
|
34
|
+
set_float = {
|
|
35
|
+
'_type': 'set_float',
|
|
36
|
+
'_inherit': 'float',
|
|
37
|
+
'_apply': set_update
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
bounds_type = {
|
|
41
|
+
'lower': 'maybe[float]',
|
|
42
|
+
'upper': 'maybe[float]'}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
particle_type = {
|
|
46
|
+
'id': 'string',
|
|
47
|
+
'position': 'tuple[float,float]',
|
|
48
|
+
'size': 'float',
|
|
49
|
+
'local': 'map[float]',
|
|
50
|
+
'exchange': 'map[float]', # {mol_id: delta_value}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
volumetric_type = {
|
|
54
|
+
'concentrations':'map[float]',
|
|
55
|
+
'counts':'map[float]',
|
|
56
|
+
'volume': 'float',
|
|
57
|
+
'_apply': volumetric_update
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
chemostat_type = {
|
|
61
|
+
'concentration': 'float'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
def register_types(core):
|
|
65
|
+
core.register('positive_float', positive_float)
|
|
66
|
+
core.register('set_float', set_float)
|
|
67
|
+
core.register('bounds', bounds_type)
|
|
68
|
+
core.register('particle', particle_type)
|
|
69
|
+
core.register('volumetric', volumetric_type)
|
|
70
|
+
|
|
71
|
+
return register_processes(core)
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import pprint
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
from process_bigraph.composite import ProcessTypes
|
|
6
|
+
from process_bigraph import Process, Step, Composite
|
|
7
|
+
|
|
8
|
+
from cdFBA.utils import model_from_file, get_objective_reaction, get_injector_spec, get_wave_spec, get_chemo_spec
|
|
9
|
+
from cdFBA.utils import get_single_dfba_spec, dfba_config, environment_spec, initial_environment
|
|
10
|
+
|
|
11
|
+
from matplotlib import pyplot as plt
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DFBA(Process):
|
|
15
|
+
"""Performs single time-step of dynamic FBA
|
|
16
|
+
|
|
17
|
+
Parameters:
|
|
18
|
+
-----------
|
|
19
|
+
model_file: string, math to cobra model file
|
|
20
|
+
"""
|
|
21
|
+
config_schema = {
|
|
22
|
+
"model_file": {
|
|
23
|
+
'_type': 'string',
|
|
24
|
+
'_default': 'iAF1260',
|
|
25
|
+
},
|
|
26
|
+
"name": 'string',
|
|
27
|
+
"kinetics": "any",
|
|
28
|
+
"reaction_map": "any",
|
|
29
|
+
"biomass_identifier": "any",
|
|
30
|
+
"bounds": "maybe[map[bounds]]",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def __init__(self, config, core):
|
|
34
|
+
super().__init__(config, core)
|
|
35
|
+
|
|
36
|
+
# TODO -- load model here rather than passing it in
|
|
37
|
+
self.model = model_from_file(self.config['model_file'])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if self.config["bounds"] is not None:
|
|
41
|
+
if len(self.config["bounds"]) != 0:
|
|
42
|
+
for reaction_id, bounds in self.config["bounds"].items():
|
|
43
|
+
if bounds["lower"] is not None:
|
|
44
|
+
self.model.reactions.get_by_id(reaction_id).lower_bound = bounds["lower"]
|
|
45
|
+
if bounds["upper"] is not None:
|
|
46
|
+
self.model.reactions.get_by_id(reaction_id).upper_bound = bounds["upper"]
|
|
47
|
+
|
|
48
|
+
# def initial_state(self):
|
|
49
|
+
# # TODO -- get the initial state from the load model, self.model
|
|
50
|
+
# return {
|
|
51
|
+
# "dfba_update": {
|
|
52
|
+
# 'Biomass_Ecoli_core': 0,
|
|
53
|
+
# 'acetate': 0,
|
|
54
|
+
# 'glucose': 0}}
|
|
55
|
+
|
|
56
|
+
def inputs(self):
|
|
57
|
+
return {
|
|
58
|
+
"shared_environment": "volumetric", #initial conditions for time-step
|
|
59
|
+
"current_update": "map[map[set_float]]",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
def outputs(self):
|
|
63
|
+
return {
|
|
64
|
+
"dfba_update": "map[set_float]"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def update(self, inputs, interval):
|
|
69
|
+
current_state = {key:inputs["shared_environment"]["counts"][key] for key, value in self.config["reaction_map"].items()}
|
|
70
|
+
current_state[self.config["name"]] = inputs["shared_environment"]["counts"][self.config["name"]]
|
|
71
|
+
state_update = current_state.copy()
|
|
72
|
+
|
|
73
|
+
for substrate_id, reaction_id in self.config["reaction_map"].items():
|
|
74
|
+
Km, Vmax = self.config["kinetics"][substrate_id]
|
|
75
|
+
substrate_concentration = inputs["shared_environment"]["concentrations"][substrate_id]
|
|
76
|
+
|
|
77
|
+
# calculate michaelis-menten flux
|
|
78
|
+
flux = Vmax * substrate_concentration / (Km + substrate_concentration)
|
|
79
|
+
|
|
80
|
+
# use the flux to constrain fba
|
|
81
|
+
self.model.reactions.get_by_id(reaction_id).lower_bound = -flux
|
|
82
|
+
|
|
83
|
+
# solve fba under these constraints
|
|
84
|
+
solution = self.model.optimize()
|
|
85
|
+
|
|
86
|
+
# gather the results
|
|
87
|
+
## update biomass
|
|
88
|
+
biomass_growth_rate = solution.fluxes[self.config["biomass_identifier"]]
|
|
89
|
+
current_biomass = current_state[self.config["name"]]
|
|
90
|
+
state_update[self.config['name']] = biomass_growth_rate * current_biomass * interval
|
|
91
|
+
|
|
92
|
+
## update substrates
|
|
93
|
+
for substrate_id, reaction_id in self.config["reaction_map"].items():
|
|
94
|
+
flux = solution.fluxes[reaction_id]
|
|
95
|
+
state_update[substrate_id] = (flux * current_biomass * interval)
|
|
96
|
+
|
|
97
|
+
return {"dfba_update": state_update}
|
|
98
|
+
|
|
99
|
+
class UpdateEnvironment(Step): #TODO =:
|
|
100
|
+
config_schema = {}
|
|
101
|
+
|
|
102
|
+
def __init__(self, config, core):
|
|
103
|
+
super().__init__(config, core)
|
|
104
|
+
|
|
105
|
+
def inputs(self):
|
|
106
|
+
return {
|
|
107
|
+
"shared_environment": "volumetric",
|
|
108
|
+
"species_updates": "map[map[set_float]]" #TODO add a species_update type
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def outputs(self):
|
|
112
|
+
return {
|
|
113
|
+
"shared_environment": "map[float]",
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def update(self, inputs):
|
|
117
|
+
species_updates = inputs["species_updates"]
|
|
118
|
+
shared_environment = inputs["shared_environment"]["counts"]
|
|
119
|
+
env_volume = inputs["shared_environment"]["volume"]
|
|
120
|
+
|
|
121
|
+
species_list = [species for species in species_updates]
|
|
122
|
+
random.shuffle(species_list)
|
|
123
|
+
|
|
124
|
+
update = shared_environment.copy()
|
|
125
|
+
|
|
126
|
+
for species in species_list:
|
|
127
|
+
for substrate_id in species_updates[species]:
|
|
128
|
+
if (shared_environment[substrate_id] + species_updates[species][substrate_id]) > 0:
|
|
129
|
+
update[substrate_id] = species_updates[species][substrate_id]
|
|
130
|
+
else:
|
|
131
|
+
update[substrate_id] = -shared_environment[substrate_id]
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
"shared_environment": {'counts': update}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class Chemostat(Process):
|
|
138
|
+
"""The Chemostat process maintains the concentration of given substrates at a fixed value at each time-step
|
|
139
|
+
"""
|
|
140
|
+
config_schema = {
|
|
141
|
+
"substrate_concentrations" : "map[float]",
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
def __init__(self, config, core):
|
|
145
|
+
super().__init__(config, core)
|
|
146
|
+
|
|
147
|
+
def inputs(self):
|
|
148
|
+
return {
|
|
149
|
+
"shared_environment": "volumetric",
|
|
150
|
+
"global_time": "float"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def outputs(self):
|
|
154
|
+
return {
|
|
155
|
+
"shared_environment": "map[float]"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
def update(self, inputs, interval):
|
|
159
|
+
shared_environment = inputs["shared_environment"]["counts"]
|
|
160
|
+
|
|
161
|
+
update = {}
|
|
162
|
+
|
|
163
|
+
for substrate, values in self.config["substrate_concentrations"].items():
|
|
164
|
+
update[substrate] = (values * inputs["shared_environment"]["volume"]) - shared_environment[substrate]
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
"shared_environment": {'counts': update}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
class WaveFunction(Process):
|
|
171
|
+
"""The WaveFunction process maintains the concentration of given substrates based on a wave-function
|
|
172
|
+
"""
|
|
173
|
+
config_schema = {
|
|
174
|
+
"substrate_params" : "map[map[float]]",
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
substrate_params = {
|
|
179
|
+
"substrate_name": {
|
|
180
|
+
"amplitude": "float",
|
|
181
|
+
"angular_frequency": "float",
|
|
182
|
+
"base_concentration": "float",
|
|
183
|
+
"phase_shift": "float"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
amplitude : float, amplitude of wave function
|
|
188
|
+
angular_frequency : float, angular frequency of wave function
|
|
189
|
+
base_concentration : float, base concentration substrate
|
|
190
|
+
phase_shift : float, phase shift of wave function (when wave starts)
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
def __init__(self, config, core):
|
|
194
|
+
super().__init__(config, core)
|
|
195
|
+
|
|
196
|
+
def inputs(self):
|
|
197
|
+
return {
|
|
198
|
+
"shared_environment": "volumetric",
|
|
199
|
+
"global_time": "float"
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
def outputs(self):
|
|
203
|
+
return {
|
|
204
|
+
"shared_environment": "map[float]"
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
def update(self, inputs, interval):
|
|
208
|
+
shared_environment = inputs["shared_environment"]["counts"]
|
|
209
|
+
t = inputs["global_time"]
|
|
210
|
+
update = {}
|
|
211
|
+
for substrate in self.config["substrate_params"]:
|
|
212
|
+
A = self.config["substrate_params"][substrate]["amplitude"]
|
|
213
|
+
w = self.config["substrate_params"][substrate]["angular_frequency"]
|
|
214
|
+
B = self.config["substrate_params"][substrate]["base_concentration"]
|
|
215
|
+
phi = self.config["substrate_params"][substrate]["phase_shift"]
|
|
216
|
+
|
|
217
|
+
current_count = (A*math.sin(w*t+phi) + B) * inputs["shared_environment"]["volume"]
|
|
218
|
+
|
|
219
|
+
update[substrate] = (current_count - shared_environment[substrate])
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
"shared_environment": {'counts': update}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
class Injector(Process):
|
|
226
|
+
"""The Injector process injects a given amount of a given substrate at regular intervals into the shared environment
|
|
227
|
+
"""
|
|
228
|
+
config_schema = {
|
|
229
|
+
"injection_params" : "map[map[float]]",
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
# injection_params = {
|
|
233
|
+
# "substrate_name" : {
|
|
234
|
+
# "amount": "float",
|
|
235
|
+
# "interval": "float",
|
|
236
|
+
# }
|
|
237
|
+
# }
|
|
238
|
+
|
|
239
|
+
def __init__(self, config, core):
|
|
240
|
+
super().__init__(config, core)
|
|
241
|
+
|
|
242
|
+
def inputs(self):
|
|
243
|
+
return {
|
|
244
|
+
"shared_environment": "volumetric",
|
|
245
|
+
"global_time": "float"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
def outputs(self):
|
|
249
|
+
return {
|
|
250
|
+
"shared_environment": "map[float]"
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
def update(self, inputs, interval):
|
|
254
|
+
shared_environment = inputs["shared_environment"]["counts"]
|
|
255
|
+
t = inputs["global_time"]
|
|
256
|
+
update = {}
|
|
257
|
+
for substrate in self.config["injection_params"]:
|
|
258
|
+
if ((t % self.config["injection_params"][substrate]["interval"]) == 0) & (t!=0.0):
|
|
259
|
+
update[substrate] = self.config["injection_params"][substrate]["amount"]
|
|
260
|
+
return {
|
|
261
|
+
"shared_environment": {'counts': update}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
def run_environment(core):
|
|
265
|
+
"""This tests that the environment runs"""
|
|
266
|
+
name1 = "E.coli"
|
|
267
|
+
name2 = "S.flexneri"
|
|
268
|
+
# define a single dFBA model
|
|
269
|
+
spec = {
|
|
270
|
+
name1: get_single_dfba_spec(model_file= "iAF1260", name=name1)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
spec[name2] = get_single_dfba_spec(model_file = "iSFxv_1172", name=name2)
|
|
274
|
+
|
|
275
|
+
spec['shared environment'] = initial_environment(volume=2, species_list=[name1, name2])
|
|
276
|
+
|
|
277
|
+
spec['dFBA Results'] = {name1:
|
|
278
|
+
{
|
|
279
|
+
"glucose": 0,
|
|
280
|
+
"acetate": 0,
|
|
281
|
+
spec[name1]['config']['name']: 0,
|
|
282
|
+
},
|
|
283
|
+
name2:
|
|
284
|
+
{
|
|
285
|
+
"glucose": 0,
|
|
286
|
+
"acetate": 0,
|
|
287
|
+
spec[name2]['config']['name']: 0,
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
spec['update environment'] = environment_spec()
|
|
292
|
+
|
|
293
|
+
injector_config = {
|
|
294
|
+
"injection_params": {
|
|
295
|
+
"glucose": {
|
|
296
|
+
"amount": 80,
|
|
297
|
+
"interval": 5,
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
spec['environment dynamics'] = get_injector_spec(config=injector_config)
|
|
303
|
+
|
|
304
|
+
pprint.pprint(spec)
|
|
305
|
+
|
|
306
|
+
# put it in a composite
|
|
307
|
+
sim = Composite({
|
|
308
|
+
"state": spec,
|
|
309
|
+
"emitter": {'mode': 'all'}},
|
|
310
|
+
core=core
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# run the simulation
|
|
314
|
+
sim.run(40)
|
|
315
|
+
results = sim.gather_results()[('emitter',)]
|
|
316
|
+
|
|
317
|
+
# print the results
|
|
318
|
+
timepoints = []
|
|
319
|
+
for timepoint in results:
|
|
320
|
+
time = timepoint.pop('global_time')
|
|
321
|
+
timepoints.append(time)
|
|
322
|
+
dfba_spec = timepoint.pop(name1)
|
|
323
|
+
print(f'TIME: {time}')
|
|
324
|
+
print(f'STATE: {timepoint}')
|
|
325
|
+
|
|
326
|
+
env = [timepoint['shared environment']['concentrations'] for timepoint in results]
|
|
327
|
+
env_combined = {}
|
|
328
|
+
for d in env:
|
|
329
|
+
for key, value in d.items():
|
|
330
|
+
if key not in env_combined:
|
|
331
|
+
env_combined[key] = []
|
|
332
|
+
env_combined[key].append(value)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
fig, ax = plt.subplots(dpi=300)
|
|
336
|
+
for key, value in env_combined.items():
|
|
337
|
+
# if not key == 'glucose':
|
|
338
|
+
# continue
|
|
339
|
+
ax.plot(timepoints, env_combined[key], label=key)
|
|
340
|
+
plt.xlabel('Time')
|
|
341
|
+
plt.ylabel('Substrate Concentration')
|
|
342
|
+
plt.legend()
|
|
343
|
+
plt.tight_layout()
|
|
344
|
+
plt.show()
|
|
345
|
+
|
|
346
|
+
if __name__ == "__main__":
|
|
347
|
+
from cdFBA import register_types
|
|
348
|
+
|
|
349
|
+
# create a core
|
|
350
|
+
core = ProcessTypes()
|
|
351
|
+
core = register_types(core)
|
|
352
|
+
|
|
353
|
+
core.register_process('DFBA', DFBA)
|
|
354
|
+
core.register_process('UpdateEnvironment', UpdateEnvironment)
|
|
355
|
+
core.register_process('Chemostat', Chemostat)
|
|
356
|
+
core.register_process('WaveFunction', WaveFunction)
|
|
357
|
+
core.register_process('Injector', Injector)
|
|
358
|
+
|
|
359
|
+
# print(get_single_dfba_spec())
|
|
360
|
+
# test_dfba_alone(core)
|
|
361
|
+
# test_dfba(core)
|
|
362
|
+
run_environment(core)
|
|
363
|
+
# test_composite()
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
"""This module contains some methods to obtain the reaction map, initial conditions, and kinetic parameters needed
|
|
2
|
+
for dFBA simulations from the minimal medium requirements of the wild-type species.
|
|
3
|
+
|
|
4
|
+
CAUTION: The initial conditions, and kinetics dataframes provide default parameter values and must be changed as needed
|
|
5
|
+
CAUTION: Substrate names are different in BiGG and AGORA databases. These functions will not work with two models form
|
|
6
|
+
different sources
|
|
7
|
+
"""
|
|
8
|
+
from cobra.io import load_model, read_sbml_model, load_json_model, load_yaml_model, load_matlab_model
|
|
9
|
+
from cobra.medium import minimal_medium
|
|
10
|
+
import pprint
|
|
11
|
+
import re
|
|
12
|
+
|
|
13
|
+
#single species functions
|
|
14
|
+
def model_from_file(model_file='textbook'):
|
|
15
|
+
"""Returns a cobra model from a model file path or BiGG Model ID
|
|
16
|
+
Parameters:
|
|
17
|
+
model_file: str, file path or BiGG Model ID
|
|
18
|
+
Returns:
|
|
19
|
+
model: cobra model
|
|
20
|
+
"""
|
|
21
|
+
if ".xml" in model_file:
|
|
22
|
+
model = read_sbml_model(model_file)
|
|
23
|
+
elif ".json" in model_file:
|
|
24
|
+
model = load_json_model(model_file)
|
|
25
|
+
elif ".yaml" in model_file:
|
|
26
|
+
model = load_yaml_model(model_file)
|
|
27
|
+
elif ".mat" in model_file:
|
|
28
|
+
model = load_matlab_model(model_file)
|
|
29
|
+
elif isinstance(model_file, str):
|
|
30
|
+
model = load_model(model_file)
|
|
31
|
+
else:
|
|
32
|
+
# error handling
|
|
33
|
+
raise ValueError("Invalid model file")
|
|
34
|
+
return model
|
|
35
|
+
|
|
36
|
+
def get_exchanges(model_file='textbook', medium_type='exchange'):
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
Parameters:
|
|
40
|
+
model_file: str, file path or BiGG Model ID
|
|
41
|
+
medium_type:
|
|
42
|
+
'default' uses the default cobra model medium
|
|
43
|
+
'minimal' uses the minimal medium for the model
|
|
44
|
+
'exchange' uses all exchange fluxes for the model
|
|
45
|
+
defaults to 'exchange'
|
|
46
|
+
Returns:
|
|
47
|
+
exchanges: list of exchange reaction IDs
|
|
48
|
+
"""
|
|
49
|
+
model=model_from_file(model_file)
|
|
50
|
+
if medium_type == 'default':
|
|
51
|
+
medium = model.medium
|
|
52
|
+
if medium_type == 'minimal':
|
|
53
|
+
medium = minimal_medium(model, model.slim_optimize()).to_dict()
|
|
54
|
+
if medium_type == 'exchange':
|
|
55
|
+
medium = {reaction.id: reaction.upper_bound for reaction in model.exchanges}
|
|
56
|
+
medium.update(model.medium)
|
|
57
|
+
medium = medium
|
|
58
|
+
return list(medium.keys())
|
|
59
|
+
|
|
60
|
+
def get_substrates(model_file='textbook', exchanges=None):
|
|
61
|
+
"""Returns a list of substrates from the model.
|
|
62
|
+
Parameters:
|
|
63
|
+
model_file : str, file path or BiGG Model ID
|
|
64
|
+
exchanges : lst, a list of exchange reaction ids
|
|
65
|
+
Returns:
|
|
66
|
+
substrates : lst, list of names of substrates required by the model organism
|
|
67
|
+
"""
|
|
68
|
+
if exchanges is None:
|
|
69
|
+
exchanges = get_exchanges(model_file)
|
|
70
|
+
model = model_from_file(model_file)
|
|
71
|
+
substrates = []
|
|
72
|
+
|
|
73
|
+
for item in [getattr(model.reactions, i).name for i in exchanges if hasattr(model.reactions, i)]:
|
|
74
|
+
|
|
75
|
+
match = re.match(r"(.*) exchange|exchange reaction for (.*)|Exchange of (.*)|echange reaction for (.*)", item, re.IGNORECASE)
|
|
76
|
+
|
|
77
|
+
if match:
|
|
78
|
+
substrates.append(match.group(1) or match.group(2) or match.group(3) or match.group(4))
|
|
79
|
+
else:
|
|
80
|
+
substrates.append(item)
|
|
81
|
+
return substrates
|
|
82
|
+
|
|
83
|
+
def get_reaction_map(model_file='textbook', exchanges=None):
|
|
84
|
+
"""Returns a reaction_name_map dictionary from a medium dictionary as obtained
|
|
85
|
+
from model.medium or cobra.medium.minimum_medium()
|
|
86
|
+
Parameters:
|
|
87
|
+
model_file : str, file path or BiGG Model ID
|
|
88
|
+
exchanges : lst, list of names of substrates required by the model organism
|
|
89
|
+
Returns:
|
|
90
|
+
reaction_name_map : dict, maps substrate names to reactions
|
|
91
|
+
"""
|
|
92
|
+
if exchanges is None:
|
|
93
|
+
exchanges = get_exchanges(model_file)
|
|
94
|
+
model = model_from_file(model_file)
|
|
95
|
+
substrates = get_substrates(model_file, exchanges)
|
|
96
|
+
ids = exchanges
|
|
97
|
+
reaction_name_map = {}
|
|
98
|
+
for i in range(len(substrates)):
|
|
99
|
+
reaction_name_map[substrates[i]] = ids[i]
|
|
100
|
+
return reaction_name_map
|
|
101
|
+
|
|
102
|
+
def get_kinetics(model_file='textbook', exchanges=None):
|
|
103
|
+
"""Returns default kinetic parameters dictionary. Values are tuples of the form (km, vmax)
|
|
104
|
+
Parameters:
|
|
105
|
+
model_file : str, file path or BiGG Model ID
|
|
106
|
+
exchanges : lst, list of exchange reaction ids
|
|
107
|
+
"""
|
|
108
|
+
if exchanges is None:
|
|
109
|
+
exchanges = get_exchanges(model_file)
|
|
110
|
+
model = model_from_file(model_file)
|
|
111
|
+
kinetics = {key: (0.5, 2.0) for key in get_substrates(model_file, exchanges)}
|
|
112
|
+
return kinetics
|
|
113
|
+
|
|
114
|
+
def get_bounds(reaction_map, upper=1000, lower=-1000):
|
|
115
|
+
"""Return dict of default upper and lower bounds for each substrate exchange reaction
|
|
116
|
+
Parameters:
|
|
117
|
+
reaction_map : dict, maps substrate names to reactions
|
|
118
|
+
upper : float, upper bound, default 1000
|
|
119
|
+
lower : float, lower bound, default -1000
|
|
120
|
+
Returns:
|
|
121
|
+
bounds : dict, default bounds for all exchange reactions
|
|
122
|
+
"""
|
|
123
|
+
return {reaction_map[key]: {'lower': lower, 'upper': upper} for key in reaction_map.keys()}
|
|
124
|
+
|
|
125
|
+
def get_objective_reaction(model_file = 'textbook'):
|
|
126
|
+
"""get a string with the name of the objective function of a cobra model
|
|
127
|
+
Parameters:
|
|
128
|
+
model: cobrapy model
|
|
129
|
+
Returns:
|
|
130
|
+
objective_reaction: str, name of the objective reaction (biomass reaction by default)
|
|
131
|
+
"""
|
|
132
|
+
model = model_from_file(model_file)
|
|
133
|
+
expression = f"{model.objective.expression}"
|
|
134
|
+
match = re.search(r'1\.0\*([^\s]+)', expression)
|
|
135
|
+
|
|
136
|
+
if match:
|
|
137
|
+
objective_reaction = match.group(1)
|
|
138
|
+
|
|
139
|
+
return objective_reaction
|
|
140
|
+
|
|
141
|
+
def dfba_config(
|
|
142
|
+
model_file="textbook",
|
|
143
|
+
name=None,
|
|
144
|
+
kinetics=None,
|
|
145
|
+
reaction_map=None,
|
|
146
|
+
biomass_identifier=None,
|
|
147
|
+
bounds=None
|
|
148
|
+
):
|
|
149
|
+
"""Construct a configuration dictionary for a single cobra model
|
|
150
|
+
Parameters:
|
|
151
|
+
model_file: str, file path or BiGG Model ID
|
|
152
|
+
name: str, name of the process
|
|
153
|
+
kinetics: dict, kinetic parameters for shared substrates
|
|
154
|
+
reaction_map: dict, maps substrate names to reaction ids
|
|
155
|
+
biomass_identifier: str, name of the biomass reaction
|
|
156
|
+
bounds: dict, bounds for exchange reactions
|
|
157
|
+
Returns:
|
|
158
|
+
config: dict, config dictionary for a single species dFBA
|
|
159
|
+
"""
|
|
160
|
+
model = model_from_file(model_file)
|
|
161
|
+
if name is None:
|
|
162
|
+
name = model.id
|
|
163
|
+
if reaction_map is None:
|
|
164
|
+
reaction_map = {
|
|
165
|
+
"glucose": "EX_glc__D_e",
|
|
166
|
+
"acetate": "EX_ac_e"
|
|
167
|
+
}
|
|
168
|
+
if bounds is None:
|
|
169
|
+
bounds = {
|
|
170
|
+
"EX_o2_e": {"lower": -2, "upper": None},
|
|
171
|
+
"ATPM": {"lower": 1, "upper": 1}
|
|
172
|
+
}
|
|
173
|
+
if kinetics is None:
|
|
174
|
+
kinetics = {
|
|
175
|
+
"glucose": (0.02, 15),
|
|
176
|
+
"acetate": (0.5, 7)}
|
|
177
|
+
if biomass_identifier is None:
|
|
178
|
+
biomass_identifier = get_objective_reaction(model_file=model_file)
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
"model_file": model_file,
|
|
182
|
+
"name": name,
|
|
183
|
+
"kinetics": kinetics,
|
|
184
|
+
"reaction_map": reaction_map,
|
|
185
|
+
"biomass_identifier": biomass_identifier,
|
|
186
|
+
"bounds": bounds,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
def get_single_dfba_spec(
|
|
190
|
+
model_file="textbook",
|
|
191
|
+
name="species",
|
|
192
|
+
config=None,
|
|
193
|
+
interval=1.0
|
|
194
|
+
):
|
|
195
|
+
"""Constructs a configuration dictionary for a dynamic FBA process
|
|
196
|
+
Parameters:
|
|
197
|
+
model_file: str, file path or BiGG Model ID
|
|
198
|
+
name: str, identifier for the model, usually species/strain name
|
|
199
|
+
config: dict, config for DFBA Process. If none provided, uses default generated using `dfba_config()`
|
|
200
|
+
interval: float, interval between consecutive dFBA calculations
|
|
201
|
+
Returns:
|
|
202
|
+
dict: dict, specification dictionary for a single species dFBA
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
if config is None:
|
|
206
|
+
config = dfba_config(model_file=model_file, name=name)
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
"_type": "process",
|
|
210
|
+
"address": "local:DFBA",
|
|
211
|
+
"config": config,
|
|
212
|
+
"inputs": {
|
|
213
|
+
"shared_environment": ["shared environment"],
|
|
214
|
+
"current_update": ["dFBA Results"]
|
|
215
|
+
},
|
|
216
|
+
"outputs": {
|
|
217
|
+
"dfba_update": ["dFBA Results", name]
|
|
218
|
+
},
|
|
219
|
+
"interval": interval
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#multi-species functions
|
|
223
|
+
def make_cdfba_composite(model_dict, medium_type=None, exchanges=None, volume=1, interval=1.0):
|
|
224
|
+
"""Construct a cdfba composite spec with all exhange metabolites included.
|
|
225
|
+
Parameters:
|
|
226
|
+
model_dict : dict, dictionary with cdfba process names as keys and model name/path as values
|
|
227
|
+
medium_type : str/lst, if str, pick one of:
|
|
228
|
+
'default' uses the default cobra model medium
|
|
229
|
+
'minimal' uses the minimal medium for the model
|
|
230
|
+
'exchange' uses all exchange fluxes for the model
|
|
231
|
+
MUST be None if exchanges is provided
|
|
232
|
+
exchanges: a list of exchange reaction ids. MUST be None if medium_type is provided
|
|
233
|
+
volume: float, volume of cdfba composite
|
|
234
|
+
interval: float, interval between consecutive dFBA calculations
|
|
235
|
+
Returns:
|
|
236
|
+
spec : dict, cdfba composite spec
|
|
237
|
+
"""
|
|
238
|
+
spec = {'dFBA Results': {}}
|
|
239
|
+
if medium_type is None:
|
|
240
|
+
if exchanges is None:
|
|
241
|
+
raise ValueError("Must provide medium_type or exchanges list")
|
|
242
|
+
|
|
243
|
+
if medium_type is not None:
|
|
244
|
+
if exchanges is not None:
|
|
245
|
+
raise ValueError("Provide only on of medium_type or exchanges list")
|
|
246
|
+
|
|
247
|
+
if exchanges is None:
|
|
248
|
+
env_exchanges = []
|
|
249
|
+
for name, model_file in model_dict.items():
|
|
250
|
+
env_exchanges.extend(get_exchanges(model_file=model_file, medium_type=medium_type))
|
|
251
|
+
|
|
252
|
+
env_exchanges = list(set(env_exchanges))
|
|
253
|
+
else:
|
|
254
|
+
env_exchanges = exchanges
|
|
255
|
+
|
|
256
|
+
initial_counts = get_initial_counts(model_dict, exchanges=env_exchanges)
|
|
257
|
+
initial_env = initial_environment(volume=volume, initial_counts=initial_counts, species_list=model_dict.keys())
|
|
258
|
+
spec['shared environment'] = initial_env
|
|
259
|
+
|
|
260
|
+
for model_name, model_file in model_dict.items():
|
|
261
|
+
if exchanges is None:
|
|
262
|
+
model_exchanges = get_exchanges(model_file=model_file, medium_type=medium_type)
|
|
263
|
+
else:
|
|
264
|
+
model_exchanges = exchanges
|
|
265
|
+
substrates = get_substrates(model_file=model_file, exchanges=model_exchanges)
|
|
266
|
+
kinetics = get_kinetics(model_file=model_file, exchanges=model_exchanges)
|
|
267
|
+
reaction_map = get_reaction_map(model_file=model_file, exchanges=model_exchanges)
|
|
268
|
+
biomass_identifier = get_objective_reaction(model_file=model_file)
|
|
269
|
+
bounds = {}
|
|
270
|
+
|
|
271
|
+
config = dfba_config(
|
|
272
|
+
model_file=model_file,
|
|
273
|
+
name=model_name,
|
|
274
|
+
kinetics=kinetics,
|
|
275
|
+
reaction_map=reaction_map,
|
|
276
|
+
biomass_identifier=biomass_identifier,
|
|
277
|
+
bounds=bounds
|
|
278
|
+
)
|
|
279
|
+
model_spec = get_single_dfba_spec(model_file=model_file, name=model_name, config=config, interval=interval)
|
|
280
|
+
spec[model_name] = model_spec
|
|
281
|
+
|
|
282
|
+
spec['dFBA Results'][model_name] = {substrate: 0 for substrate in substrates}
|
|
283
|
+
spec['dFBA Results'][model_name].update({model_name: 0})
|
|
284
|
+
spec['update environment'] = environment_spec()
|
|
285
|
+
return spec
|
|
286
|
+
|
|
287
|
+
def get_initial_counts(model_dict, biomass=0.5, initial_value=20, exchanges=None):
|
|
288
|
+
"""Returns an initial condition dict based on medium
|
|
289
|
+
Parameters:
|
|
290
|
+
model_dict: dict, dictionary with cdfba process names as keys and model name/path as values
|
|
291
|
+
biomass : float, initial biomass for all species
|
|
292
|
+
initial_value : float, initial counts of all species
|
|
293
|
+
exchanges: lst, list of exchange reaction ids
|
|
294
|
+
Returns:
|
|
295
|
+
conditions : dict, initial conditions dictionary
|
|
296
|
+
"""
|
|
297
|
+
all_substrates = []
|
|
298
|
+
for model_name in model_dict.keys():
|
|
299
|
+
model_file=model_dict[model_name]
|
|
300
|
+
substrates = get_substrates(model_file, exchanges)
|
|
301
|
+
all_substrates.extend(substrates)
|
|
302
|
+
all_substrates = list(set(all_substrates))
|
|
303
|
+
conditions = {substrate:initial_value for substrate in all_substrates}
|
|
304
|
+
biomasses = {model:biomass for model in model_dict.keys()}
|
|
305
|
+
conditions = conditions | biomasses
|
|
306
|
+
return conditions
|
|
307
|
+
|
|
308
|
+
def initial_environment(volume=1, initial_counts=None, species_list=None):
|
|
309
|
+
"""Construct initial shared environment store
|
|
310
|
+
Parameters:
|
|
311
|
+
volume : float, volume of the environment
|
|
312
|
+
initial_counts : dict, initial counts of each substrate and species biomass in the environment
|
|
313
|
+
species_list : list of strings, list of dfba species names)
|
|
314
|
+
Returns:
|
|
315
|
+
initial shared environment store spec
|
|
316
|
+
"""
|
|
317
|
+
if initial_counts is None:
|
|
318
|
+
if species_list is None:
|
|
319
|
+
raise ValueError("Error: Please provide initial_counts or species_list")
|
|
320
|
+
initial_counts = {
|
|
321
|
+
"glucose": 80,
|
|
322
|
+
"acetate": 0,
|
|
323
|
+
}
|
|
324
|
+
for species in species_list:
|
|
325
|
+
initial_counts[species] = 0.5
|
|
326
|
+
|
|
327
|
+
initial_concentration = {key:(count/volume) for key, count in initial_counts.items()}
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
"volume": volume,
|
|
331
|
+
"counts": initial_counts,
|
|
332
|
+
"concentrations": initial_concentration
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
#environmental process/step related functions
|
|
336
|
+
def environment_spec():
|
|
337
|
+
"""Construct spec dictionary for UpdateEnvironment step"""
|
|
338
|
+
return {
|
|
339
|
+
"_type": "process",
|
|
340
|
+
"address": "local:UpdateEnvironment",
|
|
341
|
+
"config": {},
|
|
342
|
+
"inputs": {
|
|
343
|
+
"species_updates": ["dFBA Results"],
|
|
344
|
+
"shared_environment": ["shared environment"]
|
|
345
|
+
},
|
|
346
|
+
"outputs": {
|
|
347
|
+
"shared_environment": ["shared environment"],
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
def get_chemo_spec(config=None):
|
|
352
|
+
"""Constructs a configuration dictionary for the Chemostat process.
|
|
353
|
+
Parameters:
|
|
354
|
+
config: dict, Chemostat configuration dictionary
|
|
355
|
+
Returns:
|
|
356
|
+
dict, spec for Chemostat process
|
|
357
|
+
"""
|
|
358
|
+
if config is None:
|
|
359
|
+
raise ValueError("Error: Please provide config")
|
|
360
|
+
return {
|
|
361
|
+
"_type": "process",
|
|
362
|
+
"address": "local:Chemostat",
|
|
363
|
+
"config": config,
|
|
364
|
+
"inputs": {
|
|
365
|
+
"shared_environment": ["shared environment"],
|
|
366
|
+
"global_time": ["global_time"],
|
|
367
|
+
},
|
|
368
|
+
"outputs": {
|
|
369
|
+
"shared_environment": ["shared environment"],
|
|
370
|
+
},
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
def get_wave_spec(config=None):
|
|
374
|
+
"""Constructs a configuration dictionary for the WaveFunction process.
|
|
375
|
+
Parameters:
|
|
376
|
+
config: dict, WaveFunction configuration dictionary
|
|
377
|
+
Returns
|
|
378
|
+
dict, spec for WaveFunction process
|
|
379
|
+
"""
|
|
380
|
+
if config is None:
|
|
381
|
+
raise ValueError("Error: Please provide config")
|
|
382
|
+
return {
|
|
383
|
+
"_type": "process",
|
|
384
|
+
"address": "local:WaveFunction",
|
|
385
|
+
"config": config,
|
|
386
|
+
"inputs": {
|
|
387
|
+
"shared_environment": ["shared environment"],
|
|
388
|
+
"global_time": ["global_time"],
|
|
389
|
+
},
|
|
390
|
+
"outputs": {
|
|
391
|
+
"shared_environment": ["shared environment"],
|
|
392
|
+
},
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
def get_injector_spec(config=None):
|
|
396
|
+
"""Constructs a configuration dictionary for the Injector process.
|
|
397
|
+
Parameters:
|
|
398
|
+
config: dict, Injector configuration dictionary
|
|
399
|
+
Returns:
|
|
400
|
+
dict, spec for Injector process
|
|
401
|
+
"""
|
|
402
|
+
if config is None:
|
|
403
|
+
raise ValueError("Error: Please provide config")
|
|
404
|
+
return {
|
|
405
|
+
"_type": "process",
|
|
406
|
+
"address": "local:Injector",
|
|
407
|
+
"config": config,
|
|
408
|
+
"inputs": {
|
|
409
|
+
"shared_environment": ["shared environment"],
|
|
410
|
+
"global_time": ["global_time"],
|
|
411
|
+
},
|
|
412
|
+
"outputs": {
|
|
413
|
+
"shared_environment": ["shared environment"],
|
|
414
|
+
},
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
def run_single_dfba_spec(model_file="textbook"):
|
|
418
|
+
model = model_from_file(model_file)
|
|
419
|
+
exchanges = get_exchanges(model_file=model_file, medium_type='exchange')
|
|
420
|
+
substrates = get_substrates(model_file=model_file, exchanges=exchanges)
|
|
421
|
+
reaction_map = get_reaction_map(model_file=model_file, exchanges=exchanges)
|
|
422
|
+
kinetics = get_kinetics(model_file=model_file, exchanges=exchanges)
|
|
423
|
+
bounds=None
|
|
424
|
+
biomass_identifier = get_objective_reaction(model_file=model_file)
|
|
425
|
+
config = dfba_config(
|
|
426
|
+
model_file=model_file,
|
|
427
|
+
name='E.coli Core',
|
|
428
|
+
kinetics=kinetics,
|
|
429
|
+
reaction_map=reaction_map,
|
|
430
|
+
biomass_identifier=biomass_identifier,
|
|
431
|
+
bounds=bounds,
|
|
432
|
+
)
|
|
433
|
+
spec = get_single_dfba_spec(
|
|
434
|
+
model_file=model_file,
|
|
435
|
+
name='E.coli Core',
|
|
436
|
+
config=config,
|
|
437
|
+
interval=1.0
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
pprint.pprint(spec)
|
|
441
|
+
print("")
|
|
442
|
+
print(f"Exchanges: {exchanges}")
|
|
443
|
+
print(f"Substrates: {substrates}")
|
|
444
|
+
print(f"Reaction Map: {reaction_map}")
|
|
445
|
+
print(f"Kinetics: {kinetics}")
|
|
446
|
+
print(f"Biomass Identifier: {biomass_identifier}")
|
|
447
|
+
print(f"Bounds: {bounds}")
|
|
448
|
+
|
|
449
|
+
def run_initial_counts(model_file="textbook"):
|
|
450
|
+
exchanges = get_exchanges(model_file=model_file, medium_type='exchange')
|
|
451
|
+
initial_counts = get_initial_counts(
|
|
452
|
+
model_dict={'E.coli Core': 'textbook'},
|
|
453
|
+
biomass=0.1,
|
|
454
|
+
initial_value=20,
|
|
455
|
+
exchanges=exchanges
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
pprint.pprint(initial_counts)
|
|
459
|
+
|
|
460
|
+
def run_cdfba_spec():
|
|
461
|
+
model_dict = {
|
|
462
|
+
'E.coli' : 'iAF1260',
|
|
463
|
+
'S. flexneri' : 'iSFxv_1172'
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
pprint.pprint(make_cdfba_composite(
|
|
467
|
+
model_dict=model_dict,
|
|
468
|
+
medium_type='exchange',
|
|
469
|
+
exchanges=None,
|
|
470
|
+
volume=1,
|
|
471
|
+
interval=1.0
|
|
472
|
+
)
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
if __name__ == '__main__':
|
|
476
|
+
# run_single_dfba_spec(model_file="textbook")
|
|
477
|
+
# run_initial_counts(model_file="textbook")
|
|
478
|
+
run_cdfba_spec()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: cdFBA
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Home-page: https://github.com/vivarium-collective/cdFBA
|
|
5
|
+
Author: Tasnif Rahman
|
|
6
|
+
Author-email: trahman@uchc.edu
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: vivarium-interface
|
|
21
|
+
Requires-Dist: cobra
|
|
22
|
+
Requires-Dist: matplotlib
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
|
|
33
|
+
# cdFBA
|
|
34
|
+
Community Dynamic Flux Balance Analysis using process-bigraph.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
#### This project is a work in progress
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
cdFBA/__init__.py
|
|
5
|
+
cdFBA/utils.py
|
|
6
|
+
cdFBA.egg-info/PKG-INFO
|
|
7
|
+
cdFBA.egg-info/SOURCES.txt
|
|
8
|
+
cdFBA.egg-info/dependency_links.txt
|
|
9
|
+
cdFBA.egg-info/requires.txt
|
|
10
|
+
cdFBA.egg-info/top_level.txt
|
|
11
|
+
cdFBA/processes/__init__.py
|
|
12
|
+
cdFBA/processes/dfba.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cdFBA
|
cdfba-0.0.1/setup.cfg
ADDED
cdfba-0.0.1/setup.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
VERSION = '0.0.1'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with open("README.md", "r") as readme:
|
|
9
|
+
description = readme.read()
|
|
10
|
+
# Patch the relative links to absolute URLs that will work on PyPI.
|
|
11
|
+
description2 = re.sub(
|
|
12
|
+
r']\(([\w/.-]+\.png)\)',
|
|
13
|
+
r'](https://github.com/vivarium-collective/cdFBA/raw/main/\1)',
|
|
14
|
+
description)
|
|
15
|
+
long_description = re.sub(
|
|
16
|
+
r']\(([\w/.-]+)\)',
|
|
17
|
+
r'](https://github.com/vivarium-collective/cdFBA/blob/main/\1)',
|
|
18
|
+
description2)
|
|
19
|
+
|
|
20
|
+
setup(
|
|
21
|
+
name="cdFBA",
|
|
22
|
+
version=VERSION,
|
|
23
|
+
author="Tasnif Rahman",
|
|
24
|
+
author_email="trahman@uchc.edu",
|
|
25
|
+
description="",
|
|
26
|
+
long_description=long_description,
|
|
27
|
+
long_description_content_type="text/markdown",
|
|
28
|
+
license="MIT",
|
|
29
|
+
license_files=["LICENSE"],
|
|
30
|
+
url="https://github.com/vivarium-collective/cdFBA",
|
|
31
|
+
# packages=find_packages(),
|
|
32
|
+
packages=[
|
|
33
|
+
'cdFBA',
|
|
34
|
+
'cdFBA.processes',
|
|
35
|
+
],
|
|
36
|
+
classifiers=[
|
|
37
|
+
"Development Status :: 3 - Alpha",
|
|
38
|
+
"Intended Audience :: Developers",
|
|
39
|
+
"License :: OSI Approved :: MIT License",
|
|
40
|
+
"Operating System :: OS Independent",
|
|
41
|
+
"Programming Language :: Python",
|
|
42
|
+
"Programming Language :: Python :: 3",
|
|
43
|
+
"Programming Language :: Python :: 3.9",
|
|
44
|
+
"Programming Language :: Python :: 3.10",
|
|
45
|
+
"Programming Language :: Python :: 3.11",
|
|
46
|
+
],
|
|
47
|
+
python_requires=">=3.9",
|
|
48
|
+
install_requires=[
|
|
49
|
+
"vivarium-interface",
|
|
50
|
+
"cobra",
|
|
51
|
+
"matplotlib"
|
|
52
|
+
]
|
|
53
|
+
)
|