Skip to content

Commit 32c8364

Browse files
committed
Updating and improving code for growth phenotype analysis and omics integration
1 parent 5976da7 commit 32c8364

File tree

9 files changed

+119
-30
lines changed

9 files changed

+119
-30
lines changed

modelseedpy/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from modelseedpy.fbapkg import (
4949
BaseFBAPkg,RevBinPkg,ReactionUsePkg,SimpleThermoPkg,TotalFluxPkg,ElementUptakePkg,BilevelPkg,
5050
CommKineticPkg,KBaseMediaPkg,FluxFittingPkg,ProteomeFittingPkg,GapfillingPkg,MetaboFBAPkg,FlexibleBiomassPkg,
51-
ProblemReplicationPkg,FullThermoPkg,MSPackageManager,ObjConstPkg
51+
ProblemReplicationPkg,FullThermoPkg,MSPackageManager,ObjConstPkg,ChangeOptPkg
5252
)
5353

5454
from modelseedpy.multiomics import (

modelseedpy/core/msgenome.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def parse_fasta_str(faa_str, split='|', h_func=None):
3838
elif split:
3939
header_data = line[1:].split(split, 1)
4040
seq_id = header_data[0]
41-
desc = header_data[1]
41+
#desc = header_data[1]
4242

4343
seq = MSFeature(seq_id, "", desc)
4444
else:

modelseedpy/core/msgrowthphenotypes.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pandas as pd
22
import logging
3+
import cobra
34
from cobra.core.dictlist import DictList
45
from modelseedpy.core.msmedia import MSMedia
56
from modelseedpy.fbapkg.mspackagemanager import MSPackageManager
@@ -33,7 +34,9 @@ def build_media(self):
3334
full_media.merge(parent.base_media,overwrite_overlap = False)
3435
return full_media
3536

36-
def simulate(self,modelutl,growth_threshold=0.001,add_missing_exchanges=False,save_fluxes=False):
37+
def simulate(self,modelutl,growth_threshold=0.001,add_missing_exchanges=False,save_fluxes=False,pfba=False):
38+
if not isinstance(modelutl,MSModelUtil):
39+
modelutl = MSModelUtil(modelutl)
3740
media = self.build_media()
3841
output = {"growth":None,"class":None,"missing_transports":[]}
3942
if add_missing_exchanges:
@@ -44,11 +47,13 @@ def simulate(self,modelutl,growth_threshold=0.001,add_missing_exchanges=False,sa
4447
if gene in modelutl.model.genes:
4548
geneobj = modelutl.model.genes.get_by_id(gene)
4649
geneobj.knock_out()
47-
solution = modelutl.model.optimize()
50+
solution = modelutl.model.optimize()
51+
output["growth"] = solution.objective_value
52+
if solution.objective_value > 0 and pfba:
53+
solution = cobra.flux_analysis.pfba(modelutl.model)
4854
if save_fluxes:
4955
output["fluxes"] = solution.fluxes
50-
output["growth"] = solution.objective_value
51-
if solution.objective_value >= growth_threshold:
56+
if output["growth"] >= growth_threshold:
5257
if self.growth > 0:
5358
output["class"] = "CP"
5459
else:
@@ -61,6 +66,8 @@ def simulate(self,modelutl,growth_threshold=0.001,add_missing_exchanges=False,sa
6166
return output
6267

6368
def gapfill_model_for_phenotype(self,modelutl,default_gapfill_templates,test_conditions,default_gapfill_models=[],blacklist=[],growth_threshold=0.001,add_missing_exchanges=False):
69+
if not isinstance(modelutl,MSModelUtil):
70+
modelutl = MSModelUtil(modelutl)
6471
self.gapfilling = MSGapfill(modelutl.model, default_gapfill_templates, default_gapfill_models, test_conditions, modelutl.reaction_scores(), blacklist)
6572
media = self.build_media()
6673
if add_missing_exchanges:
@@ -173,9 +180,7 @@ def simulate_phenotypes(self,model,biomass,add_missing_exchanges=False,correct_f
173180
model.objective = biomass
174181
modelutl = MSModelUtil(model)
175182
summary = {"Label":["Accuracy","CP","CN","FP","FN"],"Count":[0,0,0,0,0]}
176-
data = {"Phenotype":[],"Observed growth":[],"Simulated growth":[],"Class":[],"Transports missing":[]}
177-
if correct_false_negatives:
178-
data["Gapfilled reactions"] = []
183+
data = {"Phenotype":[],"Observed growth":[],"Simulated growth":[],"Class":[],"Transports missing":[],"Gapfilled reactions":[]}
179184
for pheno in self.phenotypes:
180185
with model:
181186
result = pheno.simulate(modelutl,growth_threshold,add_missing_exchanges,save_fluxes)#Result should have "growth" and "class"

modelseedpy/core/msmedia.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(self, media_id):
3232
def from_dict(d):
3333
"""
3434
Either dict with exchange bounds (example: {'cpd00027': (-10, 1000)}) or
35-
just absolute value of update (example: {''cpd00027': 10})
35+
just absolute value of uptake (example: {''cpd00027': 10})
3636
:param d:
3737
:return:
3838
"""

modelseedpy/core/msmodelutl.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
def search_name(name):
88
name = name.lower()
9-
name = re.sub(r'_[a-z]\d+$', '', name)
9+
name = re.sub(r'_[a-z]\d*$', '', name)
1010
name = re.sub(r'\W+', '', name)
1111
return name
1212

@@ -24,7 +24,11 @@ def build_metabolite_hash(self):
2424
self.add_name_to_metabolite_hash(met.id,met)
2525
self.add_name_to_metabolite_hash(met.name,met)
2626
for anno in met.annotation:
27-
self.add_name_to_metabolite_hash(met.annotation[anno],met)
27+
if isinstance(met.annotation[anno], list):
28+
for item in met.annotation[anno]:
29+
self.add_name_to_metabolite_hash(item,met)
30+
else:
31+
self.add_name_to_metabolite_hash(met.annotation[anno],met)
2832

2933
def add_name_to_metabolite_hash(self,name,met):
3034
if name not in self.metabolite_hash:
@@ -100,6 +104,7 @@ def add_exchanges_for_metabolites(self,cpds,uptake=0,excretion=0,prefix='EX_', p
100104
drain_reaction.annotation["sbo"] = 'SBO:0000627'
101105
drains.append(drain_reaction)
102106
self.model.add_reactions(drains)
107+
return drains
103108

104109
def reaction_scores(self):
105110
return {}

modelseedpy/fbapkg/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
from modelseedpy.fbapkg.problemreplicationpkg import ProblemReplicationPkg
2121
from modelseedpy.fbapkg.fullthermopkg import FullThermoPkg
2222
from modelseedpy.fbapkg.objconstpkg import ObjConstPkg
23+
from modelseedpy.fbapkg.changeoptpkg import ChangeOptPkg

modelseedpy/fbapkg/basefbapkg.py

+12
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,15 @@ def all_variables(self):
100100

101101
def all_constraints(self):
102102
return self.pkgmgr.all_constraints()
103+
104+
def add_variable_type(self,name,type):
105+
if name not in self.variables:
106+
self.variables[name] = dict()
107+
if name not in self.variable_types:
108+
self.variable_types[name] = type
109+
110+
def add_constraint_type(self,name,type):
111+
if name not in self.constraints:
112+
self.constraints[name] = dict()
113+
if name not in self.constraint_types:
114+
self.constraint_types[name] = type

modelseedpy/fbapkg/bilevelpkg.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ def __init__(self,model):
1212
BaseFBAPkg.__init__(self,model,"reaction use",{"dualconst":"string","dualub":"string","duallb":"string"},{"dualvar":"string","objective":"string"})
1313

1414
def build_package(self,filter = None,binary_variable_count = 0):
15-
self.validate_parameters(parameters, [], {
15+
self.validate_parameters({}, [], {
1616
"binary_variable_count":binary_variable_count
1717
});
18+
print("binary_variable_count:",binary_variable_count)
1819
coefficients = {}
1920
obj_coef = {}
2021
obj = self.model.solver.objective
21-
#Using the JSON calls because get_linear_coefficients is REALLY slow
2222
#Creating new objective coefficient and bound variables
2323
bound_variables = {}
2424
reactions = self.model.reactions
25-
if binary_variable_count > 0:
25+
if self.parameters["binary_variable_count"] > 0:
2626
for reaction in self.model.reactions:
27-
var = self.build_variable("fluxcomp",reaction,None)
28-
const = self.build_constraint("fluxcomp",reaction,None,None,None)
27+
var = self.build_variable("flxcmp",reaction,None)
2928
#Retreiving model data with componenent flux variables
29+
#Using the JSON calls because get_linear_coefficients is REALLY slow
3030
mdldata = self.model.solver.to_json()
3131
consthash = {}
3232
for const in mdldata["constraints"]:
@@ -35,10 +35,10 @@ def build_package(self,filter = None,binary_variable_count = 0):
3535
variables = list(self.model.solver.variables)
3636
objterms = obj.get_linear_coefficients(variables)
3737
#Adding binary variables and constraints which should not be included in dual formulation
38-
if binary_variable_count > 0:
39-
for variable in self.variables["fluxcomp"]:
40-
var = self.build_variable("bfluxcomp",variable,None)
41-
const = self.build_constraint("bfluxcomp",variable,None,None,None)
38+
if self.parameters["binary_variable_count"] > 0:
39+
for reaction in self.model.reactions:
40+
var = self.build_variable("bflxcmp",reaction,None)
41+
const = self.build_constraint("bflxcmp",reaction,None,None,None)
4242
#Now implementing dual variables and constraints
4343
varhash = {}
4444
for var in variables:
@@ -65,7 +65,6 @@ def build_package(self,filter = None,binary_variable_count = 0):
6565
coefficients[var][dvar] = 1
6666
self.build_constraint("dualvar",var,obj,objterms,coefficients)
6767
self.build_constraint("objective",None,obj,objterms,obj_coef)
68-
#Add binary variables and constaints which should not be part of the formulation
6968

7069
def build_variable(self,type,object,obj_coef):
7170
if type == "dualconst":
@@ -95,30 +94,38 @@ def build_variable(self,type,object,obj_coef):
9594
for i in range(0,self.parameters["binary_variable_count"]):
9695
value = 2**i
9796
if object.lower_bound < 0:
98-
var = BaseFBAPkg.build_variable(self,"rflxcmp"+str(i),0,-1*value*object.lower_bound/denominator,"continuous",object.id)
97+
self.add_variable_type("rflxcmp"+str(i),"reaction")
98+
var = BaseFBAPkg.build_variable(self,"rflxcmp"+str(i),0,-1*value*object.lower_bound/denominator,"continuous",object)
9999
coefs[0][var] = -1
100100
if object.upper_bound > 0:
101-
var = BaseFBAPkg.build_variable(self,"fflxcmp"+str(i),0,value*object.upper_bound/denominator,"continuous",object.id)
101+
self.add_variable_type("fflxcmp"+str(i),"reaction")
102+
var = BaseFBAPkg.build_variable(self,"fflxcmp"+str(i),0,value*object.upper_bound/denominator,"continuous",object)
102103
coefs[1][var] = -1
103104
if object.lower_bound < 0:
104105
#flux - flux_comp_0 - flux_comp_n = 0 - restriction of reverse fluxes by component fluxes
106+
self.add_constraint_type("rflxcmpc","reaction")
105107
coefs[0][object.reverse_variable] = 1
106-
BaseFBAPkg.build_constraint(self,"rflxcmpc",0,0,coefs[0],object.id)
108+
BaseFBAPkg.build_constraint(self,"rflxcmpc",0,0,coefs[0],object)
107109
if object.upper_bound > 0:
108110
#flux - flux_comp_0 - flux_comp_n = 0 - restriction of forward fluxes by component fluxes
111+
self.add_constraint_type("fflxcmpc","reaction")
109112
coefs[1][object.forward_variable] = 1
110-
BaseFBAPkg.build_constraint(self,"fflxcmpc",0,0,coefs[1],object.id)
113+
BaseFBAPkg.build_constraint(self,"fflxcmpc",0,0,coefs[1],object)
111114
return None
112115
if type == "bflxcmp" and self.parameters["binary_variable_count"] > 0:
113116
for i in range(0,self.parameters["binary_variable_count"]):
114117
if object.lower_bound < 0:
115-
var = BaseFBAPkg.build_variable(self,"brflxcmp"+str(i),0,1,"binary",object.id)
118+
self.add_variable_type("brflxcmp"+str(i),"reaction")
119+
var = BaseFBAPkg.build_variable(self,"brflxcmp"+str(i),0,1,"binary",object)
116120
othervar = self.variables["rflxcmp"+str(i)][object.id]
117-
BaseFBAPkg.build_constraint(self,"brflxcmpc"+str(i),None,0,{othervar:1,var:-1000},object.id)
121+
self.add_constraint_type("brflxcmpc"+str(i),"reaction")
122+
BaseFBAPkg.build_constraint(self,"brflxcmpc"+str(i),None,0,{othervar:1,var:-1000},object)
118123
if object.upper_bound > 0:
119-
var = BaseFBAPkg.build_variable(self,"bfflxcmp"+str(i),0,1,"binary",object.id)
124+
self.add_variable_type("bfflxcmp"+str(i),"reaction")
125+
var = BaseFBAPkg.build_variable(self,"bfflxcmp"+str(i),0,1,"binary",object)
120126
othervar = self.variables["fflxcmp"+str(i)][object.id]
121-
BaseFBAPkg.build_constraint(self,"bfflxcmpc"+str(i),None,0,{othervar:1,var:-1000},object.id)
127+
self.add_constraint_type("bfflxcmpc"+str(i),"reaction")
128+
BaseFBAPkg.build_constraint(self,"bfflxcmpc"+str(i),None,0,{othervar:1,var:-1000},object)
122129
return None
123130

124131
def build_constraint(self,type,object,objective,objterms,coefficients):

modelseedpy/fbapkg/changeoptpkg.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from __future__ import absolute_import
4+
5+
from optlang.symbolics import Zero, add
6+
from cobra.core import Gene, Metabolite, Model, Reaction
7+
from modelseedpy.fbapkg.basefbapkg import BaseFBAPkg
8+
9+
#Base class for FBA packages
10+
class ChangeOptPkg(BaseFBAPkg):
11+
def __init__(self,model):
12+
BaseFBAPkg.__init__(self,model,"change optimization",{"bgoal":"string"},{"bgoalc":"reaction"})
13+
14+
def build_package(self,target_values = {},build_objective = True):
15+
self.validate_parameters({}, [], {
16+
"target_values":target_values
17+
});
18+
#Creating objective but won't set objective unless build_objective is true
19+
goal_objective = self.model.problem.Objective(Zero,direction="max")
20+
obj_coef = dict()
21+
for rxnid in target_values:
22+
print(rxnid)
23+
if rxnid in self.model.reactions:
24+
print("FOUND!")
25+
rxn = self.model.reactions.get_by_id(rxnid)
26+
var = self.build_variable("bgoal",rxn)
27+
obj_coef[var] = target_values[rxnid]["objcoef"]
28+
const = self.build_constraint("bgoalc",rxn)
29+
#Now setting the goal objective if build_objective is true
30+
if build_objective:
31+
self.model.objective = goal_objective
32+
goal_objective.set_linear_coefficients(obj_coef)
33+
34+
def build_variable(self,type,object):
35+
if type == "bgoal":
36+
goal = self.parameters["target_values"][object.id]
37+
return BaseFBAPkg.build_variable(self,type,0,1,"binary",object.id+goal["direction"])
38+
39+
def build_constraint(self,type,object):
40+
if type == "bgoalc":
41+
#For lower: goal - vi + 1000 - 1000 gi >= 0
42+
#For higher: vi - goal + 1000 - 1000 gi >= 0
43+
lb = -1000
44+
goal = self.parameters["target_values"][object.id]
45+
var = self.variables["bgoal"][object.id+goal["direction"]]
46+
fluxvar = None
47+
if goal["flux"] < 0:
48+
fluxvar = object.reverse_variable
49+
else:
50+
fluxvar = object.forward_variable
51+
coef = {var:-1000}
52+
if goal["direction"] == "low":
53+
coef[fluxvar] = -1
54+
lb += -1*abs(goal["flux"])
55+
else:
56+
coef[fluxvar] = 1
57+
lb += abs(goal["flux"])
58+
return BaseFBAPkg.build_constraint(self,type,lb,None,coef,object)
59+

0 commit comments

Comments
 (0)