def test_transcription(): parameters = { 'sequence': toy_chromosome_config['sequence'], 'templates': toy_chromosome_config['promoters'], 'genes': toy_chromosome_config['genes'], 'promoter_affinities': toy_chromosome_config['promoter_affinities'], 'transcription_factors': ['tfA', 'tfB'], 'elongation_rate': 10.0 } chromosome = Chromosome(toy_chromosome_config) transcription = Transcription(parameters) initial_molecules = { nucleotide: 10 for nucleotide in transcription.monomer_ids } initial_molecules['ATP'] = 100000 experiment = process_in_experiment( transcription, { 'initial_state': { 'chromosome': chromosome.to_dict(), 'molecules': initial_molecules, 'proteins': { UNBOUND_RNAP_KEY: 10 }, 'factors': { 'tfA': 0.2, 'tfB': 0.7 } } }) pp(experiment.state.get_value()) experiment.update(10.0) pp(experiment.state.get_value()) print('complete!')
def __init__(self, parameters={}): if self.knowledge_base is None: self.knowledge_base = KnowledgeBase() if self.ecoli_sequence is None: self.ecoli_sequence = read_sequence(ECOLI_GENOME_PATH) self.factor_thresholds = { ('flhDp', 'CRP'): 1e-05 * units.mM, ('fliLp1', 'flhDC'): 1e-06 * units.mM, ('fliLp1', 'fliA'): 1.3e-05 * units.mM, ('fliEp1', 'flhDC'): 4e-06 * units.mM, ('fliEp1', 'fliA'): 1.1e-05 * units.mM, ('fliFp1', 'flhDC'): 7e-06 * units.mM, ('fliFp1', 'fliA'): 1e-05 * units.mM, ('flgBp', 'flhDC'): 1e-05 * units.mM, ('flgBp', 'fliA'): 8e-06 * units.mM, ('flgAp', 'flhDC'): 1.3e-05 * units.mM, ('flgAp', 'fliA'): 6e-06 * units.mM, ('flhBp', 'flhDC'): 1.5e-05 * units.mM, ('flhBp', 'fliA'): 5e-06 * units.mM, ('fliAp1', 'flhDC'): 1.7e-05 * units.mM, ('fliAp1', 'fliA'): 4e-06 * units.mM, ('flgEp', 'flhDC'): 1.9e-05 * units.mM, ('flgEp', 'fliA'): 3e-06 * units.mM, ('fliDp', 'flhDC'): 1.9e-05 * units.mM, ('fliDp', 'fliA'): 3e-06 * units.mM, ('flgKp', 'flhDC'): 2.1e-05 * units.mM, ('flgKp', 'fliA'): 1e-06 * units.mM, ('fliCp', 'fliA'): 5e-06 * units.mM, ('tarp', 'fliA'): 7e-06 * units.mM, ('motAp', 'fliA'): 9e-06 * units.mM, ('flgMp', 'fliA'): 1.1e-06 * units.mM } self.factor_thresholds.update(parameters.get('thresholds', {})) self.chromosome_config = { 'sequence': self.ecoli_sequence, 'genes': { 'flhDC': ['flhD', 'flhC'], 'fliL': ['fliL', 'fliM', 'fliN', 'fliO', 'fliP', 'fliQ', 'fliR'], 'fliE': ['fliE'], 'fliF': ['fliF', 'fliG', 'fliH', 'fliI', 'fliJ', 'fliK'], 'flgA': ['flgA', 'flgM', 'flgN'], 'flgM': ['flgM', 'flgN'], 'flgE': ['flgE'], 'flgB': [ 'flgB', 'flgC', 'flgD', 'flgE', 'flgF', 'flgG', 'flgH', 'flgI', 'flgJ' ], 'flhB': ['flhB', 'flhA', 'flhE'], 'fliA': ['fliA', 'fliZ'], # ignore 'tcyJ' for now 'fliD': ['fliD', 'fliS', 'fliT'], 'flgK': ['flgK', 'flgL'], 'fliC': ['fliC'], 'tar': ['tar', 'tap', 'cheR', 'cheB', 'cheY', 'cheZ'], 'motA': ['motA', 'motB', 'cheA', 'cheW'] }, 'promoters': { 'flhDp': { 'id': 'flhDp', 'position': 1978197, 'direction': -1, 'sites': [{ 'thresholds': { 'CRP': 1e-05 } }], 'terminators': [{ 'position': 1977266, 'strength': 1.0, 'products': ['flhDC'] }] }, 'fliLp1': { 'id': 'fliLp1', 'position': 2019618, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 4e-06 } }, { 'thresholds': { 'fliA': 1.3e-05 } }], 'terminators': [{ 'position': 2023678, 'strength': 1.0, 'products': ['fliL'] }] }, 'fliEp1': { 'id': 'fliEp1', 'position': 2013014, 'direction': -1, 'sites': [{ 'thresholds': { 'flhDC': 5e-06 } }, { 'thresholds': { 'fliA': 1.1e-05 } }], 'terminators': [{ 'position': 2012700, 'strength': 1.0, 'products': ['fliE'] }] }, 'fliFp1': { 'id': 'fliFp1', 'position': 2013229, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 7e-06 } }, { 'thresholds': { 'fliA': 1e-05 } }], 'terminators': [{ 'position': 2019513, 'strength': 1.0, 'products': ['fliF'] }] }, 'flgBp': { 'id': 'flgBp', 'position': 1130863, 'direction': -1, 'sites': [{ 'thresholds': { 'flhDC': 1e-05 } }, { 'thresholds': { 'fliA': 8e-06 } }], 'terminators': [{ 'position': 1129414, 'strength': 1.0, 'products': ['flgA'] }] }, 'flgAp': { 'id': 'flgAp', 'position': 1131018, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 1.3e-05 } }, { 'thresholds': { 'fliA': 6e-06 } }], 'terminators': [{ 'position': 1138312, 'strength': 1.0, 'products': ['flgB'] }] }, 'flhBp': { 'id': 'flhBp', 'position': 1966191, 'direction': -1, 'sites': [{ 'thresholds': { 'flhDC': 1.5e-05 } }, { 'thresholds': { 'fliA': 5e-06 } }], 'terminators': [{ 'position': 1962580, 'strength': 1.0, 'products': ['flhB'] }] }, 'fliAp1': { 'id': 'fliAp1', 'position': 2001789, 'direction': -1, 'sites': [{ 'thresholds': { 'flhDC': 1.7e-05 } }, { 'thresholds': { 'fliA': 4e-06 } }], 'terminators': [{ 'position': 1999585, 'strength': 1.0, 'products': ['fliA'] }] }, 'flgEp': { 'id': 'flgEp', 'position': 1132574, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 1.9e-05 } }, { 'thresholds': { 'fliA': 3e-06 } }], 'terminators': [{ 'position': 1133782, 'strength': 1.0, 'products': ['flgE'] }] }, 'fliDp': { 'id': 'fliDp', 'position': 2003872, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 1.9e-05 } }, { 'thresholds': { 'fliA': 3e-06 } }], 'terminators': [{ 'position': 2006078, 'strength': 1.0, 'products': ['fliD'] }] }, 'flgKp': { 'id': 'flgKp', 'position': 1138378, 'direction': 1, 'sites': [{ 'thresholds': { 'flhDC': 2.1e-05 } }, { 'thresholds': { 'fliA': 1e-06 } }], 'terminators': [{ 'position': 1140986, 'strength': 1.0, 'products': ['flgK'] }] }, 'fliCp': { 'id': 'fliCp', 'position': 2002110, 'direction': 1, 'sites': [{ 'thresholds': { 'fliA': 5e-06 } }], # {'thresholds': {'GadE': 0.55, 'H-NS': 0.6}}], 'terminators': [{ 'position': 2003606, 'strength': 1.0, 'products': ['fliC'] }] }, 'tarp': { 'id': 'tarp', 'position': 1972691, 'direction': -1, 'sites': [{ 'thresholds': { 'fliA': 7e-06 } }], # {'thresholds': {'Fnr': 1e-5}} 'terminators': [{ 'position': 1971030, 'strength': 1.0, 'products': ['tar'] }] }, 'motAp': { 'id': 'motAp', 'position': 1977139, 'direction': -1, 'sites': [{ 'thresholds': { 'fliA': 9e-06 } }], # {'thresholds': {'CpxR': 1e-5}}], 'terminators': [{ 'position': 1976252, 'strength': 1.0, 'products': ['motA'] }] }, 'flgMp': { 'id': 'flgMp', 'position': 1130128, 'direction': -1, 'sites': [{ 'thresholds': { 'fliA': 1.1e-05 } }], # {'thresholds': {'CsgD': 0.1}} 'terminators': [{ 'position': 1129414, 'strength': 1.0, 'products': ['flgM'] }] } }, 'domains': { 0: { 'id': 0, 'lead': 0, 'lag': 0, 'children': [] } }, 'rnaps': {} } # build chromosome and apply thresholds self.chromosome = Chromosome(self.chromosome_config) self.chromosome.apply_thresholds(self.factor_thresholds) self.chromosome_config['promoters'] = { key: promoter.to_dict() for key, promoter in self.chromosome.promoters.items() } self.promoters = [ 'flhDp', 'fliLp1', 'fliEp1', 'fliFp1', 'flgAp', 'flgBp', 'flhBp', 'fliAp1', 'fliDp', 'flgKp', 'fliCp', 'tarp', 'motAp' 'flgMp' ] self.flhDC_activated = [ 'fliLp1', 'fliEp1', 'fliFp1', 'flgAp', 'flgBp', 'flgEp', 'flhBp', 'fliAp1', 'fliDp', 'flgKp' ] self.fliA_activated = ['fliCp', 'tarp', 'motAp', 'flgMp'] flhDC_factors = { 'fliLp1': { 'flhDC': 1.2, 'fliA': 0.25 }, 'fliEp1': { 'flhDC': 0.45, 'fliA': 0.35 }, 'fliFp1': { 'flhDC': 0.35, 'fliA': 0.30 }, 'flgBp': { 'flhDC': 0.35, 'fliA': 0.45 }, 'flgAp': { 'flhDC': 0.15, 'fliA': 0.3 }, 'flgEp': { 'flhDC': 1.0, 'fliA': 4.0 }, 'flhBp': { 'flhDC': 0.1, 'fliA': 0.35 }, 'fliAp1': { 'flhDC': 1.0, 'fliA': 0.3 }, 'fliDp': { 'flhDC': 1.2, 'fliA': 0.25 }, 'flgKp': { 'flhDC': 1.2, 'fliA': 0.25 } } def binary_sum_gates(promoter_factors): affinities = {} first, second = list(promoter_factors[list( promoter_factors.keys())[0]].keys()) # this hard coding of simple addition is alarming and probably points # towards providing a function of promoter state for affinity rather # than a simple lookup of the affinity for each promoter state tuple. for promoter, factors in promoter_factors.items(): affinities[(promoter, first, None)] = factors[first] affinities[(promoter, None, second)] = factors[second] affinities[(promoter, first, second)] = factors[first] + factors[second] return affinities # promoter affinities are binding affinity of RNAP onto promoter self.promoter_affinities = {('flhDp', 'CRP'): 0.01} # self.promoter_affinities[('motAp', 'CpxR')] = 1.0 flhDC_affinities = binary_sum_gates(flhDC_factors) self.promoter_affinities.update(flhDC_affinities) # for promoter in self.flhDC_activated: # self.promoter_affinities[(promoter, 'flhDC')] = 1.0 for promoter in self.fliA_activated: self.promoter_affinities[(promoter, 'fliA')] = 1.0 self.promoter_affinities.update( parameters.get('promoter_affinities', {})) promoter_affinity_scaling = parameters.get('promoter_affinity_scaling', 1) self.promoter_affinities = { promoter: affinity * promoter_affinity_scaling for promoter, affinity in self.promoter_affinities.items() } self.transcripts = [ (operon, product) for operon, products in self.chromosome_config['genes'].items() for product in products ] self.protein_sequences = { (operon, product): self.knowledge_base.proteins[ self.knowledge_base.genes[product]['id']]['seq'] for operon, product in self.transcripts } self.transcript_templates = { key: generate_template(key, len(sequence), [key[1]]) for key, sequence in self.protein_sequences.items() } # transcript affinities are the affinities transcripts to bind a ribosome and translate to protein # transcript affinities are scaled relative to the requirements to build a single full flagellum. self.min_tr_affinity = parameters.get('min_tr_affinity', 1e-1) tr_affinity_scaling = { 'fliL': 2, 'fliM': 34, 'fliG': 26, 'fliH': 12, 'fliI': 6, 'fliD': 5, 'flgE': 120 } self.transcript_affinities = {} for (operon, product) in self.transcripts: self.transcript_affinities[( operon, product)] = self.min_tr_affinity * tr_affinity_scaling.get( product, 1) self.transcript_affinities.update( parameters.get('transcript_affinities', {})) self.transcription_factors = [ 'flhDC', 'fliA', 'CsgD', 'CRP', 'GadE', 'H-NS', 'CpxR', 'Fnr' ] self.complexation_monomer_ids = [ 'fliG', 'fliM', 'fliN', 'flhA', 'flhB', 'flhD', 'flhC', 'fliO', 'fliP', 'fliQ', 'fliR', 'fliJ', 'fliI', 'fliH', 'fliL', 'flgH', 'motA', 'motB', 'flgB', 'flgC', 'flgF', 'flgG', 'flgI', 'fliF', 'fliE', 'fliC', 'flgL', 'flgK', 'fliD', 'flgE' ] self.complexation_complex_ids = [ 'flhDC', 'flagellar motor switch', 'flagella', 'flagellar export apparatus subunit', 'flagellar export apparatus', 'flagellar hook', 'flagellar motor' ] self.complexation_stoichiometry = { 'flhDC': { 'flhD': -4.0, 'flhC': -2.0, 'flhDC': 1.0 }, 'flagellar motor switch reaction': { 'flagellar motor switch': 1.0, 'fliG': -26.0, 'fliM': -34.0, 'fliN': -1.0 }, 'flagellar export apparatus reaction 1': { 'flagellar export apparatus subunit': 1.0, 'flhA': -1.0, 'flhB': -1.0, 'fliO': -1.0, 'fliP': -1.0, 'fliQ': -1.0, 'fliR': -1.0, 'fliJ': -1.0, 'fliI': -6.0 }, 'flagellar export apparatus reaction 2': { 'flagellar export apparatus': 1.0, 'flagellar export apparatus subunit': -1.0, 'fliH': -12.0, }, 'flagellar motor reaction': { 'flagellar motor': 1.0, 'flagellar motor switch': -1.0, 'fliL': -2.0, 'flgH': -1.0, 'motA': -1.0, 'motB': -1.0, 'flgB': -1.0, 'flgC': -1.0, 'flgF': -1.0, 'flgG': -1.0, 'flgI': -1.0, 'fliF': -1.0, 'fliE': -1.0, }, 'flagellar hook reaction': { 'flagellar hook': 1, 'flgE': -120.0, }, 'flagellum reaction': { 'flagella': 1.0, 'flagellar export apparatus': -1.0, 'flagellar motor': -1.0, 'fliC': -1.0, 'flgL': -1.0, 'flgK': -1.0, 'fliD': -5.0, 'flagellar hook': -1, } } reaction_default = 1e-4 self.complexation_rates = { 'flhDC': reaction_default, 'flagellar motor switch reaction': reaction_default, 'flagellar export apparatus reaction 1': reaction_default, 'flagellar export apparatus reaction 2': reaction_default, 'flagellar motor reaction': reaction_default, 'flagellar hook reaction': reaction_default, 'flagellum reaction': reaction_default }
def __init__(self, initial_parameters=None): '''A stochastic transcription model .. WARNING:: Vivarium's knowledge base uses the gene name to name the protein. This means that for a gene acrA that codes for protein AcrA, you must refer to the gene, transcript, and protein each as acrA. :term:`Ports`: * **chromosome**: The linked :term:`store` should hold a representation of the chromosome in the form returned by :py:meth:`vivarium_cell.states.chromosome.Chromosome.to_dict`. * **molecules**: Expects variables with the names in the *molecule_ids* configuration. These are the monomers consumed by transcription. * **factors**: Expects variables for each transcription factor's concentration. * **transcripts**: The linked store should store the concentrations of the transcripts. * **proteins**: The linked store should hold the concentrations of the transcription factors and the RNA polymerase. Arguments: initial_parameters: The following configuration options may be provided: * **promoter_affinities** (:py:class:`dict`): Maps from binding state tuples to the binding affinity of RNA polymerase and the promoter when the promoter is at that binding state. The binding state of a promoter is which (if any) transcription factors are bound to the promoter. Such a binding state can be represented by a binding state tuple, which is a :py:class:`tuple` whose first element is the name of the promoter. All bound transcription factors are listed as subsequent elements. If no transcription factors are bound, the sole subsequent element is ``None``. .. todo:: What is the significance of the order in the binding state tuple? .. todo:: What are the units of the affinities? * **transcription_factors** (:py:class:`list`): A list of all modeled transcription factors. * **sequence**: The DNA sequence that includes all the genes whose transcription is being modeled. * **templates** (:py:class:`dict`): Maps from the name of an operon to that operon's :term:`template specification`. * **genes** (:py:class:`dict`): Maps from operon name to a list of the names of the genes in that operon. * **elongation_rate** (:py:class:`float`): The elongation rate of the RNA polymerase. * **polymerase_occlusion** (:py:class:`int`): The number of base pairs behind the polymerase where another polymerase is occluded and so cannot bind. * **symbol_to_monomer** (:py:class:`dict`): Maps from the symbols used to represent monomers in the RNA sequence to the name of the free monomer. This should generally be :py:data:`cell.data.nucleotides.nucleotides`. * **monomer_ids** (:py:class:`list`): A list of the names of the free monomers consumed by transcription. This can generally be computed as: >>> from vivarium_cell.data.nucleotides import nucleotides >>> monomer_ids = nucleotides.values() >>> print(list(monomer_ids)) ['ATP', 'GTP', 'UTP', 'CTP'] Note that we only included the ``list()`` transformation to make the output prettier. The ``dict_values`` object returned by the ``.values()`` call is sufficiently list-like for use here. * **molecule_ids** (:py:class:`list`): A list of all the molecules needed by the :term:`process`. This will generally be the same as *monomer_ids*. Example configuring the process (uses :py:func:`vivarium.library.pretty.format_dict`): >>> import random >>> >>> import numpy as np >>> >>> from vivarium_cell.states.chromosome import ( ... toy_chromosome_config, ... Chromosome, ... ) >>> from vivarium_cell.data.nucleotides import nucleotides >>> # format_dict lets us print dictionaries prettily >>> from vivarium.library.pretty import format_dict >>> >>> random.seed(0) # Needed because process is stochastic >>> np.random.seed(0) >>> # We will use the toy chromosome from toy_chromosome_config >>> print(toy_chromosome_config) {'sequence': 'ATACGGCACGTGACCGTCAACTTA', 'genes': {'oA': ['eA'], 'oAZ': ['eA', 'eZ'], 'oB': ['eB'], 'oBY': ['eB', 'eY']}, 'promoter_order': ['pA', 'pB'], 'promoters': {'pA': {'id': 'pA', 'position': 3, 'direction': 1, 'sites': [{'position': 0, 'length': 3, 'thresholds': {'tfA': <Quantity(0.3, 'millimolar')>}}], 'terminators': [{'position': 6, 'strength': 0.5, 'products': ['oA']}, {'position': 12, 'strength': 1.0, 'products': ['oAZ']}]}, 'pB': {'id': 'pB', 'position': -3, 'direction': -1, 'sites': [{'position': 0, 'length': 3, 'thresholds': {'tfB': <Quantity(0.5, 'millimolar')>}}], 'terminators': [{'position': -9, 'strength': 0.5, 'products': ['oB']}, {'position': -12, 'strength': 1.0, 'products': ['oBY']}]}}, 'promoter_affinities': {('pA', None): 1.0, ('pA', 'tfA'): 10.0, ('pB', None): 1.0, ('pB', 'tfB'): 10.0}, 'domains': {0: {'id': 0, 'lead': 0, 'lag': 0, 'children': []}}, 'rnaps': {}} >>> monomer_ids = list(nucleotides.values()) >>> configuration = { ... 'promoter_affinities': { ... ('pA', None): 1.0, ... ('pA', 'tfA'): 10.0, ... ('pB', None): 1.0, ... ('pB', 'tfB'): 10.0}, ... 'transcription_factors': ['tfA', 'tfB'], ... 'sequence': toy_chromosome_config['sequence'], ... 'templates': toy_chromosome_config['promoters'], ... 'genes': toy_chromosome_config['genes'], ... 'elongation_rate': 10.0, ... 'polymerase_occlusion': 5, ... 'symbol_to_monomer': nucleotides, ... 'monomer_ids': monomer_ids, ... 'molecule_ids': monomer_ids, ... } >>> # At this point we haven't used the toy chromosome yet >>> # because it will be specified in the chromosome port. >>> # Notice that the parameters are specific to the chromosome. >>> transcription_process = Transcription(configuration) >>> # Now we need to initialize the simulation stores >>> state = { ... 'chromosome': toy_chromosome_config, ... 'molecules': { ... nucleotide: 10 ... for nucleotide in monomer_ids ... }, ... 'proteins': {UNBOUND_RNAP_KEY: 10}, ... 'factors': {'tfA': 0.2 * units.mM, 'tfB': 0.7 * units.mM}, ... } >>> update = transcription_process.next_update(1.0, state) >>> print(update['chromosome']) {'rnaps': {'_add': [{'path': (2,), 'state': <class 'vivarium_cell.states.chromosome.Rnap'>: {'id': 2, 'template': 'pA', 'template_index': 0, 'terminator': 1, 'domain': 0, 'state': 'polymerizing', 'position': 7}}, {'path': (3,), 'state': <class 'vivarium_cell.states.chromosome.Rnap'>: {'id': 3, 'template': 'pB', 'template_index': 1, 'terminator': 0, 'domain': 0, 'state': 'occluding', 'position': 3}}, {'path': (4,), 'state': <class 'vivarium_cell.states.chromosome.Rnap'>: {'id': 4, 'template': 'pA', 'template_index': 0, 'terminator': 0, 'domain': 0, 'state': 'occluding', 'position': 0}}], '_delete': []}, 'rnap_id': 4, 'domains': {0: <class 'vivarium_cell.states.chromosome.Domain'>: {'id': 0, 'lead': 0, 'lag': 0, 'children': []}}, 'root_domain': 0} ''' if not initial_parameters: initial_parameters = {} log.debug( 'inital transcription parameters: {}'.format(initial_parameters)) super(Transcription, self).__init__(initial_parameters) self.derive_defaults('templates', 'promoter_order', keys_list) self.derive_defaults('templates', 'transcript_ids', template_products) self.sequence = self.parameters['sequence'] self.templates = self.parameters['templates'] self.genes = self.parameters['genes'] empty_chromosome = Chromosome({ 'sequence': self.sequence, 'promoters': self.templates, 'genes': self.genes }) self.sequences = empty_chromosome.sequences() self.symbol_to_monomer = self.parameters['symbol_to_monomer'] log.debug('chromosome sequence: {}'.format(self.sequence)) self.promoter_affinities = self.parameters['promoter_affinities'] self.promoter_order = self.parameters['promoter_order'] self.promoter_count = len(self.promoter_order) self.transcription_factors = self.parameters['transcription_factors'] self.molecule_ids = self.parameters['molecule_ids'] self.molecule_ids.extend(['ATP', 'ADP']) self.monomer_ids = self.parameters['monomer_ids'] self.transcript_ids = self.parameters['transcript_ids'] self.elongation = 0 self.elongation_rate = self.parameters['elongation_rate'] self.polymerase_occlusion = self.parameters['polymerase_occlusion'] self.stoichiometry = build_stoichiometry(self.promoter_count) self.initiation = StochasticSystem(self.stoichiometry, random_seed=np.random.randint( 2**31)) self.protein_ids = [UNBOUND_RNAP_KEY] + self.transcription_factors self.initial_domains = self.parameters['initial_domains'] self.concentrations_deriver_key = self.parameters[ 'concentrations_deriver_key'] self.chromosome_ports = ['rnaps', 'rnap_id', 'domains', 'root_domain'] log.debug('final transcription parameters: {}'.format(self.parameters))
def next_update(self, timestep, states): chromosome_state = states['chromosome'] # chromosome_state['rnaps'] = list(chromosome_state['rnaps'].values()) original_rnap_keys = [ rnap['id'] for rnap in chromosome_state['rnaps'].values() ] chromosome = Chromosome(self.chromosome_config(chromosome_state)) molecules = states['molecules'] proteins = states['proteins'] factors = states['factors'] # as concentrations promoter_rnaps = chromosome.promoter_rnaps() promoter_domains = chromosome.promoter_domains() # Find out how many promoters are currently blocked by a # newly initiated or occluding rnap promoter_count = len(chromosome.promoter_order) blocked_promoters = np.zeros(promoter_count, dtype=np.int64) open_domains = {} bound_domains = {} for promoter_index, promoter_key in enumerate( chromosome.promoter_order): domains = [] for rnap in promoter_rnaps.get(promoter_key, {}).values(): if rnap.is_occluding(): domains.append(rnap.domain) blocked_promoters[promoter_index] += 1 bound_domains[promoter_key] = set(domains) open_domains[promoter_key] = promoter_domains[ promoter_key] - bound_domains[promoter_key] blocked_promoters = np.array(blocked_promoters) # Make the state for a gillespie simulation out of total number of each # promoter by copy number not blocked by initiated rnap, # concatenated with the number of each promoter that is bound by rnap. # These are the two states for each promoter the simulation # will operate on, essentially going back and forth between # bound and unbound states. copy_numbers = chromosome.promoter_copy_numbers() original_unbound_rnaps = proteins[UNBOUND_RNAP_KEY] monomer_limits = { monomer: molecules[monomer] for monomer in self.monomer_ids } unbound_rnaps = original_unbound_rnaps time = 0 now = 0 elongation = Elongation(self.sequences, chromosome.promoters, monomer_limits, self.symbol_to_monomer, self.elongation) initiation_affinity = self.build_affinity_vector( chromosome.promoters, factors) while time < timestep: # build the state vector for the gillespie simulation substrate = np.concatenate([ copy_numbers - blocked_promoters, blocked_promoters, [unbound_rnaps] ]) log.debug('transcription substrate: {}'.format(substrate)) log.debug('blocked promoters: {}'.format(blocked_promoters)) # find number of monomers until next terminator distance = 1 / self.elongation_rate # chromosome.terminator_distance() # find interval of time that elongates to the point of the next terminator interval = min(distance, timestep - time) if interval == distance: # perform the elongation until the next event terminations, monomer_limits, chromosome.rnaps = elongation.step( interval, monomer_limits, chromosome.rnaps) unbound_rnaps += terminations else: elongation.store_partial(interval) terminations = 0 log.debug('time: {} --- interval: {}'.format(time, interval)) log.debug('monomer limits: {}'.format(monomer_limits)) log.debug('terminations: {}'.format(terminations)) # run simulation for interval of time to next terminator result = self.initiation.evolve(interval, substrate, initiation_affinity) log.debug('result: {}'.format(result)) # perform binding for now, event in zip(result['time'], result['events']): # RNAP has bound the promoter promoter_key = chromosome.promoter_order[event] promoter = chromosome.promoters[promoter_key] domains = open_domains[promoter_key] domain = choose_element(domains) blocked_promoters[event] += 1 bound_domains[promoter_key].add(domain) open_domains[promoter_key].remove(domain) # create a new bound RNAP and add it to the chromosome. new_rnap = chromosome.bind_rnap(event, domain) new_rnap.start_polymerizing() log.debug('newly bound RNAP: {}'.format(new_rnap)) unbound_rnaps -= 1 # deal with occluding rnap for rnap in chromosome.rnaps.values(): if rnap.is_unoccluding(self.polymerase_occlusion): log.debug('RNAP unoccluding: {}'.format(rnap)) blocked_promoters[rnap.template_index] -= 1 bound_domains[rnap.template].remove(rnap.domain) open_domains[rnap.template].add(rnap.domain) rnap.unocclude() log.debug('rnap: {}'.format(rnap)) log.debug('complete: {}'.format(elongation.complete_polymers)) time += interval # track how far elongation proceeded to start from next iteration self.elongation = elongation.elongation - int(elongation.elongation) proteins = {UNBOUND_RNAP_KEY: unbound_rnaps - original_unbound_rnaps} molecules = { key: count * -1 for key, count in elongation.monomers.items() } # 1 ATP hydrolysis cost per nucleotide elongation molecules['ATP'] = 0 molecules['ADP'] = 0 for count in elongation.monomers.values(): molecules['ATP'] -= count molecules['ADP'] += count chromosome_dict = chromosome.to_dict() rnaps = chromosome_dict['rnaps'] original = set(original_rnap_keys) current = set(rnaps.keys()) bound_rnaps = current - original completed_rnaps = original - current continuing_rnaps = original - completed_rnaps rnap_updates = { rnap_id: rnaps[rnap_id] for rnap_id in continuing_rnaps } add_rnaps = [{ 'path': (bound, ), 'state': rnaps[bound] } for bound in bound_rnaps] delete_rnaps = [(completed, ) for completed in completed_rnaps] rnap_updates['_add'] = add_rnaps rnap_updates['_delete'] = delete_rnaps chromosome_dict['rnaps'] = rnap_updates update = { 'chromosome': {key: chromosome_dict[key] for key in self.chromosome_ports}, 'proteins': proteins, 'molecules': molecules, 'transcripts': elongation.complete_polymers } log.debug('molecules update: {}'.format(update['molecules'])) return update