Skip to content

Commit b6c4439

Browse files
committed
Merge pull request #103 from aebrahim/double_deletion_bugfixes
Double deletion bugfixes
2 parents 2db6f2a + 3fdda77 commit b6c4439

File tree

9 files changed

+729
-79
lines changed

9 files changed

+729
-79
lines changed

cobra/flux_analysis/deletion_worker.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,23 @@ def __init__(self, cobra_model, n_processes=None, solver=None):
5555
for i in range(n_processes):
5656
p = Process(target=compute_fba_deletion_worker,
5757
args=[cobra_model, solver, self.job_queue, self.output_queue])
58-
p.start()
5958
self.processes.append(p)
6059

60+
def start(self):
61+
for p in self.processes:
62+
p.start()
63+
64+
def terminate(self):
65+
for p in self.processes:
66+
p.terminate()
67+
68+
def __enter__(self):
69+
self.start()
70+
return self
71+
72+
def __exit__(self, exc_type, exc_val, exc_tb):
73+
self.terminate()
74+
6175
def submit(self, indexes, label=None):
6276
self.job_queue.put((indexes, label))
6377
self.n_submitted += 1
@@ -73,6 +87,7 @@ def receive_all(self):
7387
self.n_complete += 1
7488
yield self.output_queue.get()
7589

90+
7691
@property
7792
def pids(self):
7893
return [p.pid for p in self.processes]
@@ -107,3 +122,15 @@ def receive_all(self):
107122
indexes, label = self.job_queue.pop()
108123
yield (label, compute_fba_deletion(self.lp, self.solver, self.model, indexes))
109124

125+
def start(self):
126+
None
127+
128+
def terminate(self):
129+
None
130+
131+
def __enter__(self):
132+
return self
133+
134+
def __exit__(self, exc_type, exc_val, exc_tb):
135+
None
136+

cobra/flux_analysis/double_deletion.py

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
from __future__ import with_statement, print_function
23
#cobra.flux_analysis.double_deletion.py
34
#runs flux variablity analysis on a Model object.
@@ -28,7 +29,7 @@ def moma(*args, **kwargs):
2829

2930
def double_reaction_deletion_fba(cobra_model, reaction_list1=None,
3031
reaction_list2=None, solver=None,
31-
n_processes=None, return_frame=True):
32+
number_of_processes=None, return_frame=False):
3233
"""setting n_processes=1 explicitly disables multiprocessing"""
3334
if reaction_list1 is None:
3435
reaction_indexes1 = range(len(cobra_model.reactions))
@@ -53,27 +54,28 @@ def double_reaction_deletion_fba(cobra_model, reaction_list1=None,
5354
results = numpy.empty((n_results, n_results))
5455
results.fill(numpy.nan)
5556

56-
if n_processes == 1: # explicitly disable multiprocessing
57-
pool = CobraDeletionMockPool(cobra_model, n_processes=n_processes, solver=solver)
57+
if number_of_processes == 1: # explicitly disable multiprocessing
58+
PoolClass = CobraDeletionMockPool
5859
else:
59-
pool = CobraDeletionPool(cobra_model, n_processes=n_processes, solver=solver)
60-
# submit jobs
61-
62-
for r1_index, r2_index in product(reaction_indexes1, reaction_indexes2):
63-
r1_result_index = reaction_to_result[r1_index]
64-
r2_result_index = reaction_to_result[r2_index]
65-
if r2_result_index >= r1_result_index: # upper triangle only
66-
pool.submit((r1_index, r2_index), label=(r1_result_index, r2_result_index))
67-
# if it's a point only in the lower triangle, compute it
68-
# and put it in the upper triangle
69-
elif r1_result_index not in column_index_set or r2_result_index not in row_index_set:
70-
pool.submit((r1_index, r2_index), label=(r2_result_index, r1_result_index))
71-
72-
# get results
73-
for result in pool.receive_all():
74-
results[result[0]] = result[1]
60+
PoolClass = CobraDeletionPool
61+
with PoolClass(cobra_model, n_processes=number_of_processes,
62+
solver=solver) as pool:
63+
# submit jobs
64+
65+
for r1_index, r2_index in product(reaction_indexes1, reaction_indexes2):
66+
r1_result_index = reaction_to_result[r1_index]
67+
r2_result_index = reaction_to_result[r2_index]
68+
if r2_result_index >= r1_result_index: # upper triangle only
69+
pool.submit((r1_index, r2_index), label=(r1_result_index, r2_result_index))
70+
# if it's a point only in the lower triangle, compute it
71+
# and put it in the upper triangle
72+
elif r1_result_index not in column_index_set or r2_result_index not in row_index_set:
73+
pool.submit((r1_index, r2_index), label=(r2_result_index, r1_result_index))
74+
75+
# get results
76+
for result in pool.receive_all():
77+
results[result[0]] = result[1]
7578

76-
del pool
7779

7880
# reflect results
7981
triu1, triu2 = numpy.triu_indices(n_results)
@@ -92,7 +94,8 @@ def double_reaction_deletion_fba(cobra_model, reaction_list1=None,
9294
"data": results}
9395

9496
def double_gene_deletion_fba(cobra_model, gene_list1=None, gene_list2=None,
95-
solver=None, n_processes=None, return_frame=True):
97+
solver=None, number_of_processes=None,
98+
return_frame=False):
9699
if gene_list1 is None:
97100
gene_list1 = cobra_model.genes
98101
else:
@@ -127,27 +130,28 @@ def double_gene_deletion_fba(cobra_model, gene_list1=None, gene_list2=None,
127130
results = numpy.empty((n_results, n_results))
128131
results.fill(numpy.nan)
129132

130-
if n_processes == 1: # explicitly disable multiprocessing
131-
pool = CobraDeletionMockPool(cobra_model, n_processes=n_processes, solver=solver)
133+
if number_of_processes == 1: # explicitly disable multiprocessing
134+
PoolClass = CobraDeletionMockPool
132135
else:
133-
pool = CobraDeletionPool(cobra_model, n_processes=n_processes, solver=solver)
134-
135-
for gene1, gene2 in product(gene_list1, gene_list2):
136-
g1_result_index = gene_id_to_result[gene1.id]
137-
g2_result_index = gene_id_to_result[gene2.id]
138-
if g2_result_index >= g1_result_index: # upper triangle only
139-
ko_reactions = find_gene_knockout_reactions(cobra_model, (gene1, gene2))
140-
ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions]
141-
pool.submit(ko_indexes, label=(g1_result_index, g2_result_index))
142-
# if it's a point only in the lower triangle, compute it
143-
# and put it in the upper triangle
144-
elif g1_result_index not in column_index_set or g2_result_index not in row_index_set:
145-
ko_reactions = find_gene_knockout_reactions(cobra_model, (gene1, gene2))
146-
ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions]
147-
pool.submit(ko_indexes, label=(g2_result_index, g1_result_index))
148-
149-
for result in pool.receive_all():
150-
results[result[0]] = result[1]
136+
PoolClass = CobraDeletionPool
137+
with PoolClass(cobra_model, n_processes=number_of_processes,
138+
solver=solver) as pool:
139+
for gene1, gene2 in product(gene_list1, gene_list2):
140+
g1_result_index = gene_id_to_result[gene1.id]
141+
g2_result_index = gene_id_to_result[gene2.id]
142+
if g2_result_index >= g1_result_index: # upper triangle only
143+
ko_reactions = find_gene_knockout_reactions(cobra_model, (gene1, gene2))
144+
ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions]
145+
pool.submit(ko_indexes, label=(g1_result_index, g2_result_index))
146+
# if it's a point only in the lower triangle, compute it
147+
# and put it in the upper triangle
148+
elif g1_result_index not in column_index_set or g2_result_index not in row_index_set:
149+
ko_reactions = find_gene_knockout_reactions(cobra_model, (gene1, gene2))
150+
ko_indexes = [cobra_model.reactions.index(i) for i in ko_reactions]
151+
pool.submit(ko_indexes, label=(g2_result_index, g1_result_index))
152+
153+
for result in pool.receive_all():
154+
results[result[0]] = result[1]
151155

152156
del pool
153157

@@ -169,47 +173,58 @@ def double_gene_deletion_fba(cobra_model, gene_list1=None, gene_list2=None,
169173

170174
def double_deletion(cobra_model, element_list_1=None, element_list_2=None,
171175
method='fba', single_deletion_growth_dict=None,
172-
element_type='gene', solver=None, error_reporting=None,
173-
number_of_processes=1):
174-
"""Wrapper for double_gene_deletion and double_reaction_deletion
176+
element_type='gene', solver=None,
177+
number_of_processes=None,
178+
return_frame=False, **kwargs):
179+
"""Run double gene or reaction deletions
175180
176181
cobra_model: a cobra.Model object
177182
178-
element_list_1: Is None or a list of elements (genes or reactions)
179-
180-
element_list_2: Is None or a list of elements (genes or reactions)
183+
element_list_1: None or a list of elements (genes or reactions)
181184
182-
method: 'fba' or 'moma' to run flux balance analysis or minimization
183-
of metabolic adjustments.
185+
element_list_2: None or a list of elements (genes or reactions)
184186
185-
single_deletion_growth_dict: A dictionary that provides the growth
186-
rate information for single gene knock outs. This can speed up
187-
simulations because nonviable single deletion strains imply that all
188-
double deletion strains will also be nonviable.
187+
method: 'fba' or 'moma'
188+
Whether to compute growth rates using flux balance analysis or
189+
minimization of metabolic adjustments.
190+
191+
number_of_processes: None or int
192+
The number of processor core to use. Setting 1 explicitly disables
193+
use of the multiprocessing library. By default, up to 4 cores will be
194+
used if available.
189195
190196
element_type: 'gene' or 'reaction'
191197
192-
solver: 'glpk', 'gurobi', or 'cplex'.
198+
solver: 'glpk', 'cglpk', 'gurobi', 'cplex' or None
193199
194-
error_reporting: None or True
200+
return_frame: bool
201+
If True, format data as a pandas Dataframe
195202
196203
Returns a dictionary of the elements in the x dimension (x), the y
197204
dimension (y), and the growth simulation data (data).
198205
199206
"""
207+
208+
if "error_reporting" in kwargs:
209+
warn("error_reporting option removed")
210+
kwargs.pop("error_reporting")
211+
if "single_deletion_growth_dict" in kwargs:
212+
warn("single_deletion_growth_dict option removed")
213+
kwargs.pop("single_deletion_growth_dict")
214+
200215
if method == "fba":
201216
if element_type == "gene":
202217
return double_gene_deletion_fba(cobra_model,
203218
gene_list1=element_list_1,
204219
gene_list2=element_list_2, solver=solver,
205-
return_frame=False,
206-
n_processes=number_of_processes)
220+
return_frame=return_frame,
221+
number_of_processes=number_of_processes)
207222
elif element_type == "reaction":
208223
return double_reaction_deletion_fba(cobra_model,
209224
reaction_list1=element_list_1,
210225
reaction_list2=element_list_2, solver=solver,
211-
return_frame=False,
212-
n_processes=number_of_processes)
226+
return_frame=return_frame,
227+
number_of_processes=number_of_processes)
213228
else:
214229
raise ValueError("element_type %s not gene or reaction" % element_type)
215230

cobra/manipulation/delete.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,25 @@ def undelete_model_genes(cobra_model):
7575
if hasattr(cobra_model, the_attribute):
7676
setattr(cobra_model, the_attribute, None)
7777

78-
78+
spontaneous_re = re.compile('(^|(?<=( |\()))s0001(?=( |\)|$))')
7979
def find_gene_knockout_reactions(cobra_model, gene_list):
8080
"""identify reactions which will be disabled when the genes are knocked out"""
8181

8282
potential_reactions = set()
8383
for x in gene_list:
8484
potential_reactions.update(x._reaction)
8585

86-
spontaneous_re = re.compile('(^|(?<=( |\()))s0001(?=( |\)|$))')
8786
knocked_out_reactions = []
8887
for the_reaction in potential_reactions:
89-
the_gene_reaction_relation = deepcopy(the_reaction.gene_reaction_rule)
88+
# operate on a copy
89+
gene_reaction_rule = "" + the_reaction.gene_reaction_rule
9090
for the_gene in the_reaction._genes:
91-
the_gene_re = re.compile('(^|(?<=( |\()))%s(?=( |\)|$))'%re.escape(the_gene.id))
9291
if the_gene in gene_list:
93-
the_gene_reaction_relation = the_gene_re.sub('False', the_gene_reaction_relation)
92+
gene_reaction_rule = gene_reaction_rule.replace(the_gene.id, 'False')
9493
else:
95-
the_gene_reaction_relation = the_gene_re.sub('True', the_gene_reaction_relation)
96-
the_gene_reaction_relation = spontaneous_re.sub('True', the_gene_reaction_relation)
97-
if not eval(the_gene_reaction_relation):
94+
gene_reaction_rule = gene_reaction_rule.replace(the_gene.id, 'True')
95+
gene_reaction_rule = spontaneous_re.sub('True', gene_reaction_rule)
96+
if not eval(gene_reaction_rule):
9897
knocked_out_reactions.append(the_reaction)
9998
return knocked_out_reactions
10099

documentation_builder/03_single_deletion.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.

documentation_builder/07_double_deletion.rst

Lines changed: 0 additions & 4 deletions
This file was deleted.

documentation_builder/autodoc.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ sphinx-apidoc -o . ../cobra ../cobra/oven ../cobra/external \
44
rm modules.rst
55

66
ipython nbconvert --to=rst phenotype_phase_plane.ipynb reactions.ipynb \
7-
metabolites.ipynb milp.ipynb escher.ipynb
7+
metabolites.ipynb milp.ipynb escher.ipynb deletions.ipynb

0 commit comments

Comments
 (0)