Source code for vivarium.compartments.flagella_expression

from __future__ import absolute_import, division, print_function

import os
import copy
import argparse
import random
import uuid
import copy
import pytest
import numpy as np

from vivarium.core.process import Generator
from vivarium.core.experiment import Experiment
from vivarium.core.composition import (
    simulate_compartment_in_experiment,
    plot_compartment_topology,
    plot_simulation_output,
    save_flat_timeseries,
    load_timeseries,
    assert_timeseries_close,
    REFERENCE_DATA_DIR,
    COMPARTMENT_OUT_DIR,
)
from vivarium.data.nucleotides import nucleotides
from vivarium.data.amino_acids import amino_acids
from vivarium.data.chromosomes.flagella_chromosome import FlagellaChromosome
from vivarium.plots.gene_expression import plot_timeseries_heatmaps
from vivarium.states.chromosome import Chromosome, rna_bases, sequence_monomers
from vivarium.parameters.parameters import (
    parameter_scan,
    get_parameters_logspace,
    plot_scan_results,
)
from vivarium.core.emitter import path_timeseries_from_embedded_timeseries

# vivarium libraries
from vivarium.library.dict_utils import deep_merge
from vivarium.library.units import units

# processes
from vivarium.processes.transcription import Transcription, UNBOUND_RNAP_KEY
from vivarium.processes.translation import Translation, UNBOUND_RIBOSOME_KEY
from vivarium.processes.degradation import RnaDegradation
from vivarium.processes.complexation import Complexation
from vivarium.processes.convenience_kinetics import ConvenienceKinetics, get_glc_lct_config
from vivarium.processes.metabolism import Metabolism, get_iAF1260b_config
from vivarium.processes.division_volume import DivisionVolume
from vivarium.processes.meta_division import MetaDivision
from vivarium.processes.tree_mass import TreeMass

# compartments
from vivarium.compartments.gene_expression import (
    GeneExpression,
    plot_gene_expression_output,
    gene_network_plot,
)


NAME = 'flagella_gene_expression'
COMPARTMENT_TIMESTEP = 10.0

[docs]def default_metabolism_config(): metabolism_config = get_iAF1260b_config() metabolism_config.update({ 'initial_mass': 1339.0, # fg of metabolite pools 'time_step': COMPARTMENT_TIMESTEP, 'tolerance': { 'EX_glc__D_e': [1.05, 1.0], 'EX_lcts_e': [1.05, 1.0], }}) return metabolism_config
flagella_schema_override = { 'transcription': { 'proteins': { 'CpxR': {'_divider': 'set'}, 'CRP': {'_divider': 'set'}, 'Fnr': {'_divider': 'set'}, 'endoRNAse': {'_divider': 'set'}, } }, 'translation': { 'proteins': { 'CpxR': {'_divider': 'set'}, 'CRP': {'_divider': 'set'}, 'Fnr': {'_divider': 'set'}, 'endoRNAse': {'_divider': 'set'}, } }, }
[docs]def get_flagella_expression_config(config): flagella_data = FlagellaChromosome(config) chromosome_config = flagella_data.chromosome_config sequences = flagella_data.chromosome.product_sequences() return { 'transcription': { 'sequence': chromosome_config['sequence'], 'templates': chromosome_config['promoters'], 'genes': chromosome_config['genes'], 'transcription_factors': flagella_data.transcription_factors, 'promoter_affinities': flagella_data.promoter_affinities, 'polymerase_occlusion': 30, 'elongation_rate': 50}, 'translation': { 'sequences': flagella_data.protein_sequences, 'templates': flagella_data.transcript_templates, 'concentration_keys': ['CRP', 'flhDC', 'fliA'], 'transcript_affinities': flagella_data.transcript_affinities, 'elongation_rate': 22, 'polymerase_occlusion': 50}, 'degradation': { 'sequences': sequences, 'catalytic_rates': { 'endoRNAse': 0.02}, 'michaelis_constants': { 'transcripts': { 'endoRNAse': { transcript: 1e-23 for transcript in chromosome_config['genes'].keys()}}}}, 'complexation': { 'monomer_ids': flagella_data.complexation_monomer_ids, 'complex_ids': flagella_data.complexation_complex_ids, 'stoichiometry': flagella_data.complexation_stoichiometry, 'rates': flagella_data.complexation_rates}, '_schema': copy.deepcopy(flagella_schema_override) }
[docs]class FlagellaExpressionMetabolism(Generator): name = 'flagella_expression_metabolism' defaults = get_flagella_expression_config({}) defaults.update({ 'boundary_path': ('boundary',), 'dimensions_path': ('dimensions',), 'agents_path': ('agents',), # ('..', '..', 'agents',), 'daughter_path': tuple(), 'transport': get_glc_lct_config(), 'metabolism': default_metabolism_config(), 'initial_mass': 0.0 * units.fg, 'time_step': COMPARTMENT_TIMESTEP, 'divide': True, }) def __init__(self, config=None): super(FlagellaExpressionMetabolism, self).__init__(config) if 'agent_id' not in self.config: self.config['agent_id'] = str(uuid.uuid1())
[docs] def generate_processes(self, config): daughter_path = config['daughter_path'] agent_id = config['agent_id'] # get the configs transcription_config = config['transcription'] translation_config = config['translation'] degradation_config = config['degradation'] complexation_config = config['complexation'] # update expression timestep transcription_config.update({'time_step': config['time_step']}) translation_config.update({'time_step': config['time_step']}) degradation_config.update({'time_step': config['time_step']}) complexation_config.update({'time_step': config['time_step']}) # make the expression processes transcription = Transcription(transcription_config) translation = Translation(translation_config) degradation = RnaDegradation(degradation_config) complexation = Complexation(complexation_config) mass_deriver = TreeMass(config.get('mass_deriver', { 'initial_mass': config['initial_mass']})) # Transport transport = ConvenienceKinetics(config['transport']) target_fluxes = transport.kinetic_rate_laws.reaction_ids # Metabolism # add target fluxes from transport metabolism_config = config.get('metabolism') metabolism_config.update({'constrained_reaction_ids': target_fluxes}) metabolism = Metabolism(metabolism_config) # Division condition division_condition = DivisionVolume({}) processes = { 'metabolism': metabolism, 'transport': transport, 'mass_deriver': mass_deriver, 'transcription': transcription, 'translation': translation, 'degradation': degradation, 'complexation': complexation, 'division': division_condition } # divide process set to true, add meta-division processes if config['divide']: meta_division_config = dict( {}, daughter_path=daughter_path, agent_id=agent_id, compartment=self) meta_division = MetaDivision(meta_division_config) processes['meta_division'] = meta_division return processes
[docs] def generate_topology(self, config): boundary_path = config['boundary_path'] dimensions_path = config['dimensions_path'] agents_path = config['agents_path'] external_path = boundary_path + ('external',) topology = { 'mass_deriver': { 'global': boundary_path, }, 'transcription': { 'chromosome': ('chromosome',), 'molecules': ('molecules',), 'proteins': ('proteins',), 'transcripts': ('transcripts',), 'factors': ('concentrations',), 'global': boundary_path, }, 'translation': { 'ribosomes': ('ribosomes',), 'molecules': ('molecules',), 'transcripts': ('transcripts',), 'proteins': ('proteins',), 'concentrations': ('concentrations',), 'global': boundary_path, }, 'degradation': { 'transcripts': ('transcripts',), 'proteins': ('proteins',), 'molecules': ('molecules',), 'global': boundary_path, }, 'complexation': { 'monomers': ('proteins',), 'complexes': ('proteins',), 'global': boundary_path, }, 'transport': { 'internal': ('molecules',), 'external': external_path, 'fields': ('null',), # metabolism's exchange is used 'fluxes': ('flux_bounds',), 'global': boundary_path, 'dimensions': dimensions_path, }, 'metabolism': { 'internal': ('molecules',), 'external': external_path, 'fields': ('fields',), 'reactions': ('reactions',), 'flux_bounds': ('flux_bounds',), 'global': boundary_path, 'dimensions': dimensions_path, }, 'division': { 'global': boundary_path, }, } if config['divide']: topology.update({ 'meta_division': { 'global': boundary_path, 'cells': agents_path, }}) return topology
[docs]def flagella_expression_compartment(config): flagella_expression_config = get_flagella_expression_config(config) return GeneExpression(flagella_expression_config)
[docs]def get_flagella_metabolism_initial_state(ports={}): flagella_data = FlagellaChromosome() chromosome_config = flagella_data.chromosome_config # molecules are set by metabolism return { ports.get( 'transcripts', 'transcripts'): { gene: 0 for gene in chromosome_config['genes'].keys() }, ports.get( 'proteins', 'proteins'): { 'CpxR': 10, 'CRP': 10, 'Fnr': 10, 'endoRNAse': 1, 'flagella': 8, UNBOUND_RIBOSOME_KEY: 100, # e. coli has ~ 20000 ribosomes UNBOUND_RNAP_KEY: 100 } }
[docs]def get_flagella_initial_state(ports={}): flagella_data = FlagellaChromosome() chromosome_config = flagella_data.chromosome_config molecules = {} for nucleotide in nucleotides.values(): molecules[nucleotide] = 5000000 for amino_acid in amino_acids.values(): molecules[amino_acid] = 1000000 return { ports.get( 'molecules', 'molecules'): molecules, ports.get( 'transcripts', 'transcripts'): { gene: 0 for gene in chromosome_config['genes'].keys() }, ports.get( 'proteins', 'proteins'): { 'CpxR': 10, 'CRP': 10, 'Fnr': 10, 'endoRNAse': 1, 'flagella': 8, UNBOUND_RIBOSOME_KEY: 100, # e. coli has ~ 20000 ribosomes UNBOUND_RNAP_KEY: 100 } }
[docs]def make_compartment_topology(compartment, out_dir='out'): settings = {'show_ports': True} plot_compartment_topology( compartment, settings, out_dir)
[docs]def make_flagella_network(out_dir='out'): # load the compartment flagella_compartment = flagella_expression_compartment({}) # make expression network plot flagella_expression_processes = flagella_compartment.generate_processes({}) operons = flagella_expression_processes['transcription'].genes promoters = flagella_expression_processes['transcription'].templates complexes = flagella_expression_processes['complexation'].stoichiometry data = { 'operons': operons, 'templates': promoters, 'complexes': complexes} gene_network_plot(data, out_dir)
[docs]def run_flagella_compartment( compartment, initial_state=None, out_dir='out'): # get flagella data flagella_data = FlagellaChromosome() # run simulation settings = { # a cell cycle of 2520 sec is expected to express 8 flagella. # 2 flagella expected in approximately 630 seconds. 'total_time': 2520, 'emit_step': COMPARTMENT_TIMESTEP, 'verbose': True, 'initial_state': initial_state} timeseries = simulate_compartment_in_experiment(compartment, settings) # save reference timeseries save_timeseries(timeseries, out_dir) plot_config = { 'name': 'flagella_expression', 'ports': { 'transcripts': 'transcripts', 'proteins': 'proteins', 'molecules': 'molecules'}} plot_gene_expression_output( timeseries, plot_config, out_dir) # just-in-time figure plot_config2 = plot_config.copy() plot_config2.update({ 'name': 'flagella', 'plot_ports': { 'transcripts': list(flagella_data.chromosome_config['genes'].keys()), 'proteins': flagella_data.complexation_monomer_ids + flagella_data.complexation_complex_ids, 'molecules': list(nucleotides.values()) + list(amino_acids.values())}}) plot_timeseries_heatmaps( timeseries, plot_config2, out_dir) # make a basic sim output plot_settings = { 'max_rows': 30, 'remove_zeros': True, 'skip_ports': ['chromosome', 'ribosomes']} plot_simulation_output( timeseries, plot_settings, out_dir)
[docs]def test_flagella_metabolism(seed=1): random.seed(seed) np.random.seed(seed) # make the compartment and state compartment = FlagellaExpressionMetabolism({'divide': False}) initial_state = get_flagella_metabolism_initial_state() name = compartment.name # run simulation settings = { 'total_time': 60, 'emit_step': COMPARTMENT_TIMESTEP, 'initial_state': initial_state, } timeseries = simulate_compartment_in_experiment(compartment, settings) # remove non-numerical data for timeseries comparison, convert to path_timeseries del timeseries['chromosome'] del timeseries['ribosomes'] del timeseries['dimensions'] del timeseries['boundary']['divide'] del timeseries['fields'] del timeseries['null'] path_timeseries = path_timeseries_from_embedded_timeseries(timeseries) # # save reference timeseries # out_dir = os.path.join(COMPARTMENT_OUT_DIR, name) # if not os.path.exists(out_dir): # os.makedirs(out_dir) # save_flat_timeseries(path_timeseries, out_dir) reference = load_timeseries( os.path.join(REFERENCE_DATA_DIR, name + '.csv')) assert_timeseries_close(path_timeseries, reference)
[docs]@pytest.mark.slow def test_flagella_expression(): flagella_compartment = flagella_expression_compartment({}) # initial state for flagella complexation initial_state = get_flagella_initial_state() initial_state['proteins'].update({ 'Ribosome': 100, # plenty of ribosomes 'flagella': 0, # required flagella components 'flagellar export apparatus': 1, 'flagellar motor': 1, 'fliC': 1, 'flgL': 1, 'flgK': 1, 'fliD': 5, 'flgE': 120 }) # run simulation random.seed(0) # set seed because process is stochastic settings = { 'total_time': 1000, 'emit_step': 100, 'initial_state': initial_state} timeseries = simulate_compartment_in_experiment(flagella_compartment, settings) print(timeseries['proteins']['flagella']) final_flagella = timeseries['proteins']['flagella'][-1] # this should have been long enough for flagellar complexation to occur assert final_flagella > 0
[docs]def scan_flagella_expression_parameters(): compartment = flagella_expression_compartment({}) flagella_data = FlagellaChromosome() # conditions conditions = {} # parameters scan_params = {} # # add promoter affinities # for promoter in flagella_data.chromosome_config['promoters'].keys(): # scan_params[('promoter_affinities', promoter)] = get_parameters_logspace(1e-3, 1e0, 4) # scan minimum transcript affinity -- other affinities are a scaled factor of this value scan_params[('min_tr_affinity', flagella_data.min_tr_affinity)] = get_parameters_logspace(1e-2, 1e2, 6) # # add transcription factor thresholds # for threshold in flagella_data.factor_thresholds.keys(): # scan_params[('thresholds', threshold)] = get_parameters_logspace(1e-7, 1e-4, 4) # metrics metrics = [ ('proteins', monomer) for monomer in flagella_data.complexation_monomer_ids] + [ ('proteins', complex) for complex in flagella_data.complexation_complex_ids] print('number of parameters: {}'.format(len(scan_params))) # TODO -- get this down to 10 # run the scan scan_config = { 'compartment': compartment, 'scan_parameters': scan_params, 'conditions': conditions, 'metrics': metrics, 'settings': {'total_time': 480}} results = parameter_scan(scan_config) return results
if __name__ == '__main__': out_dir = os.path.join(COMPARTMENT_OUT_DIR, NAME) if not os.path.exists(out_dir): os.makedirs(out_dir) # run scan with python vivarium/compartments/flagella_expression.py --scan parser = argparse.ArgumentParser(description='flagella expression') parser.add_argument('--scan', '-s', action='store_true', default=False,) parser.add_argument('--network', '-n', action='store_true', default=False,) parser.add_argument('--topology', '-t', action='store_true', default=False,) parser.add_argument('--metabolism', '-m', action='store_true', default=False, ) args = parser.parse_args() if args.scan: results = scan_flagella_expression_parameters() plot_scan_results(results, out_dir) elif args.network: make_flagella_network(out_dir) elif args.topology: compartment = flagella_expression_compartment({}) make_compartment_topology( compartment, out_dir ) elif args.metabolism: mtb_out_dir = os.path.join(out_dir, 'metabolism') if not os.path.exists(mtb_out_dir): os.makedirs(mtb_out_dir) compartment = FlagellaExpressionMetabolism({'divide': False}) make_compartment_topology( compartment, mtb_out_dir ) run_flagella_compartment( compartment, get_flagella_metabolism_initial_state(), mtb_out_dir ) else: compartment = flagella_expression_compartment({}) run_flagella_compartment( compartment, get_flagella_initial_state(), out_dir )