Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: integration layer with multitfa #9

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/03-thermodynamics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ or the thermodynamic constraint, see the
)
# constrain the model objective so that the feashibility relaxation recovers growth
tmodel_prot.reactions.BIOMASS_Ecoli_core_w_GAM.lower_bound = solution.objective_value
iis, status = geckopy.integration.relax_thermo_proteins(
iis, status = geckopy.integration.relaxation.relax_thermo_proteins(
tmodel_prot,
prot_candidates=[prot.id for prot in tmodel_prot.proteins],
objective_rule=geckopy.experimental.relaxation.Objective_rule.MIN_ELASTIC_SUM
Expand Down
1 change: 0 additions & 1 deletion geckopy/integration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .relaxation import relax_thermo_concentrations_proteins, relax_thermo_proteins
123 changes: 123 additions & 0 deletions geckopy/integration/multitfa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
from copy import copy, deepcopy

from cobra.core.dictlist import DictList
from multitfa.core import Thermo_met, thermo_reaction, tmodel

import geckopy


class ThermoProtReaction(thermo_reaction):
"""
Class representation of thermo reaction Object. We calculate the required thermodynamic constraints for performing tMFA. To do the constraints, we need Gibbs energy of reaction and transport.

Parameters
----------
cobra_rxn : cobra.core.Reaction
Cobra reaction object, to copy the attributes from. We copy metabolites and genes.
updated_model : core.tmodel, optional
tmodel object, with updated thermo properties, by default None

"""

def __init__(
self,
cobra_rxn,
updated_model=None,
):
self._model = updated_model
do_not_copy_by_ref = {"_model", "_metabolites", "_genes"}
for attr, value in cobra_rxn.__dict__.items():
if attr not in do_not_copy_by_ref:
self.__dict__[attr] = copy(value)

self._metabolites = {}
for met, stoic in cobra_rxn._metabolites.items():
# this is the only change; also account for proteins
new_met = (
self.model.metabolites.get_by_id(met.id)
if met in self.model.metabolites
else self.model.proteins.get_by_id(met.id)
)
self._metabolites[new_met] = stoic
new_met._reaction.add(self)
self._genes = set()
for gene in cobra_rxn._genes:
new_gene = self.model.genes.get_by_id(gene.id)
self._genes.add(new_gene)
new_gene._reaction.add(self)


class ThermoProtModel(tmodel):
def __init__(
self,
model,
Exclude_list=[],
tolerance_integral=1e-9,
compartment_info=None,
membrane_potential=None,
exclude_metabolites=[],
):

self.compartment_info = compartment_info
self.membrane_potential = membrane_potential

do_not_copy_by_ref = {
"metabolites",
"reactions",
"proteins",
"genes",
"notes",
"annotation",
}
for attr in model.__dict__:
if attr not in do_not_copy_by_ref:
self.__dict__[attr] = model.__dict__[attr]

self.metabolites = DictList()
do_not_copy_by_ref = {"_reaction", "_model"}
for metabolite in model.metabolites:
new_met = Thermo_met(
metabolite=metabolite,
updated_model=self,
)
self.metabolites.append(new_met)

self.genes = DictList()

for gene in model.genes:
new_gene = gene.__class__(None)
for attr, value in gene.__dict__.items():
if attr not in do_not_copy_by_ref:
new_gene.__dict__[attr] = (
copy(value) if attr == "formula" else value
)
new_gene._model = self
self.genes.append(new_gene)
self.proteins = DictList()
for protein in model.proteins:
new_prot = Thermo_met(
metabolite=protein,
updated_model=self,
)
# proteins do not participate in dGf calculations
self.proteins.append(new_prot)

self.reactions = DictList()
do_not_copy_by_ref = {"_model", "_metabolites", "_genes"}
for reaction in model.reactions:
# this is custom to make the reaction aware of proteins
new_reaction = ThermoProtReaction(
cobra_rxn=reaction,
updated_model=self,
)
self.reactions.append(new_reaction)

try:
self._solver = deepcopy(model.solver)
# Cplex has an issue with deep copies
except Exception: # pragma: no cover
self._solver = copy(model.solver) # pragma: no cover

self.Exclude_list = Exclude_list
self.solver.configuration.tolerances.integrality = tolerance_integral
self._var_update = False
18 changes: 18 additions & 0 deletions tests/test_integration/test_multitfa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest
from optlang import available_solvers

from geckopy.integration.multitfa import ThermoProtModel


@pytest.mark.skipif(
not (available_solvers["GUROBI"] or available_solvers["CPLEX"]),
reason="No quadratic programming available",
)
def test_protein_constrain_affects_multitfa_solution(ec_model_core):
"""Check thermo model returns different solution when protein is constrained."""
thermo_model = ThermoProtModel(ec_model_core.copy())
tsol = thermo_model.slim_optimize()
ec_model_core.proteins.prot_P25516.add_concentration(2e-5)
thermo_model = ThermoProtModel(ec_model_core)
tsol_prot = thermo_model.slim_optimize()
assert pytest.approx(tsol) != tsol_prot
2 changes: 1 addition & 1 deletion tests/test_integration/test_relaxation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from geckopy.experimental import from_copy_number
from geckopy.experimental.relaxation import Objective_rule
from geckopy.integration import (
from geckopy.integration.relaxation import (
relax_thermo_concentrations_proteins,
relax_thermo_proteins,
)
Expand Down