|
| 1 | +from copy import copy, deepcopy |
| 2 | + |
| 3 | +import geckopy |
| 4 | +from cobra.core.dictlist import DictList |
| 5 | + |
| 6 | +from multitfa.core import tmodel |
| 7 | +from multitfa.core import Thermo_met, thermo_reaction |
| 8 | + |
| 9 | + |
| 10 | +class ThermoProtReaction(thermo_reaction): |
| 11 | + """ |
| 12 | + 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. |
| 13 | +
|
| 14 | + Parameters |
| 15 | + ---------- |
| 16 | + cobra_rxn : cobra.core.Reaction |
| 17 | + Cobra reaction object, to copy the attributes from. We copy metabolites and genes. |
| 18 | + updated_model : core.tmodel, optional |
| 19 | + tmodel object, with updated thermo properties, by default None |
| 20 | +
|
| 21 | + """ |
| 22 | + |
| 23 | + def __init__( |
| 24 | + self, |
| 25 | + cobra_rxn, |
| 26 | + updated_model=None, |
| 27 | + ): |
| 28 | + self._model = updated_model |
| 29 | + do_not_copy_by_ref = {"_model", "_metabolites", "_genes"} |
| 30 | + for attr, value in cobra_rxn.__dict__.items(): |
| 31 | + if attr not in do_not_copy_by_ref: |
| 32 | + self.__dict__[attr] = copy(value) |
| 33 | + |
| 34 | + self._metabolites = {} |
| 35 | + for met, stoic in cobra_rxn._metabolites.items(): |
| 36 | + # this is the only change; also account for proteins |
| 37 | + 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) |
| 38 | + self._metabolites[new_met] = stoic |
| 39 | + new_met._reaction.add(self) |
| 40 | + self._genes = set() |
| 41 | + for gene in cobra_rxn._genes: |
| 42 | + new_gene = self.model.genes.get_by_id(gene.id) |
| 43 | + self._genes.add(new_gene) |
| 44 | + new_gene._reaction.add(self) |
| 45 | + |
| 46 | + |
| 47 | +class ThermoProtModel(tmodel): |
| 48 | + def __init__( |
| 49 | + self, |
| 50 | + model, |
| 51 | + Exclude_list=[], |
| 52 | + tolerance_integral=1e-9, |
| 53 | + compartment_info=None, |
| 54 | + membrane_potential=None, |
| 55 | + exclude_metabolites=[], |
| 56 | + ): |
| 57 | + |
| 58 | + self.compartment_info = compartment_info |
| 59 | + self.membrane_potential = membrane_potential |
| 60 | + |
| 61 | + do_not_copy_by_ref = { |
| 62 | + "metabolites", |
| 63 | + "reactions", |
| 64 | + "proteins", |
| 65 | + "genes", |
| 66 | + "notes", |
| 67 | + "annotation", |
| 68 | + } |
| 69 | + for attr in model.__dict__: |
| 70 | + if attr not in do_not_copy_by_ref: |
| 71 | + self.__dict__[attr] = model.__dict__[attr] |
| 72 | + |
| 73 | + self.metabolites = DictList() |
| 74 | + do_not_copy_by_ref = {"_reaction", "_model"} |
| 75 | + for metabolite in model.metabolites: |
| 76 | + new_met = Thermo_met( |
| 77 | + metabolite=metabolite, |
| 78 | + updated_model=self, |
| 79 | + ) |
| 80 | + self.metabolites.append(new_met) |
| 81 | + |
| 82 | + self.genes = DictList() |
| 83 | + |
| 84 | + for gene in model.genes: |
| 85 | + new_gene = gene.__class__(None) |
| 86 | + for attr, value in gene.__dict__.items(): |
| 87 | + if attr not in do_not_copy_by_ref: |
| 88 | + new_gene.__dict__[attr] = ( |
| 89 | + copy(value) if attr == "formula" else value |
| 90 | + ) |
| 91 | + new_gene._model = self |
| 92 | + self.genes.append(new_gene) |
| 93 | + self.proteins = DictList() |
| 94 | + for protein in model.proteins: |
| 95 | + new_prot = Thermo_met( |
| 96 | + metabolite=protein, |
| 97 | + updated_model=self, |
| 98 | + ) |
| 99 | + # proteins do not participate in dGf calculations |
| 100 | + new_prot.is_ignore = True |
| 101 | + self.proteins.append(new_prot) |
| 102 | + |
| 103 | + self.reactions = DictList() |
| 104 | + do_not_copy_by_ref = {"_model", "_metabolites", "_genes"} |
| 105 | + for reaction in model.reactions: |
| 106 | + # this is custom to make the reaction aware of proteins |
| 107 | + new_reaction = ThermoProtReaction( |
| 108 | + cobra_rxn=reaction, |
| 109 | + updated_model=self, |
| 110 | + ) |
| 111 | + self.reactions.append(new_reaction) |
| 112 | + |
| 113 | + try: |
| 114 | + self._solver = deepcopy(model.solver) |
| 115 | + # Cplex has an issue with deep copies |
| 116 | + except Exception: # pragma: no cover |
| 117 | + self._solver = copy(model.solver) # pragma: no cover |
| 118 | + |
| 119 | + self.Exclude_list = Exclude_list |
| 120 | + self.solver.configuration.tolerances.integrality = tolerance_integral |
| 121 | + self._var_update = False |
0 commit comments