from __future__ import print_function, division, absolute_import
from collections import defaultdict
from warnings import warn
from cobra import Reaction
from six import iteritems, string_types
import cobrame
from cobrame.core.component import create_component
from cobrame.util import mu, massbalance
[docs]class MEReaction(Reaction):
# TODO set _upper and _lower bounds as a property
"""
MEReaction is a general reaction class from which all ME-Model reactions
will inherit
This class contains functionality that can be used by all ME-model
reactions
Parameters
----------
id : str
Identifier of the MEReaction. Should follow best practices of child
class
"""
def __init__(self, id=None, name=''):
Reaction.__init__(self, id, name)
self._objective_coefficient = 0.
@property
def objective_coefficient(self):
"""
Get and set objective coefficient of reaction
Overrides method in parent class in order to enable use of optlang
interfaces.
Returns
-------
float
Objective coefficient of reaction
"""
return self._objective_coefficient
@objective_coefficient.setter
def objective_coefficient(self, value):
self._objective_coefficient = value
[docs] def check_me_mass_balance(self):
"""
Checks the mass balance of ME reaction, ignoring charge balances
Returns
-------
dict
{element: number_of_elemental_imbalances}
"""
mass_balance = self.check_mass_balance()
# ME-model is not currently charge balanced
if 'charge' in mass_balance:
mass_balance.pop('charge')
return {met: value for met, value in iteritems(mass_balance)
if abs(value) > 1e-11}
[docs] def add_subreactions(self, process_data_id, stoichiometry, scale=1.):
"""
Function to add subreaction process data to reaction stoichiometry
Parameters
----------
process_data_id : str
ID of the process data associated with the metabolic reaction.
For example, if the modifications are being added to a complex
formation reaction, the process data id would be the name of the
complex.
stoichiometry : dict
Dictionary of {metabolite_id: float} or
{metabolite_id: float * (sympy.Symbol)}
scale : float
Some processes (ie. tRNA charging) are reformulated such that other
involved metabolites need scaling
Returns
-------
dict
Stoichiometry dictionary with updated entries
"""
process_info = self._model.process_data.get_by_id(process_data_id)
for subreaction_id, count in iteritems(process_info.subreactions):
subreaction_data = \
self._model.process_data.get_by_id(subreaction_id)
if type(subreaction_data.enzyme) == list:
for enzyme in subreaction_data.enzyme:
stoichiometry[enzyme] -= mu / subreaction_data.keff / \
3600. * count * scale
elif isinstance(subreaction_data.enzyme, string_types):
stoichiometry[subreaction_data.enzyme] -= \
mu / subreaction_data.keff / 3600. * count * scale
for met, stoich in iteritems(subreaction_data.stoichiometry):
stoichiometry[met] += count * stoich * scale
return stoichiometry
[docs] def get_components_from_ids(self, id_stoichiometry,
default_type=cobrame.Metabolite, verbose=True):
"""
Function to convert stoichiometry dictionary entries from strings to
cobra objects.
{metabolite_id: value} to {:class:`cobrame.core.component.Metabolite`:
value}
Parameters
----------
id_stoichiometry: Dict {string: float}
Input Dict of {metabolite_id: value}
default_type: String
The type of cobra.Metabolite to default to if the metabolite is not
yet present in the model
verbose: Boolean
If True, print metabolites added to model if not yet present in
model
Returns
-------
dict
{:class:`cobrame.core.component.Metabolite`: float}
"""
stoic = id_stoichiometry
object_stoichiometry = {}
mets = self._model.metabolites
for key, value in iteritems(stoic):
try:
object_stoichiometry[mets.get_by_id(key)] = value
except KeyError:
new_met = create_component(key, default_type=default_type)
if verbose:
print("Created %s in %s" % (repr(new_met), repr(self)))
object_stoichiometry[new_met] = value
self._model.add_metabolites([new_met])
return object_stoichiometry
[docs] def add_biomass_from_subreactions(self, process_data, biomass=0.):
"""
Account for the biomass of metabolites added to macromolecule (protein,
complex, etc.) due to a modification such as prosthetic group addition.
Parameters
----------
process_data : :class:`cobrame.core.processdata.ProcessData`
ProcessData that is used to construct MEReaction
biomass : float
Initial biomass value in kDa
Returns
-------
float
Initial biomass value + biomass added from subreactions in kDa
"""
for subrxn, count in iteritems(process_data.subreactions):
subrxn_obj = self._model.process_data.get_by_id(subrxn)
biomass += \
subrxn_obj.calculate_biomass_contribution() / 1000. * count
return biomass # in kDa
[docs]class PostTranslationReaction(MEReaction):
"""
Reaction class that includes all posttranslational modification reactions
(translocation, protein folding, modification (for lipoproteins) etc)
There are often multiple different reactions/enzymes that can accomplish
the same modification/function. In order to account for these and
maintain one translation reaction per protein, these processes need to be
modeled as separate reactions.
Parameters
----------
id : str
Identifier of the post translation reaction
"""
def __init__(self, id):
MEReaction.__init__(self, id)
self._posttranslation_data = None
@property
def posttranslation_data(self):
"""
Get or set PostTranslationData that defines the type of post
translation modification/process (folding/translocation) that the
reaction accounts for. Can be set with instance of
PostTranslationData or with its id.
Returns
-------
:class:`cobrame.core.processdata.PostTranslationData`
The PostTranslationData that defines the PostTranslationReaction
"""
return self._posttranslation_data
@posttranslation_data.setter
def posttranslation_data(self, process_data):
if isinstance(process_data, string_types):
process_data = self._model.process_data.get_by_id(process_data)
self._posttranslation_data = process_data
process_data._parent_reactions.add(self.id)
[docs] def add_translocation_pathways(self, process_data_id, protein_id,
stoichiometry=None):
"""
Add complexes and metabolites required to translocate the protein into
cell membranes.
Parameters
----------
process_data_id : str
ID of translocation data defining post translation reaction
protein_id : str
ID of protein being translocated via post translation reaction
stoichiometry : dict
Dictionary of {metabolite_id: float} or
{metabolite_id: float * (sympy.Symbol)}
Returns
-------
dict
Stoichiometry dictionary with updated entries from translocation
"""
if not stoichiometry:
stoichiometry = defaultdict(float)
process_info = self._model.process_data.get_by_id(process_data_id)
protein = self._model.metabolites.get_by_id(protein_id)
protein_length = len(protein.amino_acid_sequence)
for translocation in process_info.translocation:
translocation_data = \
self._model.process_data.get_by_id(translocation)
for metabolite, amount in \
iteritems(translocation_data.stoichiometry):
if translocation_data.length_dependent_energy:
stoichiometry[metabolite] += amount * protein_length
else:
stoichiometry[metabolite] += amount
# Requirement of some translocation complexes vary depending
# on protein being translocated
multiplier_dict = process_info.translocation_multipliers
for enzyme, enzyme_info in iteritems(
translocation_data.enzyme_dict):
length_dependent = enzyme_info['length_dependent']
fixed_keff = enzyme_info['fixed_keff']
multiplier = multiplier_dict.get(enzyme, 1.)
length = protein_length if length_dependent else 1.
# keff = translocation_data.keff
keff = 65. if fixed_keff else translocation_data.keff / length
enzyme_stoichiometry = multiplier * mu / keff / 3600.
stoichiometry[enzyme] -= enzyme_stoichiometry
return stoichiometry
[docs] def update(self, verbose=True):
"""
Creates reaction using the associated posttranslation data and adds
chemical formula to processed protein product
This function adds the following components to the reaction
stoichiometry (using 'data' as shorthand for
:class:`cobrame.core.processdata.PostTranslationData`):
1) Processed protein product defined in data.processed_protein_id
2) Unprocessed protein reactant defined in data.unprocessed_protein_id
3) Metabolites and enzymes defined in data.subreactions
4) Translocation pathways defined in data.translocation
5) Folding mechanism defined in data.folding_mechanims w/ coupling
coefficients defined in data.keq_folding, data.k_folding,
model.global_info['temperature'], data.aggregation_propensity,
and data.propensity_scaling
6) Surface area constraints defined in data.surface_are
7) Biomass if a significant chemical modification takes place (i.e.
lipid modifications for lipoproteins)
Parameters
----------
verbose : bool
Prints when new metabolites are added to the model when executing
update()
"""
self.clear_metabolites()
stoichiometry = defaultdict(float)
metabolites = self._model.metabolites
posttranslation_data = self.posttranslation_data
unprocessed_protein = posttranslation_data.unprocessed_protein_id
processed_protein = posttranslation_data.processed_protein_id
# folding properties
folding_mechanism = posttranslation_data.folding_mechanism
aggregation_propensity = posttranslation_data.aggregation_propensity
scaling = posttranslation_data.propensity_scaling
if folding_mechanism:
temp = str(self._model.global_info['temperature'])
keq_folding = posttranslation_data.keq_folding[temp]
k_folding = posttranslation_data.k_folding[temp] * 3600. # in hr-1
# Get or make processed protein metabolite
try:
protein_met = metabolites.get_by_id(processed_protein)
except KeyError:
protein_met = cobrame.ProcessedProtein(processed_protein,
unprocessed_protein)
self._model.add_metabolites(protein_met)
# Add subreactions (e.g. lipid modifications for lipoproteins)
stoichiometry = self.add_subreactions(posttranslation_data.id,
stoichiometry)
# Add translocation pathways, if applicable
if posttranslation_data.translocation:
stoichiometry = \
self.add_translocation_pathways(posttranslation_data.id,
unprocessed_protein,
stoichiometry)
# Add folding protein coupling coefficients, if applicable
if folding_mechanism == 'folding_spontaneous':
dilution = (keq_folding + mu / k_folding)
stoichiometry[unprocessed_protein] -= (dilution + 1.)
stoichiometry[protein_met.id] += 1.
elif folding_mechanism:
dilution = aggregation_propensity * scaling * (keq_folding + 1.)+1.
stoichiometry[unprocessed_protein] -= (1. / dilution + 1.)
stoichiometry[protein_met.id] += 1. / dilution
stoichiometry[protein_met.id.replace('_folded', '')] += (1.)
else:
stoichiometry[unprocessed_protein] = -1.
stoichiometry[protein_met.id] = 1.
# Add surface area constraints for all translocated proteins, if
# applicable
surface_area = posttranslation_data.surface_area
if surface_area:
for SA, value in iteritems(surface_area):
try:
sa_constraint = metabolites.get_by_id(SA)
except KeyError:
warn('Constraint %s added to model' % SA)
sa_constraint = cobrame.Constraint(SA)
self._model.add_metabolites([sa_constraint])
stoichiometry[sa_constraint.id] += value
# Convert metabolite strings to metabolite objects
object_stoichiometry = self.get_components_from_ids(stoichiometry,
verbose=verbose)
# Add formula as sum of unprocessed protein and modification components
elements = defaultdict(int)
elements.update(metabolites.get_by_id(unprocessed_protein).elements)
elements = \
massbalance.get_elements_from_process_data(self,
posttranslation_data,
elements)
# Convert element dict to formula string and associate it with protein
massbalance.elements_to_formula(protein_met, elements)
# Add biomass from significant modifications (i.e. lipids for
# lipoproteins)
biomass = self.add_biomass_from_subreactions(posttranslation_data)
if biomass > 0 and posttranslation_data.biomass_type:
self.add_metabolites({metabolites.get_by_id(
posttranslation_data.biomass_type): biomass})
elif biomass > 0 and not posttranslation_data.biomass_type:
raise ValueError('If subreactions in PostTranslationData modify '
'the protein, the biomass_type must be provided')
self.add_metabolites(object_stoichiometry, combine=False)
[docs]class TranscriptionReaction(MEReaction):
"""Transcription of a TU to produced TranscribedGene.
RNA is transcribed on a transcription unit (TU) level. This type of
reaction produces all of the RNAs contained within a TU, as well as
accounts for the splicing/excision of RNA between tRNAs and rRNAs.
The appropriate RNA_biomass constrain is produced based on the molecular
weight of the RNAs being transcribed
Parameters
----------
id : str
Identifier of the transcription reaction. As a best practice, this ID
should be prefixed with 'transcription + _'
"""
# TODO double check how initiation is used as well as ATP cost etc.
def __init__(self, id):
MEReaction.__init__(self, id)
self._transcription_data = None
@property
def transcription_data(self):
"""
Get or set the :class:`cobrame.core.processdata.TranscriptionData`
that defines the transcription unit architecture and the features of
the RNAs being transcribed.
"""
return self._transcription_data
@transcription_data.setter
def transcription_data(self, process_data):
if isinstance(process_data, string_types):
process_data = self._model.process_data.get_by_id(process_data)
self._transcription_data = process_data
process_data._parent_reactions.add(self.id)
def _add_formula_to_transcript(self, transcript):
"""
Add element formula to transcript based on nucleotide composition.
1 OH group is removed for each nucleotide to account for polymerization
of mononucleotides. This was done to instead of considering the 3'
diphosphate group as a simplification to avoid keeping track of the
3' nucleotide in cases of transcription unit splicing.
Parameters
----------
transcript : :class:`cobra.core.component.TranscribedGene`
Instance of gene being transcribed
"""
elements = defaultdict(int)
for nuc, value in iteritems(transcript.nucleotide_count):
nuc_obj = self._model.metabolites.get_by_id(nuc)
for e, n in iteritems(nuc_obj.elements):
elements[e] += value * n
# Remove -OH for each
elements['H'] -= len(transcript.nucleotide_sequence)
elements['O'] -= len(transcript.nucleotide_sequence)
massbalance.elements_to_formula(transcript, elements)
def _add_or_update_demand_reaction(self, transcript):
"""
This is in case the TU makes multiple products and one needs a sink.
If the demand reaction is used, it means the RNA biomass doesn't count
toward the overall biomass constraint
Parameters
----------
transcript : :class:`cobrame.core.component.TranscribedGene`
Instance of gene having its demand reaction updated/added
"""
metabolites = self._model.metabolites
demand_reaction_id = "DM_" + transcript.id
if demand_reaction_id not in self._model.reactions:
demand_reaction = cobrame.MEReaction(demand_reaction_id)
self._model.add_reaction(demand_reaction)
demand_reaction.add_metabolites({transcript.id: -1})
else:
demand_reaction = \
self._model.reactions.get_by_id(demand_reaction_id)
mass_in_kda = transcript.formula_weight / 1000.
# Add biomass drain for each demand reaction
if transcript.RNA_type == 'tRNA':
demand_reaction.add_metabolites({
metabolites.tRNA_biomass: -mass_in_kda}, combine=False)
elif transcript.RNA_type == 'rRNA':
demand_reaction.add_metabolites({
metabolites.rRNA_biomass: -mass_in_kda}, combine=False)
elif transcript.RNA_type == 'ncRNA':
demand_reaction.add_metabolites({
metabolites.ncRNA_biomass: -mass_in_kda}, combine=False)
elif transcript.RNA_type == 'mRNA':
demand_reaction.add_metabolites({
metabolites.mRNA_biomass: -mass_in_kda}, combine=False)
[docs] def update(self, verbose=True):
"""
Creates reaction using the associated transcription data and adds
chemical formula to RNA products
This function adds the following components to the reaction
stoichiometry (using 'data' as shorthand for
:class:`cobrame.core.processdata.TranscriptionData`):
1) RNA_polymerase from data.RNA_polymerase w/ coupling
coefficient (if present)
2) RNA products defined in data.RNA_products
3) Nucleotide reactants defined in data.nucleotide_counts
4) If tRNA or rRNA contained in data.RNA_types, excised base products
5) Metabolites + enzymes w/ coupling coefficients defined in
data.subreactions (if present)
6) Biomass :class:`cobrame.core.component.Constraint` corresponding to
data.RNA_products and their associated masses
7) Demand reactions for each transcript product of this reaction
Parameters
----------
verbose : bool
Prints when new metabolites are added to the model when executing
update()
"""
self.clear_metabolites()
tu_id = self.transcription_data.id
stoichiometry = defaultdict(int)
tu_length = len(self.transcription_data.nucleotide_sequence)
rna_polymerase = self.transcription_data.RNA_polymerase
metabolites = self._model.metabolites
# Set Parameters
kt = self._model.global_info['kt']
r0 = self._model.global_info['r0']
m_rr = self._model.global_info['m_rr']
f_rrna = self._model.global_info['f_rRNA']
m_aa = self._model.global_info['m_aa']
c_ribo = m_rr / f_rrna / m_aa
try:
rnap = self._model.metabolites.get_by_id(rna_polymerase)
except KeyError:
warn("RNA Polymerase (%s) not found" % rna_polymerase)
else:
k_rnap = (mu * c_ribo * kt / (mu + kt * r0)) * 3 # (3*k_ribo) hr-1
coupling = -tu_length * mu / k_rnap
stoichiometry[rnap.id] = coupling
# All genes in TU must be added to model prior to creating
# transcription reaction
for transcript_id in self.transcription_data.RNA_products:
if transcript_id not in metabolites:
raise UserWarning("Transcript (%s) not found in model" %
transcript_id)
else:
transcript = self._model.metabolites.get_by_id(transcript_id)
stoichiometry[transcript.id] += 1
self._add_formula_to_transcript(transcript)
# Add modifications and subreactions to reaction stoichiometry
stoichiometry = self.add_subreactions(tu_id, stoichiometry)
base_counts = self.transcription_data.nucleotide_count
for base, count in iteritems(base_counts):
stoichiometry[base] -= count
for base, count in iteritems(self.transcription_data.excised_bases):
stoichiometry[base] += count
stoichiometry["h2o_c"] -= count
stoichiometry['h_c'] += count
stoichiometry["ppi_c"] += tu_length
new_stoich = \
self.get_components_from_ids(stoichiometry, verbose=verbose,
default_type=cobrame.TranscribedGene)
self.add_metabolites(new_stoich, combine=False)
# add biomass constraints for RNA products
trna_mass = rrna_mass = ncrna_mass = mrna_mass = 0.
for met, v in iteritems(new_stoich):
if v < 0 or not hasattr(met, "RNA_type"):
continue
if met.RNA_type == 'tRNA':
trna_mass += met.formula_weight / 1000. # kDa
if met.RNA_type == 'rRNA':
rrna_mass += met.formula_weight / 1000. # kDa
if met.RNA_type == 'ncRNA':
ncrna_mass += met.formula_weight / 1000. # kDa
if met.RNA_type == 'mRNA':
mrna_mass += met.formula_weight / 1000. # kDa
# Add demand of each transcript
self._add_or_update_demand_reaction(met)
# Add the appropriate biomass constraints for each RNA contained in
# the transcription unit
if trna_mass > 0:
self.add_metabolites({metabolites.tRNA_biomass: trna_mass},
combine=False)
if rrna_mass > 0:
self.add_metabolites({metabolites.rRNA_biomass: rrna_mass},
combine=False)
if ncrna_mass > 0:
self.add_metabolites({metabolites.ncRNA_biomass: ncrna_mass},
combine=False)
if mrna_mass > 0:
self.add_metabolites({metabolites.mRNA_biomass: mrna_mass},
combine=False)
# TODO GenericFormation should have update function to account for changes
# in component_list of GenericData
[docs]class TranslationReaction(MEReaction):
"""Reaction class for the translation of a TranscribedGene to a
TranslatedGene
Parameters
----------
id : str
Identifier of the translation reaction. As a best practice, this ID
should be prefixed with 'translation + _'
"""
def __init__(self, id):
MEReaction.__init__(self, id)
self._translation_data = None
@property
def translation_data(self):
"""
Get and set the :class:`cobra.core.processdata.TranslationData` that
defines the translation of the gene. Can be set with instance of
TranslationData or with its id.
Returns
-------
:class:`cobra.core.processdata.TranslationData`
"""
return self._translation_data
@translation_data.setter
def translation_data(self, process_data):
if isinstance(process_data, string_types):
process_data = self._model.process_data.get_by_id(process_data)
self._translation_data = process_data
process_data._parent_reactions.add(self.id)
def _add_formula_to_protein(self, translation_data, protein):
"""
Adds formula to protein based on amino acid sequence and subreactions
Some subreactions modify the composition of the protein, therefore
this must be accounted for.
Water is subtracted from the formula to with a multiplier of
len(amino_acid_sequence) - 1 to account for the condensation
reactions that occur during amino acid polymerization.
Parameters
----------
translation_data : :class:`cobra.core.processdata.TranslationData`
This is required to subtract elements removed/added to protein
when applying reaction defined in subreaction
protein : :class:`cobra.core.processdata.TranslationData`
Protein product that needs a chemical formula
"""
elements = defaultdict(int)
aa_count = self.translation_data.amino_acid_count
for aa_name, value in iteritems(aa_count):
aa_obj = self._model.metabolites.get_by_id(aa_name)
for e, n in iteritems(aa_obj.elements):
elements[e] += n * value
elements = massbalance.get_elements_from_process_data(self,
translation_data,
elements)
# subtract water from composition
protein_length = len(translation_data.amino_acid_sequence)
elements["H"] -= (protein_length - 1) * 2
elements["O"] -= protein_length - 1
massbalance.elements_to_formula(protein, elements)
[docs] def update(self, verbose=True):
"""
Creates reaction using the associated translation data and adds
chemical formula to protein product
This function adds the following components to the reaction
stoichiometry (using 'data' as shorthand for
:class:`cobrame.core.processdata.TranslationData`):
1) Amino acids defined in data.amino_acid_sequence. Subtracting water
to account for condensation reactions during polymerization
2) Ribosome w/ translation coupling coefficient (if present)
3) mRNA defined in data.mRNA w/ translation coupling coefficient
4) mRNA + nucleotides + hydrolysis ATP cost w/ degradation coupling
coefficient (if kdeg (defined in model.global_info) > 0)
5) RNA_degradosome w/ degradation coupling coefficient (if present and
kdeg > 0)
6) Protein product defined in data.protein
7) Subreactions defined in data.subreactions
8) protein_biomass :class:`cobrame.core.component.Constraint`
corresponding to the protein product's mass
9) Subtract mRNA_biomass :class:`cobrame.core.component.Constraint`
defined by mRNA degradation coupling coefficinet (if kdeg > 0)
Parameters
----------
verbose : bool
Prints when new metabolites are added to the model when executing
update()
"""
self.clear_metabolites()
translation_data = self.translation_data
protein_id = translation_data.protein
mrna_id = translation_data.mRNA
protein_length = len(translation_data.amino_acid_sequence)
nucleotide_sequence = translation_data.nucleotide_sequence
model = self._model
metabolites = self._model.metabolites
new_stoichiometry = defaultdict(int)
# Set Parameters
kt = self._model.global_info['kt']
k_deg = self._model.global_info['k_deg']
r0 = self._model.global_info['r0']
m_rr = self._model.global_info['m_rr']
f_rrna = self._model.global_info['f_rRNA']
m_aa = self._model.global_info['m_aa']
m_nt = self._model.global_info['m_nt']
f_mrna = self._model.global_info['f_mRNA']
c_ribo = m_rr / f_rrna / m_aa
c_mrna = m_nt / f_mrna / m_aa
# -----------------Add Amino Acids----------------------------------
for aa, value in iteritems(translation_data.amino_acid_count):
new_stoichiometry[aa] = -value
new_stoichiometry['h2o_c'] += value
# Length protein - 1 dehydration reactions
new_stoichiometry['h2o_c'] -= 1.
# -----------------Add Ribosome Coupling----------------------------
try:
ribosome = metabolites.get_by_id("ribosome")
except KeyError:
warn("ribosome not found")
else:
k_ribo = mu * c_ribo * kt / (mu + kt * r0) # in hr-1
coupling = -protein_length * mu / k_ribo
new_stoichiometry[ribosome.id] = coupling
# -------------------Add mRNA Coupling------------------------------
try:
transcript = metabolites.get_by_id(mrna_id)
except KeyError:
# If transcript not found add to the model as the mRNA_id
warn("transcript ('%s') not found" % mrna_id)
transcript = \
cobrame.TranscribedGene(mrna_id, mrna_id, nucleotide_sequence)
model.add_metabolites(transcript)
# Calculate coupling constraints for mRNA and degradation
k_mrna = mu * c_mrna * kt / (mu + kt * r0) * 3. # 3 nucleotides per AA
rna_amount = mu / k_mrna
deg_amount = k_deg / k_mrna
# Add mRNA coupling to stoichiometry
new_stoichiometry[transcript.id] = -(rna_amount + deg_amount)
# ---------------Add Degradation Requirements -------------------------
# Add degraded nucleotides to stoichiometry
for nucleotide, count in iteritems(transcript.nucleotide_count):
new_stoichiometry[nucleotide] += count * deg_amount
# ATP hydrolysis required for cleaving
nucleotide_length = len(transcript.nucleotide_sequence)
# .25 ATP required per nucleotide hydrolysis
hydrolysis_amount = (nucleotide_length - 1) / 4. * deg_amount
atp_hydrolysis = {'atp_c': -1, 'h2o_c': -1, 'adp_c': 1,
'pi_c': 1, 'h_c': 1}
for metabolite, value in iteritems(atp_hydrolysis):
new_stoichiometry[metabolite] += hydrolysis_amount * value
# Add degradosome coupling, if known
try:
rna_degradosome = metabolites.get_by_id("RNA_degradosome")
except KeyError:
warn("RNA_degradosome not found")
else:
deg_coupling = -deg_amount * mu / 65. / 3600 # keff of degradosome
new_stoichiometry[rna_degradosome.id] = deg_coupling
# --------------- Add Protein to Stoichiometry ------------------------
# Added protein to model if not already included
try:
protein = metabolites.get_by_id(protein_id)
except KeyError:
protein = cobrame.TranslatedGene(protein_id)
model.add_metabolites(protein)
new_stoichiometry[protein.id] = 1
# ------- Convert ids to metabolites and add to model -----------------
# add subreactions to stoichiometry
new_stoichiometry = self.add_subreactions(self.translation_data.id,
new_stoichiometry)
# convert metabolite ids to cobra metabolites
object_stoichiometry = self.get_components_from_ids(new_stoichiometry,
verbose=verbose)
# add metabolites to reaction
self.add_metabolites(object_stoichiometry, combine=False)
# -------------Update Element Dictionary and Formula-------------------
self._add_formula_to_protein(translation_data, protein)
# ------------------ Add biomass constraints --------------------------
# add biomass constraint for protein translated
protein_mass = protein.formula_weight / 1000. # kDa
self.add_metabolites({metabolites.protein_biomass: protein_mass},
combine=False)
# RNA biomass consumed due to degradation
mrna_mass = transcript.formula_weight / 1000. # kDa
self.add_metabolites(
{metabolites.mRNA_biomass: (-mrna_mass * deg_amount)},
combine=False)
[docs]class tRNAChargingReaction(MEReaction):
"""
Reaction class for the charging of a tRNA with an amino acid
Parameters
----------
id : str
Identifier for the charging reaction. As a best practice, ID should
follow the template "charging_tRNA + _ + <tRNA_locus> + _ + <codon>".
If tRNA initiates translation, <codon> should be replaced with START.
"""
def __init__(self, id):
MEReaction.__init__(self, id)
self._tRNA_data = None
@property
def tRNA_data(self):
"""
Get and set the :class:`cobra.core.processdata.tRNAData` that
defines the translation of the gene. Can be set with instance of
tRNAData or with its id.
Returns
-------
:class:`cobra.core.processdata.tRNAData`
"""
return self._tRNA_data
@tRNA_data.setter
def tRNA_data(self, process_data):
if isinstance(process_data, string_types):
process_data = self._model.process_data.get_by_id(process_data)
self._tRNA_data = process_data
process_data._parent_reactions.add(self.id)
[docs] def update(self, verbose=True):
"""
Creates reaction using the associated tRNA data
This function adds the following components to the reaction
stoichiometry (using 'data' as shorthand for
:class:`cobrame.core.processdata.tRNAData`):
1) Charged tRNA product following template:
"generic_tRNA + _ + <data.codon> + _ + <data.amino_acid>"
2) tRNA metabolite (defined in data.RNA) w/ charging coupling
coefficient
3) Charged amino acid (defined in data.amino_acid) w/ charging
coupling coefficient
5) Synthetase (defined in data.synthetase) w/ synthetase coupling
coefficient found, in part, using data.synthetase_keff
6) Post transcriptional modifications defined in data.subreactions
Parameters
----------
verbose : bool
Prints when new metabolites are added to the model when executing
update()
"""
self.clear_metabolites()
new_stoichiometry = defaultdict(float)
data = self.tRNA_data
# set tRNA coupling parameters
m_trna = self._model.global_info['m_tRNA']
m_aa = self._model.global_info['m_aa']
f_trna = self._model.global_info['f_tRNA']
kt = self._model.global_info['kt'] # hr-1
r0 = self._model.global_info['r0']
c_trna = m_trna / m_aa / f_trna
# The meaning of a generic tRNA is described in the
# TranslationReaction comments
generic_trna = "generic_tRNA_" + data.codon + "_" + data.amino_acid
new_stoichiometry[generic_trna] = 1
# Compute tRNA (and amino acid) coupling and add to stoichiometry
trna_keff = c_trna * kt * mu / (mu + r0 * kt) # per hr
trna_amount = mu / trna_keff
new_stoichiometry[data.RNA] = -trna_amount
new_stoichiometry[data.amino_acid] = -trna_amount
# Add synthetase coupling and enzyme, if known
synthetase_amount = mu / data.synthetase_keff / \
3600. * (1 + trna_amount)
if data.synthetase is not None:
new_stoichiometry[data.synthetase] = -synthetase_amount
# Add tRNA modifications to stoichiometry
new_stoichiometry = self.add_subreactions(self.tRNA_data.id,
new_stoichiometry,
scale=trna_amount)
# Convert component ids to cobra metabolites
object_stoichiometry = self.get_components_from_ids(new_stoichiometry,
verbose=verbose)
# Replace reaction stoichiometry with updated stoichiometry
self.add_metabolites(object_stoichiometry)
[docs]class SummaryVariable(MEReaction):
"""
SummaryVariables are reactions that impose global constraints on the model.
The primary example of this is the biomass_dilution SummaryVariable which
forces the rate of biomass production of macromolecules, etc. to be equal
to the rate of their dilution to daughter cells during growth.
Parameters
----------
id : str
Identifier of the SummaryVariable
"""
def __init__(self, id=None):
MEReaction.__init__(self, id)
self._objective_coefficient = 0.