def calculateRequest(self):

        # Request all unique origins of replication and replication forks
        self.oriCs.requestAll()

        # If there are no active forks return
        activeDnaPoly = self.activeDnaPoly.allMolecules()
        if len(activeDnaPoly) == 0:
            return

        # Request all active replication forks
        self.activeDnaPoly.requestAll()

        # Get sequences for all active forks
        sequenceIdx, sequenceLength = activeDnaPoly.attrs(
            'sequenceIdx', 'sequenceLength')

        sequences = buildSequences(self.sequences, sequenceIdx, sequenceLength,
                                   self._dnaPolymeraseElongationRate())

        # Count number of each dNTP in sequences for the next timestep
        sequenceComposition = np.bincount(
            sequences[sequences != polymerize.PAD_VALUE], minlength=4)

        # If one dNTP is limiting then limit the request for the other three by the same ratio
        dNtpsTotal = self.dntps.total()
        maxFractionalReactionLimit = (np.fmin(1, dNtpsTotal /
                                              sequenceComposition)).min()

        # Request dNTPs
        self.dntps.requestIs(maxFractionalReactionLimit * sequenceComposition)
Esempio n. 2
0
    def test_buildSequences(self):
        # Base case
        padding = np.empty((20, 10))
        padding.fill(P)
        allSequences = np.hstack(
            (np.random.randint(3, size=(20, 10)), padding)).astype(np.int8,
                                                                   copy=False)
        sequenceIndexes = np.array([0, 5, 8])
        polymerizedLengths = np.array([0, 4, 9])
        elngRate = 5

        sequences = buildSequences(allSequences, sequenceIndexes,
                                   polymerizedLengths, elngRate)

        comparison_sequence = np.empty((3, elngRate))
        comparison_sequence[0, :] = allSequences[0, 0:elngRate]
        comparison_sequence[1, :] = allSequences[5, 4:(4 + elngRate)]
        comparison_sequence[2, :] = allSequences[8, 9:(9 + elngRate)]

        assert_equal(sequences, comparison_sequence)

        # Un-padded case should throw exception
        allSequences = np.random.randint(3, size=(20, 10)).astype(np.int8,
                                                                  copy=False)
        sequenceIndexes = np.array([0, 5, 8])
        polymerizedLengths = np.array([0, 4, 9])
        elngRate = 5

        # TODO: Define an exeption subclass if you want to check the real message
        self.assertRaises(Exception, buildSequences, allSequences,
                          sequenceIndexes, polymerizedLengths, elngRate)
Esempio n. 3
0
	def calculateRequest(self):
		# Calculate elongation rate based on the current nutrients
		current_nutrients = self._external_states['Environment'].nutrients

		self.rnapElngRate = int(stochasticRound(self.randomState,
			self.rnaPolymeraseElongationRateDict[current_nutrients].asNumber(units.nt / units.s) * self.timeStepSec()))

		# Request all active RNA polymerases
		activeRnaPolys = self.activeRnaPolys.allMolecules()
		if len(activeRnaPolys) == 0:
			return
		self.activeRnaPolys.requestAll()

		# Determine total possible sequences of nucleotides that can be transcribed in this time step for each polymerase
		rnaIndexes, transcriptLengths = activeRnaPolys.attrs('rnaIndex', 'transcriptLength')
		sequences = buildSequences(self.rnaSequences, rnaIndexes, transcriptLengths, self.rnapElngRate)
		sequenceComposition = np.bincount(sequences[sequences != polymerize.PAD_VALUE], minlength = 4)

		# Calculate if any nucleotides are limited and request up to the number in the sequences or number available
		ntpsTotal = self.ntps.total()
		maxFractionalReactionLimit = np.fmin(1, ntpsTotal / sequenceComposition)
		self.ntps.requestIs(maxFractionalReactionLimit * sequenceComposition)

		self.writeToListener("GrowthLimits", "ntpPoolSize", self.ntps.total())
		self.writeToListener("GrowthLimits", "ntpRequestSize", maxFractionalReactionLimit * sequenceComposition)
    def evolveState(self):

        ## Module 1: Replication initiation
        # Get number of active DNA polymerases and oriCs
        activeDnaPoly = self.activeDnaPoly.molecules()
        activePolymerasePresent = (len(activeDnaPoly) > 0)
        oriCs = self.oriCs.molecules()
        n_oric = len(oriCs)
        n_chromosomes = self.full_chromosome.total()[0]

        # If there are no chromosomes and oriC's, return immediately
        if n_oric == 0 and n_chromosomes == 0:
            return

        # Get cell mass
        cellMass = (self.readFromListener("Mass", "cellMass") * units.fg)

        # Get critical initiation mass for simulation medium environment
        current_nutrients = self._external_states['Environment'].nutrients
        self.criticalInitiationMass = self.getDnaCriticalMass(
            self.nutrientToDoublingTime[current_nutrients])

        # Calculate mass per origin of replication, and compare to critical
        # initiation mass. This is a rearrangement of the equation:
        # 	(Cell Mass)/(Number of origins) > Critical mass
        # If the above inequality holds true, initiate a round of chromosome
        # replication for every origin of replication
        massFactor = cellMass / self.criticalInitiationMass
        massPerOrigin = massFactor / n_oric
        replication_initiated = False

        # If conditions are true, initiate a round of replication on every
        # origin of replication
        if massPerOrigin >= 1.0 and self.partialChromosomes.counts().sum(
        ) == 0:
            replication_initiated = True

            # Get replication round indexes of active DNA polymerases
            if activePolymerasePresent:
                replicationRound = activeDnaPoly.attr('replicationRound')
            else:
                # Set to -1 to set values for new polymerases to 0
                replicationRound = np.array([-1])

            # Get chromosome indexes of current oriCs
            chromosomeIndexOriC = oriCs.attr('chromosomeIndex')

            # Calculate number of new DNA polymerases required (4 per origin)
            n_new_polymerase = 4 * n_oric

            # Add new polymerases and oriC's
            activeDnaPolyNew = self.activeDnaPoly.moleculesNew(
                "dnaPolymerase", n_new_polymerase)
            oriCsNew = self.oriCs.moleculesNew("originOfReplication", n_oric)

            # Calculate and set attributes of newly created polymerases
            sequenceIdx = np.tile(np.array([0, 1, 2, 3]), n_oric)
            sequenceLength = np.zeros(n_new_polymerase, dtype=np.int)
            replicationRound = np.ones(
                n_new_polymerase, dtype=np.int) * (replicationRound.max() + 1)

            # Polymerases inherit index of the OriC's they were initiated from
            chromosomeIndexPolymerase = np.repeat(chromosomeIndexOriC, 4)

            activeDnaPolyNew.attrIs(
                sequenceIdx=sequenceIdx,
                sequenceLength=sequenceLength,
                replicationRound=replicationRound,
                chromosomeIndex=chromosomeIndexPolymerase,
            )

            # Calculate and set attributes of newly created oriCs
            # New OriC's share the index of the old OriC's they were
            # replicated from
            oriCsNew.attrIs(chromosomeIndex=chromosomeIndexOriC)

        # Write data from this module to a listener
        self.writeToListener("ReplicationData", "criticalMassPerOriC",
                             massPerOrigin)
        self.writeToListener("ReplicationData", "criticalInitiationMass",
                             self.criticalInitiationMass.asNumber(units.fg))

        ## Module 2: replication elongation
        # If no active polymerases are present, return immediately
        # Note: the new DNA polymerases activated in the previous module are
        # not elongated until the next timestep.
        if len(activeDnaPoly) == 0:
            return

        # Build sequences to polymerize
        dNtpCounts = self.dntps.counts()
        sequenceIdx, sequenceLengths, massDiffDna = activeDnaPoly.attrs(
            'sequenceIdx', 'sequenceLength', 'massDiff_DNA')

        sequences = buildSequences(self.sequences, sequenceIdx,
                                   sequenceLengths,
                                   self._dnaPolymeraseElongationRate())

        # Use polymerize algorithm to quickly calculate the number of
        # elongations each "polymerase" catalyzes
        reactionLimit = dNtpCounts.sum()

        result = polymerize(sequences, dNtpCounts, reactionLimit,
                            self.randomState)

        sequenceElongations = result.sequenceElongation
        dNtpsUsed = result.monomerUsages

        # Compute mass increase for each polymerizing chromosome
        massIncreaseDna = computeMassIncrease(
            sequences, sequenceElongations,
            self.polymerized_dntp_weights.asNumber(units.fg))

        updatedMass = massDiffDna + massIncreaseDna

        # Update positions of each "polymerase"
        updatedLengths = sequenceLengths + sequenceElongations

        activeDnaPoly.attrIs(sequenceLength=updatedLengths,
                             massDiff_DNA=updatedMass)

        # Update counts of polymerized metabolites
        self.dntps.countsDec(dNtpsUsed)
        self.ppi.countInc(dNtpsUsed.sum())

        ## Module 3: replication termination
        # Determine if any polymerases reached the end of their sequences. If
        # so, terminate replication and update the attributes of the remaining
        # polymerases and OriC's to reflect the new chromosome structure.
        terminalLengths = self.sequenceLengths[sequenceIdx]
        didTerminate = (updatedLengths == terminalLengths)

        terminatedChromosomes = np.bincount(sequenceIdx[didTerminate],
                                            minlength=self.sequences.shape[0])

        # If any of the polymerases were terminated, check if all polymerases
        # initiated the same round as the terminated polymerases has already
        # been removed - if they have, update attributes of the remaining
        # polymerases and oriC's, and remove the polymerases. This is not done
        # when some polymerases were initiated in the same timestep, as the
        # attributes for these new polymerases cannot be updated in the same
        # timestep.
        if didTerminate.sum() > 0 and replication_initiated == False:
            # Get attributes from active DNA polymerases and oriC's
            sequenceIdx, chromosomeIndexPolymerase, replicationRound = activeDnaPoly.attrs(
                'sequenceIdx', 'chromosomeIndex', 'replicationRound')
            chromosomeIndexOriC = oriCs.attr('chromosomeIndex')

            # Check that all terminated polymerases were initiated in the same
            # replication round
            assert np.unique(replicationRound[didTerminate]).size == 1

            # Get chromosome indexes of the terminated polymerases
            chromosomeIndexesTerminated = np.unique(
                chromosomeIndexPolymerase[didTerminate])
            newChromosomeIndex = chromosomeIndexPolymerase.max() + 1

            # Get replication round index of the terminated polymerases
            terminatedRound = replicationRound[didTerminate][0]

            for chromosomeIndexTerminated in chromosomeIndexesTerminated:
                # Get all remaining active polymerases initiated in the same
                # replication round and in the given chromosome
                replicationRoundMatch = (replicationRound == terminatedRound)
                chromosomeMatch = (
                    chromosomeIndexPolymerase == chromosomeIndexTerminated)
                remainingPolymerases = np.logical_and(replicationRoundMatch,
                                                      chromosomeMatch)

                # Get all terminated polymerases in the given chromosome
                terminatedPolymerases = np.logical_and(didTerminate,
                                                       chromosomeMatch)

                # If all active polymerases are terminated polymerases, we are
                # ready to split the chromosome and update the attributes.
                if remainingPolymerases.sum() == terminatedPolymerases.sum():

                    # For each set of polymerases initiated in the same
                    # replication round, update the chromosome indexes to a new
                    # index for half of the polymerases.
                    for roundIdx in np.arange(terminatedRound + 1,
                                              replicationRound.max() + 1):
                        replicationRoundMatch = (replicationRound == roundIdx)
                        polymerasesToSplit = np.logical_and(
                            replicationRoundMatch, chromosomeMatch)

                        n_matches = polymerasesToSplit.sum()

                        # Number of polymerases initiated in a single round
                        # must be a multiple of eight.
                        assert n_matches % 8 == 0

                        # Update the chromosome indexes for half of the polymerases
                        secondHalfIdx = np.where(polymerasesToSplit)[0][(
                            n_matches // 2):]
                        chromosomeIndexPolymerase[
                            secondHalfIdx] = newChromosomeIndex

                    # Reset chromosomeIndex for active DNA polymerases
                    activeDnaPoly.attrIs(
                        chromosomeIndex=chromosomeIndexPolymerase)

                    # Get oriC's in the chromosome getting divided
                    chromosomeMatchOriC = (
                        chromosomeIndexOriC == chromosomeIndexTerminated)
                    n_matches = chromosomeMatchOriC.sum()

                    # Number of OriC's in a dividing chromosome should be even
                    assert n_matches % 2 == 0

                    # Update the chromosome indexes for half of the OriC's
                    secondHalfIdx = np.where(chromosomeMatchOriC)[0][(
                        n_matches // 2):]
                    chromosomeIndexOriC[secondHalfIdx] = newChromosomeIndex

                    # Reset chromosomeIndex for oriC's
                    oriCs.attrIs(chromosomeIndex=chromosomeIndexOriC)

                    # Increment the new chromosome index in case another
                    # chromosome needs to be split
                    newChromosomeIndex += 1

            # Delete terminated polymerases
            activeDnaPoly.delByIndexes(np.where(didTerminate)[0])

            # Update counts of newly created chromosome halves. These will be
            # "stitched" together in the ChromosomeFormation process
            self.partialChromosomes.countsInc(terminatedChromosomes)
Esempio n. 5
0
	def evolveState(self):
		ntpCounts = self.ntps.counts()
		self.writeToListener("GrowthLimits", "ntpAllocated", ntpCounts)

		activeRnaPolys = self.activeRnaPolys.molecules()
		if len(activeRnaPolys) == 0:
			return

		# Determine sequences that can be elongated
		rnaIndexes, transcriptLengths, massDiffRna = activeRnaPolys.attrs('rnaIndex', 'transcriptLength', 'massDiff_mRNA')
		sequences = buildSequences(self.rnaSequences, rnaIndexes, transcriptLengths, self.rnapElngRate)
		ntpCountInSequence = np.bincount(sequences[sequences != polymerize.PAD_VALUE], minlength = 4)

		# Polymerize transcripts based on sequences and available nucleotides
		reactionLimit = ntpCounts.sum()
		result = polymerize(sequences, ntpCounts, reactionLimit, self.randomState)
		sequenceElongations = result.sequenceElongation
		ntpsUsed = result.monomerUsages
		nElongations = result.nReactions

		# Calculate changes in mass associated with polymerization and update active polymerases
		massIncreaseRna = computeMassIncrease(sequences, sequenceElongations, self.ntWeights)
		updatedMass = massDiffRna + massIncreaseRna
		didInitialize = (transcriptLengths == 0) & (sequenceElongations > 0)
		updatedLengths = transcriptLengths + sequenceElongations
		updatedMass[didInitialize] += self.endWeight
		activeRnaPolys.attrIs(transcriptLength = updatedLengths, massDiff_mRNA = updatedMass)

		# Determine if transcript has reached the end of the sequence
		terminalLengths = self.rnaLengths[rnaIndexes]
		didTerminate = (updatedLengths == terminalLengths)
		terminatedRnas = np.bincount(rnaIndexes[didTerminate], minlength = self.rnaSequences.shape[0])

		# Remove polymerases that have finished transcription from unique molecules
		activeRnaPolys.delByIndexes(np.where(didTerminate)[0])

		nTerminated = didTerminate.sum()
		nInitialized = didInitialize.sum()
		nElongations = ntpsUsed.sum()

		# Update bulk molecule counts
		self.ntps.countsDec(ntpsUsed)
		self.bulkRnas.countsIs(terminatedRnas)
		self.inactiveRnaPolys.countInc(nTerminated)
		self.ppi.countInc(nElongations - nInitialized)

		# Calculate stalls
		expectedElongations = np.fmin(self.rnapElngRate, terminalLengths - transcriptLengths)
		rnapStalls = expectedElongations - sequenceElongations

		# Write outputs to listeners
		self.writeToListener("TranscriptElongationListener", "countRnaSynthesized", terminatedRnas)
		self.writeToListener("TranscriptElongationListener", "countNTPsUSed", nElongations)
		self.writeToListener("GrowthLimits", "ntpUsed", ntpsUsed)
		self.writeToListener("RnapData", "rnapStalls", rnapStalls)
		self.writeToListener("RnapData", "ntpCountInSequence", ntpCountInSequence)
		self.writeToListener("RnapData", "ntpCounts", ntpCounts)
		self.writeToListener("RnapData", "expectedElongations", expectedElongations.sum())
		self.writeToListener("RnapData", "actualElongations", sequenceElongations.sum())
		self.writeToListener("RnapData", "didTerminate", didTerminate.sum())
		self.writeToListener("RnapData", "terminationLoss", (terminalLengths - transcriptLengths)[didTerminate].sum())
    def calculateRequest(self):
        # Set ribosome elongation rate based on simulation medium environment and elongation rate factor
        # which is used to create single-cell variability in growth rate
        # The maximum number of amino acids that can be elongated in a single timestep is set to 22 intentionally as the minimum number of padding values
        # on the protein sequence matrix is set to 22. If timesteps longer than 1.0s are used, this feature will lead to errors in the effective ribosome
        # elongation rate.

        current_nutrients = self._external_states['Environment'].nutrients

        if self.translationSupply:
            self.ribosomeElongationRate = np.min(
                [
                    self.maxRibosomeElongationRate,
                    int(
                        stochasticRound(
                            self.randomState,
                            self.maxRibosomeElongationRate *
                            self.timeStepSec()))
                ]
            )  # Will be set to maxRibosomeElongationRate if timeStepSec > 1.0s
        else:
            self.ribosomeElongationRate = np.min([
                22,
                int(
                    stochasticRound(
                        self.randomState, self.elngRateFactor *
                        self.ribosomeElongationRateDict[current_nutrients].
                        asNumber(units.aa / units.s) * self.timeStepSec()))
            ])

        # Request all active ribosomes
        self.activeRibosomes.requestAll()

        activeRibosomes = self.activeRibosomes.allMolecules()

        if len(activeRibosomes) == 0:
            return

        # Build sequences to request appropriate amount of amino acids to
        # polymerize for next timestep
        proteinIndexes, peptideLengths = activeRibosomes.attrs(
            'proteinIndex', 'peptideLength')

        sequences = buildSequences(self.proteinSequences, proteinIndexes,
                                   peptideLengths, self.ribosomeElongationRate)

        sequenceHasAA = (sequences != polymerize.PAD_VALUE)
        aasInSequences = np.bincount(sequences[sequenceHasAA], minlength=21)

        if self.translationSupply:
            translationSupplyRate = self.translation_aa_supply[
                current_nutrients] * self.elngRateFactor

            self.writeToListener("RibosomeData", "translationSupply",
                                 translationSupplyRate.asNumber())

            dryMass = (self.readFromListener("Mass", "dryMass") * units.fg)

            molAasRequested = translationSupplyRate * dryMass * self.timeStepSec(
            ) * units.s

            countAasRequested = units.convertNoUnitToNumber(molAasRequested *
                                                            self.nAvogadro)

            countAasRequested = np.fmin(
                countAasRequested, aasInSequences
            )  # Check if this is required. It is a better request but there may be fewer elongations.
        else:
            countAasRequested = aasInSequences

        self.aas.requestIs(countAasRequested)

        self.writeToListener("GrowthLimits", "aaPoolSize", self.aas.total())
        self.writeToListener("GrowthLimits", "aaRequestSize",
                             countAasRequested)

        # Request GTP for polymerization based on sequences
        gtpsHydrolyzed = np.int64(
            np.ceil(self.gtpPerElongation * countAasRequested.sum()))

        self.writeToListener("GrowthLimits", "gtpPoolSize",
                             self.gtp.total()[0])
        self.writeToListener("GrowthLimits", "gtpRequestSize", gtpsHydrolyzed)

        # GTP hydrolysis is carried out in Metabolism process for growth associated maintenence
        # THis is set here for metabolism to use
        self.gtpRequest = gtpsHydrolyzed
    def evolveState(self):
        # Write allocation data to listener
        self.writeToListener("GrowthLimits", "gtpAllocated", self.gtp.count())
        self.writeToListener("GrowthLimits", "aaAllocated", self.aas.counts())

        # Get number of active ribosomes
        activeRibosomes = self.activeRibosomes.molecules()

        self.writeToListener("GrowthLimits", "activeRibosomeAllocated",
                             len(activeRibosomes))

        if len(activeRibosomes) == 0:
            return

        # Build amino acids sequences for each ribosome to polymerize
        proteinIndexes, peptideLengths, massDiffProtein = activeRibosomes.attrs(
            'proteinIndex', 'peptideLength', 'massDiff_protein')

        sequences = buildSequences(self.proteinSequences, proteinIndexes,
                                   peptideLengths, self.ribosomeElongationRate)

        if sequences.size == 0:
            return

        # Calculate elongation resource capacity
        aaCountInSequence = np.bincount(
            sequences[(sequences != polymerize.PAD_VALUE)])
        aaCounts = self.aas.counts()

        # Using polymerization algorithm elongate each ribosome up to the limits
        # of amino acids, sequence, and GTP
        result = polymerize(
            sequences,
            aaCounts,
            10000000,  # Set to a large number, the limit is now taken care of in metabolism
            self.randomState)

        sequenceElongations = result.sequenceElongation
        aasUsed = result.monomerUsages
        nElongations = result.nReactions

        # Update masses of ribosomes attached to polymerizing polypeptides
        massIncreaseProtein = computeMassIncrease(sequences,
                                                  sequenceElongations,
                                                  self.aaWeightsIncorporated)

        updatedLengths = peptideLengths + sequenceElongations

        didInitialize = ((sequenceElongations > 0) & (peptideLengths == 0))

        updatedMass = massDiffProtein + massIncreaseProtein

        updatedMass[didInitialize] += self.endWeight

        # Write current average elongation to listener
        currElongRate = (sequenceElongations.sum() /
                         len(activeRibosomes)) / self.timeStepSec()
        self.writeToListener("RibosomeData", "effectiveElongationRate",
                             currElongRate)

        # Update active ribosomes, terminating if neccessary
        activeRibosomes.attrIs(peptideLength=updatedLengths,
                               massDiff_protein=updatedMass)

        # Ribosomes that reach the end of their sequences are terminated and
        # dissociated into 30S and 50S subunits. The polypeptide that they are polymerizing
        # is converted into a protein in BulkMolecules
        terminalLengths = self.proteinLengths[proteinIndexes]

        didTerminate = (updatedLengths == terminalLengths)

        terminatedProteins = np.bincount(
            proteinIndexes[didTerminate],
            minlength=self.proteinSequences.shape[0])

        activeRibosomes.delByIndexes(np.where(didTerminate)[0])
        self.bulkMonomers.countsInc(terminatedProteins)

        nTerminated = didTerminate.sum()
        nInitialized = didInitialize.sum()

        self.ribosome30S.countInc(nTerminated)
        self.ribosome50S.countInc(nTerminated)

        # Update counts of amino acids and water to reflect polymerization reactions
        self.aas.countsDec(aasUsed)
        self.h2o.countInc(nElongations - nInitialized)

        # Report stalling information
        expectedElongations = np.fmin(self.ribosomeElongationRate,
                                      terminalLengths - peptideLengths)

        ribosomeStalls = expectedElongations - sequenceElongations

        # Write data to listeners
        self.writeToListener("GrowthLimits", "aasUsed", aasUsed)
        self.writeToListener("GrowthLimits", "gtpUsed", self.gtpUsed)

        self.writeToListener("RibosomeData", "ribosomeStalls", ribosomeStalls)
        self.writeToListener("RibosomeData", "aaCountInSequence",
                             aaCountInSequence)
        self.writeToListener("RibosomeData", "aaCounts", aaCounts)

        self.writeToListener("RibosomeData", "expectedElongations",
                             expectedElongations.sum())
        self.writeToListener("RibosomeData", "actualElongations",
                             sequenceElongations.sum())
        self.writeToListener(
            "RibosomeData", "actualElongationHist",
            np.histogram(sequenceElongations, bins=np.arange(0, 23))[0])
        self.writeToListener(
            "RibosomeData", "elongationsNonTerminatingHist",
            np.histogram(sequenceElongations[~didTerminate],
                         bins=np.arange(0, 23))[0])

        self.writeToListener("RibosomeData", "didTerminate",
                             didTerminate.sum())
        self.writeToListener("RibosomeData", "terminationLoss",
                             (terminalLengths -
                              peptideLengths)[didTerminate].sum())
        self.writeToListener("RibosomeData", "numTrpATerminated",
                             terminatedProteins[self.trpAIndex])

        self.writeToListener("RibosomeData", "processElongationRate",
                             self.ribosomeElongationRate / self.timeStepSec())