gsrap 0.8.0__py3-none-any.whl → 0.8.1__py3-none-any.whl

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.
@@ -72,7 +72,7 @@ def main():
72
72
  parsedb_parser.add_argument("--precursors", action='store_true', help="Verify biosynthesis of biomass precursors and show blocked ones.")
73
73
  parsedb_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
74
74
  parsedb_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the optional eggnog-mapper annotation table(s).")
75
- parsedb_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code.")
75
+ parsedb_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code. If provided, it takes precedence over --eggnog.")
76
76
  parsedb_parser.add_argument("--goodbefore", metavar='', type=str, default='-', help="Syntax is {pure_mid}-{rid1}-{rid2}. From top to bottom, build the universe until reaction {rid1}, transport {rid2} and metabolite {pure_mid} are reached.")
77
77
  parsedb_parser.add_argument("--onlyauthor", metavar='', type=str, default='-', help="Build the universe by parsing contents of the specified author ID only. Contents affected by --goodbefore are parsed anyway.")
78
78
  parsedb_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
@@ -85,7 +85,7 @@ def main():
85
85
  mkmodel_parser.add_argument("-c", "--cores", metavar='', type=int, default=0, help="Number of cores to use (if 0, use all available cores).")
86
86
  mkmodel_parser.add_argument("-o", "--outdir", metavar='', type=str, default='./', help="Main output directory (will be created if not existing).")
87
87
  mkmodel_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the eggnog-mapper annotation table(s).")
88
- mkmodel_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code.")
88
+ mkmodel_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code. If provided, it takes precedence over --eggnog.")
89
89
  mkmodel_parser.add_argument("-u", "--universe", metavar='', type=str, default='-', help="Path to the universe model (SBML format).")
90
90
  mkmodel_parser.add_argument("-i", "--force_inclusion", metavar='', type=str, default='-', help="Force the inclusion of the specified reactions (comma-separated IDs).")
91
91
  mkmodel_parser.add_argument("-f", "--gap_fill", metavar='', type=str, default='-', help="Media to use during gap-filling (comma-separated IDs); if not provided, gap-filling will be skipped.")
gsrap/__init__.py CHANGED
@@ -72,7 +72,7 @@ def main():
72
72
  parsedb_parser.add_argument("--precursors", action='store_true', help="Verify biosynthesis of biomass precursors and show blocked ones.")
73
73
  parsedb_parser.add_argument("--biosynth", action='store_true', help="Check biosynthesis of all metabolites and detect dead-ends.")
74
74
  parsedb_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the optional eggnog-mapper annotation table(s).")
75
- parsedb_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code.")
75
+ parsedb_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code. If provided, it takes precedence over --eggnog.")
76
76
  parsedb_parser.add_argument("--goodbefore", metavar='', type=str, default='-', help="Syntax is {pure_mid}-{rid1}-{rid2}. From top to bottom, build the universe until reaction {rid1}, transport {rid2} and metabolite {pure_mid} are reached.")
77
77
  parsedb_parser.add_argument("--onlyauthor", metavar='', type=str, default='-', help="Build the universe by parsing contents of the specified author ID only. Contents affected by --goodbefore are parsed anyway.")
78
78
  parsedb_parser.add_argument("--nofigs", action='store_true', help="Do not generate figures.")
@@ -85,7 +85,7 @@ def main():
85
85
  mkmodel_parser.add_argument("-c", "--cores", metavar='', type=int, default=0, help="Number of cores to use (if 0, use all available cores).")
86
86
  mkmodel_parser.add_argument("-o", "--outdir", metavar='', type=str, default='./', help="Main output directory (will be created if not existing).")
87
87
  mkmodel_parser.add_argument("-e", "--eggnog", nargs='+', metavar='', type=str, default='-', help="Path to the eggnog-mapper annotation table(s).")
88
- mkmodel_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code.")
88
+ mkmodel_parser.add_argument("-k", "--keggorg", metavar='', type=str, default='-', help="A single KEGG Organism code. If provided, it takes precedence over --eggnog.")
89
89
  mkmodel_parser.add_argument("-u", "--universe", metavar='', type=str, default='-', help="Path to the universe model (SBML format).")
90
90
  mkmodel_parser.add_argument("-i", "--force_inclusion", metavar='', type=str, default='-', help="Force the inclusion of the specified reactions (comma-separated IDs).")
91
91
  mkmodel_parser.add_argument("-f", "--gap_fill", metavar='', type=str, default='-', help="Media to use during gap-filling (comma-separated IDs); if not provided, gap-filling will be skipped.")
@@ -17,10 +17,9 @@ def apply_medium_given_column(logger, model, medium, column, is_reference=False)
17
17
  column = column.to_dict()
18
18
 
19
19
 
20
- # add trace elements:
21
- column['fe2'] = 'NL'
22
- column['mobd'] = 'NL'
23
- column['cobalt2'] = 'NL'
20
+ # add default elements (acqueous media)
21
+ column['h2o'] = 'NL'
22
+ column['h'] = '-0.0001' # pH=7
24
23
 
25
24
 
26
25
  # reset exchanges
gsrap/commons/medium.py CHANGED
@@ -17,10 +17,9 @@ def apply_medium_given_column(logger, model, medium, column, is_reference=False)
17
17
  column = column.to_dict()
18
18
 
19
19
 
20
- # add trace elements:
21
- column['fe2'] = 'NL'
22
- column['mobd'] = 'NL'
23
- column['cobalt2'] = 'NL'
20
+ # add default elements (acqueous media)
21
+ column['h2o'] = 'NL'
22
+ column['h'] = '-0.0001' # pH=7
24
23
 
25
24
 
26
25
  # reset exchanges
@@ -44,6 +44,9 @@ from ..commons import download_keggorg
44
44
 
45
45
  from ..runsims.biosynth import biosynthesis_on_media
46
46
 
47
+ from ..parsedb.cycles import verify_egc_all
48
+
49
+
47
50
 
48
51
 
49
52
  def create_model_incore(params):
@@ -140,6 +143,9 @@ def create_model_incore(params):
140
143
 
141
144
 
142
145
  ###### CHECKS
146
+ # check erroneous EGCs
147
+ verify_egc_all(logger, model, args.outdir)
148
+
143
149
  # check blocked metabolites / dead-ends
144
150
  df_S = biosynthesis_on_media(logger, model, dbexp, args.gap_fill, args.biosynth)
145
151
  if type(df_S)==int: return 1
gsrap/mkmodel/mkmodel.py CHANGED
@@ -44,6 +44,9 @@ from ..commons import download_keggorg
44
44
 
45
45
  from ..runsims.biosynth import biosynthesis_on_media
46
46
 
47
+ from ..parsedb.cycles import verify_egc_all
48
+
49
+
47
50
 
48
51
 
49
52
  def create_model_incore(params):
@@ -140,6 +143,9 @@ def create_model_incore(params):
140
143
 
141
144
 
142
145
  ###### CHECKS
146
+ # check erroneous EGCs
147
+ verify_egc_all(logger, model, args.outdir)
148
+
143
149
  # check blocked metabolites / dead-ends
144
150
  df_S = biosynthesis_on_media(logger, model, dbexp, args.gap_fill, args.biosynth)
145
151
  if type(df_S)==int: return 1
@@ -0,0 +1,128 @@
1
+ import warnings
2
+ import os
3
+ import logging
4
+
5
+
6
+ import cobra
7
+ import gempipe
8
+
9
+
10
+ from ..commons import fba_no_warnings
11
+ from ..commons import get_optthr
12
+
13
+
14
+
15
+ def verify_egc(logger, model, mid, outdir):
16
+
17
+
18
+ # changes as not permament:
19
+ found_egc = False
20
+ with model:
21
+
22
+ # close (0; 0) all the exchange reactions:
23
+ gempipe.close_boundaries(model)
24
+
25
+
26
+ # create a dissipation reaction:
27
+ dissip = cobra.Reaction(f'__dissip__{mid}')
28
+ model.add_reactions([dissip])
29
+ dissip = model.reactions.get_by_id(f'__dissip__{mid}')
30
+
31
+
32
+ # define the dissipation reaction:
33
+ modeled_mids = [m.id for m in model.metabolites]
34
+ if mid == 'atp':
35
+ dissip_string = 'atp_c + h2o_c --> adp_c + pi_c + h_c'
36
+ elif mid == 'ctp':
37
+ dissip_string = 'ctp_c + h2o_c --> cdp_c + pi_c + h_c'
38
+ elif mid == 'gtp':
39
+ dissip_string = 'gtp_c + h2o_c --> gdp_c + pi_c + h_c'
40
+ elif mid == 'utp':
41
+ dissip_string = 'utp_c + h2o_c --> udp_c + pi_c + h_c'
42
+ elif mid == 'itp':
43
+ dissip_string = 'itp_c + h2o_c --> idp_c + pi_c + h_c'
44
+ elif mid == 'nadh':
45
+ dissip_string = 'nadh_c --> nad_c + h_c'
46
+ elif mid == 'nadph':
47
+ dissip_string = 'nadph_c --> nadp_c + h_c'
48
+ elif mid == 'fadh2':
49
+ dissip_string = 'fadh2_c --> fad_c + 2.0 h_c'
50
+ elif mid == 'accoa':
51
+ dissip_string = 'accoa_c + h2o_c --> ac_c + coa_c + h_c'
52
+ elif mid == 'glu__L':
53
+ dissip_string = 'glu__L_c + h2o_c --> akg_c + nh4_c + 2.0 h_c'
54
+ elif mid == 'q8h2':
55
+ dissip_string = 'q8h2_c --> q8_c + 2.0 h_c'
56
+ dissip.build_reaction_from_string(dissip_string)
57
+
58
+
59
+ # set the objective and optimize:
60
+ model.objective = f'__dissip__{mid}'
61
+ res, obj_value, status = fba_no_warnings(model)
62
+
63
+
64
+ # apply the threshold:
65
+ obj_value = res.objective_value
66
+ status = res.status
67
+ if status == 'optimal' and obj_value >= get_optthr():
68
+ found_egc = True
69
+
70
+
71
+ # get suspect !=0 fluxes
72
+ fluxes = res.fluxes
73
+ # get interesting fluxes (get_optthr() tries to take into account the approximation in glpk and cplex solvers)
74
+ fluxes_interesting = fluxes[(fluxes > get_optthr()) | (fluxes < -get_optthr())]
75
+
76
+
77
+ # create a model for escher, remove Rs not beloning to the cycle
78
+ model_copy = model.copy()
79
+ all_rids = [r.id for r in model_copy.reactions]
80
+ to_delete = set(all_rids) - set(fluxes_interesting.index)
81
+
82
+
83
+ # trick to avoid the WARNING "cobra/core/group.py:147: UserWarning: need to pass in a list"
84
+ # triggered when trying to remove reactions that are included in groups.
85
+ with warnings.catch_warnings(): # temporarily suppress warnings for this block
86
+ warnings.simplefilter("ignore") # ignore all warnings
87
+ cobra_logger = logging.getLogger("cobra.util.solver")
88
+ old_level = cobra_logger.level
89
+ cobra_logger.setLevel(logging.ERROR)
90
+
91
+ # triggering code
92
+ model_copy.remove_reactions(to_delete) # should work also with IDs
93
+
94
+ # restore original behaviour:
95
+ cobra_logger.setLevel(old_level)
96
+
97
+
98
+ # save JSON to direct import in Escher:
99
+ outfile = os.path.join(outdir, f'EGC_{mid}.json')
100
+ cobra.io.save_json_model(model_copy, outfile)
101
+
102
+
103
+ # log some messages
104
+ rid_labels = []
105
+ for rid, flux in fluxes_interesting.to_dict().items():
106
+ rid_label = "'" + rid + "'"
107
+ # mark reversible reactions composing the cycle:
108
+ r = model.reactions.get_by_id(rid)
109
+ if r.lower_bound < 0 and r.upper_bound > 0:
110
+ rid_label = rid_label + '(<=>)'
111
+ rid_labels.append(rid_label)
112
+ logger.warning(f"Found erroneous EGC (N={len(model_copy.reactions)}) for '{mid}' (f={obj_value}): [{', '.join(rid_labels)}]. EGC saved to '{outfile}' to be inspected with Escher-FBA.")
113
+
114
+
115
+ return found_egc
116
+
117
+
118
+
119
+ def verify_egc_all(logger, model, outdir='./', mids_to_check=['atp','ctp','gtp','utp','itp','nadh','nadph','fadh2','accoa','glu__L','q8h2']):
120
+
121
+
122
+ all_results = []
123
+ for mid in mids_to_check:
124
+ all_results.append(verify_egc(logger, model, mid, outdir))
125
+ if any(all_results)==False:
126
+ logger.info("Found 0 erroneous energy-generating cycles (EGCs).")
127
+
128
+
@@ -287,15 +287,7 @@ def introduce_transporters(logger, db, model, idcollection_dict, kegg_reaction_t
287
287
  r = model.reactions.get_by_id(f'EX_{mid_e}')
288
288
  r.name = f"Exchange for {model.metabolites.get_by_id(mid_e).name}"
289
289
  r.build_reaction_from_string(f'{mid_e} --> ')
290
- if mid_e in [
291
- # basics:
292
- 'glc__D_e', 'nh4_e', 'pi_e', 'so4_e', 'h2o_e', 'h_e', 'o2_e', 'co2_e',
293
- # metals:
294
- 'cu2_e', 'mobd_e', 'fe2_e', 'cobalt2_e',
295
- ]:
296
- r.bounds = (-1000, 1000)
297
- else:
298
- r.bounds = (0, 1000)
290
+ r.bounds = (0, 1000)
299
291
 
300
292
  # add SBO annotation
301
293
  r.annotation['sbo'] = ['SBO:0000627'] # exchange reaction
@@ -19,6 +19,33 @@ def get_rids_with_mancheck_gpr():
19
19
  return rids_mancheck_gpr
20
20
 
21
21
 
22
+ def get_rids_with_mancheck_balancing():
23
+ rids_mancheck_bal = [ # same reactions involving ATP can be reversible
24
+
25
+ # SECTION "reversible both in KEGG and MetaCyc"
26
+ 'PGK', 'SUCOAS', 'ADK1', 'GK1', 'NNATr', 'CYTK1', 'ACKr',
27
+ 'DGK1', 'PPAKr', 'ATPSr', 'NDPK10',
28
+
29
+ ### SECTION "reversible in KEGG but not in MetaCyc" ###
30
+ 'CYTK2', # clearly reversible in KEGG but not in MetaCyc (RXN-7913)
31
+ 'DADK', # clearly reversible in KEGG but not in MetaCyc (DEOXYADENYLATE-KINASE-RXN)
32
+ 'UMPK', # clearly reversible in KEGG but not in MetaCyc (RXN-12002)
33
+ 'NDPK1', # clearly reversible in KEGG but not in MetaCyc (GDPKIN-RXN)
34
+ 'NDPK2', # clearly reversible in KEGG but not in MetaCyc (UDPKIN-RXN)
35
+ 'NDPK3', # clearly reversible in KEGG but not in MetaCyc (CDPKIN-RXN)
36
+ 'NDPK4', # clearly reversible in KEGG but not in MetaCyc (DTDPKIN-RXN)
37
+ 'NDPK5', # clearly reversible in KEGG but not in MetaCyc (DGDPKIN-RXN)
38
+ 'NDPK6', # clearly reversible in KEGG but not in MetaCyc (DUDPKIN-RXN)
39
+ 'NDPK7', # clearly reversible in KEGG but not in MetaCyc (DCDPKIN-RXN)
40
+ 'NDPK8', # clearly reversible in KEGG but not in MetaCyc (DADPKIN-RXN)
41
+ 'NDPK9', # clearly reversible in KEGG but not in MetaCyc (RXN-14120)
42
+
43
+ ### SECTION "missing reversibility info" ###
44
+ 'LPHERA',
45
+ ]
46
+ return rids_mancheck_bal
47
+
48
+
22
49
 
23
50
  def get_manual_sinks():
24
51
 
@@ -35,6 +35,8 @@ from ..runsims.biosynth import biosynthesis_on_media
35
35
 
36
36
  from ..mkmodel.polishing import remove_disconnected
37
37
 
38
+ from .cycles import verify_egc_all
39
+
38
40
 
39
41
 
40
42
 
@@ -173,6 +175,9 @@ def main(args, logger):
173
175
 
174
176
 
175
177
  ###### CHECKS 2
178
+ # check erroneous EGCs
179
+ verify_egc_all(logger, universe, args.outdir)
180
+
176
181
  # check growth on minmal media
177
182
  df_G = grow_on_media(logger, universe, dbexp, args.media, '-', True)
178
183
  if type(df_G)==int: return 1
@@ -4,6 +4,7 @@ import cobra
4
4
 
5
5
  from .manual import get_deprecated_kos
6
6
  from .manual import get_rids_with_mancheck_gpr
7
+ from .manual import get_rids_with_mancheck_balancing
7
8
 
8
9
 
9
10
 
@@ -138,6 +139,14 @@ def add_reaction(logger, model, rid, row, kr_ids, kegg_reaction_to_others, addty
138
139
  return 1
139
140
 
140
141
 
142
+ # check if reversible and using ATP
143
+ if r.lower_bound < 0 and r.upper_bound > 0:
144
+ for m in r.metabolites:
145
+ if m.id.rsplit('_', 1)[0] == 'atp':
146
+ if rid not in get_rids_with_mancheck_balancing():
147
+ logger.warning(f"Reaction '{rid}' involves ATP and is reversible: are you sure?")
148
+
149
+
141
150
  return 0
142
151
 
143
152
 
@@ -0,0 +1,128 @@
1
+ import warnings
2
+ import os
3
+ import logging
4
+
5
+
6
+ import cobra
7
+ import gempipe
8
+
9
+
10
+ from ..commons import fba_no_warnings
11
+ from ..commons import get_optthr
12
+
13
+
14
+
15
+ def verify_egc(logger, model, mid, outdir):
16
+
17
+
18
+ # changes as not permament:
19
+ found_egc = False
20
+ with model:
21
+
22
+ # close (0; 0) all the exchange reactions:
23
+ gempipe.close_boundaries(model)
24
+
25
+
26
+ # create a dissipation reaction:
27
+ dissip = cobra.Reaction(f'__dissip__{mid}')
28
+ model.add_reactions([dissip])
29
+ dissip = model.reactions.get_by_id(f'__dissip__{mid}')
30
+
31
+
32
+ # define the dissipation reaction:
33
+ modeled_mids = [m.id for m in model.metabolites]
34
+ if mid == 'atp':
35
+ dissip_string = 'atp_c + h2o_c --> adp_c + pi_c + h_c'
36
+ elif mid == 'ctp':
37
+ dissip_string = 'ctp_c + h2o_c --> cdp_c + pi_c + h_c'
38
+ elif mid == 'gtp':
39
+ dissip_string = 'gtp_c + h2o_c --> gdp_c + pi_c + h_c'
40
+ elif mid == 'utp':
41
+ dissip_string = 'utp_c + h2o_c --> udp_c + pi_c + h_c'
42
+ elif mid == 'itp':
43
+ dissip_string = 'itp_c + h2o_c --> idp_c + pi_c + h_c'
44
+ elif mid == 'nadh':
45
+ dissip_string = 'nadh_c --> nad_c + h_c'
46
+ elif mid == 'nadph':
47
+ dissip_string = 'nadph_c --> nadp_c + h_c'
48
+ elif mid == 'fadh2':
49
+ dissip_string = 'fadh2_c --> fad_c + 2.0 h_c'
50
+ elif mid == 'accoa':
51
+ dissip_string = 'accoa_c + h2o_c --> ac_c + coa_c + h_c'
52
+ elif mid == 'glu__L':
53
+ dissip_string = 'glu__L_c + h2o_c --> akg_c + nh4_c + 2.0 h_c'
54
+ elif mid == 'q8h2':
55
+ dissip_string = 'q8h2_c --> q8_c + 2.0 h_c'
56
+ dissip.build_reaction_from_string(dissip_string)
57
+
58
+
59
+ # set the objective and optimize:
60
+ model.objective = f'__dissip__{mid}'
61
+ res, obj_value, status = fba_no_warnings(model)
62
+
63
+
64
+ # apply the threshold:
65
+ obj_value = res.objective_value
66
+ status = res.status
67
+ if status == 'optimal' and obj_value >= get_optthr():
68
+ found_egc = True
69
+
70
+
71
+ # get suspect !=0 fluxes
72
+ fluxes = res.fluxes
73
+ # get interesting fluxes (get_optthr() tries to take into account the approximation in glpk and cplex solvers)
74
+ fluxes_interesting = fluxes[(fluxes > get_optthr()) | (fluxes < -get_optthr())]
75
+
76
+
77
+ # create a model for escher, remove Rs not beloning to the cycle
78
+ model_copy = model.copy()
79
+ all_rids = [r.id for r in model_copy.reactions]
80
+ to_delete = set(all_rids) - set(fluxes_interesting.index)
81
+
82
+
83
+ # trick to avoid the WARNING "cobra/core/group.py:147: UserWarning: need to pass in a list"
84
+ # triggered when trying to remove reactions that are included in groups.
85
+ with warnings.catch_warnings(): # temporarily suppress warnings for this block
86
+ warnings.simplefilter("ignore") # ignore all warnings
87
+ cobra_logger = logging.getLogger("cobra.util.solver")
88
+ old_level = cobra_logger.level
89
+ cobra_logger.setLevel(logging.ERROR)
90
+
91
+ # triggering code
92
+ model_copy.remove_reactions(to_delete) # should work also with IDs
93
+
94
+ # restore original behaviour:
95
+ cobra_logger.setLevel(old_level)
96
+
97
+
98
+ # save JSON to direct import in Escher:
99
+ outfile = os.path.join(outdir, f'EGC_{mid}.json')
100
+ cobra.io.save_json_model(model_copy, outfile)
101
+
102
+
103
+ # log some messages
104
+ rid_labels = []
105
+ for rid, flux in fluxes_interesting.to_dict().items():
106
+ rid_label = "'" + rid + "'"
107
+ # mark reversible reactions composing the cycle:
108
+ r = model.reactions.get_by_id(rid)
109
+ if r.lower_bound < 0 and r.upper_bound > 0:
110
+ rid_label = rid_label + '(<=>)'
111
+ rid_labels.append(rid_label)
112
+ logger.warning(f"Found erroneous EGC (N={len(model_copy.reactions)}) for '{mid}' (f={obj_value}): [{', '.join(rid_labels)}]. EGC saved to '{outfile}' to be inspected with Escher-FBA.")
113
+
114
+
115
+ return found_egc
116
+
117
+
118
+
119
+ def verify_egc_all(logger, model, outdir='./', mids_to_check=['atp','ctp','gtp','utp','itp','nadh','nadph','fadh2','accoa','glu__L','q8h2']):
120
+
121
+
122
+ all_results = []
123
+ for mid in mids_to_check:
124
+ all_results.append(verify_egc(logger, model, mid, outdir))
125
+ if any(all_results)==False:
126
+ logger.info("Found 0 erroneous energy-generating cycles (EGCs).")
127
+
128
+
@@ -287,15 +287,7 @@ def introduce_transporters(logger, db, model, idcollection_dict, kegg_reaction_t
287
287
  r = model.reactions.get_by_id(f'EX_{mid_e}')
288
288
  r.name = f"Exchange for {model.metabolites.get_by_id(mid_e).name}"
289
289
  r.build_reaction_from_string(f'{mid_e} --> ')
290
- if mid_e in [
291
- # basics:
292
- 'glc__D_e', 'nh4_e', 'pi_e', 'so4_e', 'h2o_e', 'h_e', 'o2_e', 'co2_e',
293
- # metals:
294
- 'cu2_e', 'mobd_e', 'fe2_e', 'cobalt2_e',
295
- ]:
296
- r.bounds = (-1000, 1000)
297
- else:
298
- r.bounds = (0, 1000)
290
+ r.bounds = (0, 1000)
299
291
 
300
292
  # add SBO annotation
301
293
  r.annotation['sbo'] = ['SBO:0000627'] # exchange reaction
gsrap/parsedb/manual.py CHANGED
@@ -19,6 +19,33 @@ def get_rids_with_mancheck_gpr():
19
19
  return rids_mancheck_gpr
20
20
 
21
21
 
22
+ def get_rids_with_mancheck_balancing():
23
+ rids_mancheck_bal = [ # same reactions involving ATP can be reversible
24
+
25
+ # SECTION "reversible both in KEGG and MetaCyc"
26
+ 'PGK', 'SUCOAS', 'ADK1', 'GK1', 'NNATr', 'CYTK1', 'ACKr',
27
+ 'DGK1', 'PPAKr', 'ATPSr', 'NDPK10',
28
+
29
+ ### SECTION "reversible in KEGG but not in MetaCyc" ###
30
+ 'CYTK2', # clearly reversible in KEGG but not in MetaCyc (RXN-7913)
31
+ 'DADK', # clearly reversible in KEGG but not in MetaCyc (DEOXYADENYLATE-KINASE-RXN)
32
+ 'UMPK', # clearly reversible in KEGG but not in MetaCyc (RXN-12002)
33
+ 'NDPK1', # clearly reversible in KEGG but not in MetaCyc (GDPKIN-RXN)
34
+ 'NDPK2', # clearly reversible in KEGG but not in MetaCyc (UDPKIN-RXN)
35
+ 'NDPK3', # clearly reversible in KEGG but not in MetaCyc (CDPKIN-RXN)
36
+ 'NDPK4', # clearly reversible in KEGG but not in MetaCyc (DTDPKIN-RXN)
37
+ 'NDPK5', # clearly reversible in KEGG but not in MetaCyc (DGDPKIN-RXN)
38
+ 'NDPK6', # clearly reversible in KEGG but not in MetaCyc (DUDPKIN-RXN)
39
+ 'NDPK7', # clearly reversible in KEGG but not in MetaCyc (DCDPKIN-RXN)
40
+ 'NDPK8', # clearly reversible in KEGG but not in MetaCyc (DADPKIN-RXN)
41
+ 'NDPK9', # clearly reversible in KEGG but not in MetaCyc (RXN-14120)
42
+
43
+ ### SECTION "missing reversibility info" ###
44
+ 'LPHERA',
45
+ ]
46
+ return rids_mancheck_bal
47
+
48
+
22
49
 
23
50
  def get_manual_sinks():
24
51
 
gsrap/parsedb/parsedb.py CHANGED
@@ -35,6 +35,8 @@ from ..runsims.biosynth import biosynthesis_on_media
35
35
 
36
36
  from ..mkmodel.polishing import remove_disconnected
37
37
 
38
+ from .cycles import verify_egc_all
39
+
38
40
 
39
41
 
40
42
 
@@ -173,6 +175,9 @@ def main(args, logger):
173
175
 
174
176
 
175
177
  ###### CHECKS 2
178
+ # check erroneous EGCs
179
+ verify_egc_all(logger, universe, args.outdir)
180
+
176
181
  # check growth on minmal media
177
182
  df_G = grow_on_media(logger, universe, dbexp, args.media, '-', True)
178
183
  if type(df_G)==int: return 1
@@ -4,6 +4,7 @@ import cobra
4
4
 
5
5
  from .manual import get_deprecated_kos
6
6
  from .manual import get_rids_with_mancheck_gpr
7
+ from .manual import get_rids_with_mancheck_balancing
7
8
 
8
9
 
9
10
 
@@ -138,6 +139,14 @@ def add_reaction(logger, model, rid, row, kr_ids, kegg_reaction_to_others, addty
138
139
  return 1
139
140
 
140
141
 
142
+ # check if reversible and using ATP
143
+ if r.lower_bound < 0 and r.upper_bound > 0:
144
+ for m in r.metabolites:
145
+ if m.id.rsplit('_', 1)[0] == 'atp':
146
+ if rid not in get_rids_with_mancheck_balancing():
147
+ logger.warning(f"Reaction '{rid}' involves ATP and is reversible: are you sure?")
148
+
149
+
141
150
  return 0
142
151
 
143
152
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gsrap
3
- Version: 0.8.0
3
+ Version: 0.8.1
4
4
  Summary:
5
5
  License: GNU General Public License v3.0
6
6
  Author: Gioele Lazzari
@@ -1,5 +1,5 @@
1
- gsrap/.ipynb_checkpoints/__init__-checkpoint.py,sha256=JlR5ICkhkJwQrMHJOFOZg1R-0aYQAZu9h51SlC67Mtw,14064
2
- gsrap/__init__.py,sha256=JlR5ICkhkJwQrMHJOFOZg1R-0aYQAZu9h51SlC67Mtw,14064
1
+ gsrap/.ipynb_checkpoints/__init__-checkpoint.py,sha256=lOurIE_Gn0jYS3ks3UmX11uuMrMScHADH9ivFoLpg5k,14160
2
+ gsrap/__init__.py,sha256=lOurIE_Gn0jYS3ks3UmX11uuMrMScHADH9ivFoLpg5k,14160
3
3
  gsrap/assets/.ipynb_checkpoints/PM1-checkpoint.csv,sha256=0qjaMVG_t9aFxbHbxON6ecmEUnWPwN9nhmxc61QFeCU,8761
4
4
  gsrap/assets/.ipynb_checkpoints/PM2A-checkpoint.csv,sha256=rjYTdwe8lpRS552BYiUP3J71juG2ywVdR5Sux6fjZTY,8816
5
5
  gsrap/assets/.ipynb_checkpoints/PM3B-checkpoint.csv,sha256=42IGX_2O5bRYSiHoMuVKT-T-bzVj0cSRZBvGOrbnQMA,8130
@@ -21,7 +21,7 @@ gsrap/commons/.ipynb_checkpoints/figures-checkpoint.py,sha256=IRHSQXrCi4SQoISEfN
21
21
  gsrap/commons/.ipynb_checkpoints/fluxbal-checkpoint.py,sha256=jgC3-vI9Tbjvqohh2mJwFra4rl_pbUzHWrSa_QAxVO4,1262
22
22
  gsrap/commons/.ipynb_checkpoints/keggutils-checkpoint.py,sha256=M2nhHRiNH_xObHSxOIdt7ix59MrPdl9q3HNICC8X36M,4514
23
23
  gsrap/commons/.ipynb_checkpoints/logutils-checkpoint.py,sha256=VsnrkIsUftS3MOOwAd0n0peQ7a2X5ZEx930eCtzmW7g,1317
24
- gsrap/commons/.ipynb_checkpoints/medium-checkpoint.py,sha256=VYKN8X1PNERP6uQDbznZXfgflLEvnw4j1T8AIAdrE7s,2902
24
+ gsrap/commons/.ipynb_checkpoints/medium-checkpoint.py,sha256=wcWiuZ-mqryoYBrsIHkIen6fBssR_1FGVoXUTApylNc,2901
25
25
  gsrap/commons/.ipynb_checkpoints/metrics-checkpoint.py,sha256=gvqF2c0e31m5qQWQ11JF4-eMqxtuONy_7lUiC7uaXX4,3291
26
26
  gsrap/commons/.ipynb_checkpoints/sbmlutils-checkpoint.py,sha256=gkY02qbGXrbYStn2F8J0KM0fmqati2Nbvi128EF7coI,365
27
27
  gsrap/commons/__init__.py,sha256=QuHINLSWNb0XKagHRWXzU5UVxw3ECTncvR7llRKblso,241
@@ -34,7 +34,7 @@ gsrap/commons/figures.py,sha256=IRHSQXrCi4SQoISEfNB0rDhvUzbjcgsPi9zUSefsRto,4316
34
34
  gsrap/commons/fluxbal.py,sha256=jgC3-vI9Tbjvqohh2mJwFra4rl_pbUzHWrSa_QAxVO4,1262
35
35
  gsrap/commons/keggutils.py,sha256=M2nhHRiNH_xObHSxOIdt7ix59MrPdl9q3HNICC8X36M,4514
36
36
  gsrap/commons/logutils.py,sha256=VsnrkIsUftS3MOOwAd0n0peQ7a2X5ZEx930eCtzmW7g,1317
37
- gsrap/commons/medium.py,sha256=VYKN8X1PNERP6uQDbznZXfgflLEvnw4j1T8AIAdrE7s,2902
37
+ gsrap/commons/medium.py,sha256=wcWiuZ-mqryoYBrsIHkIen6fBssR_1FGVoXUTApylNc,2901
38
38
  gsrap/commons/metrics.py,sha256=gvqF2c0e31m5qQWQ11JF4-eMqxtuONy_7lUiC7uaXX4,3291
39
39
  gsrap/commons/sbmlutils.py,sha256=gkY02qbGXrbYStn2F8J0KM0fmqati2Nbvi128EF7coI,365
40
40
  gsrap/getmaps/.ipynb_checkpoints/__init__-checkpoint.py,sha256=L4gLwk1vgnPlQuIP-FPnvy9uXnmGVQ4Rvjv3uyciDfk,92
@@ -47,30 +47,32 @@ gsrap/mkmodel/.ipynb_checkpoints/__init__-checkpoint.py,sha256=PNze-26HMOwfdJ92K
47
47
  gsrap/mkmodel/.ipynb_checkpoints/biologcuration-checkpoint.py,sha256=Nn7z-js-mzzeO23kVM2L7sJ5PNle7AkCUeBcEAYjlFU,15378
48
48
  gsrap/mkmodel/.ipynb_checkpoints/gapfill-checkpoint.py,sha256=BPZw4sszlBhAYfHnV0pA7EpG0b2ePwS6kUfFt0Ww-ss,5159
49
49
  gsrap/mkmodel/.ipynb_checkpoints/gapfillutils-checkpoint.py,sha256=S6nFUZ1Bbdf13nVJhGK2S5C_V3hd5zwTg2o5nzejngg,3123
50
- gsrap/mkmodel/.ipynb_checkpoints/mkmodel-checkpoint.py,sha256=0ekGXmNULzVbkl6QW_Z8xDrHlevgtVDWEURJJR2uQRM,10323
50
+ gsrap/mkmodel/.ipynb_checkpoints/mkmodel-checkpoint.py,sha256=3o4_B3ALcq6GYLAZ7zteNOcLTfE3KVJO6s9L4uMmw8E,10448
51
51
  gsrap/mkmodel/.ipynb_checkpoints/polishing-checkpoint.py,sha256=R1UdFPxN8N27Iu0jsYW2N_1BkWEbBHaMYW6NkCYZK_k,3256
52
52
  gsrap/mkmodel/.ipynb_checkpoints/pruner-checkpoint.py,sha256=FAZid-0H6j66wR2dVKRAaMaDREVt1edflmZXbX7blXg,9836
53
53
  gsrap/mkmodel/__init__.py,sha256=PNze-26HMOwfdJ92KiXpr--VV1ftVfo3CAxBZgeokp8,92
54
54
  gsrap/mkmodel/biologcuration.py,sha256=Nn7z-js-mzzeO23kVM2L7sJ5PNle7AkCUeBcEAYjlFU,15378
55
55
  gsrap/mkmodel/gapfill.py,sha256=BPZw4sszlBhAYfHnV0pA7EpG0b2ePwS6kUfFt0Ww-ss,5159
56
56
  gsrap/mkmodel/gapfillutils.py,sha256=S6nFUZ1Bbdf13nVJhGK2S5C_V3hd5zwTg2o5nzejngg,3123
57
- gsrap/mkmodel/mkmodel.py,sha256=0ekGXmNULzVbkl6QW_Z8xDrHlevgtVDWEURJJR2uQRM,10323
57
+ gsrap/mkmodel/mkmodel.py,sha256=3o4_B3ALcq6GYLAZ7zteNOcLTfE3KVJO6s9L4uMmw8E,10448
58
58
  gsrap/mkmodel/polishing.py,sha256=R1UdFPxN8N27Iu0jsYW2N_1BkWEbBHaMYW6NkCYZK_k,3256
59
59
  gsrap/mkmodel/pruner.py,sha256=FAZid-0H6j66wR2dVKRAaMaDREVt1edflmZXbX7blXg,9836
60
60
  gsrap/parsedb/.ipynb_checkpoints/__init__-checkpoint.py,sha256=1k2K1gz4lIdXAwHEdJ0OhdkPu83woGv0Z4TpT1kGrTk,97
61
61
  gsrap/parsedb/.ipynb_checkpoints/annotation-checkpoint.py,sha256=Y02_zXJj_tS1GyBdfuLBy9YJjMgx3mjX6tqr1KhQ-9Q,4810
62
62
  gsrap/parsedb/.ipynb_checkpoints/completeness-checkpoint.py,sha256=yhFiEslK1qmMCk_GWZ7UZtX02FUqLU39UafG5886WsY,12016
63
- gsrap/parsedb/.ipynb_checkpoints/introduce-checkpoint.py,sha256=TpW-Hp_rq6AGUQ-IVFwU8Vhij6poKWz8EF-NhdsAOsI,17414
64
- gsrap/parsedb/.ipynb_checkpoints/manual-checkpoint.py,sha256=F16wU8vLyM6V4F611ABuMJtwSAskL5KEgCJ7EQm_F9Y,2177
65
- gsrap/parsedb/.ipynb_checkpoints/parsedb-checkpoint.py,sha256=OPc8PrTVD2szrmvZISlyhP1Q51AlaoQ_EghAJs4jfFU,7465
66
- gsrap/parsedb/.ipynb_checkpoints/repeating-checkpoint.py,sha256=9PgsSw-H84eN_dFUwK5FLgbqvydsdic4-VjCrZqkfnY,5703
63
+ gsrap/parsedb/.ipynb_checkpoints/cycles-checkpoint.py,sha256=HJ58LcHQseQ1eploysfXd5Y8Rip8n62qhje4pmL22VM,4761
64
+ gsrap/parsedb/.ipynb_checkpoints/introduce-checkpoint.py,sha256=UuwGWGB2saG9VDMoboumeRBWhHOO68bs5_1r2RSkyVo,17145
65
+ gsrap/parsedb/.ipynb_checkpoints/manual-checkpoint.py,sha256=qMKYshVftSGCRAjHC87E6n9-6kAiffFFCgHOUbqlyC0,3625
66
+ gsrap/parsedb/.ipynb_checkpoints/parsedb-checkpoint.py,sha256=M44zFmaYu50LYDjFH3IdiezjPbzuDIzZ9ukzwU4ZBBM,7583
67
+ gsrap/parsedb/.ipynb_checkpoints/repeating-checkpoint.py,sha256=WwPOzlZgsZWmJ-rvhFg21iOJ6gajgKFc2vCIHh6weBg,6103
67
68
  gsrap/parsedb/__init__.py,sha256=1k2K1gz4lIdXAwHEdJ0OhdkPu83woGv0Z4TpT1kGrTk,97
68
69
  gsrap/parsedb/annotation.py,sha256=Y02_zXJj_tS1GyBdfuLBy9YJjMgx3mjX6tqr1KhQ-9Q,4810
69
70
  gsrap/parsedb/completeness.py,sha256=yhFiEslK1qmMCk_GWZ7UZtX02FUqLU39UafG5886WsY,12016
70
- gsrap/parsedb/introduce.py,sha256=TpW-Hp_rq6AGUQ-IVFwU8Vhij6poKWz8EF-NhdsAOsI,17414
71
- gsrap/parsedb/manual.py,sha256=F16wU8vLyM6V4F611ABuMJtwSAskL5KEgCJ7EQm_F9Y,2177
72
- gsrap/parsedb/parsedb.py,sha256=OPc8PrTVD2szrmvZISlyhP1Q51AlaoQ_EghAJs4jfFU,7465
73
- gsrap/parsedb/repeating.py,sha256=9PgsSw-H84eN_dFUwK5FLgbqvydsdic4-VjCrZqkfnY,5703
71
+ gsrap/parsedb/cycles.py,sha256=HJ58LcHQseQ1eploysfXd5Y8Rip8n62qhje4pmL22VM,4761
72
+ gsrap/parsedb/introduce.py,sha256=UuwGWGB2saG9VDMoboumeRBWhHOO68bs5_1r2RSkyVo,17145
73
+ gsrap/parsedb/manual.py,sha256=qMKYshVftSGCRAjHC87E6n9-6kAiffFFCgHOUbqlyC0,3625
74
+ gsrap/parsedb/parsedb.py,sha256=M44zFmaYu50LYDjFH3IdiezjPbzuDIzZ9ukzwU4ZBBM,7583
75
+ gsrap/parsedb/repeating.py,sha256=WwPOzlZgsZWmJ-rvhFg21iOJ6gajgKFc2vCIHh6weBg,6103
74
76
  gsrap/runsims/.ipynb_checkpoints/__init__-checkpoint.py,sha256=6E6E1gWgH0V7ls4Omx4mxxC85gMJ_27YqhjugJzlZtY,97
75
77
  gsrap/runsims/.ipynb_checkpoints/biosynth-checkpoint.py,sha256=fUlHUo4CfB4rGX9Dth87B1p5E5sz7i6spR7ZoqDDGaI,2836
76
78
  gsrap/runsims/.ipynb_checkpoints/cnps-checkpoint.py,sha256=A0U8QPqW_uyrtHs99F286aEDEC6eukHXeMWrmnd0efA,5636
@@ -89,8 +91,8 @@ gsrap/runsims/precursors.py,sha256=1RNt_Rxs0L1lolDmYh4_CiZgiwHfU5B_AcomJO6vJ28,2
89
91
  gsrap/runsims/runsims.py,sha256=2FC5Gs8oSYyZTjHF3A7aXB_O6myVfcn3bCxQfLJlZTk,2842
90
92
  gsrap/runsims/simplegrowth.py,sha256=tCQHTMUqum1YwlBKRTNaQoag2co_yQlCaKmISOARAlE,2353
91
93
  gsrap/runsims/singleomission.py,sha256=jMuKAi0pINP8Jlrm-yI-tX7D110VzttR3YfTSnDRe4I,2847
92
- gsrap-0.8.0.dist-info/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
93
- gsrap-0.8.0.dist-info/METADATA,sha256=T5COI9B29df6TdmUbZvFrQsficCTN3SVzJGHJ5yw4Us,898
94
- gsrap-0.8.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
95
- gsrap-0.8.0.dist-info/entry_points.txt,sha256=S9MY0DjfnbKGlZbp5bV7W6dNFy3APoEV84u9x6MV1eI,36
96
- gsrap-0.8.0.dist-info/RECORD,,
94
+ gsrap-0.8.1.dist-info/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
95
+ gsrap-0.8.1.dist-info/METADATA,sha256=TvK87lEyotFJA3LRgzVFROv7mHMya-p0xPv5EUQNUJE,898
96
+ gsrap-0.8.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
97
+ gsrap-0.8.1.dist-info/entry_points.txt,sha256=S9MY0DjfnbKGlZbp5bV7W6dNFy3APoEV84u9x6MV1eI,36
98
+ gsrap-0.8.1.dist-info/RECORD,,
File without changes