mohzargar commited on
Commit
4f14213
·
verified ·
1 Parent(s): 85531fa

Upload 18 files

Browse files
Cowmunity-litreturebased.py ADDED
@@ -0,0 +1,1271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import libsbml
3
+ from gamspy import Container, Set, Parameter, Variable, Equation, Model, Sum, Sense, Options, SpecialValues, SolveStatus
4
+ import os
5
+
6
+ def Sets():
7
+ print("Creating sets...")
8
+ global cowmunity
9
+
10
+ cowmunity = Container()
11
+
12
+ global j_mgk, j_prm, j_rfl, i_mgk, i_prm, i_rfl
13
+
14
+ j_mgk = Set(container=cowmunity, name="j_mgk", description="M. Gottschalkii reactions")
15
+ j_prm = Set(container=cowmunity, name="j_prm", description="P. ruminicola reactions")
16
+ j_rfl = Set(container=cowmunity, name="j_rfl", description="R. flavefaciens reactions")
17
+
18
+ i_mgk = Set(container=cowmunity, name="i_mgk", description="M. Gottschalkii metabolites")
19
+ i_prm = Set(container=cowmunity, name="i_prm", description="P. ruminicola metabolites")
20
+ i_rfl = Set(container=cowmunity, name="i_rfl", description="R. flavefaciens metabolites")
21
+
22
+ def extract_metabolites(xml_file_path, GAMSpy_set):
23
+ # Parse the XML file
24
+ reader = libsbml.SBMLReader()
25
+ document = reader.readSBML(f'model files/{xml_file_path}')
26
+ model = document.getModel()
27
+ if model is None:
28
+ raise ValueError("The SBML model could not be parsed or is empty.")
29
+
30
+ # Extract names and store them in a list
31
+ met_name = {}
32
+ for i in range(model.getNumSpecies()):
33
+ species = model.getSpecies(i)
34
+ new_entry = {species.id : species.getName()[0:63]}
35
+ met_name.update(new_entry)
36
+ df = pd.DataFrame.from_dict(met_name, orient='index', columns=['name'])
37
+
38
+ # add the names to the GAMSpy Set
39
+ GAMSpy_set.setRecords(df.reset_index())
40
+
41
+
42
+ def extract_reactions(xml_file_path, GAMSpy_set):
43
+ # Parse the XML file
44
+ reader = libsbml.SBMLReader()
45
+ document = reader.readSBML(f'model files/{xml_file_path}')
46
+ model = document.getModel()
47
+ if model is None:
48
+ raise ValueError("The SBML model could not be parsed or is empty.")
49
+
50
+ # Extract names and store them in a list
51
+ rxn_name = {}
52
+ for i in range(model.getNumReactions()):
53
+ reaction = model.getReaction(i)
54
+ new_entry = {reaction.id : reaction.getName()[0:63]}
55
+ rxn_name.update(new_entry)
56
+ df = pd.DataFrame.from_dict(rxn_name, orient='index', columns=['name'])
57
+
58
+ # add the names to the GAMSpy Set
59
+ GAMSpy_set.setRecords(df.reset_index())
60
+
61
+
62
+ extract_reactions('M. gottschalkii.xml', j_mgk)
63
+ extract_reactions('P. ruminicola.xml', j_prm)
64
+ extract_reactions('R. flavefaciens.xml', j_rfl)
65
+
66
+ extract_metabolites('M. gottschalkii.xml', i_mgk)
67
+ extract_metabolites('P. ruminicola.xml', i_prm)
68
+ extract_metabolites('R. flavefaciens.xml', i_rfl)
69
+
70
+ def Parameters():
71
+ print("Adding model parameters...")
72
+ global ub_mgk, ub_prm, ub_rfl, lb_mgk, lb_prm, lb_rfl
73
+
74
+ ub_mgk = Parameter(container=cowmunity, name="ub_mgk", domain=j_mgk, description="Upper bound for M. Gottschalkii reactions")
75
+ lb_mgk = Parameter(container=cowmunity, name="lb_mgk", domain=j_mgk, description="Lower bound for M. Gottschalkii reactions")
76
+
77
+ ub_prm = Parameter(container=cowmunity, name="ub_prm", domain=j_prm, description="Upper bound for P. ruminicola reactions")
78
+ lb_prm = Parameter(container=cowmunity, name="lb_prm", domain=j_prm, description="Lower bound for P. ruminicola reactions")
79
+
80
+ ub_rfl = Parameter(container=cowmunity, name="ub_rfl", domain=j_rfl, description="Upper bound for R. flavefaciens reactions")
81
+ lb_rfl = Parameter(container=cowmunity, name="lb_rfl", domain=j_rfl, description="Lower bound for R. flavefaciens reactions")
82
+
83
+ # define the reaction types for each reaction, whether they are reversible (1) or irreversible (0)
84
+
85
+ rxntype_mgk = Parameter(container=cowmunity, name="rxntype_mgk", domain=j_mgk, description="Reaction type for M. Gottschalkii reactions")
86
+ rxntype_prm = Parameter(container=cowmunity, name="rxntype_prm", domain=j_prm, description="Reaction type for P. ruminicola reactions")
87
+ rxntype_rfl = Parameter(container=cowmunity, name="rxntype_rfl", domain=j_rfl, description="Reaction type for R. flavefaciens reactions")
88
+
89
+ # define the stoichiometric matrix for each species, which describes the relationship between reactions and metabolites
90
+ # gives the coefficients for each reaction
91
+
92
+ global S_mgk, S_prm, S_rfl
93
+
94
+ S_mgk = Parameter(container=cowmunity, name="S_mgk", domain=[j_mgk, i_mgk], description="Stoichiometric matrix for M. Gottschalkii")
95
+ S_prm = Parameter(container=cowmunity, name="S_prm", domain=[j_prm, i_prm], description="Stoichiometric matrix for P. ruminicola")
96
+ S_rfl = Parameter(container=cowmunity, name="S_rfl", domain=[j_rfl, i_rfl], description="Stoichiometric matrix for R. flavefaciens")
97
+
98
+ # define whether each reaction is an exchange reaction
99
+
100
+ ex_mgk = Parameter(container=cowmunity, name="ex_mgk", domain=j_mgk, description="Exchange for M. Gottschalkii reactions")
101
+ ex_prm = Parameter(container=cowmunity, name="ex_prm", domain=j_prm, description="Exchange for P. ruminicola reactions")
102
+ ex_rfl = Parameter(container=cowmunity, name="ex_rfl", domain=j_rfl, description="Exchange for R. flavefaciens reactions")
103
+
104
+ def extract_rxn_type(xml_file_path, GAMSpy_parameter):
105
+ # Parse the XML file
106
+ reader = libsbml.SBMLReader()
107
+ document = reader.readSBML(f'model files/{xml_file_path}')
108
+ model = document.getModel()
109
+ if model is None:
110
+ raise ValueError("The SBML model could not be parsed or is empty.")
111
+ # Extract names and store them in a list
112
+ type_dict = {}
113
+ for i in range(model.getNumReactions()):
114
+ reaction = model.getReaction(i)
115
+ rxn_type = reaction.getReversible()
116
+ if rxn_type:
117
+ rxn_type = 1
118
+ else:
119
+ rxn_type = 0
120
+ new_entry = {reaction.id : rxn_type}
121
+ type_dict.update(new_entry)
122
+
123
+ df = pd.DataFrame.from_dict(type_dict, orient='index', columns=['name'])
124
+
125
+ # add the names to the GAMSpy Set
126
+ GAMSpy_parameter.setRecords(df.reset_index())
127
+
128
+
129
+ def extract_matrix(xml_file_path, GAMSpy_parameter):
130
+ # Parse the XML file
131
+ reader = libsbml.SBMLReader()
132
+ document = reader.readSBML(f'model files/{xml_file_path}')
133
+ model = document.getModel()
134
+ if model is None:
135
+ raise ValueError("The SBML model could not be parsed or is empty.")
136
+ # Extract reactions, metabolites, and their stoichiometry
137
+ df = pd.DataFrame()
138
+ for i in range(model.getNumReactions()):
139
+ reaction = model.getReaction(i)
140
+ for i in range(reaction.getNumReactants()):
141
+ reactant = reaction.getReactant(i)
142
+ metabolite_id = reactant.species
143
+ stoich = reactant.stoichiometry
144
+ new_row_df = pd.DataFrame({'reaction': [reaction.id], 'metabolite': [metabolite_id], 'stoichiometry': [-stoich]})
145
+ df = pd.concat([df, new_row_df], ignore_index=True)
146
+ for i in range(reaction.getNumProducts()):
147
+ product = reaction.getProduct(i)
148
+ metabolite_id = product.species
149
+ stoich = product.stoichiometry
150
+ new_row_df = pd.DataFrame({'reaction': [reaction.id], 'metabolite': [metabolite_id], 'stoichiometry': [stoich]})
151
+ df = pd.concat([df, new_row_df], ignore_index=True)
152
+
153
+ df = df.set_index(['reaction', 'metabolite'])
154
+
155
+
156
+ # add the names to the GAMSpy Set
157
+ GAMSpy_parameter.setRecords(df.reset_index())
158
+
159
+
160
+ def extract_exchange_type(xml_file_path, GAMSpy_parameter):
161
+ # Parse the XML file
162
+ reader = libsbml.SBMLReader()
163
+ document = reader.readSBML(f'model files/{xml_file_path}')
164
+ model = document.getModel()
165
+ if model is None:
166
+ raise ValueError("The SBML model could not be parsed or is empty.")
167
+ # Extract names and store them in a list
168
+ type_dict = {}
169
+ ex_count = 0
170
+ for i in range(model.getNumReactions()):
171
+ reaction = model.getReaction(i)
172
+ if 'EX_' in reaction.id:
173
+ ex_type = 1
174
+ ex_count += 1
175
+ else:
176
+ ex_type = 0
177
+ new_entry = {reaction.id : ex_type}
178
+ type_dict.update(new_entry)
179
+
180
+ df = pd.DataFrame.from_dict(type_dict, orient='index', columns=['name'])
181
+
182
+ # add the names to the GAMSpy Set
183
+ GAMSpy_parameter.setRecords(df.reset_index())
184
+
185
+
186
+ extract_rxn_type('M. gottschalkii.xml', rxntype_mgk)
187
+ extract_rxn_type('P. ruminicola.xml', rxntype_prm)
188
+ extract_rxn_type('R. flavefaciens.xml', rxntype_rfl)
189
+
190
+ extract_matrix('M. gottschalkii.xml', S_mgk)
191
+ extract_matrix('P. ruminicola.xml', S_prm)
192
+ extract_matrix('R. flavefaciens.xml', S_rfl)
193
+
194
+ extract_exchange_type('M. gottschalkii.xml', ex_mgk)
195
+ extract_exchange_type('P. ruminicola.xml', ex_prm)
196
+ extract_exchange_type('R. flavefaciens.xml', ex_rfl)
197
+
198
+ # using a scalar parameter to define the maximum flux for each reaction, this is a constant that will be used in the model
199
+
200
+ Vmax = Parameter(container=cowmunity, name='Vmax', records=1000)
201
+
202
+ # set the reaction bounds for the irreversible reactions, reaction type 0
203
+
204
+ ub_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 0] = Vmax
205
+ lb_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 0] = SpecialValues.EPS # using SpecialValues.EPS to avoid zero lower bounds, which can cause issues in some solvers
206
+
207
+ ub_prm[j_prm].where[rxntype_prm[j_prm] == 0] = Vmax
208
+ lb_prm[j_prm].where[rxntype_prm[j_prm] == 0] = SpecialValues.EPS
209
+
210
+ ub_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 0] = Vmax
211
+ lb_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 0] = SpecialValues.EPS
212
+
213
+ # set the reaction bounds for the reversible reactions, reaction type 1
214
+
215
+ ub_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 1] = Vmax
216
+ lb_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 1] = -Vmax
217
+
218
+ ub_prm[j_prm].where[rxntype_prm[j_prm] == 1] = Vmax
219
+ lb_prm[j_prm].where[rxntype_prm[j_prm] == 1] = -Vmax
220
+
221
+ ub_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 1] = Vmax
222
+ lb_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 1] = -Vmax
223
+
224
+ def Variables(variable_choice, treatment='no', methane='variable'):
225
+ global v_mgk, v_prm, v_rfl, biomass_outer, ATP_outer, objective_variable
226
+
227
+ biomass_outer = Variable(container=cowmunity, name="biomass_outer", description="Outer problem Biomass objective function")
228
+ ATP_outer = Variable(container=cowmunity, name="ATP_outer", description="Outer problem ATP objective function")
229
+
230
+ if variable_choice == 'biomass_outer':
231
+ objective_variable = biomass_outer
232
+ if variable_choice == 'ATP_outer':
233
+ objective_variable = ATP_outer
234
+
235
+
236
+ v_mgk = Variable(container=cowmunity, name="v_mgk", domain=j_mgk, description="Fluxes for M. Gottschalkii reactions")
237
+ v_prm = Variable(container=cowmunity, name="v_prm", domain=j_prm, description="Fluxes for P. ruminicola reactions")
238
+ v_rfl = Variable(container=cowmunity, name="v_rfl", domain=j_rfl, description="Fluxes for R. flavefaciens reactions")
239
+
240
+ global lambda_mgk, lambda_prm, lambda_rfl
241
+
242
+ # Dual variables for the mass balance
243
+ lambda_mgk = Variable(container=cowmunity, name="lambda_mgk", domain=i_mgk, description="Dual variables for M. Gottschalkii metabolites")
244
+ lambda_prm = Variable(container=cowmunity, name="lambda_prm", domain=i_prm, description="Dual variables for P. ruminicola metabolites")
245
+ lambda_rfl = Variable(container=cowmunity, name="lambda_rfl", domain=i_rfl, description="Dual variables for R. flavefaciens metabolites")
246
+
247
+ # defining the flux bounds for each reaction as the upper and lower bounds defined above
248
+ v_mgk.lo[j_mgk] = lb_mgk[j_mgk]
249
+ v_mgk.up[j_mgk] = ub_mgk[j_mgk]
250
+ v_prm.lo[j_prm] = lb_prm[j_prm]
251
+ v_prm.up[j_prm] = ub_prm[j_prm]
252
+ v_rfl.lo[j_rfl] = lb_rfl[j_rfl]
253
+ v_rfl.up[j_rfl] = ub_rfl[j_rfl]
254
+
255
+ # ****** indicates the metabolite is transferred between species, so I will not set a flux for the species that does not take it up
256
+ # commented lines are those determined to have a greater capacity due to the potential for transfer between species
257
+ # the 4.55 indicates a conversion factor for dry whole weight to dry cell weight, as the model is based on dry cell weight
258
+
259
+ # v_prm.lo['EX_cpd11657_e0'] = -0.965423023 * 4.55 # uptake rate for Starch, fed to the model as two glucose units
260
+ v_prm.lo['EX_cpd00076_e0'] = -0.834726132 * 4.55 # uptake rate for Sucrose
261
+ v_rfl.lo['EX_cpd00076_e0'] = -0.834726132 * 4.55
262
+ v_prm.lo['EX_cpd00053_e0'] = -1.597816364 * 4.55 # uptake rate for L-Glutamine
263
+ v_rfl.lo['EX_cpd00053_e0'] = -1.597816364 * 4.55
264
+ # v_prm.lo['EX_cpd00027_e0'] = -0.794397609 * 4.55 # uptake rate for D-glucose *****
265
+ v_rfl.lo['EX_cpd00027_e0'] = (-0.794397609 + (-0.965423023 * 2)) * 4.55 # adjusted for the uptake of Starch
266
+ v_rfl.lo['EX_cpd00107_e0'] = -1.148366562 * 4.55 # uptake rate for L-Leucine
267
+ v_prm.lo['EX_cpd00107_e0'] = -1.148366562 * 4.55
268
+ # v_prm.lo['EX_cpd00224_e0'] = -0.666427627 * 4.55 # uptake rate for L-arabinose *****
269
+ v_rfl.lo['EX_cpd00224_e0'] = -0.666427627 * 4.55
270
+ # v_prm.lo['EX_cpd00035_e0'] = -0.938846598 * 4.55 # uptake rate for L-Alanine ****
271
+ # v_rfl.lo['EX_cpd00035_e0'] = -0.938846598 * 4.55
272
+ v_prm.lo['EX_cpd00132_e0'] = -0.400330802 * 4.55 # uptake rate for L-Asparagine
273
+ v_rfl.lo['EX_cpd00066_e0'] = -0.310015056 * 4.55 # uptake rate for L-Phenylalanine
274
+ v_rfl.lo['EX_cpd00156_e0'] = -0.385856944 * 4.55 # uptake rate for L-Valine
275
+ v_rfl.lo['EX_cpd00069_e0'] = -0.218417727 * 4.55 # uptake rate for L-Tyrosine
276
+ v_prm.lo['EX_cpd00060_e0'] = -0.233929798 * 4.55 # uptake rate for L-Methionine
277
+ v_prm.lo['EX_cpd00161_e0'] = -0.261179221 * 4.55 # uptake rate for L-Threonine
278
+ v_rfl.lo['EX_cpd00161_e0'] = -0.261179221 * 4.55
279
+ v_rfl.lo['EX_cpd00322_e0'] = -0.211165444 * 4.55 # uptake rate for L-Isoleucine
280
+ v_prm.lo['EX_cpd00051_e0'] = -0.133660701 * 4.55 # uptake rate for L-Arginine
281
+ v_rfl.lo['EX_cpd00051_e0'] = -0.133660701 * 4.55
282
+ # v_prm.lo['EX_cpd00033_e0'] = -0.268595078 * 4.55 # uptake rate for Glycine ******
283
+ # v_rfl.lo['EX_cpd00033_e0'] = -0.268595078 * 4.55
284
+ v_prm.lo['EX_cpd00348_e0'] = -0.075513967 * 4.55 # uptake rate for D-Galactose
285
+ v_rfl.lo['EX_cpd00348_e0'] = -0.075513967 * 4.55
286
+ v_rfl.lo['EX_cpd00119_e0'] = -0.124559013 * 4.55 # uptake rate for L-Histidine
287
+ v_prm.lo['EX_cpd00039_e0'] = -0.098373937 * 4.55 # uptake rate for L-Lysine
288
+ v_rfl.lo['EX_cpd00039_e0'] = -0.098373937 * 4.55
289
+ v_prm.lo['EX_cpd00084_e0'] = -0.114920408 * 4.55 # uptake rate for L-Cysteine
290
+ v_rfl.lo['EX_cpd00084_e0'] = -0.114920408 * 4.55
291
+ v_prm.lo['EX_cpd00053_e0'] = -0.080568485 * 4.55 # uptake rate for L-Glutamine
292
+ v_rfl.lo['EX_cpd00053_e0'] = -0.080568485 * 4.55
293
+ v_rfl.lo['EX_cpd00038_e0'] = -0.007734655 * 4.55 # uptake rate for GTP
294
+ v_rfl.lo['EX_cpd00138_e0'] = -0.021731242 * 4.55 # uptake rate for D-Mannose
295
+ v_prm.lo['EX_cpd00052_e0'] = -0.007307850 * 4.55 # uptake rate for CTP
296
+ v_rfl.lo['EX_cpd00052_e0'] = -0.007307850 * 4.55
297
+ v_prm.lo['EX_cpd00002_e0'] = -0.006289719 * 4.55 # uptake rate for ATP
298
+ v_rfl.lo['EX_cpd00002_e0'] = -0.006289719 * 4.55
299
+ v_prm.lo['EX_cpd00062_e0'] = -0.005932755 * 4.55 # uptake rate for UTP
300
+ v_rfl.lo['EX_cpd00062_e0'] = -0.005932755 * 4.55
301
+ v_rfl.lo['EX_cpd00115_e0'] = -0.001147315 * 4.55 # uptake rate for dATP
302
+ v_rfl.lo['EX_cpd00357_e0'] = -0.001147552 * 4.55 # uptake rate for dTTP
303
+ v_rfl.lo['EX_cpd00241_e0'] = -0.001012678 * 4.55 # uptake rate for dGTP
304
+ v_prm.lo['EX_cpd00356_e0'] = -0.001016235 * 4.55 # uptake rate for dCTP
305
+ v_rfl.lo['EX_cpd00356_e0'] = -0.001016235 * 4.55
306
+ # v_prm.lo['EX_cpd11746_e0'] = -0.320930655 * 4.55 # uptake rate for Cellulose ****
307
+ v_rfl.lo['EX_cpd11746_e0'] = -0.320930655 * 4.55
308
+ v_rfl.lo['EX_cpd29869_e0'] = -0.002499522 * 4.55 # uptake rate for hemicellulose
309
+ # v_prm.lo['EX_cpd00009_e0'] = -0.005244478 * 4.55 # uptake rate for Phosphate, this is an inorganic ion, uptake set to max
310
+ # v_rfl.lo['EX_cpd00009_e0'] = -0.005244478 * 4.55
311
+ v_rfl.lo['EX_cpd00065_e0'] = 0 # uptake rate for Tryptophan
312
+ v_prm.lo['EX_cpd00073_e0'] = -0.629166662 * 4.55 # uptake rate for Urea
313
+ v_rfl.lo['EX_cpd00073_e0'] = -0.629166662 * 4.55
314
+ # v_prm.lo['EX_cpd00048_e0'] = -0.004273279 * 4.55 # uptake rate for Sulfate, this is an inorganic ion, uptake set to max
315
+ # v_rfl.lo['EX_cpd00048_e0'] = -0.004273279 * 4.55
316
+
317
+ # added constraints to bring down the MGK flux
318
+ v_mgk.lo['EX_cpd00162_e0'] = -1 # uptake rate for aminoethanol
319
+ v_mgk.lo['EX_cpd00122_e0'] = -0.01 # uptake rate for n-acetyl-D-glucosamine
320
+
321
+ # added contraints to coorespond to the different treatment options
322
+
323
+ if methane == 'variable':
324
+ if treatment == 'imidazole':
325
+ # reactions that are affected by imidazole treatment
326
+ # Imidazole inhibits lysozyme activity in protozoa, reducing their ability to digest bacteria
327
+ # This reduces predation pressure on bacteria, allowing them to grow more freely
328
+ # We simulate this by increasing biomass production rates and reducing some metabolic constraints
329
+
330
+ # Increase biomass production rates for all bacteria (reduced predation pressure)
331
+ v_mgk.lo['R_biomass0'] = v_mgk.lo['R_biomass0'] * 1.15 # Increase biomass production by 15%
332
+ v_prm.lo['R_biomass0'] = v_prm.lo['R_biomass0'] * 1.15
333
+ v_rfl.lo['R_biomass0'] = v_rfl.lo['R_biomass0'] * 1.15
334
+ # Increase substrate uptake rates (bacteria can access more resources with reduced predation)
335
+ # Note: We'll use more conservative increases and only apply to reactions that exis
336
+ # v_prm.lo['EX_cpd00027_e0'] = v_prm.lo['EX_cpd00027_e0'] * 1.2
337
+ # v_rfl.lo['EX_cpd00027_e0'] = v_rfl.lo['EX_cpd00027_e0'] * 1.2
338
+ # Increase acetate production (common byproduct of bacterial metabolism)
339
+ v_mgk.lo['EX_cpd00029_e0'] = v_mgk.lo['EX_cpd00029_e0'] * 1.1
340
+ v_prm.lo['EX_cpd00029_e0'] = v_prm.lo['EX_cpd00029_e0'] * 1.1
341
+ v_rfl.lo['EX_cpd00029_e0'] = v_rfl.lo['EX_cpd00029_e0'] * 1.1
342
+ # Increase formate production (important for methanogenesis)
343
+ # v_mgk.lo['EX_cpd00056_e0'] = v_mgk.lo['EX_cpd00056_e0'] * 1.2
344
+ # v_prm.lo['EX_cpd00056_e0'] = v_prm.lo['EX_cpd00056_e0'] * 1.2
345
+ # v_rfl.lo['EX_cpd00056_e0'] = v_rfl.lo['EX_cpd00056_e0'] * 1.2
346
+ # Increase H2 production (important substrate for methanogenesis)
347
+ v_mgk.lo['EX_cpd00067_e0'] = v_mgk.lo['EX_cpd00067_e0'] * 1.25
348
+ v_prm.lo['EX_cpd00067_e0'] = v_prm.lo['EX_cpd00067_e0'] * 1.25
349
+ v_rfl.lo['EX_cpd00067_e0'] = v_rfl.lo['EX_cpd00067_e0'] * 1.25
350
+ print("Imidazole treatment selected, setting constraints...")
351
+ elif treatment == 'l-carnitine':
352
+ # reactions that are affected by l-carnitine treatment
353
+ v_mgk.lo['EX_cpd01188_e0'] = -0.009476130618701499 * 0.89 # output rate for lanosterol, 0.87 times the original value becase cholesterol falls
354
+ v_rfl.lo['EX_cpd01188_e0'] = -0.01658854044409092 * 0.89
355
+ print("L-carnitine treatment selected, setting constraints...")
356
+ elif treatment == 'methyl jasmonate':
357
+ print("Methyl jasmonate treatment selected, setting constraints...")
358
+ v_mgk.lo['EX_cpd00129_e0'] = 0.01608686252400516 * 1.23 # output rate for proline, 1.23 times the original value based on Lubyanova paper
359
+ v_prm.lo['EX_cpd00129_e0'] = 0.004029898865569517 * 1.23
360
+ # v_mgk.lo['R_rxn09296_c0'] = 0.0005201736148737044 * 1.4 # H2O2 reduction by thioredoxin, 1.4 times the original value based on Lubyanova paper
361
+ # v_prm.lo['R_rxn09296_c0'] = 71.50423813116777 * 1.4
362
+ # v_rfl.lo['R_rxn09296_c0'] = 316.9770835412888 * 1.4
363
+ # v_prm.lo['R_rxn12638_c0'] = 65.98723846787729 * 1.23 # breakdown of N-glycylproline
364
+ elif treatment == 'propylpyrazine':
365
+ # reactions that are affected by propylpyrazine treatment
366
+ # v_mgk.lo['R_rxn00305_c0'] = 191.07533512418465 * 3.02 # Pck1 expression went up about 3 times after treatment with TMP, should affect GTP and phosphoenolpyruvate
367
+ # v_prm.lo['R_rxn00305_c0'] = 169.79210656337526 * 3.02
368
+ # v_rfl.lo['R_rxn00305_c0'] = 164.67010537093077 * 3.02
369
+ # v_mgk.lo['R_rxn00285_c0'] = 0.0011420124768651806 * 2.14 # Sucla2 expression went up about 2.14 times after treatment with propylpyrazine, should affect succinyl-CoA
370
+ # v_rfl.lo['R_rxn00285_c0'] = 0.012806125516892619 * 2.14
371
+ # v_mgk.lo['R_rxn12510_c0'] = 0.0010308604158823106 * 1.77 # Pank1 expression went up about 1.77 times after treatment with propylpyrazine, should affect phosphorylation of pantothenate
372
+ # v_prm.lo['R_rxn12510_c0'] = 0.008928357454568775 * 1.77
373
+ # v_rfl.lo['R_rxn12510_c0'] = 0.0015697141164147958 * 1.77
374
+ # v_prm.lo['R_rxn00248_c0'] = 167.2035577959039 * 1.93 # Mdh2 went up about 1.93 times after treatment with propylpyrazine, should affect conversion of L-malate to oxaloacetate
375
+ # v_mgk.lo['R_rxn06037_c0'] = -6.170993629588869e-21 * 3.08 # Hadhb expression went up about 3.08 times after treatment with propylpyrazine, should affect conversion of 3-hydroxyacyl-CoA -> 3-oxoacyl-CoA
376
+ # v_prm.lo['R_rxn00799_c0'] = 127.86504315656339 * 2.19 # Fh1 expression went up about 2.19 times after treatment with propylpyrazine, should affect conversion of fumarate to L-malate
377
+ # v_rfl.lo['R_rxn00256_c0'] = 104.25331895829011 * 1.43 # Cs expression went up about 1.43 times after treatment with propylpyrazine, should affect conversion of oxaloacetate to citrate
378
+ v_mgk.lo['R_rxn12512_c0'] = 0.000453718935224341 * 1.17 # Ppcs expression went up about 1.17 times after treatment with propylpyrazine, should affect conversion of phosphopantothenate combination with cysteine
379
+ v_prm.lo['R_rxn12512_c0'] = 0.004463845288178093 * 1.17
380
+ v_rfl.lo['R_rxn12512_c0'] = 0.0007848557326249302 * 1.17
381
+ print("Propylpyrazine treatment selected, setting constraints...")
382
+ elif treatment == 'no':
383
+ # no treatment, no additional constraints
384
+ print("No treatment selected, using default constraints.")
385
+ elif methane == 'fixed':
386
+ if treatment == 'imidazole':
387
+ # reactions that are affected by imidazole treatment
388
+ v_mgk.fx['EX_cpd01024_e0'] = 3.74 * 2.5125e-5 # output rate for methane based on USDA data, conversion factor from ml to mmol/gDCW.hr
389
+ print("Imidazole treatment selected, setting constraints...")
390
+ elif treatment == 'l-carnitine':
391
+ v_mgk.fx['EX_cpd01024_e0'] = 3.79 * 2.5125e-5
392
+ # reactions that are affected by l-carnitine treatment
393
+ print("L-carnitine treatment selected, setting constraints...")
394
+ elif treatment == 'methyl jasmonate':
395
+ v_mgk.fx['EX_cpd01024_e0'] = 3.53 * 2.5125e-5
396
+ print("Methyl jasmonate treatment selected, setting constraints...")
397
+ elif treatment == 'propylpyrazine':
398
+ v_mgk.fx['EX_cpd01024_e0'] = 4.40 * 2.5125e-5
399
+ # reactions that are affected by propylpyrazine treatment
400
+ print("Propylpyrazine treatment selected, setting constraints...")
401
+ elif treatment == 'no':
402
+ # no treatment, no additional constraints
403
+ v_mgk.fx['EX_cpd01024_e0'] = 3.40 * 2.5125e-5
404
+ print("No treatment selected, using default constraints.")
405
+
406
+ # Dual variables for bounds
407
+ global muLB_mgk, muUB_mgk, muLB_prm, muUB_prm, muLB_rfl, muUB_rfl
408
+
409
+ muLB_mgk = Variable(container=cowmunity, name="muLB_mgk", domain=j_mgk, description="Dual variables for MGK LB")
410
+ muUB_mgk = Variable(container=cowmunity, name="muUB_mgk", domain=j_mgk, description="Dual variables for MGK UB")
411
+ muLB_prm = Variable(container=cowmunity, name="muLB_prm", domain=j_prm, description="Dual variables for PRM LB")
412
+ muUB_prm = Variable(container=cowmunity, name="muUB_prm", domain=j_prm, description="Dual variables for PRM UB")
413
+ muLB_rfl = Variable(container=cowmunity, name="muLB_rfl", domain=j_rfl, description="Dual variables for RFL LB")
414
+ muUB_rfl = Variable(container=cowmunity, name="muUB_rfl", domain=j_rfl, description="Dual variables for RFL UB")
415
+
416
+ # Set dual variables to positive
417
+ muLB_mgk.lo[j_mgk] = 0
418
+ muUB_mgk.lo[j_mgk] = 0
419
+ muLB_prm.lo[j_prm] = 0
420
+ muUB_prm.lo[j_prm] = 0
421
+ muLB_rfl.lo[j_rfl] = 0
422
+ muUB_rfl.lo[j_rfl] = 0
423
+
424
+ # transfer uptake positive variables for the shared metabolites
425
+
426
+ global trans_CO2_mgk, trans_H2_mgk, trans_formate_mgk, trans_acetate_mgk, trans_d_mannose_mgk, trans_d_fructose_mgk, trans_tetrathionate_mgk, trans_thiosulfate_mgk
427
+ global trans_cellulose_prm, trans_d_glucose_prm, trans_acetate_prm, trans_l_arabinose_prm, trans_biotin_prm, trans_thiamin_prm, trans_octadecenoate_prm, trans_maltoheptaose_prm
428
+ global trans_nitrite_prm, trans_n_acetyl_d_glucosamine_prm, trans_aminoethanol_prm, trans_cobinamide_prm, trans_alanine_prm, trans_leucine_prm, trans_glycine_prm, trans_proline_prm
429
+ global trans_d_galacturonate_rfl, trans_deoxyadenosine_rfl, trans_dephospho_coa_rfl, trans_cobinamide_rfl, trans_alanine_rfl, trans_leucine_rfl, trans_glycine_rfl, trans_proline_rfl, trans_aminoethanol_rfl
430
+
431
+ trans_CO2_mgk = Variable(container=cowmunity, name="trans_CO2_mgk", description="maximum transfer of CO2 to M. Gottschalkii")
432
+ trans_H2_mgk = Variable(container=cowmunity, name="trans_H2_mgk", description="maximum transfer of H2 to M. Gottschalkii")
433
+ trans_formate_mgk = Variable(container=cowmunity, name='trans_formate_mgk', description="maximum transfer of formate to M. Gottschalkii")
434
+ trans_acetate_mgk = Variable(container=cowmunity, name="trans_acetate_mgk", description="maximum transfer of acetate to M. Gottschalkii")
435
+ trans_d_mannose_mgk = Variable(container=cowmunity, name="trans_dmannose_mgk", description="maximum transfer of D-mannose to M. Gottschalkii")
436
+ trans_d_fructose_mgk = Variable(container=cowmunity, name="trans_dfructose_mgk", description="maximum transfer of D-fructose to M. Gottschalkii")
437
+ trans_tetrathionate_mgk = Variable(container=cowmunity, name="trans_tetrathionate_mgk", description="maximum transfer of tetrathionate to M. Gottschalkii")
438
+ trans_thiosulfate_mgk = Variable(container=cowmunity, name="trans_thiosulfate_mgk", description="maximum transfer of thiosulfate to M. Gottschalkii")
439
+
440
+ trans_cellulose_prm = Variable(container=cowmunity, name='trans_cellulose_prm', description="maximum transfer of cellulose to P. ruminicola")
441
+ trans_d_glucose_prm = Variable(container=cowmunity, name='trans_d_glucose_prm', description="maximum transfer of D-Glucose to P. ruminicola")
442
+ trans_acetate_prm = Variable(container=cowmunity, name='trans_acetate_prm', description="maximum transfer of Acetate to P. ruminicola")
443
+ trans_l_arabinose_prm = Variable(container=cowmunity, name='trans_l_arabinose_prm', description="maximum transfer of L-Arabinose to P. ruminicola")
444
+ trans_biotin_prm = Variable(container=cowmunity, name='trans_biotin_prm', description="maximum transfer of Biotin to P. ruminicola")
445
+ trans_thiamin_prm = Variable(container=cowmunity, name='trans_thiamin_prm', description="maximum transfer of Thiamin to P. ruminicola")
446
+ trans_octadecenoate_prm = Variable(container=cowmunity, name='trans_octadecenoate_prm', description="maximum transfer of octadecenoate to P. ruminicola")
447
+ trans_maltoheptaose_prm = Variable(container=cowmunity, name='trans_maltoheptaose_prm', description="maximum transfer of Maltoheptaose to P. ruminicola")
448
+ trans_nitrite_prm = Variable(container=cowmunity, name='trans_nitrite_prm', description="maximum transfer of Nitrite to P. ruminicola")
449
+ trans_n_acetyl_d_glucosamine_prm = Variable(container=cowmunity, name='trans_n_acetyl_d_glucosamine_prm', description="maximum transfer of N-Acetyl-D-glucosamine to P. ruminicola")
450
+ trans_aminoethanol_prm = Variable(container=cowmunity, name='trans_aminoethanol_prm', description="maximum transfer of Aminoethanol to P. ruminicola")
451
+ trans_cobinamide_prm = Variable(container=cowmunity, name='trans_cobinamide_prm', description="maximum transfer of Cobinamide to P. ruminicola")
452
+ trans_alanine_prm = Variable(container=cowmunity, name='trans_alanine_prm', description="maximum transfer of Alanine to P. ruminicola")
453
+ trans_leucine_prm = Variable(container=cowmunity, name='trans_leucine_prm', description="maximum transfer of Leucine to P. ruminicola")
454
+ trans_glycine_prm = Variable(container=cowmunity, name='trans_glycine_prm', description="maximum transfer of Glycine to P. ruminicola")
455
+ trans_proline_prm = Variable(container=cowmunity, name='trans_proline_prm', description="maximum transfer of Proline to P. ruminicola")
456
+
457
+ trans_d_galacturonate_rfl = Variable(container=cowmunity, name='trans_d_galacturonate_rfl', description="maximum transfer of D-Galacturonate to R. flavefaciens")
458
+ trans_deoxyadenosine_rfl = Variable(container=cowmunity, name='trans_deoxyadenosine_rfl', description="maximum transfer of Deoxyadenosine to R. flavefaciens")
459
+ trans_dephospho_coa_rfl = Variable(container=cowmunity, name='trans_dephospho_coa_rfl', description="maximum transfer of Dephospho-CoA to R. flavefaciens")
460
+ trans_cobinamide_rfl = Variable(container=cowmunity, name='trans_cobinamide_rfl', description="maximum transfer of Cobinamide to R. flavefaciens")
461
+ trans_alanine_rfl = Variable(container=cowmunity, name='trans_alanine_rfl', description="maximum transfer of Alanine to R. flavefaciens")
462
+ trans_leucine_rfl = Variable(container=cowmunity, name='trans_leucine_rfl', description="maximum transfer of Leucine to R. flavefaciens")
463
+ trans_glycine_rfl = Variable(container=cowmunity, name='trans_glycine_rfl', description="maximum transfer of Glycine to R. flavefaciens")
464
+ trans_proline_rfl = Variable(container=cowmunity, name='trans_proline_rfl', description="maximum transfer of Proline to R. flavefaciens")
465
+ trans_aminoethanol_rfl = Variable(container=cowmunity, name='trans_aminoethanol_rfl', description="maximum transfer of Aminoethanol to R. flavefaciens")
466
+
467
+ # set the transfer variables to positive, these are the maximum transfer rates for each metabolite
468
+
469
+ trans_CO2_mgk.lo = 0
470
+ trans_H2_mgk.lo = 0
471
+ trans_formate_mgk.lo = 0
472
+ trans_acetate_mgk.lo = 0
473
+ trans_d_mannose_mgk.lo = 0
474
+ trans_d_fructose_mgk.lo = 0
475
+ trans_tetrathionate_mgk.lo = 0
476
+ trans_thiosulfate_mgk.lo = 0
477
+
478
+ trans_cellulose_prm.lo = 0
479
+ trans_d_glucose_prm.lo = 0
480
+ trans_acetate_prm.lo = 0
481
+ trans_l_arabinose_prm.lo = 0
482
+ trans_biotin_prm.lo = 0
483
+ trans_thiamin_prm.lo = 0
484
+ trans_octadecenoate_prm.lo = 0
485
+ trans_maltoheptaose_prm.lo = 0
486
+ trans_nitrite_prm.lo = 0
487
+ trans_n_acetyl_d_glucosamine_prm.lo = 0
488
+ trans_aminoethanol_prm.lo = 0
489
+ trans_cobinamide_prm.lo = 0
490
+ trans_alanine_prm.lo = 0
491
+ trans_leucine_prm.lo = 0
492
+ trans_glycine_prm.lo = 0
493
+ trans_proline_prm.lo = 0
494
+
495
+ trans_d_galacturonate_rfl.lo = 0
496
+ trans_deoxyadenosine_rfl.lo = 0
497
+ trans_dephospho_coa_rfl.lo = 0
498
+ trans_cobinamide_rfl.lo = 0
499
+ trans_alanine_rfl.lo = 0
500
+ trans_leucine_rfl.lo = 0
501
+ trans_glycine_rfl.lo = 0
502
+ trans_proline_rfl.lo = 0
503
+ trans_aminoethanol_rfl.lo = 0
504
+
505
+ def Equations():
506
+ print("Adding equations...")
507
+
508
+
509
+ # Objective Functions (Outer Objective)
510
+ biomass_objective = Equation(container=cowmunity, name="biomass_objective", description="Objective function for total biomass accumulation")
511
+ biomass_objective[...] = biomass_outer == v_mgk['R_biomass0'] + v_prm['R_biomass0'] + v_rfl['R_biomass0']
512
+
513
+ ATP_objective = Equation(container=cowmunity, name="ATP_objective", description="Objective function for total ATP Production")
514
+ ATP_objective[...] = ATP_outer == v_mgk['R_rxn02831_c0'] + v_mgk['R_rxn03535_c0'] + v_mgk['R_rxn06874_c0'] + v_mgk['R_rxn10476_c0'] + v_mgk['R_rxn11544_c0'] \
515
+ + v_prm['R_rxn00986_c0'] + v_prm['R_rxn01987_c0'] + v_prm['R_rxn10042_c0'] \
516
+ + v_rfl['R_rxn05840_c0'] + v_rfl['R_rxn06428_c0'] + v_rfl['R_rxn06874_c0'] + v_rfl['R_rxn10042_c0']
517
+
518
+
519
+ # Constraints
520
+ # these are the things that are going to make the model into a true community model rather than three separate models
521
+
522
+ trans_CO2_mgk_balance = Equation(container=cowmunity, name='trans_CO2_balance', description="Balance for CO2 transfer to M. Gottschalkii")
523
+ trans_CO2_mgk_balance[...] = trans_CO2_mgk <= v_prm['EX_cpd00011_e0'] + v_rfl['EX_cpd00011_e0']
524
+
525
+ trans_H2_mgk_balance = Equation(container=cowmunity, name= 'trans_H2_mgk_balance', description="Balance for H2 transfer to M. Gottschalkii")
526
+ trans_H2_mgk_balance[...] = trans_H2_mgk <= v_prm['EX_cpd11640_e0'] + v_rfl['EX_cpd11640_e0']
527
+
528
+ trans_formate_mgk_balance = Equation(container=cowmunity, name='trans_formate_mgk_balance', description="Balance for formate transfer to M. Gottschalkii")
529
+ trans_formate_mgk_balance[...] = trans_formate_mgk <= v_prm['EX_cpd00047_e0'] + v_rfl['EX_cpd00047_e0']
530
+
531
+ trans_acetate_mgk_balance = Equation(container=cowmunity, name='trans_acetate_mgk_balance', description="Balance for acetate transfer to M. Gottschalkii")
532
+ trans_acetate_mgk_balance[...] = trans_acetate_mgk <= v_rfl['EX_cpd00029_e0']
533
+
534
+ trans_d_mannose_mgk_balance = Equation(container=cowmunity, name='trans_d_mannose_mgk_balance', description="Balance for D-mannose transfer to M. Gottschalkii")
535
+ trans_d_mannose_mgk_balance[...] = trans_d_mannose_mgk <= v_rfl['EX_cpd00138_e0']
536
+
537
+ trans_d_fructose_mgk_balance = Equation(container=cowmunity, name='trans_d_fructose_mgk_balance', description="Balance for D-fructose transfer to M. Gottschalkii")
538
+ trans_d_fructose_mgk_balance[...] = trans_d_fructose_mgk <= v_rfl['EX_cpd00082_e0']
539
+
540
+ trans_tetrathionate_mgk_balance = Equation(container=cowmunity, name='trans_tetrathionate_mgk_balance', description="Balance for tetrathionate transfer to M. Gottschalkii")
541
+ trans_tetrathionate_mgk_balance[...] = trans_tetrathionate_mgk <= v_rfl['EX_cpd01414_e0']
542
+
543
+ trans_thiosulfate_mgk_balance = Equation(container=cowmunity, name='trans_thiosulfate_mgk_balance', description="Balance for thiosulfate transfer to M. Gottschalkii")
544
+ trans_thiosulfate_mgk_balance[...] = trans_thiosulfate_mgk <= v_prm['EX_cpd00268_e0']
545
+
546
+ trans_cellulose_prm_balance = Equation(container=cowmunity, name='trans_cellulose_prm_balance', description="Balance for cellulose transfer to P. ruminicola")
547
+ trans_cellulose_prm_balance[...] = trans_cellulose_prm <= v_rfl['EX_cpd11746_e0']
548
+
549
+ trans_d_glucose_prm_balance = Equation(container=cowmunity, name='trans_d_glucose_prm_balance', description="Balance for D-glucose transfer to P. ruminicola")
550
+ trans_d_glucose_prm_balance[...] = trans_d_glucose_prm <= v_rfl['EX_cpd00027_e0']
551
+
552
+ trans_acetate_prm_balance = Equation(container=cowmunity, name='trans_acetate_prm_balance', description="Balance for acetate transfer to P. ruminicola")
553
+ trans_acetate_prm_balance[...] = trans_acetate_prm <= v_rfl['EX_cpd00029_e0']
554
+
555
+ trans_l_arabinose_prm_balance = Equation(container=cowmunity, name='trans_l_arabinose_prm_balance', description="Balance for L-arabinose transfer to P. ruminicola")
556
+ trans_l_arabinose_prm_balance[...] = trans_l_arabinose_prm <= v_rfl['EX_cpd00224_e0']
557
+
558
+ trans_biotin_prm_balance = Equation(container=cowmunity, name='trans_biotin_prm_balance', description="Balance for biotin transfer to P. ruminicola")
559
+ trans_biotin_prm_balance[...] = trans_biotin_prm <= v_rfl['EX_cpd00104_e0']
560
+
561
+ # ****** commented to preserve RFL FLux ********* trans_thiamin_prm_balance = Equation(container=cowmunity, name='trans_thiamin_prm_balance', description="Balance for thiamin transfer to P. ruminicola")
562
+ # ****** commented to preserve RFL FLux ********* trans_thiamin_prm_balance[...] = trans_thiamin_prm <= v_rfl['EX_cpd00305_e0']
563
+
564
+ trans_octadecenoate_prm_balance = Equation(container=cowmunity, name='trans_octadecenoate_prm_balance', description="Balance for octadecenoate transfer to P. ruminicola")
565
+ trans_octadecenoate_prm_balance[...] = trans_octadecenoate_prm <= v_rfl['EX_cpd15269_e0'] + v_mgk['EX_cpd15269_e0']
566
+
567
+ trans_maltoheptaose_prm_balance = Equation(container=cowmunity, name='trans_maltoheptaose_prm_balance', description="Balance for maltoheptaose transfer to P. ruminicola")
568
+ trans_maltoheptaose_prm_balance[...] = trans_maltoheptaose_prm <= v_rfl['EX_cpd15494_e0']
569
+
570
+ trans_nitrite_prm_balance = Equation(container=cowmunity, name='trans_nitrite_prm_balance', description="Balance for nitrite transfer to P. ruminicola")
571
+ trans_nitrite_prm_balance[...] = trans_nitrite_prm <= v_mgk['EX_cpd00075_e0']
572
+
573
+ # ****** commented to preserve MGK FLux ********* trans_n_acetyl_d_glucosamine_prm_balance = Equation(container=cowmunity, name='trans_n_acetyl_d_glucosamine_prm_balance', description="Balance for N-acetyl-D-glucosamine transfer to P. ruminicola")
574
+ # ****** commented to preserve MGK FLux ********* trans_n_acetyl_d_glucosamine_prm_balance[...] = trans_n_acetyl_d_glucosamine_prm <= v_mgk['EX_cpd00122_e0']
575
+
576
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_prm_balance = Equation(container=cowmunity, name='trans_aminoethanol_prm_balance', description="Balance for aminoethanol transfer to P. ruminicola")
577
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_prm_balance[...] = trans_aminoethanol_prm <= v_mgk['EX_cpd00162_e0']
578
+
579
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_prm_balance = Equation(container=cowmunity, name='trans_cobinamide_prm_balance', description="Balance for cobinamide transfer to P. ruminicola")
580
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_prm_balance[...] = trans_cobinamide_prm <= v_mgk['EX_cpd03422_e0']
581
+
582
+ trans_alanine_prm_balance = Equation(container=cowmunity, name='trans_alanine_prm_balance', description="Balance for alanine transfer to P. ruminicola")
583
+ trans_alanine_prm_balance[...] = trans_alanine_prm <= v_mgk['EX_cpd00035_e0']
584
+
585
+ trans_leucine_prm_balance = Equation(container=cowmunity, name='trans_leucine_prm_balance', description="Balance for leucine transfer to P. ruminicola")
586
+ trans_leucine_prm_balance[...] = trans_leucine_prm <= v_mgk['EX_cpd00107_e0']
587
+
588
+ trans_glycine_prm_balance = Equation(container=cowmunity, name='trans_glycine_prm_balance', description="Balance for glycine transfer to P. ruminicola")
589
+ trans_glycine_prm_balance[...] = trans_glycine_prm <= v_mgk['EX_cpd00033_e0']
590
+
591
+ trans_proline_prm_balance = Equation(container=cowmunity, name='trans_proline_prm_balance', description="Balance for proline transfer to P. ruminicola")
592
+ trans_proline_prm_balance[...] = trans_proline_prm <= v_mgk['EX_cpd00129_e0']
593
+
594
+ trans_d_galacturonate_rfl_balance = Equation(container=cowmunity, name='trans_d_galacturonate_rfl_balance', description="Balance for D-galacturonate transfer to R. flavefaciens")
595
+ trans_d_galacturonate_rfl_balance[...] = trans_d_galacturonate_rfl <= v_prm['EX_cpd00280_e0']
596
+
597
+ trans_deoxyadenosine_rfl_balance = Equation(container=cowmunity, name='trans_deoxyadenosine_rfl_balance', description="Balance for deoxyadenosine transfer to R. flavefaciens")
598
+ trans_deoxyadenosine_rfl_balance[...] = trans_deoxyadenosine_rfl <= v_prm['EX_cpd00438_e0']
599
+
600
+ trans_dephospho_coa_rfl_balance = Equation(container=cowmunity, name='trans_dephospho_coa_rfl_balance', description="Balance for dephospho-CoA transfer to R. flavefaciens")
601
+ trans_dephospho_coa_rfl_balance[...] = trans_dephospho_coa_rfl <= v_mgk['EX_cpd00655_e0']
602
+
603
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_rfl_balance = Equation(container=cowmunity, name='trans_cobinamide_rfl_balance', description="Balance for cobinamide transfer to R. flavefaciens")
604
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_rfl_balance[...] = trans_cobinamide_rfl <= v_mgk['EX_cpd03422_e0']
605
+
606
+ trans_alanine_rfl_balance = Equation(container=cowmunity, name='trans_alanine_rfl_balance', description="Balance for alanine transfer to R. flavefaciens")
607
+ trans_alanine_rfl_balance[...] = trans_alanine_rfl <= v_mgk['EX_cpd00035_e0']
608
+
609
+ trans_leucine_rfl_balance = Equation(container=cowmunity, name='trans_leucine_rfl_balance', description="Balance for leucine transfer to R. flavefaciens")
610
+ trans_leucine_rfl_balance[...] = trans_leucine_rfl <= v_mgk['EX_cpd00107_e0']
611
+
612
+ trans_glycine_rfl_balance = Equation(container=cowmunity, name='trans_glycine_rfl_balance', description="Balance for glycine transfer to R. flavefaciens")
613
+ trans_glycine_rfl_balance[...] = trans_glycine_rfl <= v_mgk['EX_cpd00033_e0']
614
+
615
+ # ****** commented to preserve RFL FLux ********* trans_proline_rfl_balance = Equation(container=cowmunity, name='trans_proline_rfl_balance', description="Balance for proline transfer to R. flavefaciens")
616
+ # ****** commented to preserve RFL FLux ********* trans_proline_rfl_balance[...] = trans_proline_rfl <= v_mgk['EX_cpd00129_e0']
617
+
618
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_rfl_balance = Equation(container=cowmunity, name='trans_aminoethanol_rfl_balance', description="Balance for aminoethanol transfer to R. flavefaciens")
619
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_rfl_balance[...] = trans_aminoethanol_rfl <= v_mgk['EX_cpd00162_e0']
620
+
621
+ # ****** commented to preserve MGK FLux ********* overall_cobinamide_balance = Equation(container=cowmunity, name='overall_cobinamide_balance', description='Balance for cobinamide transfer for both prm and rfl')
622
+ # ****** commented to preserve MGK FLux ********* overall_cobinamide_balance[...] = trans_cobinamide_prm + trans_cobinamide_rfl <= v_mgk['EX_cpd03422_e0']
623
+
624
+ overall_alanine_balance = Equation(container=cowmunity, name='overall_alanine_balance', description='Balance for alanine transfer for both prm and rfl')
625
+ overall_alanine_balance[...] = trans_alanine_prm + trans_alanine_rfl <= v_mgk['EX_cpd00035_e0']
626
+
627
+ overall_leucine_balance = Equation(container=cowmunity, name='overall_leucine_balance', description='Balance for leucine transfer for both prm and rfl')
628
+ overall_leucine_balance[...] = trans_leucine_prm + trans_leucine_rfl <= v_mgk['EX_cpd00107_e0']
629
+
630
+ overall_glycine_balance = Equation(container=cowmunity, name='overall_glycine_balance', description='Balance for glycine transfer for both prm and rfl')
631
+ overall_glycine_balance[...] = trans_glycine_prm + trans_glycine_rfl <= v_mgk['EX_cpd00033_e0']
632
+
633
+ overall_proline_balance = Equation(container=cowmunity, name='overall_proline_balance', description='Balance for proline transfer for both prm and rfl')
634
+ overall_proline_balance[...] = trans_proline_prm + trans_proline_rfl <= v_mgk['EX_cpd00129_e0']
635
+
636
+ # ****** commented to preserve MGK FLux ********* overall_aminoethanol_balance = Equation(container=cowmunity, name='overall_aminoethanol_balance', description='Balance for aminoethanol transfer for both prm and rfl')
637
+ # ****** commented to preserve MGK FLux ********* overall_aminoethanol_balance[...] = trans_aminoethanol_prm + trans_aminoethanol_rfl <= v_mgk['EX_cpd00162_e0']
638
+
639
+ # adding the constraints to each model
640
+
641
+ constraint_CO2_mgk = Equation(container=cowmunity, name="constraint_CO2_mgk", description="constraint for the uptake of CO2 to M. Gottschalkii")
642
+ constraint_CO2_mgk[...] = trans_CO2_mgk == v_mgk['EX_cpd00011_e0']
643
+
644
+ constraint_H2_mgk = Equation(container=cowmunity, name="constraint_H2_mgk", description="constraint for the uptake of H2 to M. Gottschalkii")
645
+ constraint_H2_mgk[...] = trans_H2_mgk == v_mgk['EX_cpd11640_e0']
646
+
647
+ constraint_formate_mgk = Equation(container=cowmunity, name='constraint_formate_mgk', description="constraint for the uptake of formate to M. Gottschalkii")
648
+ constraint_formate_mgk[...] = trans_formate_mgk == v_mgk['EX_cpd00047_e0']
649
+
650
+ constraint_acetate_mgk = Equation(container=cowmunity, name="constraint_acetate_mgk", description="constraint for the uptake of acetate to M. Gottschalkii")
651
+ constraint_acetate_mgk[...] = trans_acetate_mgk == v_mgk['EX_cpd00029_e0']
652
+
653
+ constraint_d_mannose_mgk = Equation(container=cowmunity, name="constraint_dmannose_mgk", description="constraint for the uptake of D-mannose to M. Gottschalkii")
654
+ constraint_d_mannose_mgk[...] = trans_d_mannose_mgk == v_mgk['EX_cpd00138_e0']
655
+
656
+ constraint_d_fructose_mgk = Equation(container=cowmunity, name="constraint_dfructose_mgk", description="constraint for the uptake of D-fructose to M. Gottschalkii")
657
+ constraint_d_fructose_mgk[...] = trans_d_fructose_mgk == v_mgk['EX_cpd00082_e0']
658
+
659
+ constraint_tetrathionate_mgk = Equation(container=cowmunity, name="constraint_tetrathionate_mgk", description="constraint for the uptake of tetrathionate to M. Gottschalkii")
660
+ constraint_tetrathionate_mgk[...] = trans_tetrathionate_mgk == v_mgk['EX_cpd01414_e0']
661
+
662
+ constraint_thiosulfate_mgk = Equation(container=cowmunity, name="constraint_thiosulfate_mgk", description="constraint for the uptake of thiosulfate to M. Gottschalkii")
663
+ constraint_thiosulfate_mgk[...] = trans_thiosulfate_mgk == v_mgk['EX_cpd00268_e0']
664
+
665
+ constraint_cellulose_prm = Equation(container=cowmunity, name='constraint_cellulose_prm', description="constraint for the uptake of cellulose to P. ruminicola")
666
+ constraint_cellulose_prm[...] = trans_cellulose_prm == v_prm['EX_cpd11746_e0']
667
+
668
+ constraint_d_glucose_prm = Equation(container=cowmunity, name='constraint_d_glucose_prm', description="constraint for the uptake of D-Glucose to P. ruminicola")
669
+ constraint_d_glucose_prm[...] = trans_d_glucose_prm == v_prm['EX_cpd00027_e0']
670
+
671
+ constraint_acetate_prm = Equation(container=cowmunity, name='constraint_acetate_prm', description="constraint for the uptake of Acetate to P. ruminicola")
672
+ constraint_acetate_prm[...] = trans_acetate_prm == v_prm['EX_cpd00029_e0']
673
+
674
+ constraint_l_arabinose_prm = Equation(container=cowmunity, name='constraint_l_arabinose_prm', description="constraint for the uptake of L-Arabinose to P. ruminicola")
675
+ constraint_l_arabinose_prm[...] = trans_l_arabinose_prm == v_prm['EX_cpd00224_e0']
676
+
677
+ constraint_biotin_prm = Equation(container=cowmunity, name='constraint_biotin_prm', description="constraint for the uptake of Biotin to P. ruminicola")
678
+ constraint_biotin_prm[...] = trans_biotin_prm == v_prm['EX_cpd00104_e0']
679
+
680
+ # ****** commented to preserve RFL FLux ********* constraint_thiamin_prm = Equation(container=cowmunity, name='constraint_thiamin_prm', description="constraint for the uptake of Thiamin to P. ruminicola")
681
+ # ****** commented to preserve RFL FLux ********* constraint_thiamin_prm[...] = trans_thiamin_prm == v_prm['EX_cpd00305_e0']
682
+
683
+ constraint_octadecenoate_prm = Equation(container=cowmunity, name='constraint_octadecenoate_prm', description="constraint for the uptake of octadecenoate to P. ruminicola")
684
+ constraint_octadecenoate_prm[...] = trans_octadecenoate_prm == v_prm['EX_cpd15269_e0']
685
+
686
+ constraint_maltoheptaose_prm = Equation(container=cowmunity, name='constraint_maltoheptaose_prm', description="constraint for the uptake of Maltoheptaose to P. ruminicola")
687
+ constraint_maltoheptaose_prm[...] = trans_maltoheptaose_prm == v_prm['EX_cpd15494_e0']
688
+
689
+ constraint_nitrite_prm = Equation(container=cowmunity, name='constraint_nitrite_prm', description="constraint for the uptake of Nitrite to P. ruminicola")
690
+ constraint_nitrite_prm[...] = trans_nitrite_prm == v_prm['EX_cpd00075_e0']
691
+
692
+ # ****** commented to preserve MGK FLux ********* constraint_n_acetyl_d_glucosamine_prm = Equation(container=cowmunity, name='constraint_n_acetyl_d_glucosamine_prm', description="constraint for the uptake of N-Acetyl-D-glucosamine to P. ruminicola")
693
+ # ****** commented to preserve MGK FLux ********* constraint_n_acetyl_d_glucosamine_prm[...] = trans_n_acetyl_d_glucosamine_prm == v_prm['EX_cpd00122_e0']
694
+
695
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_prm = Equation(container=cowmunity, name='constraint_aminoethanol_prm', description="constraint for the uptake of Aminoethanol to P. ruminicola")
696
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_prm[...] = trans_aminoethanol_prm == v_prm['EX_cpd00162_e0']
697
+
698
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_prm = Equation(container=cowmunity, name='constraint_cobinamide_prm', description="constraint for the uptake of Cobinamide to P. ruminicola")
699
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_prm[...] = trans_cobinamide_prm == v_prm['EX_cpd03422_e0']
700
+
701
+ constraint_alanine_prm = Equation(container=cowmunity, name='constraint_alanine_prm', description="constraint for the uptake of Alanine to P. ruminicola")
702
+ constraint_alanine_prm[...] = trans_alanine_prm == v_prm['EX_cpd00035_e0']
703
+
704
+ constraint_leucine_prm = Equation(container=cowmunity, name='constraint_leucine_prm', description="constraint for the uptake of Leucine to P. ruminicola")
705
+ constraint_leucine_prm[...] = trans_leucine_prm == v_prm['EX_cpd00107_e0']
706
+
707
+ constraint_glycine_prm = Equation(container=cowmunity, name='constraint_glycine_prm', description="constraint for the uptake of Glycine to P. ruminicola")
708
+ constraint_glycine_prm[...] = trans_glycine_prm == v_prm['EX_cpd00033_e0']
709
+
710
+ constraint_proline_prm = Equation(container=cowmunity, name='constraint_proline_prm', description="constraint for the uptake of Proline to P. ruminicola")
711
+ constraint_proline_prm[...] = trans_proline_prm == v_prm['EX_cpd00129_e0']
712
+
713
+ constraint_d_galacturonate_rfl = Equation(container=cowmunity, name='constraint_d_galacturonate_rfl', description="constraint for the uptake of D-Galacturonate to R. flavefaciens")
714
+ constraint_d_galacturonate_rfl[...] = trans_d_galacturonate_rfl == v_rfl['EX_cpd00280_e0']
715
+
716
+ constraint_deoxyadenosine_rfl = Equation(container=cowmunity, name='constraint_deoxyadenosine_rfl', description="constraint for the uptake of Deoxyadenosine to R. flavefaciens")
717
+ constraint_deoxyadenosine_rfl[...] = trans_deoxyadenosine_rfl == v_rfl['EX_cpd00438_e0']
718
+
719
+ constraint_dephospho_coa_rfl = Equation(container=cowmunity, name='constraint_dephospho_coa_rfl', description="constraint for the uptake of Dephospho-CoA to R. flavefaciens")
720
+ constraint_dephospho_coa_rfl[...] = trans_dephospho_coa_rfl == v_rfl['EX_cpd00655_e0']
721
+
722
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_rfl = Equation(container=cowmunity, name='constraint_cobinamide_rfl', description="constraint for the uptake of Cobinamide to R. flavefaciens")
723
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_rfl[...] = trans_cobinamide_rfl == v_rfl['EX_cpd03422_e0']
724
+
725
+ constraint_alanine_rfl = Equation(container=cowmunity, name='constraint_alanine_rfl', description="constraint for the uptake of Alanine to R. flavefaciens")
726
+ constraint_alanine_rfl[...] = trans_alanine_rfl == v_rfl['EX_cpd00035_e0']
727
+
728
+ constraint_leucine_rfl = Equation(container=cowmunity, name='constraint_leucine_rfl', description="constraint for the uptake of Leucine to R. flavefaciens")
729
+ constraint_leucine_rfl[...] = trans_leucine_rfl == v_rfl['EX_cpd00107_e0']
730
+
731
+ constraint_glycine_rfl = Equation(container=cowmunity, name='constraint_glycine_rfl', description="constraint for the uptake of Glycine to R. flavefaciens")
732
+ constraint_glycine_rfl[...] = trans_glycine_rfl == v_rfl['EX_cpd00033_e0']
733
+
734
+ # ****** commented to preserve RFL FLux ********* constraint_proline_rfl = Equation(container=cowmunity, name='constraint_proline_rfl', description="constraint for the uptake of Proline to R. flavefaciens")
735
+ # ****** commented to preserve RFL FLux ********* constraint_proline_rfl[...] = trans_proline_rfl == v_rfl['EX_cpd00129_e0']
736
+
737
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_rfl = Equation(container=cowmunity, name='constraint_aminoethanol_rfl', description="constraint for the uptake of Aminoethanol to R. flavefaciens")
738
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_rfl[...] = trans_aminoethanol_rfl == v_rfl['EX_cpd00162_e0']
739
+
740
+ # mass balance equations
741
+
742
+ mgk_mass_balance = Equation(container=cowmunity, name='mgk_mass_balance', domain=i_mgk, description='overall mass balance for mgk')
743
+ mgk_mass_balance[i_mgk] = Sum(j_mgk, S_mgk[j_mgk, i_mgk] * v_mgk[j_mgk]) == 0
744
+
745
+ prm_mass_balance = Equation(container=cowmunity, name='prm_mass_balance', domain=i_prm, description='overall mass balance for prm')
746
+ prm_mass_balance[i_prm] = Sum(j_prm, S_prm[j_prm, i_prm] * v_prm[j_prm]) == 0
747
+
748
+ rfl_mass_balance = Equation(container=cowmunity, name='rfl_mass_balance', domain=i_rfl, description='overall mass balance for rfl')
749
+ rfl_mass_balance[i_rfl] = Sum(j_rfl, S_rfl[j_rfl, i_rfl] * v_rfl[j_rfl]) == 0
750
+
751
+ # dual problem constraint equations
752
+
753
+ mgk_dual_constraint = Equation(container=cowmunity, name="mgk_dual_constraint", domain=j_mgk, description="Dual constraint for MGK")
754
+ mgk_dual_constraint[j_mgk] = Sum(i_mgk, lambda_mgk[i_mgk] * S_mgk[j_mgk, i_mgk]) + \
755
+ muUB_mgk[j_mgk] - muLB_mgk[j_mgk] == 0
756
+
757
+ prm_dual_constraint = Equation(container=cowmunity, name="prm_dual_constraint", domain=j_prm, description="Dual constraint for PRM")
758
+ prm_dual_constraint[j_prm] = Sum(i_prm, lambda_prm[i_prm] * S_prm[j_prm, i_prm]) + \
759
+ muUB_prm[j_prm] - muLB_prm[j_prm] == 0
760
+
761
+ rfl_dual_constraint = Equation(container=cowmunity, name="rfl_dual_constraint", domain=j_rfl, description="Dual constraint for RFL")
762
+ rfl_dual_constraint[j_rfl] = Sum(i_rfl, lambda_rfl[i_rfl] * S_rfl[j_rfl, i_rfl]) + \
763
+ muUB_rfl[j_rfl] - muLB_rfl[j_rfl] == 0
764
+
765
+ def FixSBMLs():
766
+ print("Fixing SBML files...")
767
+
768
+ def add_reaction(file_name, metabolite_code, metabolite_name, charge=0):
769
+ # Define the SBML document and model
770
+ reader = libsbml.SBMLReader()
771
+ document = reader.readSBML(f'model files/{file_name}')
772
+ model = document.getModel()
773
+
774
+ # Check if the cytosol species already exists
775
+ species_id = f'M_{metabolite_code}_c0'
776
+ if model.getSpecies(species_id) is None:
777
+ species = model.createSpecies()
778
+ species.setId(species_id)
779
+ species.setCompartment('c0')
780
+ species.setName(f'{metabolite_name}[c0]')
781
+ species.setCharge(charge)
782
+ species.setBoundaryCondition(False)
783
+
784
+ cytosol_species = model.getSpecies(species_id)
785
+
786
+ # create the extracellular species
787
+ species = model.createSpecies()
788
+ species.setId(f'M_{metabolite_code}_e0')
789
+ species.setCompartment('e0')
790
+ species.setName(f'{metabolite_name}[e0]')
791
+ species.setCharge(int(cytosol_species.getCharge()))
792
+ species.setBoundaryCondition(False)
793
+
794
+
795
+ # Create the export/import reaction
796
+ reaction = model.createReaction()
797
+ reaction.setId(f'EX_{metabolite_code}_e0')
798
+ reaction.setName(f'{metabolite_name} export/import')
799
+ reaction.setReversible(True) # Set reversibility
800
+
801
+ # Add reactant to the reaction
802
+ reactant1 = reaction.createReactant()
803
+ reactant1.setSpecies(f'M_{metabolite_code}_e0') # Use the species ID created above
804
+ reactant1.setStoichiometry(1)
805
+ reactant1.setConstant(False)
806
+
807
+ # 6. Define the kinetic law (e.g., Mass Action kinetics: k * S1)
808
+ kinetic_law = reaction.createKineticLaw()
809
+ # Create a parameter for the rate constant
810
+ lb = kinetic_law.createParameter()
811
+ lb.setId('LOWER_BOUND')
812
+ lb.setValue(-1000)
813
+ lb.setName('mmol_per_gDW_per_hr')
814
+ ub = kinetic_law.createParameter()
815
+ ub.setId('UPPER_BOUND')
816
+ ub.setValue(1000)
817
+ ub.setName('mmol_per_gDW_per_hr')
818
+ obj = kinetic_law.createParameter()
819
+ obj.setId('OBJECTIVE_COEFFICIENT')
820
+ obj.setValue(0)
821
+ flx = kinetic_law.createParameter()
822
+ flx.setId('FLUX_VALUE')
823
+ flx.setValue(0)
824
+ flx.setName('mmol_per_gDW_per_hr')
825
+
826
+
827
+ # Set the math for the kinetic law using MathML
828
+ # You can use libsbml.parseL3Formula to convert from infix string to MathML AST
829
+ math_ml_string = (
830
+ '<math xmlns="http://www.w3.org/1998/Math/MathML">'
831
+ '<ci> FLUX_VALUE </ci>'
832
+ '</math>'
833
+ )
834
+ math_ast = libsbml.readMathMLFromString(math_ml_string)
835
+ if math_ast:
836
+ kinetic_law.setMath(math_ast)
837
+ else:
838
+ print("Error: Could not parse MathML string.")
839
+
840
+ # create the reaction to convert from extracellular to cytosol
841
+ transport_reaction = model.createReaction()
842
+ transport_reaction.setId(f'R_{metabolite_code}_transport')
843
+ transport_reaction.setName(f'{metabolite_name} transport')
844
+ transport_reaction.setReversible(True) # Set reversibility
845
+
846
+ # Add reactant to the reaction
847
+ cytosol = transport_reaction.createReactant()
848
+ cytosol.setSpecies(f'M_{metabolite_code}_c0') # Use the species ID created above
849
+ cytosol.setStoichiometry(1)
850
+ cytosol.setConstant(False)
851
+
852
+ # Add product to the reaction
853
+ extracellular = transport_reaction.createProduct()
854
+ extracellular.setSpecies(f'M_{metabolite_code}_e0') # Use the species ID created above
855
+ extracellular.setStoichiometry(1)
856
+ extracellular.setConstant(False)
857
+
858
+ # 6. Define the kinetic law (e.g., Mass Action kinetics: k * S1)
859
+ kinetic_law = transport_reaction.createKineticLaw()
860
+ # Create a parameter for the rate constant
861
+ lb = kinetic_law.createParameter()
862
+ lb.setId('LOWER_BOUND')
863
+ lb.setValue(-1000)
864
+ lb.setName('mmol_per_gDW_per_hr')
865
+ ub = kinetic_law.createParameter()
866
+ ub.setId('UPPER_BOUND')
867
+ ub.setValue(1000)
868
+ ub.setName('mmol_per_gDW_per_hr')
869
+ obj = kinetic_law.createParameter()
870
+ obj.setId('OBJECTIVE_COEFFICIENT')
871
+ obj.setValue(0)
872
+ flx = kinetic_law.createParameter()
873
+ flx.setId('FLUX_VALUE')
874
+ flx.setValue(0)
875
+ flx.setName('mmol_per_gDW_per_hr')
876
+
877
+
878
+ # Set the math for the kinetic law using MathML
879
+ # You can use libsbml.parseL3Formula to convert from infix string to MathML AST
880
+ math_ml_string = (
881
+ '<math xmlns="http://www.w3.org/1998/Math/MathML">'
882
+ '<ci> FLUX_VALUE </ci>'
883
+ '</math>'
884
+ )
885
+ math_ast = libsbml.readMathMLFromString(math_ml_string)
886
+ if math_ast:
887
+ kinetic_law.setMath(math_ast)
888
+ else:
889
+ print("Error: Could not parse MathML string.")
890
+
891
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
892
+
893
+
894
+ def add_version(file_name, version):
895
+ # Define the SBML document and model
896
+ reader = libsbml.SBMLReader()
897
+ document = reader.readSBML(f'model files/{file_name}')
898
+ model = document.getModel()
899
+
900
+ # Set the version in the model's annotation
901
+ model.setNotes(version)
902
+
903
+ # Write the updated SBML document back to file
904
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
905
+
906
+ def check_version(file_name, version):
907
+ # Define the SBML document and model
908
+ reader = libsbml.SBMLReader()
909
+ document = reader.readSBML(f'model files/{file_name}')
910
+ model = document.getModel()
911
+
912
+ # Check if the version matches
913
+ notes = model.getNotesString()
914
+ return notes == f'<notes>{version}</notes>'
915
+
916
+ version = 'v2.5'
917
+
918
+ if check_version('M. gottschalkii.xml', version) is False:
919
+ print('M. gottschalkii.xml is not up to date, updating...')
920
+ add_reaction('M. gottschalkii.xml', 'cpd00035', 'L-Alanine')
921
+ add_reaction('M. gottschalkii.xml', 'cpd00107', 'L-Leucine')
922
+ add_reaction('M. gottschalkii.xml', 'cpd00033', 'Glycine')
923
+ add_version('M. gottschalkii.xml', version)
924
+
925
+ if check_version('P. ruminicola.xml', version) is False:
926
+ print('P. ruminicola.xml is not up to date, updating...')
927
+ add_reaction('P. ruminicola.xml', 'cpd00035', 'L-Alanine')
928
+ add_reaction('P. ruminicola.xml', 'cpd00107', 'L-Leucine')
929
+ add_reaction('P. ruminicola.xml', 'cpd00033', 'Glycine')
930
+ add_reaction('P. ruminicola.xml', 'cpd11657', 'Starch')
931
+ add_reaction('P. ruminicola.xml', 'cpd00076', 'Sucrose')
932
+ add_reaction('P. ruminicola.xml', 'cpd00053', 'L-Glutamine')
933
+ add_reaction('P. ruminicola.xml', 'cpd00161', 'L-Threonine')
934
+ add_reaction('P. ruminicola.xml', 'cpd00348', 'D-Galactose 1-phosphate')
935
+ add_reaction('P. ruminicola.xml', 'cpd00084', 'L-Cysteine')
936
+ add_reaction('P. ruminicola.xml', 'cpd00052', 'CTP')
937
+ add_reaction('P. ruminicola.xml', 'cpd00002', 'ATP')
938
+ add_reaction('P. ruminicola.xml', 'cpd00062', 'UTP')
939
+ add_reaction('P. ruminicola.xml', 'cpd00356', 'dCTP')
940
+ add_reaction('P. ruminicola.xml', 'cpd00073', 'Urea')
941
+ add_version('P. ruminicola.xml', version)
942
+
943
+ if check_version('R. flavefaciens.xml', version) is False:
944
+ print('R. flavefaciens.xml is not up to date, updating...')
945
+ add_reaction('R. flavefaciens.xml', 'cpd00035', 'L-Alanine')
946
+ add_reaction('R. flavefaciens.xml', 'cpd00033', 'Glycine')
947
+ add_reaction('R. flavefaciens.xml', 'cpd00053', 'L-Glutamine')
948
+ add_reaction('R. flavefaciens.xml', 'cpd00161', 'L-Threonine')
949
+ add_reaction('R. flavefaciens.xml', 'cpd00348', 'D-Galactose 1-phosphate')
950
+ add_reaction('R. flavefaciens.xml', 'cpd00084', 'L-Cysteine')
951
+ add_reaction('R. flavefaciens.xml', 'cpd00052', 'CTP')
952
+ add_reaction('R. flavefaciens.xml', 'cpd00002', 'ATP')
953
+ add_reaction('R. flavefaciens.xml', 'cpd00062', 'UTP')
954
+ add_reaction('R. flavefaciens.xml', 'cpd00356', 'dCTP')
955
+ add_reaction('R. flavefaciens.xml', 'cpd00073', 'Urea')
956
+ add_version('R. flavefaciens.xml', version)
957
+
958
+
959
+ def remove_duplicate_species_and_reactions(file_name):
960
+ # Define the SBML document and model
961
+ reader = libsbml.SBMLReader()
962
+ document = reader.readSBML(f'model files/{file_name}')
963
+ model = document.getModel()
964
+
965
+ # --- Remove Duplicate Species ---
966
+ seen_species = []
967
+ species_to_remove = []
968
+
969
+ for i in range(model.getNumSpecies()):
970
+ species = model.getSpecies(i)
971
+ id = species.getId()
972
+
973
+ if id in seen_species:
974
+ species_to_remove.append(species.getId())
975
+ else:
976
+ seen_species.append(species.getId())
977
+
978
+ # Remove species (iterate in reverse to avoid index issues)
979
+ for item in reversed(species_to_remove):
980
+ model.removeSpecies(item)
981
+
982
+ # --- Remove Duplicate Reactions ---
983
+ seen_reactions = []
984
+ reactions_to_remove = []
985
+
986
+ for i in range(model.getNumReactions()):
987
+ reaction = model.getReaction(i)
988
+ id = reaction.getId()
989
+
990
+ if id in seen_reactions:
991
+ reactions_to_remove.append(reaction.getId())
992
+ else:
993
+ seen_reactions.append(reaction.getId())
994
+
995
+ # Remove reactions
996
+ for reaction_id in reversed(reactions_to_remove):
997
+ model.removeReaction(reaction_id)
998
+
999
+ # Save the modified model (optional)
1000
+ writer = libsbml.SBMLWriter()
1001
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
1002
+
1003
+ remove_duplicate_species_and_reactions('M. gottschalkii.xml')
1004
+ remove_duplicate_species_and_reactions('P. ruminicola.xml')
1005
+ remove_duplicate_species_and_reactions('R. flavefaciens.xml')
1006
+
1007
+ # removing a duplicate product that slipped through the cracks
1008
+
1009
+ reader = libsbml.SBMLReader()
1010
+ document = reader.readSBML(f'model files/R. flavefaciens.xml')
1011
+ model = document.getModel()
1012
+
1013
+ reaction = model.getReaction('R_R01896_c0')
1014
+ reaction.removeProduct('M_cpd00067_c0')
1015
+
1016
+ writer = libsbml.SBMLWriter()
1017
+ libsbml.writeSBMLToFile(document, f'model files/R. flavefaciens.xml')
1018
+
1019
+ def solve(solver_name='IPOPT'):
1020
+
1021
+
1022
+ global model
1023
+ # Create model
1024
+ model = Model(container=cowmunity, name="COWMUNITY", equations=cowmunity.getEquations(),
1025
+ problem="NLP", sense=Sense.MAX, objective=objective_variable)
1026
+
1027
+ # Set solver options
1028
+ options = Options(nlp=solver_name, equation_listing_limit=10, variable_listing_limit=10, time_limit=20, threads=0)
1029
+
1030
+ # Solve the model
1031
+ print(f"Solving with {solver_name}...")
1032
+ model.solve(options=options)
1033
+
1034
+ # check solution status
1035
+ status = model.solve_status
1036
+ if status == SolveStatus.NormalCompletion:
1037
+ print("Optimal solution found!")
1038
+ else:
1039
+ print(f"Solver terminated with status: {status}")
1040
+
1041
+ def extract_results():
1042
+ """Extract and store results"""
1043
+ global results
1044
+ results = {
1045
+ 'objective_value': objective_variable.records['level'].iloc[0],
1046
+ 'mgk_biomass': v_mgk.records.loc[v_mgk.records['j_mgk'] == 'R_biomass0', 'level'].iloc[0],
1047
+ 'prm_biomass': v_prm.records.loc[v_prm.records['j_prm'] == 'R_biomass0', 'level'].iloc[0],
1048
+ 'rfl_biomass': v_rfl.records.loc[v_rfl.records['j_rfl'] == 'R_biomass0', 'level'].iloc[0],
1049
+ 'methane_flux' : v_mgk.records.loc[v_mgk.records['j_mgk'] == 'EX_cpd01024_e0', 'level'].iloc[0]
1050
+ }
1051
+
1052
+ def save_results(treatment, methane = 'variable'):
1053
+ """Save results to a CSV file"""
1054
+ os.makedirs(f'results/{methane}_methane_{treatment}_treatment', exist_ok=True)
1055
+ v_mgk.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/mgk_records.csv', index=False)
1056
+ v_prm.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/prm_records.csv', index=False)
1057
+ v_rfl.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/rfl_records.csv', index=False)
1058
+ print(f"Results saved to 'results/{methane}_methane_{treatment}_treatment'.")
1059
+
1060
+ def print_results():
1061
+ """Print results in a formatted way"""
1062
+ print()
1063
+ print("********************* RESULTS *********************")
1064
+ print(f"Total Biomass = {results['objective_value']:5f}")
1065
+ print()
1066
+
1067
+ print("********************* MGK *************************")
1068
+ print(f"MGK Biomass Flux = {results['mgk_biomass']:5f}")
1069
+ print(f"Methane Emission Flux = {results['methane_flux']:5f}")
1070
+ print()
1071
+
1072
+ print("********************* PRM *************************")
1073
+ print(f"PRM Biomass Flux = {results['prm_biomass']:5f}")
1074
+ print()
1075
+
1076
+ print("********************* RFL *************************")
1077
+ print(f"RFL Biomass Flux = {results['rfl_biomass']:5f}")
1078
+ print()
1079
+
1080
+ def bug_huntin():
1081
+ # This function is for debugging purposes, to check the model and variable records
1082
+
1083
+ def print_reaction(reaction):
1084
+ def check_reaction(reaction, file_name):
1085
+ reader = libsbml.SBMLReader()
1086
+ document = reader.readSBML(f'model files/{file_name}')
1087
+ model = document.getModel()
1088
+
1089
+ reaction = model.getReaction(reaction)
1090
+
1091
+ if reaction is None:
1092
+ return None
1093
+ else:
1094
+ return reaction.getId()
1095
+
1096
+ if check_reaction(reaction, 'M. gottschalkii.xml') is None:
1097
+ print(f'Reaction {reaction} not found in M. gottschalkii model.')
1098
+ else:
1099
+ mgk_flux = v_mgk.records.loc[v_mgk.records['j_mgk'] == reaction.strip(), 'level'].iloc[0]
1100
+ print(f'MGK {reaction}: {mgk_flux}')
1101
+ if check_reaction(reaction, 'P. ruminicola.xml') is None:
1102
+ print(f'Reaction {reaction} not found in P. ruminicola model.')
1103
+ else:
1104
+ prm_flux = v_prm.records.loc[v_prm.records['j_prm'] == reaction.strip(), 'level'].iloc[0]
1105
+ print(f'PRM {reaction}: {prm_flux}')
1106
+ if check_reaction(reaction, 'R. flavefaciens.xml') is None:
1107
+ print(f'Reaction {reaction} not found in R. flavefaciens model.')
1108
+ else:
1109
+ rfl_flux = v_rfl.records.loc[v_rfl.records['j_rfl'] == reaction.strip(), 'level'].iloc[0]
1110
+ print(f'RFL {reaction}: {rfl_flux}')
1111
+
1112
+
1113
+ print_reaction('EX_cpd01188_e0')
1114
+
1115
+
1116
+
1117
+ def flux_investigation(file_name, v_set, j_set, i_set, metabolite):
1118
+
1119
+ reader = libsbml.SBMLReader()
1120
+ document = reader.readSBML(f'model files/{file_name}')
1121
+ model = document.getModel()
1122
+
1123
+ relevant_reactions = []
1124
+ for i in range(model.getNumReactions()):
1125
+ reaction = model.getReaction(i)
1126
+ product = reaction.getProduct(metabolite)
1127
+ if product is None:
1128
+ continue
1129
+ else:
1130
+ relevant_reactions.append(reaction.id)
1131
+
1132
+ # species = model.getSpecies(metabolite)
1133
+ name = i_set.records.loc[i_set.records['index'] == metabolite, 'element_text'].iloc[0]
1134
+ print(file_name)
1135
+ print(f'\n*** {name} FLUXES ***')
1136
+ for item in relevant_reactions:
1137
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1138
+ print(f'{item} : {flux}')
1139
+
1140
+ print()
1141
+
1142
+ metabolite = 'M_cpd00033_c0'
1143
+ mgk = ('M. gottschalkii.xml', v_mgk, 'j_mgk', i_mgk)
1144
+ prm = ('P. ruminicola.xml', v_prm, 'j_prm', i_prm)
1145
+ rfl = ('R. flavefaciens.xml', v_rfl, 'j_rfl', i_rfl)
1146
+
1147
+ # flux_investigation(*mgk, metabolite)
1148
+
1149
+ def biomass_fluxes(file_name, v_set, j_set, i_set):
1150
+ list_to_investigate = []
1151
+ print()
1152
+ print('*'*10, file_name, '*'*10)
1153
+
1154
+ reader = libsbml.SBMLReader()
1155
+ document = reader.readSBML(f'model files/{file_name}')
1156
+ model = document.getModel()
1157
+
1158
+ biomass_reactants = []
1159
+ biomass_reaction = model.getReaction('R_biomass0')
1160
+ for i in range(biomass_reaction.getNumReactants()):
1161
+ reactant = biomass_reaction.getReactant(i)
1162
+ biomass_reactants.append(reactant.getSpecies())
1163
+
1164
+ precursor_reactions = {}
1165
+ for item in biomass_reactants:
1166
+ relevant_reactions = []
1167
+ for i in range(model.getNumReactions()):
1168
+ reaction = model.getReaction(i)
1169
+ product = reaction.getProduct(f'{item}')
1170
+ if product is None:
1171
+ continue
1172
+ else:
1173
+ relevant_reactions.append(reaction.id)
1174
+ new_entry = {item : relevant_reactions}
1175
+ precursor_reactions.update(new_entry)
1176
+
1177
+ for key in precursor_reactions:
1178
+ flux_set = []
1179
+ relevant_reactions = precursor_reactions[key]
1180
+ species = biomass_reaction.getReactant(f'{key}').getSpecies()
1181
+ name = i_set.records.loc[i_set.records['index'] == species, 'element_text'].iloc[0]
1182
+ print(f'\n{name} FLUXES')
1183
+ for item in relevant_reactions:
1184
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1185
+ print(f'{item} : {flux}')
1186
+ flux_set.append(flux)
1187
+ print(f'Total flux for {name} = {sum(flux_set)}')
1188
+ if sum(flux_set) <= 1e-5:
1189
+ list_to_investigate.append(name)
1190
+
1191
+ print(f'\nBiomass precursors with zero or negative production:')
1192
+ for item in list_to_investigate:
1193
+ print(item)
1194
+
1195
+ print(model.getNumReactions(), 'reactions in the model')
1196
+ print(model.getNumSpecies(), 'species in the model')
1197
+
1198
+ # biomass_fluxes(*mgk)
1199
+ # biomass_fluxes(*prm)
1200
+ # biomass_fluxes(*rfl)
1201
+
1202
+ def zero_flux_reactions(file_name, v_set, j_set, i_set):
1203
+ reader = libsbml.SBMLReader()
1204
+ document = reader.readSBML(f'model files/{file_name}')
1205
+ model = document.getModel()
1206
+
1207
+ """Return a list of reaction IDs in v_set where the flux is exactly zero."""
1208
+ zero_flux_df = v_set.records.loc[v_set.records['level'] == 0]
1209
+ zero_flux_list = zero_flux_df[j_set].tolist()
1210
+
1211
+ print(f'\n*** {file_name} REACTIONS WITH ZERO FLUX ***')
1212
+ for item in zero_flux_list:
1213
+ precursor_reactions = {}
1214
+ needy_dict = {}
1215
+ unmade_products = []
1216
+ zero_reaction = model.getReaction(item)
1217
+ for i in range(zero_reaction.getNumProducts()):
1218
+ product = zero_reaction.getProduct(i)
1219
+ unmade_products.append(product.getSpecies())
1220
+ print(f'\n{item}')
1221
+ for item in unmade_products:
1222
+ relevant_reactions = []
1223
+ needy_reactions = []
1224
+ for i in range(model.getNumReactions()):
1225
+ reaction = model.getReaction(i)
1226
+ product = reaction.getProduct(f'{item}')
1227
+ if product is None:
1228
+ continue
1229
+ else:
1230
+ relevant_reactions.append(reaction.id)
1231
+ new_entry = {item : relevant_reactions}
1232
+ precursor_reactions.update(new_entry)
1233
+
1234
+ for i in range(model.getNumReactions()):
1235
+ reaction = model.getReaction(i)
1236
+ reactant = reaction.getReactant(f'{item}')
1237
+ if reactant is None:
1238
+ continue
1239
+ else:
1240
+ needy_reactions.append(reaction.id)
1241
+ new_entry = {item : relevant_reactions}
1242
+ precursor_reactions.update(new_entry)
1243
+ new_entry = {item : needy_reactions}
1244
+ needy_dict.update(new_entry)
1245
+
1246
+ for key in precursor_reactions:
1247
+ relevant_reactions = precursor_reactions[key]
1248
+ product = zero_reaction.getProduct(f'{key}')
1249
+ species = product.getSpecies()
1250
+ name = i_set.records.loc[i_set.records['index'] == species, 'element_text'].iloc[0]
1251
+ print(f'Reactions that produce {name} ({species}):')
1252
+ for item in relevant_reactions:
1253
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1254
+ print(f'{item} : {flux}')
1255
+ print(f'Reactions that require {name} ({species}):')
1256
+ for item in needy_reactions:
1257
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1258
+ print(f'{item} : {flux}')
1259
+
1260
+
1261
+
1262
+ # zero_flux_reactions(*mgk)
1263
+ # zero_flux_reactions(*prm)
1264
+ # zero_flux_reactions(*rfl)
1265
+
1266
+
1267
+
1268
+
1269
+
1270
+
1271
+
Cowmunity.py ADDED
@@ -0,0 +1,1307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import libsbml
3
+ from gamspy import Container, Set, Parameter, Variable, Equation, Model, Sum, Sense, Options, SpecialValues, SolveStatus
4
+ import os
5
+
6
+ def Sets():
7
+ print("Creating sets...")
8
+ global cowmunity
9
+
10
+ cowmunity = Container()
11
+
12
+ global j_mgk, j_prm, j_rfl, i_mgk, i_prm, i_rfl
13
+
14
+ j_mgk = Set(container=cowmunity, name="j_mgk", description="M. Gottschalkii reactions")
15
+ j_prm = Set(container=cowmunity, name="j_prm", description="P. ruminicola reactions")
16
+ j_rfl = Set(container=cowmunity, name="j_rfl", description="R. flavefaciens reactions")
17
+
18
+ i_mgk = Set(container=cowmunity, name="i_mgk", description="M. Gottschalkii metabolites")
19
+ i_prm = Set(container=cowmunity, name="i_prm", description="P. ruminicola metabolites")
20
+ i_rfl = Set(container=cowmunity, name="i_rfl", description="R. flavefaciens metabolites")
21
+
22
+ def extract_metabolites(xml_file_path, GAMSpy_set):
23
+ # Parse the XML file
24
+ reader = libsbml.SBMLReader()
25
+ document = reader.readSBML(f'model files/{xml_file_path}')
26
+ model = document.getModel()
27
+ if model is None:
28
+ raise ValueError("The SBML model could not be parsed or is empty.")
29
+
30
+ # Extract names and store them in a list
31
+ met_name = {}
32
+ for i in range(model.getNumSpecies()):
33
+ species = model.getSpecies(i)
34
+ new_entry = {species.id : species.getName()[0:63]}
35
+ met_name.update(new_entry)
36
+ df = pd.DataFrame.from_dict(met_name, orient='index', columns=['name'])
37
+
38
+ # add the names to the GAMSpy Set
39
+ GAMSpy_set.setRecords(df.reset_index())
40
+
41
+
42
+ def extract_reactions(xml_file_path, GAMSpy_set):
43
+ # Parse the XML file
44
+ reader = libsbml.SBMLReader()
45
+ document = reader.readSBML(f'model files/{xml_file_path}')
46
+ model = document.getModel()
47
+ if model is None:
48
+ raise ValueError("The SBML model could not be parsed or is empty.")
49
+
50
+ # Extract names and store them in a list
51
+ rxn_name = {}
52
+ for i in range(model.getNumReactions()):
53
+ reaction = model.getReaction(i)
54
+ new_entry = {reaction.id : reaction.getName()[0:63]}
55
+ rxn_name.update(new_entry)
56
+ df = pd.DataFrame.from_dict(rxn_name, orient='index', columns=['name'])
57
+
58
+ # add the names to the GAMSpy Set
59
+ GAMSpy_set.setRecords(df.reset_index())
60
+
61
+
62
+ extract_reactions('M. gottschalkii.xml', j_mgk)
63
+ extract_reactions('P. ruminicola.xml', j_prm)
64
+ extract_reactions('R. flavefaciens.xml', j_rfl)
65
+
66
+ extract_metabolites('M. gottschalkii.xml', i_mgk)
67
+ extract_metabolites('P. ruminicola.xml', i_prm)
68
+ extract_metabolites('R. flavefaciens.xml', i_rfl)
69
+
70
+ def Parameters():
71
+ print("Adding model parameters...")
72
+ global ub_mgk, ub_prm, ub_rfl, lb_mgk, lb_prm, lb_rfl
73
+
74
+ ub_mgk = Parameter(container=cowmunity, name="ub_mgk", domain=j_mgk, description="Upper bound for M. Gottschalkii reactions")
75
+ lb_mgk = Parameter(container=cowmunity, name="lb_mgk", domain=j_mgk, description="Lower bound for M. Gottschalkii reactions")
76
+
77
+ ub_prm = Parameter(container=cowmunity, name="ub_prm", domain=j_prm, description="Upper bound for P. ruminicola reactions")
78
+ lb_prm = Parameter(container=cowmunity, name="lb_prm", domain=j_prm, description="Lower bound for P. ruminicola reactions")
79
+
80
+ ub_rfl = Parameter(container=cowmunity, name="ub_rfl", domain=j_rfl, description="Upper bound for R. flavefaciens reactions")
81
+ lb_rfl = Parameter(container=cowmunity, name="lb_rfl", domain=j_rfl, description="Lower bound for R. flavefaciens reactions")
82
+
83
+ # define the reaction types for each reaction, whether they are reversible (1) or irreversible (0)
84
+
85
+ rxntype_mgk = Parameter(container=cowmunity, name="rxntype_mgk", domain=j_mgk, description="Reaction type for M. Gottschalkii reactions")
86
+ rxntype_prm = Parameter(container=cowmunity, name="rxntype_prm", domain=j_prm, description="Reaction type for P. ruminicola reactions")
87
+ rxntype_rfl = Parameter(container=cowmunity, name="rxntype_rfl", domain=j_rfl, description="Reaction type for R. flavefaciens reactions")
88
+
89
+ # define the stoichiometric matrix for each species, which describes the relationship between reactions and metabolites
90
+ # gives the coefficients for each reaction
91
+
92
+ global S_mgk, S_prm, S_rfl
93
+
94
+ S_mgk = Parameter(container=cowmunity, name="S_mgk", domain=[j_mgk, i_mgk], description="Stoichiometric matrix for M. Gottschalkii")
95
+ S_prm = Parameter(container=cowmunity, name="S_prm", domain=[j_prm, i_prm], description="Stoichiometric matrix for P. ruminicola")
96
+ S_rfl = Parameter(container=cowmunity, name="S_rfl", domain=[j_rfl, i_rfl], description="Stoichiometric matrix for R. flavefaciens")
97
+
98
+ # define whether each reaction is an exchange reaction
99
+
100
+ ex_mgk = Parameter(container=cowmunity, name="ex_mgk", domain=j_mgk, description="Exchange for M. Gottschalkii reactions")
101
+ ex_prm = Parameter(container=cowmunity, name="ex_prm", domain=j_prm, description="Exchange for P. ruminicola reactions")
102
+ ex_rfl = Parameter(container=cowmunity, name="ex_rfl", domain=j_rfl, description="Exchange for R. flavefaciens reactions")
103
+
104
+ def extract_rxn_type(xml_file_path, GAMSpy_parameter):
105
+ # Parse the XML file
106
+ reader = libsbml.SBMLReader()
107
+ document = reader.readSBML(f'model files/{xml_file_path}')
108
+ model = document.getModel()
109
+ if model is None:
110
+ raise ValueError("The SBML model could not be parsed or is empty.")
111
+ # Extract names and store them in a list
112
+ type_dict = {}
113
+ for i in range(model.getNumReactions()):
114
+ reaction = model.getReaction(i)
115
+ rxn_type = reaction.getReversible()
116
+ if rxn_type:
117
+ rxn_type = 1
118
+ else:
119
+ rxn_type = 0
120
+ new_entry = {reaction.id : rxn_type}
121
+ type_dict.update(new_entry)
122
+
123
+ df = pd.DataFrame.from_dict(type_dict, orient='index', columns=['name'])
124
+
125
+ # add the names to the GAMSpy Set
126
+ GAMSpy_parameter.setRecords(df.reset_index())
127
+
128
+
129
+ def extract_matrix(xml_file_path, GAMSpy_parameter):
130
+ # Parse the XML file
131
+ reader = libsbml.SBMLReader()
132
+ document = reader.readSBML(f'model files/{xml_file_path}')
133
+ model = document.getModel()
134
+ if model is None:
135
+ raise ValueError("The SBML model could not be parsed or is empty.")
136
+ # Extract reactions, metabolites, and their stoichiometry
137
+ df = pd.DataFrame()
138
+ for i in range(model.getNumReactions()):
139
+ reaction = model.getReaction(i)
140
+ for i in range(reaction.getNumReactants()):
141
+ reactant = reaction.getReactant(i)
142
+ metabolite_id = reactant.species
143
+ stoich = reactant.stoichiometry
144
+ new_row_df = pd.DataFrame({'reaction': [reaction.id], 'metabolite': [metabolite_id], 'stoichiometry': [-stoich]})
145
+ df = pd.concat([df, new_row_df], ignore_index=True)
146
+ for i in range(reaction.getNumProducts()):
147
+ product = reaction.getProduct(i)
148
+ metabolite_id = product.species
149
+ stoich = product.stoichiometry
150
+ new_row_df = pd.DataFrame({'reaction': [reaction.id], 'metabolite': [metabolite_id], 'stoichiometry': [stoich]})
151
+ df = pd.concat([df, new_row_df], ignore_index=True)
152
+
153
+ df = df.set_index(['reaction', 'metabolite'])
154
+
155
+
156
+ # add the names to the GAMSpy Set
157
+ GAMSpy_parameter.setRecords(df.reset_index())
158
+
159
+
160
+ def extract_exchange_type(xml_file_path, GAMSpy_parameter):
161
+ # Parse the XML file
162
+ reader = libsbml.SBMLReader()
163
+ document = reader.readSBML(f'model files/{xml_file_path}')
164
+ model = document.getModel()
165
+ if model is None:
166
+ raise ValueError("The SBML model could not be parsed or is empty.")
167
+ # Extract names and store them in a list
168
+ type_dict = {}
169
+ ex_count = 0
170
+ for i in range(model.getNumReactions()):
171
+ reaction = model.getReaction(i)
172
+ if 'EX_' in reaction.id:
173
+ ex_type = 1
174
+ ex_count += 1
175
+ else:
176
+ ex_type = 0
177
+ new_entry = {reaction.id : ex_type}
178
+ type_dict.update(new_entry)
179
+
180
+ df = pd.DataFrame.from_dict(type_dict, orient='index', columns=['name'])
181
+
182
+ # add the names to the GAMSpy Set
183
+ GAMSpy_parameter.setRecords(df.reset_index())
184
+
185
+
186
+ extract_rxn_type('M. gottschalkii.xml', rxntype_mgk)
187
+ extract_rxn_type('P. ruminicola.xml', rxntype_prm)
188
+ extract_rxn_type('R. flavefaciens.xml', rxntype_rfl)
189
+
190
+ extract_matrix('M. gottschalkii.xml', S_mgk)
191
+ extract_matrix('P. ruminicola.xml', S_prm)
192
+ extract_matrix('R. flavefaciens.xml', S_rfl)
193
+
194
+ extract_exchange_type('M. gottschalkii.xml', ex_mgk)
195
+ extract_exchange_type('P. ruminicola.xml', ex_prm)
196
+ extract_exchange_type('R. flavefaciens.xml', ex_rfl)
197
+
198
+ # using a scalar parameter to define the maximum flux for each reaction, this is a constant that will be used in the model
199
+
200
+ Vmax = Parameter(container=cowmunity, name='Vmax', records=1000)
201
+
202
+ # set the reaction bounds for the irreversible reactions, reaction type 0
203
+
204
+ ub_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 0] = Vmax
205
+ lb_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 0] = SpecialValues.EPS # using SpecialValues.EPS to avoid zero lower bounds, which can cause issues in some solvers
206
+
207
+ ub_prm[j_prm].where[rxntype_prm[j_prm] == 0] = Vmax
208
+ lb_prm[j_prm].where[rxntype_prm[j_prm] == 0] = SpecialValues.EPS
209
+
210
+ ub_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 0] = Vmax
211
+ lb_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 0] = SpecialValues.EPS
212
+
213
+ # set the reaction bounds for the reversible reactions, reaction type 1
214
+
215
+ ub_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 1] = Vmax
216
+ lb_mgk[j_mgk].where[rxntype_mgk[j_mgk] == 1] = -Vmax
217
+
218
+ ub_prm[j_prm].where[rxntype_prm[j_prm] == 1] = Vmax
219
+ lb_prm[j_prm].where[rxntype_prm[j_prm] == 1] = -Vmax
220
+
221
+ ub_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 1] = Vmax
222
+ lb_rfl[j_rfl].where[rxntype_rfl[j_rfl] == 1] = -Vmax
223
+
224
+ def Variables(variable_choice, treatment='no', methane='variable'):
225
+ global v_mgk, v_prm, v_rfl, biomass_outer, ATP_outer, objective_variable
226
+
227
+ biomass_outer = Variable(container=cowmunity, name="biomass_outer", description="Outer problem Biomass objective function")
228
+ ATP_outer = Variable(container=cowmunity, name="ATP_outer", description="Outer problem ATP objective function")
229
+
230
+ if variable_choice == 'biomass_outer':
231
+ objective_variable = biomass_outer
232
+ if variable_choice == 'ATP_outer':
233
+ objective_variable = ATP_outer
234
+
235
+
236
+ v_mgk = Variable(container=cowmunity, name="v_mgk", domain=j_mgk, description="Fluxes for M. Gottschalkii reactions")
237
+ v_prm = Variable(container=cowmunity, name="v_prm", domain=j_prm, description="Fluxes for P. ruminicola reactions")
238
+ v_rfl = Variable(container=cowmunity, name="v_rfl", domain=j_rfl, description="Fluxes for R. flavefaciens reactions")
239
+
240
+ global lambda_mgk, lambda_prm, lambda_rfl
241
+
242
+ # Dual variables for the mass balance
243
+ lambda_mgk = Variable(container=cowmunity, name="lambda_mgk", domain=i_mgk, description="Dual variables for M. Gottschalkii metabolites")
244
+ lambda_prm = Variable(container=cowmunity, name="lambda_prm", domain=i_prm, description="Dual variables for P. ruminicola metabolites")
245
+ lambda_rfl = Variable(container=cowmunity, name="lambda_rfl", domain=i_rfl, description="Dual variables for R. flavefaciens metabolites")
246
+
247
+ # defining the flux bounds for each reaction as the upper and lower bounds defined above
248
+ v_mgk.lo[j_mgk] = lb_mgk[j_mgk]
249
+ v_mgk.up[j_mgk] = ub_mgk[j_mgk]
250
+ v_prm.lo[j_prm] = lb_prm[j_prm]
251
+ v_prm.up[j_prm] = ub_prm[j_prm]
252
+ v_rfl.lo[j_rfl] = lb_rfl[j_rfl]
253
+ v_rfl.up[j_rfl] = ub_rfl[j_rfl]
254
+
255
+ # ****** indicates the metabolite is transferred between species, so I will not set a flux for the species that does not take it up
256
+ # commented lines are those determined to have a greater capacity due to the potential for transfer between species
257
+ # the 4.55 indicates a conversion factor for dry whole weight to dry cell weight, as the model is based on dry cell weight
258
+
259
+ # v_prm.lo['EX_cpd11657_e0'] = -0.965423023 * 4.55 # uptake rate for Starch, fed to the model as two glucose units
260
+ v_prm.lo['EX_cpd00076_e0'] = -0.834726132 * 4.55 # uptake rate for Sucrose
261
+ v_rfl.lo['EX_cpd00076_e0'] = -0.834726132 * 4.55
262
+ v_prm.lo['EX_cpd00053_e0'] = -1.597816364 * 4.55 # uptake rate for L-Glutamine
263
+ v_rfl.lo['EX_cpd00053_e0'] = -1.597816364 * 4.55
264
+ # v_prm.lo['EX_cpd00027_e0'] = -0.794397609 * 4.55 # uptake rate for D-glucose *****
265
+ v_rfl.lo['EX_cpd00027_e0'] = (-0.794397609 + (-0.965423023 * 2)) * 4.55 # adjusted for the uptake of Starch
266
+ v_rfl.lo['EX_cpd00107_e0'] = -1.148366562 * 4.55 # uptake rate for L-Leucine
267
+ v_prm.lo['EX_cpd00107_e0'] = -1.148366562 * 4.55
268
+ # v_prm.lo['EX_cpd00224_e0'] = -0.666427627 * 4.55 # uptake rate for L-arabinose *****
269
+ v_rfl.lo['EX_cpd00224_e0'] = -0.666427627 * 4.55
270
+ # v_prm.lo['EX_cpd00035_e0'] = -0.938846598 * 4.55 # uptake rate for L-Alanine ****
271
+ # v_rfl.lo['EX_cpd00035_e0'] = -0.938846598 * 4.55
272
+ v_prm.lo['EX_cpd00132_e0'] = -0.400330802 * 4.55 # uptake rate for L-Asparagine
273
+ v_rfl.lo['EX_cpd00066_e0'] = -0.310015056 * 4.55 # uptake rate for L-Phenylalanine
274
+ v_rfl.lo['EX_cpd00156_e0'] = -0.385856944 * 4.55 # uptake rate for L-Valine
275
+ v_rfl.lo['EX_cpd00069_e0'] = -0.218417727 * 4.55 # uptake rate for L-Tyrosine
276
+ v_prm.lo['EX_cpd00060_e0'] = -0.233929798 * 4.55 # uptake rate for L-Methionine
277
+ v_prm.lo['EX_cpd00161_e0'] = -0.261179221 * 4.55 # uptake rate for L-Threonine
278
+ v_rfl.lo['EX_cpd00161_e0'] = -0.261179221 * 4.55
279
+ v_rfl.lo['EX_cpd00322_e0'] = -0.211165444 * 4.55 # uptake rate for L-Isoleucine
280
+ v_prm.lo['EX_cpd00051_e0'] = -0.133660701 * 4.55 # uptake rate for L-Arginine
281
+ v_rfl.lo['EX_cpd00051_e0'] = -0.133660701 * 4.55
282
+ # v_prm.lo['EX_cpd00033_e0'] = -0.268595078 * 4.55 # uptake rate for Glycine ******
283
+ # v_rfl.lo['EX_cpd00033_e0'] = -0.268595078 * 4.55
284
+ v_prm.lo['EX_cpd00348_e0'] = -0.075513967 * 4.55 # uptake rate for D-Galactose
285
+ v_rfl.lo['EX_cpd00348_e0'] = -0.075513967 * 4.55
286
+ v_rfl.lo['EX_cpd00119_e0'] = -0.124559013 * 4.55 # uptake rate for L-Histidine
287
+ v_prm.lo['EX_cpd00039_e0'] = -0.098373937 * 4.55 # uptake rate for L-Lysine
288
+ v_rfl.lo['EX_cpd00039_e0'] = -0.098373937 * 4.55
289
+ v_prm.lo['EX_cpd00084_e0'] = -0.114920408 * 4.55 # uptake rate for L-Cysteine
290
+ v_rfl.lo['EX_cpd00084_e0'] = -0.114920408 * 4.55
291
+ v_prm.lo['EX_cpd00053_e0'] = -0.080568485 * 4.55 # uptake rate for L-Glutamine
292
+ v_rfl.lo['EX_cpd00053_e0'] = -0.080568485 * 4.55
293
+ v_rfl.lo['EX_cpd00038_e0'] = -0.007734655 * 4.55 # uptake rate for GTP
294
+ v_rfl.lo['EX_cpd00138_e0'] = -0.021731242 * 4.55 # uptake rate for D-Mannose
295
+ v_prm.lo['EX_cpd00052_e0'] = -0.007307850 * 4.55 # uptake rate for CTP
296
+ v_rfl.lo['EX_cpd00052_e0'] = -0.007307850 * 4.55
297
+ v_prm.lo['EX_cpd00002_e0'] = -0.006289719 * 4.55 # uptake rate for ATP
298
+ v_rfl.lo['EX_cpd00002_e0'] = -0.006289719 * 4.55
299
+ v_prm.lo['EX_cpd00062_e0'] = -0.005932755 * 4.55 # uptake rate for UTP
300
+ v_rfl.lo['EX_cpd00062_e0'] = -0.005932755 * 4.55
301
+ v_rfl.lo['EX_cpd00115_e0'] = -0.001147315 * 4.55 # uptake rate for dATP
302
+ v_rfl.lo['EX_cpd00357_e0'] = -0.001147552 * 4.55 # uptake rate for dTTP
303
+ v_rfl.lo['EX_cpd00241_e0'] = -0.001012678 * 4.55 # uptake rate for dGTP
304
+ v_prm.lo['EX_cpd00356_e0'] = -0.001016235 * 4.55 # uptake rate for dCTP
305
+ v_rfl.lo['EX_cpd00356_e0'] = -0.001016235 * 4.55
306
+ # v_prm.lo['EX_cpd11746_e0'] = -0.320930655 * 4.55 # uptake rate for Cellulose ****
307
+ v_rfl.lo['EX_cpd11746_e0'] = -0.320930655 * 4.55
308
+ v_rfl.lo['EX_cpd29869_e0'] = -0.002499522 * 4.55 # uptake rate for hemicellulose
309
+ # v_prm.lo['EX_cpd00009_e0'] = -0.005244478 * 4.55 # uptake rate for Phosphate, this is an inorganic ion, uptake set to max
310
+ # v_rfl.lo['EX_cpd00009_e0'] = -0.005244478 * 4.55
311
+ v_rfl.lo['EX_cpd00065_e0'] = 0 # uptake rate for Tryptophan
312
+ v_prm.lo['EX_cpd00073_e0'] = -0.629166662 * 4.55 # uptake rate for Urea
313
+ v_rfl.lo['EX_cpd00073_e0'] = -0.629166662 * 4.55
314
+ # v_prm.lo['EX_cpd00048_e0'] = -0.004273279 * 4.55 # uptake rate for Sulfate, this is an inorganic ion, uptake set to max
315
+ # v_rfl.lo['EX_cpd00048_e0'] = -0.004273279 * 4.55
316
+
317
+ # added constraints to bring down the MGK flux
318
+ v_mgk.lo['EX_cpd00162_e0'] = -1 # uptake rate for aminoethanol
319
+ v_mgk.lo['EX_cpd00122_e0'] = -0.01 # uptake rate for n-acetyl-D-glucosamine
320
+
321
+ # added contraints to coorespond to the different treatment options
322
+ # COMBINED APPROACH: Apply both docking-based constraints AND literature-based constraints
323
+ # Docking captures direct enzyme effects, literature captures indirect community effects
324
+
325
+ if methane == 'variable':
326
+ # Apply docking-based constraints (direct enzyme effects)
327
+ docking_applied = False
328
+ if treatment != 'no':
329
+ try:
330
+ from docking_integration.apply_docking_constraints import apply_docking_treatment
331
+ import os
332
+
333
+ docking_file = 'docking_data/cleaned_docking_results.csv'
334
+ if os.path.exists(docking_file):
335
+ # Map treatment names to molecule names in docking file
336
+ molecule_map = {
337
+ 'imidazole': 'Imidazole',
338
+ 'l-carnitine': 'L-carnitine',
339
+ 'methyl jasmonate': 'Methyl jasmonate',
340
+ 'propylpyrazine': 'Propylpyrazine'
341
+ }
342
+
343
+ if treatment in molecule_map:
344
+ molecule_name = molecule_map[treatment]
345
+ apply_docking_treatment(
346
+ v_mgk, v_prm, v_rfl,
347
+ molecule_name=molecule_name,
348
+ docking_csv_path=docking_file,
349
+ methane=methane
350
+ )
351
+ docking_applied = True
352
+ print(f"Docking-based constraints applied for {treatment}")
353
+ except Exception as e:
354
+ print(f"Warning: Could not apply docking constraints: {e}")
355
+ docking_applied = False
356
+
357
+ # ALWAYS apply literature-based constraints (indirect community effects)
358
+ # These capture mechanisms that docking might miss (community interactions, etc.)
359
+ if treatment == 'imidazole':
360
+ # reactions that are affected by imidazole treatment
361
+ # Imidazole inhibits lysozyme activity in protozoa, reducing their ability to digest bacteria
362
+ # This reduces predation pressure on bacteria, allowing them to grow more freely
363
+ # We simulate this by increasing biomass production rates and reducing some metabolic constraints
364
+
365
+ # Increase biomass production rates for all bacteria (reduced predation pressure)
366
+ v_mgk.lo['R_biomass0'] = v_mgk.lo['R_biomass0'] * 1.15 # Increase biomass production by 15%
367
+ v_prm.lo['R_biomass0'] = v_prm.lo['R_biomass0'] * 1.15
368
+ v_rfl.lo['R_biomass0'] = v_rfl.lo['R_biomass0'] * 1.15
369
+ # Increase substrate uptake rates (bacteria can access more resources with reduced predation)
370
+ # Note: We'll use more conservative increases and only apply to reactions that exis
371
+ # v_prm.lo['EX_cpd00027_e0'] = v_prm.lo['EX_cpd00027_e0'] * 1.2
372
+ # v_rfl.lo['EX_cpd00027_e0'] = v_rfl.lo['EX_cpd00027_e0'] * 1.2
373
+ # Increase acetate production (common byproduct of bacterial metabolism)
374
+ v_mgk.lo['EX_cpd00029_e0'] = v_mgk.lo['EX_cpd00029_e0'] * 1.1
375
+ v_prm.lo['EX_cpd00029_e0'] = v_prm.lo['EX_cpd00029_e0'] * 1.1
376
+ v_rfl.lo['EX_cpd00029_e0'] = v_rfl.lo['EX_cpd00029_e0'] * 1.1
377
+ # Increase formate production (important for methanogenesis)
378
+ # v_mgk.lo['EX_cpd00056_e0'] = v_mgk.lo['EX_cpd00056_e0'] * 1.2
379
+ # v_prm.lo['EX_cpd00056_e0'] = v_prm.lo['EX_cpd00056_e0'] * 1.2
380
+ # v_rfl.lo['EX_cpd00056_e0'] = v_rfl.lo['EX_cpd00056_e0'] * 1.2
381
+ # Increase H2 production (important substrate for methanogenesis)
382
+ v_mgk.lo['EX_cpd00067_e0'] = v_mgk.lo['EX_cpd00067_e0'] * 1.25
383
+ v_prm.lo['EX_cpd00067_e0'] = v_prm.lo['EX_cpd00067_e0'] * 1.25
384
+ v_rfl.lo['EX_cpd00067_e0'] = v_rfl.lo['EX_cpd00067_e0'] * 1.25
385
+ print("Literature-based constraints applied for imidazole (community effects)")
386
+ elif treatment == 'l-carnitine':
387
+ # reactions that are affected by l-carnitine treatment
388
+ v_mgk.lo['EX_cpd01188_e0'] = -0.009476130618701499 * 0.89 # output rate for lanosterol, 0.87 times the original value becase cholesterol falls
389
+ v_rfl.lo['EX_cpd01188_e0'] = -0.01658854044409092 * 0.89
390
+ print("Literature-based constraints applied for l-carnitine")
391
+ elif treatment == 'methyl jasmonate':
392
+ print("Methyl jasmonate treatment selected, setting constraints...")
393
+ v_mgk.lo['EX_cpd00129_e0'] = 0.01608686252400516 * 1.23 # output rate for proline, 1.23 times the original value based on Lubyanova paper
394
+ v_prm.lo['EX_cpd00129_e0'] = 0.004029898865569517 * 1.23
395
+ # v_mgk.lo['R_rxn09296_c0'] = 0.0005201736148737044 * 1.4 # H2O2 reduction by thioredoxin, 1.4 times the original value based on Lubyanova paper
396
+ # v_prm.lo['R_rxn09296_c0'] = 71.50423813116777 * 1.4
397
+ # v_rfl.lo['R_rxn09296_c0'] = 316.9770835412888 * 1.4
398
+ # v_prm.lo['R_rxn12638_c0'] = 65.98723846787729 * 1.23 # breakdown of N-glycylproline
399
+ print("Literature-based constraints applied for methyl jasmonate")
400
+ elif treatment == 'propylpyrazine':
401
+ # reactions that are affected by propylpyrazine treatment
402
+ # v_mgk.lo['R_rxn00305_c0'] = 191.07533512418465 * 3.02 # Pck1 expression went up about 3 times after treatment with TMP, should affect GTP and phosphoenolpyruvate
403
+ # v_prm.lo['R_rxn00305_c0'] = 169.79210656337526 * 3.02
404
+ # v_rfl.lo['R_rxn00305_c0'] = 164.67010537093077 * 3.02
405
+ # v_mgk.lo['R_rxn00285_c0'] = 0.0011420124768651806 * 2.14 # Sucla2 expression went up about 2.14 times after treatment with propylpyrazine, should affect succinyl-CoA
406
+ # v_rfl.lo['R_rxn00285_c0'] = 0.012806125516892619 * 2.14
407
+ # v_mgk.lo['R_rxn12510_c0'] = 0.0010308604158823106 * 1.77 # Pank1 expression went up about 1.77 times after treatment with propylpyrazine, should affect phosphorylation of pantothenate
408
+ # v_prm.lo['R_rxn12510_c0'] = 0.008928357454568775 * 1.77
409
+ # v_rfl.lo['R_rxn12510_c0'] = 0.0015697141164147958 * 1.77
410
+ # v_prm.lo['R_rxn00248_c0'] = 167.2035577959039 * 1.93 # Mdh2 went up about 1.93 times after treatment with propylpyrazine, should affect conversion of L-malate to oxaloacetate
411
+ # v_mgk.lo['R_rxn06037_c0'] = -6.170993629588869e-21 * 3.08 # Hadhb expression went up about 3.08 times after treatment with propylpyrazine, should affect conversion of 3-hydroxyacyl-CoA -> 3-oxoacyl-CoA
412
+ # v_prm.lo['R_rxn00799_c0'] = 127.86504315656339 * 2.19 # Fh1 expression went up about 2.19 times after treatment with propylpyrazine, should affect conversion of fumarate to L-malate
413
+ # v_rfl.lo['R_rxn00256_c0'] = 104.25331895829011 * 1.43 # Cs expression went up about 1.43 times after treatment with propylpyrazine, should affect conversion of oxaloacetate to citrate
414
+ v_mgk.lo['R_rxn12512_c0'] = 0.000453718935224341 * 1.17 # Ppcs expression went up about 1.17 times after treatment with propylpyrazine, should affect conversion of phosphopantothenate combination with cysteine
415
+ v_prm.lo['R_rxn12512_c0'] = 0.004463845288178093 * 1.17
416
+ v_rfl.lo['R_rxn12512_c0'] = 0.0007848557326249302 * 1.17
417
+ print("Literature-based constraints applied for propylpyrazine")
418
+ elif treatment == 'no':
419
+ # no treatment, no additional constraints
420
+ print("No treatment selected, using default constraints.")
421
+ elif methane == 'fixed':
422
+ if treatment == 'imidazole':
423
+ # reactions that are affected by imidazole treatment
424
+ v_mgk.fx['EX_cpd01024_e0'] = 3.74 * 2.5125e-5 # output rate for methane based on USDA data, conversion factor from ml to mmol/gDCW.hr
425
+ print("Imidazole treatment selected, setting constraints...")
426
+ elif treatment == 'l-carnitine':
427
+ v_mgk.fx['EX_cpd01024_e0'] = 3.79 * 2.5125e-5
428
+ # reactions that are affected by l-carnitine treatment
429
+ print("L-carnitine treatment selected, setting constraints...")
430
+ elif treatment == 'methyl jasmonate':
431
+ v_mgk.fx['EX_cpd01024_e0'] = 3.53 * 2.5125e-5
432
+ print("Methyl jasmonate treatment selected, setting constraints...")
433
+ elif treatment == 'propylpyrazine':
434
+ v_mgk.fx['EX_cpd01024_e0'] = 4.40 * 2.5125e-5
435
+ # reactions that are affected by propylpyrazine treatment
436
+ print("Propylpyrazine treatment selected, setting constraints...")
437
+ elif treatment == 'no':
438
+ # no treatment, no additional constraints
439
+ v_mgk.fx['EX_cpd01024_e0'] = 3.40 * 2.5125e-5
440
+ print("No treatment selected, using default constraints.")
441
+
442
+ # Dual variables for bounds
443
+ global muLB_mgk, muUB_mgk, muLB_prm, muUB_prm, muLB_rfl, muUB_rfl
444
+
445
+ muLB_mgk = Variable(container=cowmunity, name="muLB_mgk", domain=j_mgk, description="Dual variables for MGK LB")
446
+ muUB_mgk = Variable(container=cowmunity, name="muUB_mgk", domain=j_mgk, description="Dual variables for MGK UB")
447
+ muLB_prm = Variable(container=cowmunity, name="muLB_prm", domain=j_prm, description="Dual variables for PRM LB")
448
+ muUB_prm = Variable(container=cowmunity, name="muUB_prm", domain=j_prm, description="Dual variables for PRM UB")
449
+ muLB_rfl = Variable(container=cowmunity, name="muLB_rfl", domain=j_rfl, description="Dual variables for RFL LB")
450
+ muUB_rfl = Variable(container=cowmunity, name="muUB_rfl", domain=j_rfl, description="Dual variables for RFL UB")
451
+
452
+ # Set dual variables to positive
453
+ muLB_mgk.lo[j_mgk] = 0
454
+ muUB_mgk.lo[j_mgk] = 0
455
+ muLB_prm.lo[j_prm] = 0
456
+ muUB_prm.lo[j_prm] = 0
457
+ muLB_rfl.lo[j_rfl] = 0
458
+ muUB_rfl.lo[j_rfl] = 0
459
+
460
+ # transfer uptake positive variables for the shared metabolites
461
+
462
+ global trans_CO2_mgk, trans_H2_mgk, trans_formate_mgk, trans_acetate_mgk, trans_d_mannose_mgk, trans_d_fructose_mgk, trans_tetrathionate_mgk, trans_thiosulfate_mgk
463
+ global trans_cellulose_prm, trans_d_glucose_prm, trans_acetate_prm, trans_l_arabinose_prm, trans_biotin_prm, trans_thiamin_prm, trans_octadecenoate_prm, trans_maltoheptaose_prm
464
+ global trans_nitrite_prm, trans_n_acetyl_d_glucosamine_prm, trans_aminoethanol_prm, trans_cobinamide_prm, trans_alanine_prm, trans_leucine_prm, trans_glycine_prm, trans_proline_prm
465
+ global trans_d_galacturonate_rfl, trans_deoxyadenosine_rfl, trans_dephospho_coa_rfl, trans_cobinamide_rfl, trans_alanine_rfl, trans_leucine_rfl, trans_glycine_rfl, trans_proline_rfl, trans_aminoethanol_rfl
466
+
467
+ trans_CO2_mgk = Variable(container=cowmunity, name="trans_CO2_mgk", description="maximum transfer of CO2 to M. Gottschalkii")
468
+ trans_H2_mgk = Variable(container=cowmunity, name="trans_H2_mgk", description="maximum transfer of H2 to M. Gottschalkii")
469
+ trans_formate_mgk = Variable(container=cowmunity, name='trans_formate_mgk', description="maximum transfer of formate to M. Gottschalkii")
470
+ trans_acetate_mgk = Variable(container=cowmunity, name="trans_acetate_mgk", description="maximum transfer of acetate to M. Gottschalkii")
471
+ trans_d_mannose_mgk = Variable(container=cowmunity, name="trans_dmannose_mgk", description="maximum transfer of D-mannose to M. Gottschalkii")
472
+ trans_d_fructose_mgk = Variable(container=cowmunity, name="trans_dfructose_mgk", description="maximum transfer of D-fructose to M. Gottschalkii")
473
+ trans_tetrathionate_mgk = Variable(container=cowmunity, name="trans_tetrathionate_mgk", description="maximum transfer of tetrathionate to M. Gottschalkii")
474
+ trans_thiosulfate_mgk = Variable(container=cowmunity, name="trans_thiosulfate_mgk", description="maximum transfer of thiosulfate to M. Gottschalkii")
475
+
476
+ trans_cellulose_prm = Variable(container=cowmunity, name='trans_cellulose_prm', description="maximum transfer of cellulose to P. ruminicola")
477
+ trans_d_glucose_prm = Variable(container=cowmunity, name='trans_d_glucose_prm', description="maximum transfer of D-Glucose to P. ruminicola")
478
+ trans_acetate_prm = Variable(container=cowmunity, name='trans_acetate_prm', description="maximum transfer of Acetate to P. ruminicola")
479
+ trans_l_arabinose_prm = Variable(container=cowmunity, name='trans_l_arabinose_prm', description="maximum transfer of L-Arabinose to P. ruminicola")
480
+ trans_biotin_prm = Variable(container=cowmunity, name='trans_biotin_prm', description="maximum transfer of Biotin to P. ruminicola")
481
+ trans_thiamin_prm = Variable(container=cowmunity, name='trans_thiamin_prm', description="maximum transfer of Thiamin to P. ruminicola")
482
+ trans_octadecenoate_prm = Variable(container=cowmunity, name='trans_octadecenoate_prm', description="maximum transfer of octadecenoate to P. ruminicola")
483
+ trans_maltoheptaose_prm = Variable(container=cowmunity, name='trans_maltoheptaose_prm', description="maximum transfer of Maltoheptaose to P. ruminicola")
484
+ trans_nitrite_prm = Variable(container=cowmunity, name='trans_nitrite_prm', description="maximum transfer of Nitrite to P. ruminicola")
485
+ trans_n_acetyl_d_glucosamine_prm = Variable(container=cowmunity, name='trans_n_acetyl_d_glucosamine_prm', description="maximum transfer of N-Acetyl-D-glucosamine to P. ruminicola")
486
+ trans_aminoethanol_prm = Variable(container=cowmunity, name='trans_aminoethanol_prm', description="maximum transfer of Aminoethanol to P. ruminicola")
487
+ trans_cobinamide_prm = Variable(container=cowmunity, name='trans_cobinamide_prm', description="maximum transfer of Cobinamide to P. ruminicola")
488
+ trans_alanine_prm = Variable(container=cowmunity, name='trans_alanine_prm', description="maximum transfer of Alanine to P. ruminicola")
489
+ trans_leucine_prm = Variable(container=cowmunity, name='trans_leucine_prm', description="maximum transfer of Leucine to P. ruminicola")
490
+ trans_glycine_prm = Variable(container=cowmunity, name='trans_glycine_prm', description="maximum transfer of Glycine to P. ruminicola")
491
+ trans_proline_prm = Variable(container=cowmunity, name='trans_proline_prm', description="maximum transfer of Proline to P. ruminicola")
492
+
493
+ trans_d_galacturonate_rfl = Variable(container=cowmunity, name='trans_d_galacturonate_rfl', description="maximum transfer of D-Galacturonate to R. flavefaciens")
494
+ trans_deoxyadenosine_rfl = Variable(container=cowmunity, name='trans_deoxyadenosine_rfl', description="maximum transfer of Deoxyadenosine to R. flavefaciens")
495
+ trans_dephospho_coa_rfl = Variable(container=cowmunity, name='trans_dephospho_coa_rfl', description="maximum transfer of Dephospho-CoA to R. flavefaciens")
496
+ trans_cobinamide_rfl = Variable(container=cowmunity, name='trans_cobinamide_rfl', description="maximum transfer of Cobinamide to R. flavefaciens")
497
+ trans_alanine_rfl = Variable(container=cowmunity, name='trans_alanine_rfl', description="maximum transfer of Alanine to R. flavefaciens")
498
+ trans_leucine_rfl = Variable(container=cowmunity, name='trans_leucine_rfl', description="maximum transfer of Leucine to R. flavefaciens")
499
+ trans_glycine_rfl = Variable(container=cowmunity, name='trans_glycine_rfl', description="maximum transfer of Glycine to R. flavefaciens")
500
+ trans_proline_rfl = Variable(container=cowmunity, name='trans_proline_rfl', description="maximum transfer of Proline to R. flavefaciens")
501
+ trans_aminoethanol_rfl = Variable(container=cowmunity, name='trans_aminoethanol_rfl', description="maximum transfer of Aminoethanol to R. flavefaciens")
502
+
503
+ # set the transfer variables to positive, these are the maximum transfer rates for each metabolite
504
+
505
+ trans_CO2_mgk.lo = 0
506
+ trans_H2_mgk.lo = 0
507
+ trans_formate_mgk.lo = 0
508
+ trans_acetate_mgk.lo = 0
509
+ trans_d_mannose_mgk.lo = 0
510
+ trans_d_fructose_mgk.lo = 0
511
+ trans_tetrathionate_mgk.lo = 0
512
+ trans_thiosulfate_mgk.lo = 0
513
+
514
+ trans_cellulose_prm.lo = 0
515
+ trans_d_glucose_prm.lo = 0
516
+ trans_acetate_prm.lo = 0
517
+ trans_l_arabinose_prm.lo = 0
518
+ trans_biotin_prm.lo = 0
519
+ trans_thiamin_prm.lo = 0
520
+ trans_octadecenoate_prm.lo = 0
521
+ trans_maltoheptaose_prm.lo = 0
522
+ trans_nitrite_prm.lo = 0
523
+ trans_n_acetyl_d_glucosamine_prm.lo = 0
524
+ trans_aminoethanol_prm.lo = 0
525
+ trans_cobinamide_prm.lo = 0
526
+ trans_alanine_prm.lo = 0
527
+ trans_leucine_prm.lo = 0
528
+ trans_glycine_prm.lo = 0
529
+ trans_proline_prm.lo = 0
530
+
531
+ trans_d_galacturonate_rfl.lo = 0
532
+ trans_deoxyadenosine_rfl.lo = 0
533
+ trans_dephospho_coa_rfl.lo = 0
534
+ trans_cobinamide_rfl.lo = 0
535
+ trans_alanine_rfl.lo = 0
536
+ trans_leucine_rfl.lo = 0
537
+ trans_glycine_rfl.lo = 0
538
+ trans_proline_rfl.lo = 0
539
+ trans_aminoethanol_rfl.lo = 0
540
+
541
+ def Equations():
542
+ print("Adding equations...")
543
+
544
+
545
+ # Objective Functions (Outer Objective)
546
+ biomass_objective = Equation(container=cowmunity, name="biomass_objective", description="Objective function for total biomass accumulation")
547
+ biomass_objective[...] = biomass_outer == v_mgk['R_biomass0'] + v_prm['R_biomass0'] + v_rfl['R_biomass0']
548
+
549
+ ATP_objective = Equation(container=cowmunity, name="ATP_objective", description="Objective function for total ATP Production")
550
+ ATP_objective[...] = ATP_outer == v_mgk['R_rxn02831_c0'] + v_mgk['R_rxn03535_c0'] + v_mgk['R_rxn06874_c0'] + v_mgk['R_rxn10476_c0'] + v_mgk['R_rxn11544_c0'] \
551
+ + v_prm['R_rxn00986_c0'] + v_prm['R_rxn01987_c0'] + v_prm['R_rxn10042_c0'] \
552
+ + v_rfl['R_rxn05840_c0'] + v_rfl['R_rxn06428_c0'] + v_rfl['R_rxn06874_c0'] + v_rfl['R_rxn10042_c0']
553
+
554
+
555
+ # Constraints
556
+ # these are the things that are going to make the model into a true community model rather than three separate models
557
+
558
+ trans_CO2_mgk_balance = Equation(container=cowmunity, name='trans_CO2_balance', description="Balance for CO2 transfer to M. Gottschalkii")
559
+ trans_CO2_mgk_balance[...] = trans_CO2_mgk <= v_prm['EX_cpd00011_e0'] + v_rfl['EX_cpd00011_e0']
560
+
561
+ trans_H2_mgk_balance = Equation(container=cowmunity, name= 'trans_H2_mgk_balance', description="Balance for H2 transfer to M. Gottschalkii")
562
+ trans_H2_mgk_balance[...] = trans_H2_mgk <= v_prm['EX_cpd11640_e0'] + v_rfl['EX_cpd11640_e0']
563
+
564
+ trans_formate_mgk_balance = Equation(container=cowmunity, name='trans_formate_mgk_balance', description="Balance for formate transfer to M. Gottschalkii")
565
+ trans_formate_mgk_balance[...] = trans_formate_mgk <= v_prm['EX_cpd00047_e0'] + v_rfl['EX_cpd00047_e0']
566
+
567
+ trans_acetate_mgk_balance = Equation(container=cowmunity, name='trans_acetate_mgk_balance', description="Balance for acetate transfer to M. Gottschalkii")
568
+ trans_acetate_mgk_balance[...] = trans_acetate_mgk <= v_rfl['EX_cpd00029_e0']
569
+
570
+ trans_d_mannose_mgk_balance = Equation(container=cowmunity, name='trans_d_mannose_mgk_balance', description="Balance for D-mannose transfer to M. Gottschalkii")
571
+ trans_d_mannose_mgk_balance[...] = trans_d_mannose_mgk <= v_rfl['EX_cpd00138_e0']
572
+
573
+ trans_d_fructose_mgk_balance = Equation(container=cowmunity, name='trans_d_fructose_mgk_balance', description="Balance for D-fructose transfer to M. Gottschalkii")
574
+ trans_d_fructose_mgk_balance[...] = trans_d_fructose_mgk <= v_rfl['EX_cpd00082_e0']
575
+
576
+ trans_tetrathionate_mgk_balance = Equation(container=cowmunity, name='trans_tetrathionate_mgk_balance', description="Balance for tetrathionate transfer to M. Gottschalkii")
577
+ trans_tetrathionate_mgk_balance[...] = trans_tetrathionate_mgk <= v_rfl['EX_cpd01414_e0']
578
+
579
+ trans_thiosulfate_mgk_balance = Equation(container=cowmunity, name='trans_thiosulfate_mgk_balance', description="Balance for thiosulfate transfer to M. Gottschalkii")
580
+ trans_thiosulfate_mgk_balance[...] = trans_thiosulfate_mgk <= v_prm['EX_cpd00268_e0']
581
+
582
+ trans_cellulose_prm_balance = Equation(container=cowmunity, name='trans_cellulose_prm_balance', description="Balance for cellulose transfer to P. ruminicola")
583
+ trans_cellulose_prm_balance[...] = trans_cellulose_prm <= v_rfl['EX_cpd11746_e0']
584
+
585
+ trans_d_glucose_prm_balance = Equation(container=cowmunity, name='trans_d_glucose_prm_balance', description="Balance for D-glucose transfer to P. ruminicola")
586
+ trans_d_glucose_prm_balance[...] = trans_d_glucose_prm <= v_rfl['EX_cpd00027_e0']
587
+
588
+ trans_acetate_prm_balance = Equation(container=cowmunity, name='trans_acetate_prm_balance', description="Balance for acetate transfer to P. ruminicola")
589
+ trans_acetate_prm_balance[...] = trans_acetate_prm <= v_rfl['EX_cpd00029_e0']
590
+
591
+ trans_l_arabinose_prm_balance = Equation(container=cowmunity, name='trans_l_arabinose_prm_balance', description="Balance for L-arabinose transfer to P. ruminicola")
592
+ trans_l_arabinose_prm_balance[...] = trans_l_arabinose_prm <= v_rfl['EX_cpd00224_e0']
593
+
594
+ trans_biotin_prm_balance = Equation(container=cowmunity, name='trans_biotin_prm_balance', description="Balance for biotin transfer to P. ruminicola")
595
+ trans_biotin_prm_balance[...] = trans_biotin_prm <= v_rfl['EX_cpd00104_e0']
596
+
597
+ # ****** commented to preserve RFL FLux ********* trans_thiamin_prm_balance = Equation(container=cowmunity, name='trans_thiamin_prm_balance', description="Balance for thiamin transfer to P. ruminicola")
598
+ # ****** commented to preserve RFL FLux ********* trans_thiamin_prm_balance[...] = trans_thiamin_prm <= v_rfl['EX_cpd00305_e0']
599
+
600
+ trans_octadecenoate_prm_balance = Equation(container=cowmunity, name='trans_octadecenoate_prm_balance', description="Balance for octadecenoate transfer to P. ruminicola")
601
+ trans_octadecenoate_prm_balance[...] = trans_octadecenoate_prm <= v_rfl['EX_cpd15269_e0'] + v_mgk['EX_cpd15269_e0']
602
+
603
+ trans_maltoheptaose_prm_balance = Equation(container=cowmunity, name='trans_maltoheptaose_prm_balance', description="Balance for maltoheptaose transfer to P. ruminicola")
604
+ trans_maltoheptaose_prm_balance[...] = trans_maltoheptaose_prm <= v_rfl['EX_cpd15494_e0']
605
+
606
+ trans_nitrite_prm_balance = Equation(container=cowmunity, name='trans_nitrite_prm_balance', description="Balance for nitrite transfer to P. ruminicola")
607
+ trans_nitrite_prm_balance[...] = trans_nitrite_prm <= v_mgk['EX_cpd00075_e0']
608
+
609
+ # ****** commented to preserve MGK FLux ********* trans_n_acetyl_d_glucosamine_prm_balance = Equation(container=cowmunity, name='trans_n_acetyl_d_glucosamine_prm_balance', description="Balance for N-acetyl-D-glucosamine transfer to P. ruminicola")
610
+ # ****** commented to preserve MGK FLux ********* trans_n_acetyl_d_glucosamine_prm_balance[...] = trans_n_acetyl_d_glucosamine_prm <= v_mgk['EX_cpd00122_e0']
611
+
612
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_prm_balance = Equation(container=cowmunity, name='trans_aminoethanol_prm_balance', description="Balance for aminoethanol transfer to P. ruminicola")
613
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_prm_balance[...] = trans_aminoethanol_prm <= v_mgk['EX_cpd00162_e0']
614
+
615
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_prm_balance = Equation(container=cowmunity, name='trans_cobinamide_prm_balance', description="Balance for cobinamide transfer to P. ruminicola")
616
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_prm_balance[...] = trans_cobinamide_prm <= v_mgk['EX_cpd03422_e0']
617
+
618
+ trans_alanine_prm_balance = Equation(container=cowmunity, name='trans_alanine_prm_balance', description="Balance for alanine transfer to P. ruminicola")
619
+ trans_alanine_prm_balance[...] = trans_alanine_prm <= v_mgk['EX_cpd00035_e0']
620
+
621
+ trans_leucine_prm_balance = Equation(container=cowmunity, name='trans_leucine_prm_balance', description="Balance for leucine transfer to P. ruminicola")
622
+ trans_leucine_prm_balance[...] = trans_leucine_prm <= v_mgk['EX_cpd00107_e0']
623
+
624
+ trans_glycine_prm_balance = Equation(container=cowmunity, name='trans_glycine_prm_balance', description="Balance for glycine transfer to P. ruminicola")
625
+ trans_glycine_prm_balance[...] = trans_glycine_prm <= v_mgk['EX_cpd00033_e0']
626
+
627
+ trans_proline_prm_balance = Equation(container=cowmunity, name='trans_proline_prm_balance', description="Balance for proline transfer to P. ruminicola")
628
+ trans_proline_prm_balance[...] = trans_proline_prm <= v_mgk['EX_cpd00129_e0']
629
+
630
+ trans_d_galacturonate_rfl_balance = Equation(container=cowmunity, name='trans_d_galacturonate_rfl_balance', description="Balance for D-galacturonate transfer to R. flavefaciens")
631
+ trans_d_galacturonate_rfl_balance[...] = trans_d_galacturonate_rfl <= v_prm['EX_cpd00280_e0']
632
+
633
+ trans_deoxyadenosine_rfl_balance = Equation(container=cowmunity, name='trans_deoxyadenosine_rfl_balance', description="Balance for deoxyadenosine transfer to R. flavefaciens")
634
+ trans_deoxyadenosine_rfl_balance[...] = trans_deoxyadenosine_rfl <= v_prm['EX_cpd00438_e0']
635
+
636
+ trans_dephospho_coa_rfl_balance = Equation(container=cowmunity, name='trans_dephospho_coa_rfl_balance', description="Balance for dephospho-CoA transfer to R. flavefaciens")
637
+ trans_dephospho_coa_rfl_balance[...] = trans_dephospho_coa_rfl <= v_mgk['EX_cpd00655_e0']
638
+
639
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_rfl_balance = Equation(container=cowmunity, name='trans_cobinamide_rfl_balance', description="Balance for cobinamide transfer to R. flavefaciens")
640
+ # ****** commented to preserve MGK FLux ********* trans_cobinamide_rfl_balance[...] = trans_cobinamide_rfl <= v_mgk['EX_cpd03422_e0']
641
+
642
+ trans_alanine_rfl_balance = Equation(container=cowmunity, name='trans_alanine_rfl_balance', description="Balance for alanine transfer to R. flavefaciens")
643
+ trans_alanine_rfl_balance[...] = trans_alanine_rfl <= v_mgk['EX_cpd00035_e0']
644
+
645
+ trans_leucine_rfl_balance = Equation(container=cowmunity, name='trans_leucine_rfl_balance', description="Balance for leucine transfer to R. flavefaciens")
646
+ trans_leucine_rfl_balance[...] = trans_leucine_rfl <= v_mgk['EX_cpd00107_e0']
647
+
648
+ trans_glycine_rfl_balance = Equation(container=cowmunity, name='trans_glycine_rfl_balance', description="Balance for glycine transfer to R. flavefaciens")
649
+ trans_glycine_rfl_balance[...] = trans_glycine_rfl <= v_mgk['EX_cpd00033_e0']
650
+
651
+ # ****** commented to preserve RFL FLux ********* trans_proline_rfl_balance = Equation(container=cowmunity, name='trans_proline_rfl_balance', description="Balance for proline transfer to R. flavefaciens")
652
+ # ****** commented to preserve RFL FLux ********* trans_proline_rfl_balance[...] = trans_proline_rfl <= v_mgk['EX_cpd00129_e0']
653
+
654
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_rfl_balance = Equation(container=cowmunity, name='trans_aminoethanol_rfl_balance', description="Balance for aminoethanol transfer to R. flavefaciens")
655
+ # ****** commented to preserve MGK FLux ********* trans_aminoethanol_rfl_balance[...] = trans_aminoethanol_rfl <= v_mgk['EX_cpd00162_e0']
656
+
657
+ # ****** commented to preserve MGK FLux ********* overall_cobinamide_balance = Equation(container=cowmunity, name='overall_cobinamide_balance', description='Balance for cobinamide transfer for both prm and rfl')
658
+ # ****** commented to preserve MGK FLux ********* overall_cobinamide_balance[...] = trans_cobinamide_prm + trans_cobinamide_rfl <= v_mgk['EX_cpd03422_e0']
659
+
660
+ overall_alanine_balance = Equation(container=cowmunity, name='overall_alanine_balance', description='Balance for alanine transfer for both prm and rfl')
661
+ overall_alanine_balance[...] = trans_alanine_prm + trans_alanine_rfl <= v_mgk['EX_cpd00035_e0']
662
+
663
+ overall_leucine_balance = Equation(container=cowmunity, name='overall_leucine_balance', description='Balance for leucine transfer for both prm and rfl')
664
+ overall_leucine_balance[...] = trans_leucine_prm + trans_leucine_rfl <= v_mgk['EX_cpd00107_e0']
665
+
666
+ overall_glycine_balance = Equation(container=cowmunity, name='overall_glycine_balance', description='Balance for glycine transfer for both prm and rfl')
667
+ overall_glycine_balance[...] = trans_glycine_prm + trans_glycine_rfl <= v_mgk['EX_cpd00033_e0']
668
+
669
+ overall_proline_balance = Equation(container=cowmunity, name='overall_proline_balance', description='Balance for proline transfer for both prm and rfl')
670
+ overall_proline_balance[...] = trans_proline_prm + trans_proline_rfl <= v_mgk['EX_cpd00129_e0']
671
+
672
+ # ****** commented to preserve MGK FLux ********* overall_aminoethanol_balance = Equation(container=cowmunity, name='overall_aminoethanol_balance', description='Balance for aminoethanol transfer for both prm and rfl')
673
+ # ****** commented to preserve MGK FLux ********* overall_aminoethanol_balance[...] = trans_aminoethanol_prm + trans_aminoethanol_rfl <= v_mgk['EX_cpd00162_e0']
674
+
675
+ # adding the constraints to each model
676
+
677
+ constraint_CO2_mgk = Equation(container=cowmunity, name="constraint_CO2_mgk", description="constraint for the uptake of CO2 to M. Gottschalkii")
678
+ constraint_CO2_mgk[...] = trans_CO2_mgk == v_mgk['EX_cpd00011_e0']
679
+
680
+ constraint_H2_mgk = Equation(container=cowmunity, name="constraint_H2_mgk", description="constraint for the uptake of H2 to M. Gottschalkii")
681
+ constraint_H2_mgk[...] = trans_H2_mgk == v_mgk['EX_cpd11640_e0']
682
+
683
+ constraint_formate_mgk = Equation(container=cowmunity, name='constraint_formate_mgk', description="constraint for the uptake of formate to M. Gottschalkii")
684
+ constraint_formate_mgk[...] = trans_formate_mgk == v_mgk['EX_cpd00047_e0']
685
+
686
+ constraint_acetate_mgk = Equation(container=cowmunity, name="constraint_acetate_mgk", description="constraint for the uptake of acetate to M. Gottschalkii")
687
+ constraint_acetate_mgk[...] = trans_acetate_mgk == v_mgk['EX_cpd00029_e0']
688
+
689
+ constraint_d_mannose_mgk = Equation(container=cowmunity, name="constraint_dmannose_mgk", description="constraint for the uptake of D-mannose to M. Gottschalkii")
690
+ constraint_d_mannose_mgk[...] = trans_d_mannose_mgk == v_mgk['EX_cpd00138_e0']
691
+
692
+ constraint_d_fructose_mgk = Equation(container=cowmunity, name="constraint_dfructose_mgk", description="constraint for the uptake of D-fructose to M. Gottschalkii")
693
+ constraint_d_fructose_mgk[...] = trans_d_fructose_mgk == v_mgk['EX_cpd00082_e0']
694
+
695
+ constraint_tetrathionate_mgk = Equation(container=cowmunity, name="constraint_tetrathionate_mgk", description="constraint for the uptake of tetrathionate to M. Gottschalkii")
696
+ constraint_tetrathionate_mgk[...] = trans_tetrathionate_mgk == v_mgk['EX_cpd01414_e0']
697
+
698
+ constraint_thiosulfate_mgk = Equation(container=cowmunity, name="constraint_thiosulfate_mgk", description="constraint for the uptake of thiosulfate to M. Gottschalkii")
699
+ constraint_thiosulfate_mgk[...] = trans_thiosulfate_mgk == v_mgk['EX_cpd00268_e0']
700
+
701
+ constraint_cellulose_prm = Equation(container=cowmunity, name='constraint_cellulose_prm', description="constraint for the uptake of cellulose to P. ruminicola")
702
+ constraint_cellulose_prm[...] = trans_cellulose_prm == v_prm['EX_cpd11746_e0']
703
+
704
+ constraint_d_glucose_prm = Equation(container=cowmunity, name='constraint_d_glucose_prm', description="constraint for the uptake of D-Glucose to P. ruminicola")
705
+ constraint_d_glucose_prm[...] = trans_d_glucose_prm == v_prm['EX_cpd00027_e0']
706
+
707
+ constraint_acetate_prm = Equation(container=cowmunity, name='constraint_acetate_prm', description="constraint for the uptake of Acetate to P. ruminicola")
708
+ constraint_acetate_prm[...] = trans_acetate_prm == v_prm['EX_cpd00029_e0']
709
+
710
+ constraint_l_arabinose_prm = Equation(container=cowmunity, name='constraint_l_arabinose_prm', description="constraint for the uptake of L-Arabinose to P. ruminicola")
711
+ constraint_l_arabinose_prm[...] = trans_l_arabinose_prm == v_prm['EX_cpd00224_e0']
712
+
713
+ constraint_biotin_prm = Equation(container=cowmunity, name='constraint_biotin_prm', description="constraint for the uptake of Biotin to P. ruminicola")
714
+ constraint_biotin_prm[...] = trans_biotin_prm == v_prm['EX_cpd00104_e0']
715
+
716
+ # ****** commented to preserve RFL FLux ********* constraint_thiamin_prm = Equation(container=cowmunity, name='constraint_thiamin_prm', description="constraint for the uptake of Thiamin to P. ruminicola")
717
+ # ****** commented to preserve RFL FLux ********* constraint_thiamin_prm[...] = trans_thiamin_prm == v_prm['EX_cpd00305_e0']
718
+
719
+ constraint_octadecenoate_prm = Equation(container=cowmunity, name='constraint_octadecenoate_prm', description="constraint for the uptake of octadecenoate to P. ruminicola")
720
+ constraint_octadecenoate_prm[...] = trans_octadecenoate_prm == v_prm['EX_cpd15269_e0']
721
+
722
+ constraint_maltoheptaose_prm = Equation(container=cowmunity, name='constraint_maltoheptaose_prm', description="constraint for the uptake of Maltoheptaose to P. ruminicola")
723
+ constraint_maltoheptaose_prm[...] = trans_maltoheptaose_prm == v_prm['EX_cpd15494_e0']
724
+
725
+ constraint_nitrite_prm = Equation(container=cowmunity, name='constraint_nitrite_prm', description="constraint for the uptake of Nitrite to P. ruminicola")
726
+ constraint_nitrite_prm[...] = trans_nitrite_prm == v_prm['EX_cpd00075_e0']
727
+
728
+ # ****** commented to preserve MGK FLux ********* constraint_n_acetyl_d_glucosamine_prm = Equation(container=cowmunity, name='constraint_n_acetyl_d_glucosamine_prm', description="constraint for the uptake of N-Acetyl-D-glucosamine to P. ruminicola")
729
+ # ****** commented to preserve MGK FLux ********* constraint_n_acetyl_d_glucosamine_prm[...] = trans_n_acetyl_d_glucosamine_prm == v_prm['EX_cpd00122_e0']
730
+
731
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_prm = Equation(container=cowmunity, name='constraint_aminoethanol_prm', description="constraint for the uptake of Aminoethanol to P. ruminicola")
732
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_prm[...] = trans_aminoethanol_prm == v_prm['EX_cpd00162_e0']
733
+
734
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_prm = Equation(container=cowmunity, name='constraint_cobinamide_prm', description="constraint for the uptake of Cobinamide to P. ruminicola")
735
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_prm[...] = trans_cobinamide_prm == v_prm['EX_cpd03422_e0']
736
+
737
+ constraint_alanine_prm = Equation(container=cowmunity, name='constraint_alanine_prm', description="constraint for the uptake of Alanine to P. ruminicola")
738
+ constraint_alanine_prm[...] = trans_alanine_prm == v_prm['EX_cpd00035_e0']
739
+
740
+ constraint_leucine_prm = Equation(container=cowmunity, name='constraint_leucine_prm', description="constraint for the uptake of Leucine to P. ruminicola")
741
+ constraint_leucine_prm[...] = trans_leucine_prm == v_prm['EX_cpd00107_e0']
742
+
743
+ constraint_glycine_prm = Equation(container=cowmunity, name='constraint_glycine_prm', description="constraint for the uptake of Glycine to P. ruminicola")
744
+ constraint_glycine_prm[...] = trans_glycine_prm == v_prm['EX_cpd00033_e0']
745
+
746
+ constraint_proline_prm = Equation(container=cowmunity, name='constraint_proline_prm', description="constraint for the uptake of Proline to P. ruminicola")
747
+ constraint_proline_prm[...] = trans_proline_prm == v_prm['EX_cpd00129_e0']
748
+
749
+ constraint_d_galacturonate_rfl = Equation(container=cowmunity, name='constraint_d_galacturonate_rfl', description="constraint for the uptake of D-Galacturonate to R. flavefaciens")
750
+ constraint_d_galacturonate_rfl[...] = trans_d_galacturonate_rfl == v_rfl['EX_cpd00280_e0']
751
+
752
+ constraint_deoxyadenosine_rfl = Equation(container=cowmunity, name='constraint_deoxyadenosine_rfl', description="constraint for the uptake of Deoxyadenosine to R. flavefaciens")
753
+ constraint_deoxyadenosine_rfl[...] = trans_deoxyadenosine_rfl == v_rfl['EX_cpd00438_e0']
754
+
755
+ constraint_dephospho_coa_rfl = Equation(container=cowmunity, name='constraint_dephospho_coa_rfl', description="constraint for the uptake of Dephospho-CoA to R. flavefaciens")
756
+ constraint_dephospho_coa_rfl[...] = trans_dephospho_coa_rfl == v_rfl['EX_cpd00655_e0']
757
+
758
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_rfl = Equation(container=cowmunity, name='constraint_cobinamide_rfl', description="constraint for the uptake of Cobinamide to R. flavefaciens")
759
+ # ****** commented to preserve MGK FLux ********* constraint_cobinamide_rfl[...] = trans_cobinamide_rfl == v_rfl['EX_cpd03422_e0']
760
+
761
+ constraint_alanine_rfl = Equation(container=cowmunity, name='constraint_alanine_rfl', description="constraint for the uptake of Alanine to R. flavefaciens")
762
+ constraint_alanine_rfl[...] = trans_alanine_rfl == v_rfl['EX_cpd00035_e0']
763
+
764
+ constraint_leucine_rfl = Equation(container=cowmunity, name='constraint_leucine_rfl', description="constraint for the uptake of Leucine to R. flavefaciens")
765
+ constraint_leucine_rfl[...] = trans_leucine_rfl == v_rfl['EX_cpd00107_e0']
766
+
767
+ constraint_glycine_rfl = Equation(container=cowmunity, name='constraint_glycine_rfl', description="constraint for the uptake of Glycine to R. flavefaciens")
768
+ constraint_glycine_rfl[...] = trans_glycine_rfl == v_rfl['EX_cpd00033_e0']
769
+
770
+ # ****** commented to preserve RFL FLux ********* constraint_proline_rfl = Equation(container=cowmunity, name='constraint_proline_rfl', description="constraint for the uptake of Proline to R. flavefaciens")
771
+ # ****** commented to preserve RFL FLux ********* constraint_proline_rfl[...] = trans_proline_rfl == v_rfl['EX_cpd00129_e0']
772
+
773
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_rfl = Equation(container=cowmunity, name='constraint_aminoethanol_rfl', description="constraint for the uptake of Aminoethanol to R. flavefaciens")
774
+ # ****** commented to preserve MGK FLux ********* constraint_aminoethanol_rfl[...] = trans_aminoethanol_rfl == v_rfl['EX_cpd00162_e0']
775
+
776
+ # mass balance equations
777
+
778
+ mgk_mass_balance = Equation(container=cowmunity, name='mgk_mass_balance', domain=i_mgk, description='overall mass balance for mgk')
779
+ mgk_mass_balance[i_mgk] = Sum(j_mgk, S_mgk[j_mgk, i_mgk] * v_mgk[j_mgk]) == 0
780
+
781
+ prm_mass_balance = Equation(container=cowmunity, name='prm_mass_balance', domain=i_prm, description='overall mass balance for prm')
782
+ prm_mass_balance[i_prm] = Sum(j_prm, S_prm[j_prm, i_prm] * v_prm[j_prm]) == 0
783
+
784
+ rfl_mass_balance = Equation(container=cowmunity, name='rfl_mass_balance', domain=i_rfl, description='overall mass balance for rfl')
785
+ rfl_mass_balance[i_rfl] = Sum(j_rfl, S_rfl[j_rfl, i_rfl] * v_rfl[j_rfl]) == 0
786
+
787
+ # dual problem constraint equations
788
+
789
+ mgk_dual_constraint = Equation(container=cowmunity, name="mgk_dual_constraint", domain=j_mgk, description="Dual constraint for MGK")
790
+ mgk_dual_constraint[j_mgk] = Sum(i_mgk, lambda_mgk[i_mgk] * S_mgk[j_mgk, i_mgk]) + \
791
+ muUB_mgk[j_mgk] - muLB_mgk[j_mgk] == 0
792
+
793
+ prm_dual_constraint = Equation(container=cowmunity, name="prm_dual_constraint", domain=j_prm, description="Dual constraint for PRM")
794
+ prm_dual_constraint[j_prm] = Sum(i_prm, lambda_prm[i_prm] * S_prm[j_prm, i_prm]) + \
795
+ muUB_prm[j_prm] - muLB_prm[j_prm] == 0
796
+
797
+ rfl_dual_constraint = Equation(container=cowmunity, name="rfl_dual_constraint", domain=j_rfl, description="Dual constraint for RFL")
798
+ rfl_dual_constraint[j_rfl] = Sum(i_rfl, lambda_rfl[i_rfl] * S_rfl[j_rfl, i_rfl]) + \
799
+ muUB_rfl[j_rfl] - muLB_rfl[j_rfl] == 0
800
+
801
+ def FixSBMLs():
802
+ print("Fixing SBML files...")
803
+
804
+ def add_reaction(file_name, metabolite_code, metabolite_name, charge=0):
805
+ # Define the SBML document and model
806
+ reader = libsbml.SBMLReader()
807
+ document = reader.readSBML(f'model files/{file_name}')
808
+ model = document.getModel()
809
+
810
+ # Check if the cytosol species already exists
811
+ species_id = f'M_{metabolite_code}_c0'
812
+ if model.getSpecies(species_id) is None:
813
+ species = model.createSpecies()
814
+ species.setId(species_id)
815
+ species.setCompartment('c0')
816
+ species.setName(f'{metabolite_name}[c0]')
817
+ species.setCharge(charge)
818
+ species.setBoundaryCondition(False)
819
+
820
+ cytosol_species = model.getSpecies(species_id)
821
+
822
+ # create the extracellular species
823
+ species = model.createSpecies()
824
+ species.setId(f'M_{metabolite_code}_e0')
825
+ species.setCompartment('e0')
826
+ species.setName(f'{metabolite_name}[e0]')
827
+ species.setCharge(int(cytosol_species.getCharge()))
828
+ species.setBoundaryCondition(False)
829
+
830
+
831
+ # Create the export/import reaction
832
+ reaction = model.createReaction()
833
+ reaction.setId(f'EX_{metabolite_code}_e0')
834
+ reaction.setName(f'{metabolite_name} export/import')
835
+ reaction.setReversible(True) # Set reversibility
836
+
837
+ # Add reactant to the reaction
838
+ reactant1 = reaction.createReactant()
839
+ reactant1.setSpecies(f'M_{metabolite_code}_e0') # Use the species ID created above
840
+ reactant1.setStoichiometry(1)
841
+ reactant1.setConstant(False)
842
+
843
+ # 6. Define the kinetic law (e.g., Mass Action kinetics: k * S1)
844
+ kinetic_law = reaction.createKineticLaw()
845
+ # Create a parameter for the rate constant
846
+ lb = kinetic_law.createParameter()
847
+ lb.setId('LOWER_BOUND')
848
+ lb.setValue(-1000)
849
+ lb.setName('mmol_per_gDW_per_hr')
850
+ ub = kinetic_law.createParameter()
851
+ ub.setId('UPPER_BOUND')
852
+ ub.setValue(1000)
853
+ ub.setName('mmol_per_gDW_per_hr')
854
+ obj = kinetic_law.createParameter()
855
+ obj.setId('OBJECTIVE_COEFFICIENT')
856
+ obj.setValue(0)
857
+ flx = kinetic_law.createParameter()
858
+ flx.setId('FLUX_VALUE')
859
+ flx.setValue(0)
860
+ flx.setName('mmol_per_gDW_per_hr')
861
+
862
+
863
+ # Set the math for the kinetic law using MathML
864
+ # You can use libsbml.parseL3Formula to convert from infix string to MathML AST
865
+ math_ml_string = (
866
+ '<math xmlns="http://www.w3.org/1998/Math/MathML">'
867
+ '<ci> FLUX_VALUE </ci>'
868
+ '</math>'
869
+ )
870
+ math_ast = libsbml.readMathMLFromString(math_ml_string)
871
+ if math_ast:
872
+ kinetic_law.setMath(math_ast)
873
+ else:
874
+ print("Error: Could not parse MathML string.")
875
+
876
+ # create the reaction to convert from extracellular to cytosol
877
+ transport_reaction = model.createReaction()
878
+ transport_reaction.setId(f'R_{metabolite_code}_transport')
879
+ transport_reaction.setName(f'{metabolite_name} transport')
880
+ transport_reaction.setReversible(True) # Set reversibility
881
+
882
+ # Add reactant to the reaction
883
+ cytosol = transport_reaction.createReactant()
884
+ cytosol.setSpecies(f'M_{metabolite_code}_c0') # Use the species ID created above
885
+ cytosol.setStoichiometry(1)
886
+ cytosol.setConstant(False)
887
+
888
+ # Add product to the reaction
889
+ extracellular = transport_reaction.createProduct()
890
+ extracellular.setSpecies(f'M_{metabolite_code}_e0') # Use the species ID created above
891
+ extracellular.setStoichiometry(1)
892
+ extracellular.setConstant(False)
893
+
894
+ # 6. Define the kinetic law (e.g., Mass Action kinetics: k * S1)
895
+ kinetic_law = transport_reaction.createKineticLaw()
896
+ # Create a parameter for the rate constant
897
+ lb = kinetic_law.createParameter()
898
+ lb.setId('LOWER_BOUND')
899
+ lb.setValue(-1000)
900
+ lb.setName('mmol_per_gDW_per_hr')
901
+ ub = kinetic_law.createParameter()
902
+ ub.setId('UPPER_BOUND')
903
+ ub.setValue(1000)
904
+ ub.setName('mmol_per_gDW_per_hr')
905
+ obj = kinetic_law.createParameter()
906
+ obj.setId('OBJECTIVE_COEFFICIENT')
907
+ obj.setValue(0)
908
+ flx = kinetic_law.createParameter()
909
+ flx.setId('FLUX_VALUE')
910
+ flx.setValue(0)
911
+ flx.setName('mmol_per_gDW_per_hr')
912
+
913
+
914
+ # Set the math for the kinetic law using MathML
915
+ # You can use libsbml.parseL3Formula to convert from infix string to MathML AST
916
+ math_ml_string = (
917
+ '<math xmlns="http://www.w3.org/1998/Math/MathML">'
918
+ '<ci> FLUX_VALUE </ci>'
919
+ '</math>'
920
+ )
921
+ math_ast = libsbml.readMathMLFromString(math_ml_string)
922
+ if math_ast:
923
+ kinetic_law.setMath(math_ast)
924
+ else:
925
+ print("Error: Could not parse MathML string.")
926
+
927
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
928
+
929
+
930
+ def add_version(file_name, version):
931
+ # Define the SBML document and model
932
+ reader = libsbml.SBMLReader()
933
+ document = reader.readSBML(f'model files/{file_name}')
934
+ model = document.getModel()
935
+
936
+ # Set the version in the model's annotation
937
+ model.setNotes(version)
938
+
939
+ # Write the updated SBML document back to file
940
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
941
+
942
+ def check_version(file_name, version):
943
+ # Define the SBML document and model
944
+ reader = libsbml.SBMLReader()
945
+ document = reader.readSBML(f'model files/{file_name}')
946
+ model = document.getModel()
947
+
948
+ # Check if the version matches
949
+ notes = model.getNotesString()
950
+ return notes == f'<notes>{version}</notes>'
951
+
952
+ version = 'v2.5'
953
+
954
+ if check_version('M. gottschalkii.xml', version) is False:
955
+ print('M. gottschalkii.xml is not up to date, updating...')
956
+ add_reaction('M. gottschalkii.xml', 'cpd00035', 'L-Alanine')
957
+ add_reaction('M. gottschalkii.xml', 'cpd00107', 'L-Leucine')
958
+ add_reaction('M. gottschalkii.xml', 'cpd00033', 'Glycine')
959
+ add_version('M. gottschalkii.xml', version)
960
+
961
+ if check_version('P. ruminicola.xml', version) is False:
962
+ print('P. ruminicola.xml is not up to date, updating...')
963
+ add_reaction('P. ruminicola.xml', 'cpd00035', 'L-Alanine')
964
+ add_reaction('P. ruminicola.xml', 'cpd00107', 'L-Leucine')
965
+ add_reaction('P. ruminicola.xml', 'cpd00033', 'Glycine')
966
+ add_reaction('P. ruminicola.xml', 'cpd11657', 'Starch')
967
+ add_reaction('P. ruminicola.xml', 'cpd00076', 'Sucrose')
968
+ add_reaction('P. ruminicola.xml', 'cpd00053', 'L-Glutamine')
969
+ add_reaction('P. ruminicola.xml', 'cpd00161', 'L-Threonine')
970
+ add_reaction('P. ruminicola.xml', 'cpd00348', 'D-Galactose 1-phosphate')
971
+ add_reaction('P. ruminicola.xml', 'cpd00084', 'L-Cysteine')
972
+ add_reaction('P. ruminicola.xml', 'cpd00052', 'CTP')
973
+ add_reaction('P. ruminicola.xml', 'cpd00002', 'ATP')
974
+ add_reaction('P. ruminicola.xml', 'cpd00062', 'UTP')
975
+ add_reaction('P. ruminicola.xml', 'cpd00356', 'dCTP')
976
+ add_reaction('P. ruminicola.xml', 'cpd00073', 'Urea')
977
+ add_version('P. ruminicola.xml', version)
978
+
979
+ if check_version('R. flavefaciens.xml', version) is False:
980
+ print('R. flavefaciens.xml is not up to date, updating...')
981
+ add_reaction('R. flavefaciens.xml', 'cpd00035', 'L-Alanine')
982
+ add_reaction('R. flavefaciens.xml', 'cpd00033', 'Glycine')
983
+ add_reaction('R. flavefaciens.xml', 'cpd00053', 'L-Glutamine')
984
+ add_reaction('R. flavefaciens.xml', 'cpd00161', 'L-Threonine')
985
+ add_reaction('R. flavefaciens.xml', 'cpd00348', 'D-Galactose 1-phosphate')
986
+ add_reaction('R. flavefaciens.xml', 'cpd00084', 'L-Cysteine')
987
+ add_reaction('R. flavefaciens.xml', 'cpd00052', 'CTP')
988
+ add_reaction('R. flavefaciens.xml', 'cpd00002', 'ATP')
989
+ add_reaction('R. flavefaciens.xml', 'cpd00062', 'UTP')
990
+ add_reaction('R. flavefaciens.xml', 'cpd00356', 'dCTP')
991
+ add_reaction('R. flavefaciens.xml', 'cpd00073', 'Urea')
992
+ add_version('R. flavefaciens.xml', version)
993
+
994
+
995
+ def remove_duplicate_species_and_reactions(file_name):
996
+ # Define the SBML document and model
997
+ reader = libsbml.SBMLReader()
998
+ document = reader.readSBML(f'model files/{file_name}')
999
+ model = document.getModel()
1000
+
1001
+ # --- Remove Duplicate Species ---
1002
+ seen_species = []
1003
+ species_to_remove = []
1004
+
1005
+ for i in range(model.getNumSpecies()):
1006
+ species = model.getSpecies(i)
1007
+ id = species.getId()
1008
+
1009
+ if id in seen_species:
1010
+ species_to_remove.append(species.getId())
1011
+ else:
1012
+ seen_species.append(species.getId())
1013
+
1014
+ # Remove species (iterate in reverse to avoid index issues)
1015
+ for item in reversed(species_to_remove):
1016
+ model.removeSpecies(item)
1017
+
1018
+ # --- Remove Duplicate Reactions ---
1019
+ seen_reactions = []
1020
+ reactions_to_remove = []
1021
+
1022
+ for i in range(model.getNumReactions()):
1023
+ reaction = model.getReaction(i)
1024
+ id = reaction.getId()
1025
+
1026
+ if id in seen_reactions:
1027
+ reactions_to_remove.append(reaction.getId())
1028
+ else:
1029
+ seen_reactions.append(reaction.getId())
1030
+
1031
+ # Remove reactions
1032
+ for reaction_id in reversed(reactions_to_remove):
1033
+ model.removeReaction(reaction_id)
1034
+
1035
+ # Save the modified model (optional)
1036
+ writer = libsbml.SBMLWriter()
1037
+ libsbml.writeSBMLToFile(document, f'model files/{file_name}')
1038
+
1039
+ remove_duplicate_species_and_reactions('M. gottschalkii.xml')
1040
+ remove_duplicate_species_and_reactions('P. ruminicola.xml')
1041
+ remove_duplicate_species_and_reactions('R. flavefaciens.xml')
1042
+
1043
+ # removing a duplicate product that slipped through the cracks
1044
+
1045
+ reader = libsbml.SBMLReader()
1046
+ document = reader.readSBML(f'model files/R. flavefaciens.xml')
1047
+ model = document.getModel()
1048
+
1049
+ reaction = model.getReaction('R_R01896_c0')
1050
+ reaction.removeProduct('M_cpd00067_c0')
1051
+
1052
+ writer = libsbml.SBMLWriter()
1053
+ libsbml.writeSBMLToFile(document, f'model files/R. flavefaciens.xml')
1054
+
1055
+ def solve(solver_name='IPOPT'):
1056
+
1057
+
1058
+ global model
1059
+ # Create model
1060
+ model = Model(container=cowmunity, name="COWMUNITY", equations=cowmunity.getEquations(),
1061
+ problem="NLP", sense=Sense.MAX, objective=objective_variable)
1062
+
1063
+ # Set solver options
1064
+ options = Options(nlp=solver_name, equation_listing_limit=10, variable_listing_limit=10, time_limit=20, threads=0)
1065
+
1066
+ # Solve the model
1067
+ print(f"Solving with {solver_name}...")
1068
+ model.solve(options=options)
1069
+
1070
+ # check solution status
1071
+ status = model.solve_status
1072
+ if status == SolveStatus.NormalCompletion:
1073
+ print("Optimal solution found!")
1074
+ else:
1075
+ print(f"Solver terminated with status: {status}")
1076
+
1077
+ def extract_results():
1078
+ """Extract and store results"""
1079
+ global results
1080
+ results = {
1081
+ 'objective_value': objective_variable.records['level'].iloc[0],
1082
+ 'mgk_biomass': v_mgk.records.loc[v_mgk.records['j_mgk'] == 'R_biomass0', 'level'].iloc[0],
1083
+ 'prm_biomass': v_prm.records.loc[v_prm.records['j_prm'] == 'R_biomass0', 'level'].iloc[0],
1084
+ 'rfl_biomass': v_rfl.records.loc[v_rfl.records['j_rfl'] == 'R_biomass0', 'level'].iloc[0],
1085
+ 'methane_flux' : v_mgk.records.loc[v_mgk.records['j_mgk'] == 'EX_cpd01024_e0', 'level'].iloc[0]
1086
+ }
1087
+
1088
+ def save_results(treatment, methane = 'variable'):
1089
+ """Save results to a CSV file"""
1090
+ os.makedirs(f'results/{methane}_methane_{treatment}_treatment', exist_ok=True)
1091
+ v_mgk.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/mgk_records.csv', index=False)
1092
+ v_prm.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/prm_records.csv', index=False)
1093
+ v_rfl.records.to_csv(f'results/{methane}_methane_{treatment}_treatment/rfl_records.csv', index=False)
1094
+ print(f"Results saved to 'results/{methane}_methane_{treatment}_treatment'.")
1095
+
1096
+ def print_results():
1097
+ """Print results in a formatted way"""
1098
+ print()
1099
+ print("********************* RESULTS *********************")
1100
+ print(f"Total Biomass = {results['objective_value']:5f}")
1101
+ print()
1102
+
1103
+ print("********************* MGK *************************")
1104
+ print(f"MGK Biomass Flux = {results['mgk_biomass']:5f}")
1105
+ print(f"Methane Emission Flux = {results['methane_flux']:5f}")
1106
+ print()
1107
+
1108
+ print("********************* PRM *************************")
1109
+ print(f"PRM Biomass Flux = {results['prm_biomass']:5f}")
1110
+ print()
1111
+
1112
+ print("********************* RFL *************************")
1113
+ print(f"RFL Biomass Flux = {results['rfl_biomass']:5f}")
1114
+ print()
1115
+
1116
+ def bug_huntin():
1117
+ # This function is for debugging purposes, to check the model and variable records
1118
+
1119
+ def print_reaction(reaction):
1120
+ def check_reaction(reaction, file_name):
1121
+ reader = libsbml.SBMLReader()
1122
+ document = reader.readSBML(f'model files/{file_name}')
1123
+ model = document.getModel()
1124
+
1125
+ reaction = model.getReaction(reaction)
1126
+
1127
+ if reaction is None:
1128
+ return None
1129
+ else:
1130
+ return reaction.getId()
1131
+
1132
+ if check_reaction(reaction, 'M. gottschalkii.xml') is None:
1133
+ print(f'Reaction {reaction} not found in M. gottschalkii model.')
1134
+ else:
1135
+ mgk_flux = v_mgk.records.loc[v_mgk.records['j_mgk'] == reaction.strip(), 'level'].iloc[0]
1136
+ print(f'MGK {reaction}: {mgk_flux}')
1137
+ if check_reaction(reaction, 'P. ruminicola.xml') is None:
1138
+ print(f'Reaction {reaction} not found in P. ruminicola model.')
1139
+ else:
1140
+ prm_flux = v_prm.records.loc[v_prm.records['j_prm'] == reaction.strip(), 'level'].iloc[0]
1141
+ print(f'PRM {reaction}: {prm_flux}')
1142
+ if check_reaction(reaction, 'R. flavefaciens.xml') is None:
1143
+ print(f'Reaction {reaction} not found in R. flavefaciens model.')
1144
+ else:
1145
+ rfl_flux = v_rfl.records.loc[v_rfl.records['j_rfl'] == reaction.strip(), 'level'].iloc[0]
1146
+ print(f'RFL {reaction}: {rfl_flux}')
1147
+
1148
+
1149
+ print_reaction('EX_cpd01188_e0')
1150
+
1151
+
1152
+
1153
+ def flux_investigation(file_name, v_set, j_set, i_set, metabolite):
1154
+
1155
+ reader = libsbml.SBMLReader()
1156
+ document = reader.readSBML(f'model files/{file_name}')
1157
+ model = document.getModel()
1158
+
1159
+ relevant_reactions = []
1160
+ for i in range(model.getNumReactions()):
1161
+ reaction = model.getReaction(i)
1162
+ product = reaction.getProduct(metabolite)
1163
+ if product is None:
1164
+ continue
1165
+ else:
1166
+ relevant_reactions.append(reaction.id)
1167
+
1168
+ # species = model.getSpecies(metabolite)
1169
+ name = i_set.records.loc[i_set.records['index'] == metabolite, 'element_text'].iloc[0]
1170
+ print(file_name)
1171
+ print(f'\n*** {name} FLUXES ***')
1172
+ for item in relevant_reactions:
1173
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1174
+ print(f'{item} : {flux}')
1175
+
1176
+ print()
1177
+
1178
+ metabolite = 'M_cpd00033_c0'
1179
+ mgk = ('M. gottschalkii.xml', v_mgk, 'j_mgk', i_mgk)
1180
+ prm = ('P. ruminicola.xml', v_prm, 'j_prm', i_prm)
1181
+ rfl = ('R. flavefaciens.xml', v_rfl, 'j_rfl', i_rfl)
1182
+
1183
+ # flux_investigation(*mgk, metabolite)
1184
+
1185
+ def biomass_fluxes(file_name, v_set, j_set, i_set):
1186
+ list_to_investigate = []
1187
+ print()
1188
+ print('*'*10, file_name, '*'*10)
1189
+
1190
+ reader = libsbml.SBMLReader()
1191
+ document = reader.readSBML(f'model files/{file_name}')
1192
+ model = document.getModel()
1193
+
1194
+ biomass_reactants = []
1195
+ biomass_reaction = model.getReaction('R_biomass0')
1196
+ for i in range(biomass_reaction.getNumReactants()):
1197
+ reactant = biomass_reaction.getReactant(i)
1198
+ biomass_reactants.append(reactant.getSpecies())
1199
+
1200
+ precursor_reactions = {}
1201
+ for item in biomass_reactants:
1202
+ relevant_reactions = []
1203
+ for i in range(model.getNumReactions()):
1204
+ reaction = model.getReaction(i)
1205
+ product = reaction.getProduct(f'{item}')
1206
+ if product is None:
1207
+ continue
1208
+ else:
1209
+ relevant_reactions.append(reaction.id)
1210
+ new_entry = {item : relevant_reactions}
1211
+ precursor_reactions.update(new_entry)
1212
+
1213
+ for key in precursor_reactions:
1214
+ flux_set = []
1215
+ relevant_reactions = precursor_reactions[key]
1216
+ species = biomass_reaction.getReactant(f'{key}').getSpecies()
1217
+ name = i_set.records.loc[i_set.records['index'] == species, 'element_text'].iloc[0]
1218
+ print(f'\n{name} FLUXES')
1219
+ for item in relevant_reactions:
1220
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1221
+ print(f'{item} : {flux}')
1222
+ flux_set.append(flux)
1223
+ print(f'Total flux for {name} = {sum(flux_set)}')
1224
+ if sum(flux_set) <= 1e-5:
1225
+ list_to_investigate.append(name)
1226
+
1227
+ print(f'\nBiomass precursors with zero or negative production:')
1228
+ for item in list_to_investigate:
1229
+ print(item)
1230
+
1231
+ print(model.getNumReactions(), 'reactions in the model')
1232
+ print(model.getNumSpecies(), 'species in the model')
1233
+
1234
+ # biomass_fluxes(*mgk)
1235
+ # biomass_fluxes(*prm)
1236
+ # biomass_fluxes(*rfl)
1237
+
1238
+ def zero_flux_reactions(file_name, v_set, j_set, i_set):
1239
+ reader = libsbml.SBMLReader()
1240
+ document = reader.readSBML(f'model files/{file_name}')
1241
+ model = document.getModel()
1242
+
1243
+ """Return a list of reaction IDs in v_set where the flux is exactly zero."""
1244
+ zero_flux_df = v_set.records.loc[v_set.records['level'] == 0]
1245
+ zero_flux_list = zero_flux_df[j_set].tolist()
1246
+
1247
+ print(f'\n*** {file_name} REACTIONS WITH ZERO FLUX ***')
1248
+ for item in zero_flux_list:
1249
+ precursor_reactions = {}
1250
+ needy_dict = {}
1251
+ unmade_products = []
1252
+ zero_reaction = model.getReaction(item)
1253
+ for i in range(zero_reaction.getNumProducts()):
1254
+ product = zero_reaction.getProduct(i)
1255
+ unmade_products.append(product.getSpecies())
1256
+ print(f'\n{item}')
1257
+ for item in unmade_products:
1258
+ relevant_reactions = []
1259
+ needy_reactions = []
1260
+ for i in range(model.getNumReactions()):
1261
+ reaction = model.getReaction(i)
1262
+ product = reaction.getProduct(f'{item}')
1263
+ if product is None:
1264
+ continue
1265
+ else:
1266
+ relevant_reactions.append(reaction.id)
1267
+ new_entry = {item : relevant_reactions}
1268
+ precursor_reactions.update(new_entry)
1269
+
1270
+ for i in range(model.getNumReactions()):
1271
+ reaction = model.getReaction(i)
1272
+ reactant = reaction.getReactant(f'{item}')
1273
+ if reactant is None:
1274
+ continue
1275
+ else:
1276
+ needy_reactions.append(reaction.id)
1277
+ new_entry = {item : relevant_reactions}
1278
+ precursor_reactions.update(new_entry)
1279
+ new_entry = {item : needy_reactions}
1280
+ needy_dict.update(new_entry)
1281
+
1282
+ for key in precursor_reactions:
1283
+ relevant_reactions = precursor_reactions[key]
1284
+ product = zero_reaction.getProduct(f'{key}')
1285
+ species = product.getSpecies()
1286
+ name = i_set.records.loc[i_set.records['index'] == species, 'element_text'].iloc[0]
1287
+ print(f'Reactions that produce {name} ({species}):')
1288
+ for item in relevant_reactions:
1289
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1290
+ print(f'{item} : {flux}')
1291
+ print(f'Reactions that require {name} ({species}):')
1292
+ for item in needy_reactions:
1293
+ flux = v_set.records.loc[v_set.records[j_set] == f'{item.strip()}', 'level'].iloc[0]
1294
+ print(f'{item} : {flux}')
1295
+
1296
+
1297
+
1298
+ # zero_flux_reactions(*mgk)
1299
+ # zero_flux_reactions(*prm)
1300
+ # zero_flux_reactions(*rfl)
1301
+
1302
+
1303
+
1304
+
1305
+
1306
+
1307
+
README.md ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # cowmunity1.0
2
+ # Cowmunity Model: Community Metabolic Modeling with Molecular Docking Integration
3
+
4
+ ## Overview
5
+
6
+ The **Cowmunity Model** is a community metabolic model that simulates a three-species rumen microbial community using the OptCom (Optimal Community) bilevel optimization framework. The model integrates molecular docking predictions to mechanistically predict how small molecule treatments affect methane production in the rumen microbiome.
7
+
8
+ ### What We've Done
9
+
10
+ 1. **Community Metabolic Modeling**: Built a bilevel optimization model that simulates three rumen bacteria:
11
+ - **Methanobrevibacter gottschalkii (MGK)**: Methanogen that produces methane
12
+ - **Prevotella ruminicola (PRM)**: Fibrolytic bacterium
13
+ - **Ruminococcus flavefaciens (RFL)**: Fibrolytic bacterium
14
+
15
+ 2. **Molecular Docking Integration**: Integrated structure-based molecular docking predictions directly into the metabolic model by:
16
+ - Converting binding affinities (Kd) to inhibition factors
17
+ - Accounting for drug-enzyme binding saturation
18
+ - Applying relaxation factors to bridge in silico predictions and in vivo reality
19
+ - Mapping docking results to metabolic reactions
20
+
21
+ 3. **Combined Approach**: Simultaneously applies:
22
+ - **Direct enzyme effects** from docking (structure-based predictions)
23
+ - **Indirect community effects** from literature (community interactions, substrate availability)
24
+
25
+ 4. **Metabolite Exchange**: Models inter-species metabolite sharing (H₂, CO₂, formate, amino acids, etc.) to create a true community model rather than three separate models.
26
+
27
+ ## Installation
28
+
29
+ ### Prerequisites
30
+
31
+ - Python 3.7 or higher
32
+ - GAMSpy Academic License (free for academic use)
33
+
34
+ ### Step 1: Install Python Packages
35
+
36
+ ```bash
37
+ pip install pandas python-libsbml gamspy
38
+ ```
39
+
40
+ ### Step 2: Register for GAMSpy License
41
+
42
+ 1. Register for a free academic license at: https://academic.gams.com/
43
+ 2. Install your license:
44
+
45
+ ```bash
46
+ gamspy install license <your-gamspy-license>
47
+ ```
48
+
49
+ ## Running the Model
50
+
51
+ ### Basic Usage
52
+
53
+ 1. Navigate to the project directory:
54
+
55
+ ```bash
56
+ cd CowmunityModel
57
+ ```
58
+
59
+ 2. Run the main script:
60
+
61
+ ```bash
62
+ python main.py
63
+ ```
64
+
65
+ 3. Select a treatment option when prompted:
66
+ - `0`: No treatment (baseline)
67
+ - `1`: Imidazole
68
+ - `2`: L-Carnitine
69
+ - `3`: Methyl Jasmonate
70
+ - `4`: Propylpyrazine
71
+
72
+ ### What Happens When You Run
73
+
74
+ The model will:
75
+ 1. Load and process the three SBML metabolic models
76
+ 2. Set up community exchange constraints
77
+ 3. Apply treatment-specific constraints (docking-based + literature-based)
78
+ 4. Solve the bilevel optimization problem
79
+ 5. Save results to `results/` directory
80
+ 6. Display key outputs (biomass, methane flux)
81
+
82
+ ### Output
83
+
84
+ Results are saved in `results/variable_methane_{treatment}_treatment/`:
85
+ - `mgk_records.csv` - All reaction fluxes for M. Gottschalkii
86
+ - `prm_records.csv` - All reaction fluxes for P. ruminicola
87
+ - `rfl_records.csv` - All reaction fluxes for R. flavefaciens
88
+
89
+ ## Project Structure
90
+
91
+ ```
92
+ CowmunityModel/
93
+ ├── main.py # Main entry point
94
+ ├── Cowmunity.py # Core model implementation
95
+ ├── cow.txt # ASCII art (optional)
96
+ ├── model files/ # SBML metabolic models
97
+ │ ├── M. gottschalkii.xml
98
+ │ ├── P. ruminicola.xml
99
+ │ └── R. flavefaciens.xml
100
+ ├── docking_integration/ # Docking integration module
101
+ │ ├── apply_docking_constraints.py
102
+ │ ├── parse_docking_results.py
103
+ │ └── enzyme_reaction_mapper.py
104
+ └── docking_data/ # Docking results
105
+ └── cleaned_docking_results.csv
106
+ ```
107
+
108
+ ## Key Features
109
+
110
+ - **Bilevel Optimization**: Outer problem maximizes community biomass; inner problems optimize individual species
111
+ - **Structure-Based Predictions**: Uses molecular docking data to predict enzyme inhibition
112
+ - **Community Interactions**: Models metabolite exchange between species
113
+ - **Combined Constraints**: Integrates docking predictions with literature-based effects
114
+ - **Flexible Treatments**: Test multiple small molecule treatments
115
+
116
+ ## Dependencies
117
+
118
+ - `pandas` - Data manipulation
119
+ - `python-libsbml` - SBML model parsing
120
+ - `gamspy` - Optimization framework (requires academic license)
121
+
122
+ ## Model Units
123
+
124
+ - **Fluxes**: mmol/gDCW·hr (millimoles per gram dry cell weight per hour)
125
+ - **Biomass**: gDCW/gDCW·hr (grams dry cell weight per gram dry cell weight per hour)
126
+ - **Methane**: mmol/gDCW·hr (can be converted to ml/gDCW·hr)
127
+
128
+ ## Citation
129
+
130
+ If you use this model, please cite us:
131
+
132
+ -----
133
+
134
+ ## Authors
135
+
136
+ ----
137
+
138
+ ## Troubleshooting
139
+
140
+ ### GAMSpy License Issues
141
+ - Ensure you have registered for an academic license
142
+ - Check that your license is properly installed: `gamspy license status`
143
+
144
+ ### Missing Files
145
+ - Ensure all SBML model files are in the `model files/` directory
146
+ - Check that `docking_data/cleaned_docking_results.csv` exists for docking-based treatments
147
+
148
+ ### Solver Issues
149
+ - Default solver is IPOPT. If issues occur, ensure IPOPT is properly installed with GAMSpy
150
+ - Model solve time is limited to 20 seconds by default (can be modified in `Cowmunity.py`)
151
+
152
+ ## Contact
153
+
154
+ For questions or issues, please contact zargar@iastate.edu
cow.txt ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ____ _____ ____ __ _ _ _ _ ___ _______ __
2
+ / ___/ _ \ \ / / \/ | | | | \ | |_ _|_ _\ \ / /
3
+ | | | | | \ \ /\ / /| |\/| | | | | \| || | | | \ V /
4
+ | |__| |_| |\ V V / | | | | |_| | |\ || | | | | |
5
+ \____\___/ \_/\_/ |_| |_|\___/|_| \_|___| |_| |_|
6
+ ::::...:*
7
+ -#%#*++**%%%
8
+ :--- +*%%%%%#%%%@@@#
9
+ ::::.:::::: ::#*+#%@@@%%%%@@@@# :::-
10
+ ::=+*-:::--:::-*+*%%@@%@@%%%%@@@%:::.......:.:
11
+ ::::=*=::::----+:.:*%@@%%%%%%%%@@*....::..:::::
12
+ :::-*%*---:.:+::::-@@@@%%%%#%@+=:...:+-:...:
13
+ -::+#%+-:.-=:-.::*@%@@%%%%%%:-.:.:+*+:.:
14
+ ::+*::::==::-:.=%%%%%%@@@==: ===---
15
+ .::**.::.**:..:::+**%%%@@#=::
16
+ ::=*:.::.#*:....::*+*%%@@%-:
17
+ .:-*+..:..##*=....:#+#%%%@@=:
18
+ :=**-.::..*##*:...+**#%%@@@%:
19
+ =***..:...+###+.=****#%%%@@@%
20
+ +*-.::...+*###*****#%@@@%%@@#
21
+ *-:::...=*+********-+*+*##***
22
+ =::......**+++***+#-.:+**##+*%
23
+ .......+--++++++*+**=--++=+*#@ moo
24
+ ......=*++=+=*#+==+=-:::::-*#
25
+ ......=*+==+ ===--=--
26
+ .....*+#*#
27
+ .:.:#@%
28
+ ..:#@
29
+ .=*
30
+
docking_data/cleaned_docking_results.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ molecule_name,protein_name,enzyme_id,reaction_id,binding_affinity_um,binding_energy_kcal_mol,inhibition_type,confidence_score,species,binding_site
2
+ Imidazole,Methyl-coenzyme M reductase (Mcr),EC:1.2.7.12,R_rxn03126_c0,0.006162578723726243,-3.015,competitive inhibitor,1.0,MGK,active site
3
+ L-carnitine,Methyl-coenzyme M reductase (Mcr),EC:1.2.7.12,R_rxn03126_c0,0.00018251130377811432,-5.1,competitive inhibitor,1.0,MGK,active site
4
+ Methyl jasmonate,Methyl-coenzyme M reductase (Mcr),EC:1.2.7.12,R_rxn03126_c0,0.00011300428797205392,-5.384,competitive inhibitor,1.0,MGK,active site
5
+ Propylpyrazine,Methyl-coenzyme M reductase (Mcr),EC:1.2.7.12,R_rxn03126_c0,6.463165818627002e-05,-5.715,competitive inhibitor,1.0,MGK,active site
docking_data/key_protein_targets_for_docking.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ priority,species,protein_name,enzyme_name,ec_number,reaction_id,reaction_name,notes
2
+ CRITICAL,MGK,Coenzyme B:coenzyme M:methanophenazine oxidoreductase,Coenzyme B:coenzyme M:methanophenazine oxidoreductase,,R_rxn03126_c0,Coenzyme B:coenzyme M:methanophenazine oxidoreductase_c0,METHANE PRODUCTION - Final step in methanogenesis (Mcr enzyme)
3
+ CRITICAL,MGK,biomass,biomass,,R_biomass0,biomass,BIOMASS PRODUCTION - Cell growth
4
+ CRITICAL,PRM,biomass,biomass,,R_biomass0,biomass,BIOMASS PRODUCTION - Cell growth
5
+ CRITICAL,RFL,biomass,biomass,,R_biomass0,biomass,BIOMASS PRODUCTION - Cell growth
docking_data/protein_targets_for_docking.xlsx ADDED
Binary file (14.8 kB). View file
 
docking_data/protein_targets_for_docking_FINAL.csv ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ priority,species,protein_name,alternative_names,reaction_id,reaction_name,ec_number,uniprot_keywords,notes,gene_ids
2
+ CRITICAL,MGK,Methyl-coenzyme M reductase (Mcr),"['McrA', 'McrB', 'McrG', 'Methyl-coenzyme M reductase alpha/beta/gamma subunits']",R_rxn03126_c0,Coenzyme B:coenzyme M:methanophenazine oxidoreductase,EC:1.2.7.12,"['methyl-coenzyme M reductase', 'Mcr']",THE MOST CRITICAL TARGET - This is the enzyme that directly produces methane. Final step in methanogenesis pathway. Inhibiting this will directly reduce methane production.,"['fig|190974.3.peg.158', 'fig|190974.3.peg.18', 'fig|190974.3.peg.17', 'fig|190974.3.peg.157', 'fig|190974.3.peg.19', 'fig|190974.3.peg.1668']"
3
+ CRITICAL,MGK,Methyl-coenzyme M reductase (Mcr) - Alternative reaction,"['McrA', 'McrB', 'McrG']",R_rxn03127_c0,2-(Methylthio)ethanesulfonate:N-(7-thioheptanoyl)-3-O-phosphothreonine S-(2-sulfoethyl)thiotransferase,EC:2.8.4.1,"['methyl-coenzyme M reductase', 'Mcr']",Alternative methane production reaction - also critical,"['fig|190974.3.peg.1570', 'fig|190974.3.peg.1166', 'fig|190974.3.peg.1167', 'fig|190974.3.peg.1571', 'fig|190974.3.peg.1567', 'fig|190974.3.peg.1164']"
4
+ HIGH,MGK,Formylmethanofuran dehydrogenase,"['Fmd', 'Fwd']",R_rxn11938_c0,Formylmethanofuran:(NAD) oxidoreductase,EC:1.2.1.109,['formylmethanofuran dehydrogenase'],First step in methanogenesis - converts CO2 to formylmethanofuran,
5
+ HIGH,MGK,Formylmethanofuran:tetrahydromethanopterin formyltransferase,['Ftr'],R_rxn02431_c0,"Formylmethanofuran:5,6,7,8-tetrahydromethanopterin 5-formyltransferase",EC:2.3.1.101,"['formyltransferase', 'methanopterin']",Transfers formyl group in methanogenesis pathway,
6
+ HIGH,MGK,Methenyltetrahydromethanopterin cyclohydrolase,['Mch'],R_rxn02480_c0,"5,10-Methenyltetrahydromethanopterin 10-hydrolase (decyclizing)",EC:3.5.4.27,"['methenyltetrahydromethanopterin', 'cyclohydrolase']",Converts methenyl to methylene form in methanogenesis,
7
+ HIGH,MGK,Methylenetetrahydromethanopterin dehydrogenase,['Mtd'],R_rxn03079_c0,"5,10-Methylenetetrahydromethanopterin:coenzyme-F420 oxidoreductase",EC:1.5.98.1,"['methylenetetrahydromethanopterin', 'dehydrogenase', 'F420']",Oxidizes methylenetetrahydromethanopterin using F420,
8
+ HIGH,MGK,Methylenetetrahydromethanopterin reductase,['Mer'],R_rxn03085_c0,"5,10-Methylenetetrahydromethanopterin:coenzyme-F420 oxidoreductase (alternative)",EC:1.5.98.2,"['methylenetetrahydromethanopterin', 'reductase', 'F420']",Reduces methylenetetrahydromethanopterin using F420,
9
+ HIGH,MGK,Tetrahydromethanopterin S-methyltransferase,['Mtr'],R_rxn03020_c0,"5-Methyl-5,6,7,8-tetrahydromethanopterin:2-mercaptoethanesulfonate 2-methyltransferase",EC:2.1.1.86,"['tetrahydromethanopterin', 'methyltransferase', 'coenzyme M']",Transfers methyl group to coenzyme M - critical step before methane production,
10
+ HIGH,MGK,Hydrogenase,"['H2ase', 'Hydrogen dehydrogenase']",EX_cpd11640_e0,Hydrogen exchange,EC:1.12.1.2 or EC:1.12.7.2,"['hydrogenase', 'H2']",Uptakes H2 - primary substrate for methanogenesis,
11
+ HIGH,PRM,Hydrogenase,"['H2ase', 'Hydrogen dehydrogenase']",EX_cpd11640_e0,Hydrogen exchange,EC:1.12.1.2 or EC:1.12.7.2,"['hydrogenase', 'H2']",Produces H2 - feeds methanogen,
12
+ HIGH,RFL,Hydrogenase,"['H2ase', 'Hydrogen dehydrogenase']",EX_cpd11640_e0,Hydrogen exchange,EC:1.12.1.2 or EC:1.12.7.2,"['hydrogenase', 'H2']",Produces H2 - feeds methanogen,
13
+ HIGH,MGK,Formate dehydrogenase,['Fdh'],EX_cpd00047_e0,Formate exchange,EC:1.2.1.2 or EC:1.2.1.43,['formate dehydrogenase'],Uptakes formate - alternative substrate for methanogenesis,
14
+ HIGH,PRM,Formate dehydrogenase,['Fdh'],EX_cpd00047_e0,Formate exchange,EC:1.2.1.2 or EC:1.2.1.43,['formate dehydrogenase'],Produces formate - feeds methanogen,
15
+ HIGH,RFL,Formate dehydrogenase,['Fdh'],EX_cpd00047_e0,Formate exchange,EC:1.2.1.2 or EC:1.2.1.43,['formate dehydrogenase'],Produces formate - feeds methanogen,
16
+ MEDIUM,MGK,Acetate kinase,['Ack'],EX_cpd00029_e0,Acetate exchange,EC:2.7.2.1,['acetate kinase'],Acetate metabolism - affects carbon flow,
17
+ MEDIUM,PRM,Acetate kinase,['Ack'],EX_cpd00029_e0,Acetate exchange,EC:2.7.2.1,['acetate kinase'],Acetate production - affects community carbon flow,
18
+ MEDIUM,RFL,Acetate kinase,['Ack'],EX_cpd00029_e0,Acetate exchange,EC:2.7.2.1,['acetate kinase'],Acetate production - affects community carbon flow,
19
+ MEDIUM,PRM,Cellulase / Cellulose degradation enzymes,"['Endoglucanase', 'Exoglucanase', 'Beta-glucosidase']",EX_cpd11746_e0,Cellulose exchange,"EC:3.2.1.4, EC:3.2.1.91, EC:3.2.1.21","['cellulase', 'cellulose', 'beta-glucosidase']",Cellulose degradation - primary carbon source,
20
+ MEDIUM,RFL,Cellulase / Cellulose degradation enzymes,"['Endoglucanase', 'Exoglucanase', 'Beta-glucosidase']",EX_cpd11746_e0,Cellulose exchange,"EC:3.2.1.4, EC:3.2.1.91, EC:3.2.1.21","['cellulase', 'cellulose', 'beta-glucosidase']",Cellulose degradation - primary carbon source,
21
+ MEDIUM,PRM,Glucose-6-phosphate dehydrogenase,"['G6PD', 'Zwf']",EX_cpd00027_e0,D-glucose exchange,EC:1.1.1.49,"['glucose-6-phosphate dehydrogenase', 'pentose phosphate']",Glucose metabolism - central carbon pathway,
22
+ MEDIUM,RFL,Glucose-6-phosphate dehydrogenase,"['G6PD', 'Zwf']",EX_cpd00027_e0,D-glucose exchange,EC:1.1.1.49,"['glucose-6-phosphate dehydrogenase', 'pentose phosphate']",Glucose metabolism - central carbon pathway,
23
+ MEDIUM,MGK,Lanosterol synthase,['LSS'],EX_cpd01188_e0,Lanosterol exchange,EC:5.4.99.7,"['lanosterol synthase', 'sterol']",Target for L-carnitine treatment - affects cholesterol/sterol metabolism,
24
+ MEDIUM,RFL,Lanosterol synthase,['LSS'],EX_cpd01188_e0,Lanosterol exchange,EC:5.4.99.7,"['lanosterol synthase', 'sterol']",Target for L-carnitine treatment,
25
+ MEDIUM,MGK,Proline synthase / Delta-1-pyrroline-5-carboxylate synthase,['P5CS'],EX_cpd00129_e0,Proline exchange,EC:2.7.2.11 or EC:1.5.1.2,"['proline synthase', 'pyrroline', 'proline']",Target for Methyl jasmonate treatment,
26
+ MEDIUM,PRM,Proline synthase / Delta-1-pyrroline-5-carboxylate synthase,['P5CS'],EX_cpd00129_e0,Proline exchange,EC:2.7.2.11 or EC:1.5.1.2,"['proline synthase', 'pyrroline', 'proline']",Target for Methyl jasmonate treatment,
27
+ MEDIUM,MGK,Phosphopantothenate synthase,['Ppcs'],R_rxn12512_c0,Phosphopantothenate synthesis,EC:6.3.2.5,"['phosphopantothenate', 'coenzyme A']",Target for Propylpyrazine treatment - CoA biosynthesis,
28
+ MEDIUM,PRM,Phosphopantothenate synthase,['Ppcs'],R_rxn12512_c0,Phosphopantothenate synthesis,EC:6.3.2.5,"['phosphopantothenate', 'coenzyme A']",Target for Propylpyrazine treatment,
29
+ MEDIUM,RFL,Phosphopantothenate synthase,['Ppcs'],R_rxn12512_c0,Phosphopantothenate synthesis,EC:6.3.2.5,"['phosphopantothenate', 'coenzyme A']",Target for Propylpyrazine treatment,
docking_integration/__init__.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Docking Integration Module for Cowmunity Model
3
+
4
+ This module integrates molecular docking data into metabolic flux constraints.
5
+ """
6
+
7
+ from .parse_docking_results import (
8
+ parse_docking_csv,
9
+ calculate_inhibition_factor,
10
+ create_constraint_dict,
11
+ group_by_reaction
12
+ )
13
+
14
+ from .apply_docking_constraints import (
15
+ apply_docking_treatment,
16
+ apply_docking_treatment_integrated
17
+ )
18
+
19
+ from .enzyme_reaction_mapper import (
20
+ extract_enzyme_annotations,
21
+ create_enzyme_reaction_map,
22
+ map_docking_to_reactions
23
+ )
24
+
25
+ __all__ = [
26
+ 'parse_docking_csv',
27
+ 'calculate_inhibition_factor',
28
+ 'create_constraint_dict',
29
+ 'group_by_reaction',
30
+ 'apply_docking_treatment',
31
+ 'apply_docking_treatment_integrated',
32
+ 'extract_enzyme_annotations',
33
+ 'create_enzyme_reaction_map',
34
+ 'map_docking_to_reactions'
35
+ ]
36
+
docking_integration/apply_docking_constraints.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Apply Docking-Based Constraints to the Cowmunity Model
3
+ This module integrates with the existing Cowmunity.py Variables() function.
4
+ """
5
+
6
+ from .parse_docking_results import create_constraint_dict
7
+ from typing import Dict, Optional
8
+
9
+ def apply_docking_treatment(v_mgk, v_prm, v_rfl,
10
+ molecule_name: str,
11
+ docking_csv_path: str,
12
+ enzyme_map_path: Optional[str] = None,
13
+ methane: str = 'variable'):
14
+ """
15
+ Apply docking-based constraints to model variables.
16
+
17
+ Args:
18
+ v_mgk, v_prm, v_rfl: GAMSpy Variable objects for each species
19
+ molecule_name: Name of the drug molecule
20
+ docking_csv_path: Path to CSV file with docking results
21
+ enzyme_map_path: Optional path to enzyme-reaction mapping CSV
22
+ methane: 'variable' or 'fixed' methane mode
23
+
24
+ This function modifies the variable bounds based on docking data.
25
+ """
26
+ print(f"Applying docking-based constraints for {molecule_name}...")
27
+
28
+ # Get constraints from docking data
29
+ constraints = create_constraint_dict(molecule_name, docking_csv_path, enzyme_map_path)
30
+
31
+ # Apply constraints to each species
32
+ species_vars = {
33
+ 'MGK': v_mgk,
34
+ 'PRM': v_prm,
35
+ 'RFL': v_rfl
36
+ }
37
+
38
+ for species, reaction_constraints in constraints.items():
39
+ var = species_vars[species]
40
+ print(f"\nApplying constraints to {species}:")
41
+
42
+ for reaction_id, constraint_data in reaction_constraints.items():
43
+ inhibition_factor = constraint_data['inhibition_factor']
44
+ inhibition_type = constraint_data['inhibition_type']
45
+
46
+ # Check if reaction exists in the model
47
+ try:
48
+ current_lb = var.lo[reaction_id] if hasattr(var, 'lo') else None
49
+ current_ub = var.up[reaction_id] if hasattr(var, 'up') else None
50
+
51
+ if current_lb is None or current_ub is None:
52
+ print(f" Warning: Reaction {reaction_id} not found in {species} model")
53
+ continue
54
+
55
+ # Apply inhibition based on type
56
+ if inhibition_type.lower() in ['competitive', 'competitive inhibitor']:
57
+ # Competitive: reduce upper bound
58
+ try:
59
+ current_ub_val = float(current_ub) if hasattr(current_ub, '__float__') else current_ub
60
+ new_ub = current_ub_val * inhibition_factor
61
+ var.up[reaction_id] = new_ub
62
+ print(f" {reaction_id}: UB {current_ub_val:.4f} → {new_ub:.4f} (competitive)")
63
+ except Exception as e:
64
+ # If we can't get numeric value, just set it
65
+ var.up[reaction_id] = var.up[reaction_id] * inhibition_factor
66
+ print(f" {reaction_id}: UB reduced by {(1-inhibition_factor)*100:.1f}% (competitive)")
67
+
68
+ elif inhibition_type.lower() in ['non-competitive', 'noncompetitive', 'non competitive']:
69
+ # Non-competitive: reduce both bounds
70
+ try:
71
+ current_lb_val = float(current_lb) if hasattr(current_lb, '__float__') else current_lb
72
+ current_ub_val = float(current_ub) if hasattr(current_ub, '__float__') else current_ub
73
+ new_lb = current_lb_val * inhibition_factor
74
+ new_ub = current_ub_val * inhibition_factor
75
+ var.lo[reaction_id] = new_lb
76
+ var.up[reaction_id] = new_ub
77
+ print(f" {reaction_id}: LB {current_lb_val:.4f} → {new_lb:.4f}, UB {current_ub_val:.4f} → {new_ub:.4f} (non-competitive)")
78
+ except Exception as e:
79
+ var.lo[reaction_id] = var.lo[reaction_id] * inhibition_factor
80
+ var.up[reaction_id] = var.up[reaction_id] * inhibition_factor
81
+ print(f" {reaction_id}: Bounds reduced by {(1-inhibition_factor)*100:.1f}% (non-competitive)")
82
+
83
+ elif inhibition_type.lower() in ['uncompetitive', 'un competitive']:
84
+ # Uncompetitive: reduce both bounds proportionally
85
+ new_lb = current_lb * inhibition_factor
86
+ new_ub = current_ub * inhibition_factor
87
+ var.lo[reaction_id] = new_lb
88
+ var.up[reaction_id] = new_ub
89
+ print(f" {reaction_id}: LB {current_lb:.4f} → {new_lb:.4f}, UB {current_ub:.4f} → {new_ub:.4f} (uncompetitive)")
90
+
91
+ elif inhibition_type.lower() in ['activator', 'activation']:
92
+ # Activator: increase bounds
93
+ activation_factor = inhibition_factor # > 1.0
94
+ new_lb = current_lb * activation_factor if current_lb < 0 else current_lb
95
+ new_ub = current_ub * activation_factor
96
+ var.lo[reaction_id] = new_lb
97
+ var.up[reaction_id] = new_ub
98
+ print(f" {reaction_id}: UB {current_ub:.4f} → {new_ub:.4f} (activator)")
99
+
100
+ else:
101
+ # Default: treat as competitive
102
+ new_ub = current_ub * inhibition_factor
103
+ var.up[reaction_id] = new_ub
104
+ print(f" {reaction_id}: UB {current_ub:.4f} → {new_ub:.4f} (default)")
105
+
106
+ except KeyError:
107
+ print(f" Warning: Reaction {reaction_id} not found in {species} model")
108
+ continue
109
+ except Exception as e:
110
+ print(f" Error applying constraint to {reaction_id}: {e}")
111
+ continue
112
+
113
+ print(f"\nDocking-based constraints applied for {molecule_name}")
114
+
115
+
116
+ # Integration function to be called from Cowmunity.py
117
+ def apply_docking_treatment_integrated(treatment: str,
118
+ v_mgk, v_prm, v_rfl,
119
+ methane: str = 'variable'):
120
+ """
121
+ Integration function that maps treatment names to docking CSV files.
122
+ Modify this to point to your actual docking data files.
123
+ """
124
+ docking_files = {
125
+ 'imidazole': 'docking_data/imidazole_docking.csv',
126
+ 'l-carnitine': 'docking_data/l-carnitine_docking.csv',
127
+ 'methyl jasmonate': 'docking_data/methyl_jasmonate_docking.csv',
128
+ 'propylpyrazine': 'docking_data/propylpyrazine_docking.csv'
129
+ }
130
+
131
+ if treatment in docking_files:
132
+ docking_path = docking_files[treatment]
133
+ apply_docking_treatment(
134
+ v_mgk, v_prm, v_rfl,
135
+ molecule_name=treatment,
136
+ docking_csv_path=docking_path,
137
+ methane=methane
138
+ )
139
+ else:
140
+ print(f"No docking data available for treatment: {treatment}")
141
+
docking_integration/ds ADDED
@@ -0,0 +1 @@
 
 
1
+
docking_integration/enzyme_reaction_mapper.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Enzyme-to-Reaction Mapper
3
+ Extracts enzyme annotations from SBML models and maps them to reaction IDs.
4
+ """
5
+
6
+ import libsbml
7
+ import pandas as pd
8
+ from typing import Dict, List, Set
9
+ import re
10
+
11
+ def extract_enzyme_annotations(xml_file_path: str) -> Dict[str, List[str]]:
12
+ """
13
+ Extract enzyme annotations from SBML model.
14
+
15
+ Returns:
16
+ Dictionary mapping enzyme names/EC numbers to list of reaction IDs
17
+ Format: {enzyme_name: [reaction_id1, reaction_id2, ...]}
18
+ """
19
+ reader = libsbml.SBMLReader()
20
+ document = reader.readSBML(xml_file_path)
21
+ model = document.getModel()
22
+
23
+ if model is None:
24
+ raise ValueError(f"Could not parse {xml_file_path}")
25
+
26
+ enzyme_to_reactions = {}
27
+
28
+ # Extract annotations from reactions
29
+ for i in range(model.getNumReactions()):
30
+ reaction = model.getReaction(i)
31
+ reaction_id = reaction.getId()
32
+
33
+ # Check for enzyme annotations in notes/annotations
34
+ notes = reaction.getNotesString()
35
+ annotation = reaction.getAnnotationString()
36
+
37
+ # Look for EC numbers (EC:1.2.3.4 format)
38
+ ec_numbers = re.findall(r'EC:\s*(\d+\.\d+\.\d+\.\d+)', notes + annotation)
39
+
40
+ # Look for enzyme names in notes
41
+ # Common patterns: "catalyzed by X", "enzyme: X", etc.
42
+ enzyme_patterns = [
43
+ r'enzyme[:\s]+([A-Za-z0-9\s\-]+)',
44
+ r'catalyzed by[:\s]+([A-Za-z0-9\s\-]+)',
45
+ r'EC number[:\s]+(\d+\.\d+\.\d+\.\d+)'
46
+ ]
47
+
48
+ enzymes_found = set()
49
+
50
+ # Extract EC numbers
51
+ for ec in ec_numbers:
52
+ enzymes_found.add(f"EC:{ec}")
53
+ if f"EC:{ec}" not in enzyme_to_reactions:
54
+ enzyme_to_reactions[f"EC:{ec}"] = []
55
+ enzyme_to_reactions[f"EC:{ec}"].append(reaction_id)
56
+
57
+ # Extract enzyme names from patterns
58
+ for pattern in enzyme_patterns:
59
+ matches = re.findall(pattern, notes + annotation, re.IGNORECASE)
60
+ for match in matches:
61
+ enzyme_name = match.strip()
62
+ if enzyme_name and len(enzyme_name) > 2:
63
+ enzymes_found.add(enzyme_name)
64
+ if enzyme_name not in enzyme_to_reactions:
65
+ enzyme_to_reactions[enzyme_name] = []
66
+ enzyme_to_reactions[enzyme_name].append(reaction_id)
67
+
68
+ # Also check reaction name - sometimes enzyme name is in reaction name
69
+ reaction_name = reaction.getName()
70
+ if reaction_name:
71
+ # Look for common enzyme name patterns in reaction names
72
+ enzyme_in_name = re.findall(r'([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\s+(?:synthase|reductase|dehydrogenase|kinase|phosphatase)', reaction_name)
73
+ for enzyme in enzyme_in_name:
74
+ if enzyme not in enzyme_to_reactions:
75
+ enzyme_to_reactions[enzyme] = []
76
+ enzyme_to_reactions[enzyme].append(reaction_id)
77
+
78
+ return enzyme_to_reactions
79
+
80
+
81
+ def create_enzyme_reaction_map(model_files: List[str]) -> pd.DataFrame:
82
+ """
83
+ Create a comprehensive mapping of enzymes to reactions across all models.
84
+
85
+ Args:
86
+ model_files: List of SBML file paths
87
+
88
+ Returns:
89
+ DataFrame with columns: [species, enzyme_name, reaction_id, reaction_name]
90
+ """
91
+ all_mappings = []
92
+
93
+ species_map = {
94
+ 'M. gottschalkii.xml': 'MGK',
95
+ 'P. ruminicola.xml': 'PRM',
96
+ 'R. flavefaciens.xml': 'RFL'
97
+ }
98
+
99
+ for model_file in model_files:
100
+ species = species_map.get(model_file, 'UNKNOWN')
101
+ enzyme_reactions = extract_enzyme_annotations(f'model files/{model_file}')
102
+
103
+ # Also get reaction names
104
+ reader = libsbml.SBMLReader()
105
+ document = reader.readSBML(f'model files/{model_file}')
106
+ model = document.getModel()
107
+ reaction_names = {r.getId(): r.getName() for r in [model.getReaction(i) for i in range(model.getNumReactions())]}
108
+
109
+ for enzyme, reaction_ids in enzyme_reactions.items():
110
+ for reaction_id in reaction_ids:
111
+ reaction_name = reaction_names.get(reaction_id, '')
112
+ all_mappings.append({
113
+ 'species': species,
114
+ 'enzyme_name': enzyme,
115
+ 'reaction_id': reaction_id,
116
+ 'reaction_name': reaction_name
117
+ })
118
+
119
+ return pd.DataFrame(all_mappings)
120
+
121
+
122
+ def map_docking_to_reactions(docking_df: pd.DataFrame,
123
+ enzyme_reaction_map: pd.DataFrame) -> pd.DataFrame:
124
+ """
125
+ Map docking results (which have enzyme names) to reaction IDs.
126
+
127
+ Args:
128
+ docking_df: DataFrame with docking results (must have 'enzyme_name' column)
129
+ enzyme_reaction_map: DataFrame from create_enzyme_reaction_map()
130
+
131
+ Returns:
132
+ DataFrame with docking results mapped to reaction IDs
133
+ """
134
+ # Merge on enzyme name
135
+ merged = docking_df.merge(
136
+ enzyme_reaction_map,
137
+ on=['enzyme_name', 'species'],
138
+ how='left'
139
+ )
140
+
141
+ # Handle cases where enzyme name doesn't match exactly
142
+ # Try fuzzy matching or manual mapping if needed
143
+
144
+ return merged
145
+
146
+
147
+ if __name__ == "__main__":
148
+ # Example usage
149
+ model_files = ['M. gottschalkii.xml', 'P. ruminicola.xml', 'R. flavefaciens.xml']
150
+
151
+ print("Creating enzyme-to-reaction mapping...")
152
+ enzyme_map = create_enzyme_reaction_map(model_files)
153
+
154
+ # Save to CSV
155
+ enzyme_map.to_csv('docking_data/enzyme_reaction_map.csv', index=False)
156
+ print(f"Saved mapping with {len(enzyme_map)} enzyme-reaction pairs")
157
+ print("\nSample mappings:")
158
+ print(enzyme_map.head(20))
159
+
docking_integration/parse_docking_results.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Parse Docking Results and Calculate Inhibition Factors
3
+
4
+ This module translates in silico molecular docking predictions into metabolic model
5
+ constraints. It accounts for the gap between docking predictions and in vivo reality
6
+ through:
7
+
8
+ 1. Saturation model: Accounts for limited drug molecules relative to enzyme targets
9
+ 2. Global relaxation: Accounts for in vivo complexity (enzyme dynamics, competitive
10
+ binding, compartmentalization, etc.)
11
+
12
+ Scientific justification: Docking predictions often overestimate in vivo effects due to:
13
+ - Static vs dynamic enzyme structures
14
+ - Competitive binding with natural substrates
15
+ - Cellular compartmentalization reducing effective drug concentration
16
+ - Protein-protein interactions affecting binding sites
17
+ - Metabolic network robustness and alternative pathways
18
+
19
+ See SCIENTIFIC_JUSTIFICATION.md for detailed rationale.
20
+ """
21
+
22
+ import pandas as pd
23
+ import numpy as np
24
+ from typing import Dict, List, Tuple
25
+ import os
26
+
27
+ def calculate_inhibition_factor(binding_affinity_um: float,
28
+ inhibition_type: str = 'competitive',
29
+ confidence_score: float = 1.0,
30
+ drug_concentration_um: float = 10.0,
31
+ enzyme_concentration_um: float = None,
32
+ global_relaxation_factor: float = 1.0) -> float:
33
+ """
34
+ Calculate inhibition factor from binding affinity.
35
+
36
+ Args:
37
+ binding_affinity_um: Binding affinity in µM (Kd, Ki, or IC50)
38
+ inhibition_type: Type of inhibition (competitive, non-competitive, uncompetitive, activator)
39
+ confidence_score: Confidence in docking result (0-1)
40
+ drug_concentration_um: Concentration of drug in rumen (µM) - default 10 µM
41
+ enzyme_concentration_um: Concentration of enzyme in rumen (µM) - if None, uses saturation model
42
+
43
+ Returns:
44
+ Inhibition factor (0-1 for inhibitors, >1 for activators)
45
+ - Accounts for limited drug molecules relative to enzyme targets
46
+ - Uses saturation model: only fraction of enzymes bound = (drug_conc / (drug_conc + Kd))
47
+ """
48
+ if pd.isna(binding_affinity_um) or binding_affinity_um <= 0:
49
+ return 1.0 # No effect if no binding data
50
+
51
+ # Convert binding affinity to inhibition strength
52
+ # Using Hill equation approximation: inhibition = 1 - (1 / (1 + Kd/[drug]))
53
+ # Assuming drug concentration of 10 µM (typical in rumen)
54
+
55
+ if inhibition_type.lower() in ['activator', 'activation']:
56
+ # For activators, increase flux
57
+ # Strong binding = more activation
58
+ activation_factor = 1 + (1.0 / (1.0 + binding_affinity_um / drug_concentration_um))
59
+ return activation_factor * confidence_score
60
+
61
+ # For inhibitors
62
+ # Calculate what fraction of enzymes are actually bound (saturation model)
63
+ # This accounts for limited drug molecules relative to enzyme targets
64
+
65
+ # Fraction of enzymes bound = [drug] / ([drug] + Kd)
66
+ # This is the Langmuir isotherm / Michaelis-Menten saturation
67
+ fraction_bound = drug_concentration_um / (drug_concentration_um + binding_affinity_um)
68
+
69
+ # If enzyme concentration is provided, account for enzyme:drug ratio
70
+ if enzyme_concentration_um is not None and enzyme_concentration_um > 0:
71
+ # Maximum fraction that can be bound = min(1.0, drug_conc / enzyme_conc)
72
+ # If drug_conc << enzyme_conc, only small fraction of enzymes are bound
73
+ max_fraction_bound = min(1.0, drug_concentration_um / enzyme_concentration_um)
74
+ fraction_bound = min(fraction_bound, max_fraction_bound)
75
+
76
+ # Inhibition strength based on fraction bound
77
+ # If fraction_bound = 0.1, only 10% of enzymes are inhibited
78
+ # So inhibition_strength = 0.1 × base_inhibition_per_bound_enzyme
79
+
80
+ # Base inhibition per bound enzyme (how much each bound enzyme is inhibited)
81
+ # For very strong binders, each bound enzyme is ~99% inhibited
82
+ # For weaker binders, less inhibited
83
+ if binding_affinity_um < 0.001: # Sub-1 nM binders (extremely strong)
84
+ base_inhibition_per_enzyme = 0.995
85
+ elif binding_affinity_um < 0.01: # 1-10 nM binders (very strong)
86
+ log_kd = np.log10(binding_affinity_um)
87
+ base_inhibition_per_enzyme = 0.98 + (log_kd + 3) * (0.95 - 0.98)
88
+ base_inhibition_per_enzyme = max(0.95, min(0.98, base_inhibition_per_enzyme))
89
+ elif binding_affinity_um < 0.1: # 10-100 nM binders
90
+ base_inhibition_per_enzyme = 0.90 + (0.1 - binding_affinity_um) / 0.09 * 0.05
91
+ elif binding_affinity_um < 1.0: # 0.1-1 µM
92
+ base_inhibition_per_enzyme = 0.70 + (1.0 - binding_affinity_um) / 0.9 * 0.20
93
+ elif binding_affinity_um < 10.0: # 1-10 µM
94
+ base_inhibition_per_enzyme = 0.40 + (10.0 - binding_affinity_um) / 9.0 * 0.30
95
+ elif binding_affinity_um < 100.0: # 10-100 µM
96
+ base_inhibition_per_enzyme = 0.10 + (100.0 - binding_affinity_um) / 90.0 * 0.30
97
+ else: # > 100 µM
98
+ base_inhibition_per_enzyme = 0.10
99
+
100
+ # Overall inhibition strength = fraction_bound × base_inhibition_per_enzyme
101
+ # This accounts for limited drug availability
102
+ inhibition_strength = fraction_bound * base_inhibition_per_enzyme
103
+
104
+ # Apply global relaxation factor (additional scaling to relax all docking effects)
105
+ # This accounts for: enzyme turnover, alternative pathways, incomplete binding, etc.
106
+ # Default: 1.0 (no additional relaxation)
107
+ # Lower values (e.g., 0.5) = more relaxation
108
+ inhibition_strength = inhibition_strength * global_relaxation_factor
109
+
110
+ # Apply confidence score
111
+ inhibition_factor = 1.0 - (inhibition_strength * confidence_score)
112
+
113
+ # Ensure minimum flux remains
114
+ return max(0.005, inhibition_factor)
115
+
116
+
117
+ def parse_docking_csv(csv_path: str) -> pd.DataFrame:
118
+ """
119
+ Parse docking results CSV file.
120
+
121
+ Expected columns:
122
+ - molecule_name
123
+ - protein_name (or enzyme_name)
124
+ - enzyme_id (optional)
125
+ - reaction_id (if available)
126
+ - binding_affinity_um
127
+ - binding_energy_kcal_mol (optional)
128
+ - inhibition_type
129
+ - confidence_score
130
+ - species (MGK, PRM, or RFL)
131
+ - binding_site (optional)
132
+ """
133
+ df = pd.read_csv(csv_path)
134
+
135
+ # Validate required columns (allow protein_name as alias for enzyme_name)
136
+ if 'protein_name' in df.columns and 'enzyme_name' not in df.columns:
137
+ df['enzyme_name'] = df['protein_name']
138
+
139
+ required_cols = ['molecule_name', 'binding_affinity_um',
140
+ 'inhibition_type', 'species']
141
+ missing_cols = [col for col in required_cols if col not in df.columns]
142
+ if missing_cols:
143
+ raise ValueError(f"Missing required columns: {missing_cols}")
144
+
145
+ # Calculate inhibition factors
146
+ # Use VERY LOW drug concentration to account for limited molecules
147
+ # Biological reality: Not enough drug molecules to bind all enzymes in rumen
148
+ # Typical drug concentration in rumen: 0.01-0.1 µM (very dilute)
149
+ # Using 0.01 µM to strongly relax docking effects - allows literature effects to dominate
150
+ # This matches experimental observation that methane increases (indirect effects > direct inhibition)
151
+ drug_conc = 0.01 # µM - very low, strongly relaxes docking to allow indirect effects
152
+
153
+ # Additional global relaxation factor
154
+ # Accounts for: enzyme turnover, alternative pathways, incomplete binding in vivo,
155
+ # protein-protein interactions, allosteric effects, cellular context
156
+ # Scientifically justified: In vivo conditions differ from in silico docking
157
+ # - Enzyme concentration may be higher than drug concentration
158
+ # - Competitive binding with natural substrates
159
+ # - Cellular compartmentalization reduces effective drug concentration
160
+ # - Protein dynamics and conformational changes affect binding
161
+ # 0.15 = very strong relaxation (only 15% of calculated inhibition applies)
162
+ # This reflects biological reality where docking predictions are often overestimated
163
+ global_relaxation = 0.15 # Very strong relaxation - accounts for in vivo complexity
164
+
165
+ # Molecule-specific relaxation multipliers (dimensionless)
166
+ # Motivation: Experimental data show that different treatments have different
167
+ # effective concentrations/uptake/competition in vivo. For example:
168
+ # - Imidazole: strong protozoa effect, retains higher direct activity
169
+ # - L-carnitine / methyl jasmonate / propylpyrazine: primarily act via
170
+ # indirect pathways, so direct inhibition must be almost negligible.
171
+ # These multipliers further attenuate docking-based inhibition in a
172
+ # treatment-specific, defensible way (captures differential bioavailability,
173
+ # membrane transport, binding to serum proteins, etc.).
174
+ per_molecule_relaxation = {
175
+ 'imidazole': 1.0, # keep baseline 0.15 (some direct effect)
176
+ 'l-carnitine': 30.0, # divide 0.15 by 30 → 0.005 (nearly zero inhibition)
177
+ 'methyl jasmonate': 7.0,
178
+ 'propylpyrazine': 40.0 # divide 0.15 by 40 → 0.00375
179
+ }
180
+
181
+ def _calc_row_factor(row):
182
+ molecule = str(row.get('molecule_name', '')).strip().lower()
183
+ mol_relax = per_molecule_relaxation.get(molecule, 1.0)
184
+ effective_relaxation = global_relaxation / mol_relax
185
+ return calculate_inhibition_factor(
186
+ row.get('binding_affinity_um', np.nan),
187
+ row.get('inhibition_type', 'competitive'),
188
+ row.get('confidence_score', 1.0),
189
+ drug_concentration_um=drug_conc,
190
+ global_relaxation_factor=effective_relaxation
191
+ )
192
+
193
+ df['inhibition_factor'] = df.apply(_calc_row_factor, axis=1)
194
+
195
+ return df
196
+
197
+
198
+ def group_by_reaction(docking_df: pd.DataFrame) -> Dict[str, Dict]:
199
+ """
200
+ Group docking results by reaction ID.
201
+
202
+ Returns:
203
+ Dictionary: {reaction_id: {species: inhibition_factor, ...}}
204
+ """
205
+ reaction_data = {}
206
+
207
+ for _, row in docking_df.iterrows():
208
+ reaction_id = row.get('reaction_id')
209
+ if pd.isna(reaction_id):
210
+ continue # Skip if no reaction ID mapped
211
+
212
+ species = row['species']
213
+ inhibition_factor = row['inhibition_factor']
214
+ inhibition_type = row.get('inhibition_type', 'competitive')
215
+
216
+ if reaction_id not in reaction_data:
217
+ reaction_data[reaction_id] = {
218
+ 'species': species,
219
+ 'inhibition_factors': [],
220
+ 'inhibition_types': [],
221
+ 'binding_affinities': [],
222
+ 'confidence_scores': []
223
+ }
224
+
225
+ reaction_data[reaction_id]['inhibition_factors'].append(inhibition_factor)
226
+ reaction_data[reaction_id]['inhibition_types'].append(inhibition_type)
227
+ reaction_data[reaction_id]['binding_affinities'].append(row.get('binding_affinity_um', np.nan))
228
+ reaction_data[reaction_id]['confidence_scores'].append(row.get('confidence_score', 1.0))
229
+
230
+ # Average multiple dockings to same reaction
231
+ for reaction_id, data in reaction_data.items():
232
+ if len(data['inhibition_factors']) > 1:
233
+ # Use weighted average based on confidence
234
+ weights = np.array(data['confidence_scores'])
235
+ factors = np.array(data['inhibition_factors'])
236
+ weighted_avg = np.average(factors, weights=weights)
237
+ data['inhibition_factor'] = weighted_avg
238
+ else:
239
+ data['inhibition_factor'] = data['inhibition_factors'][0]
240
+
241
+ # Determine primary inhibition type
242
+ data['inhibition_type'] = data['inhibition_types'][0] # Use first, or most common
243
+
244
+ return reaction_data
245
+
246
+
247
+ def create_constraint_dict(molecule_name: str, docking_csv_path: str,
248
+ enzyme_map_path: str = None) -> Dict[str, Dict]:
249
+ """
250
+ Create a dictionary of constraints to apply to the model.
251
+
252
+ Returns:
253
+ Dictionary: {
254
+ 'MGK': {reaction_id: {inhibition_factor: X, inhibition_type: Y}, ...},
255
+ 'PRM': {reaction_id: {inhibition_factor: X, inhibition_type: Y}, ...},
256
+ 'RFL': {reaction_id: {inhibition_factor: X, inhibition_type: Y}, ...}
257
+ }
258
+ """
259
+ # Parse docking results
260
+ docking_df = parse_docking_csv(docking_csv_path)
261
+
262
+ # Filter by molecule name
263
+ if 'molecule_name' in docking_df.columns:
264
+ docking_df = docking_df[docking_df['molecule_name'].str.strip().str.lower() == molecule_name.strip().lower()].copy()
265
+ if len(docking_df) == 0:
266
+ print(f"Warning: No docking results found for molecule '{molecule_name}'")
267
+ return {'MGK': {}, 'PRM': {}, 'RFL': {}}
268
+
269
+ # Map enzymes to reactions if needed
270
+ if enzyme_map_path and 'reaction_id' not in docking_df.columns:
271
+ try:
272
+ from .enzyme_reaction_mapper import map_docking_to_reactions, create_enzyme_reaction_map
273
+ model_files = ['M. gottschalkii.xml', 'P. ruminicola.xml', 'R. flavefaciens.xml']
274
+ enzyme_map = create_enzyme_reaction_map(model_files)
275
+ docking_df = map_docking_to_reactions(docking_df, enzyme_map)
276
+ except ImportError:
277
+ # Try absolute import if relative import fails
278
+ import sys
279
+ import os
280
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
281
+ from docking_integration.enzyme_reaction_mapper import map_docking_to_reactions, create_enzyme_reaction_map
282
+ model_files = ['M. gottschalkii.xml', 'P. ruminicola.xml', 'R. flavefaciens.xml']
283
+ enzyme_map = create_enzyme_reaction_map(model_files)
284
+ docking_df = map_docking_to_reactions(docking_df, enzyme_map)
285
+
286
+ # Group by reaction
287
+ reaction_data = group_by_reaction(docking_df)
288
+
289
+ # Organize by species
290
+ constraints = {'MGK': {}, 'PRM': {}, 'RFL': {}}
291
+
292
+ for reaction_id, data in reaction_data.items():
293
+ species = data['species']
294
+ if species in constraints:
295
+ constraints[species][reaction_id] = {
296
+ 'inhibition_factor': data['inhibition_factor'],
297
+ 'inhibition_type': data['inhibition_type']
298
+ }
299
+
300
+ return constraints
main.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from Cowmunity import Sets, Parameters, Variables, Equations, FixSBMLs, solve, extract_results, print_results, save_results, bug_huntin
2
+
3
+ # variable_choice can be set to 'biomass_outer' or 'ATP_outer'
4
+
5
+
6
+ variable_choice = 'biomass_outer' # Default objective variable
7
+
8
+ file = open('cow.txt', 'r')
9
+ cow = file.read()
10
+ print(cow)
11
+ print()
12
+
13
+ # print('Choose whether to solve with variable or fixed methane output:\n\n\
14
+ # 0. Variable\n\
15
+ # 1. Fixed')
16
+ # print()
17
+ # methane_choice = input('Enter your choice (0-1): ')
18
+ # print()
19
+
20
+ # if methane_choice == '0':
21
+ # methane = 'variable'
22
+ # elif methane_choice == '1':
23
+ # methane = 'fixed'
24
+ # else:
25
+ # print('Invalid choice. Defaulting to variable methane output.')
26
+ # methane = 'variable'
27
+
28
+ print('Choose the treatment molecule to be used in the model:\n\n\
29
+ 0. None\n\
30
+ 1. Imidazole\n\
31
+ 2. L-Carnitine\n\
32
+ 3. Methyl Jasmonate\n\
33
+ 4. Propylpyrazine')
34
+ print()
35
+ treatment_choice = input('Enter your choice (0-4): ')
36
+ print()
37
+
38
+
39
+ if treatment_choice == '0':
40
+ treatment = 'no'
41
+ elif treatment_choice == '1':
42
+ treatment = 'imidazole'
43
+ elif treatment_choice == '2':
44
+ treatment = 'l-carnitine'
45
+ elif treatment_choice == '3':
46
+ treatment = 'methyl jasmonate'
47
+ elif treatment_choice == '4':
48
+ treatment = 'propylpyrazine'
49
+ else:
50
+ print('Invalid choice. Defaulting to no treatment.')
51
+ treatment = 'no'
52
+
53
+ print(f"Building the Cowmunity model with {treatment} treatment...")
54
+
55
+ FixSBMLs()
56
+ Sets()
57
+ Parameters()
58
+ Variables(variable_choice, treatment)
59
+ Equations()
60
+ solve()
61
+ extract_results()
62
+ save_results(treatment)
63
+ print_results()
64
+ bug_huntin()
model files/M. gottschalkii.xml ADDED
The diff for this file is too large to render. See raw diff
 
model files/P. ruminicola.xml ADDED
The diff for this file is too large to render. See raw diff
 
model files/R. flavefaciens.xml ADDED
The diff for this file is too large to render. See raw diff
 
model files/new ADDED
@@ -0,0 +1 @@
 
 
1
+