Beispiel #1
0
def applyInverseLaplaceTransformMethod(kinetics, E0, Elist, densStates, T=None):
    """
    Calculate the microcanonical rate coefficient for a reaction using the
    inverse Laplace transform method, where `kinetics` is the high pressure 
    limit rate coefficient, `E0` is the ground-state energy of the transition
    state, `Elist` is the array of energies in J/mol at which to evaluate the
    microcanonial rate, and `densStates` is the density of states of the
    reactant.
    """
    
    k = numpy.zeros_like((Elist))
    
    if isinstance(kinetics, ArrheniusModel) and (T is not None or (kinetics.Ea >= 0 and kinetics.n >= 0)):
        A = kinetics.A
        n = kinetics.n
        Ea = kinetics.Ea
        dE = Elist[1] - Elist[0]

        # The inverse Laplace transform is not defined for Ea < 0 or n < 0
        # In these cases we move the offending portion into the preexponential
        # at the temperature of interest
        # This is an approximation, but it's not worth a more robust procedure
        if Ea < 0:
            A *= math.exp(-Ea / constants.R / T)
            Ea = 0.0
        if n < 0:
            A *= T**n
            n = 0.0

        if n == 0:
            # Determine the microcanonical rate directly
            s = int(math.floor(Ea / dE))
            for r in range(len(Elist)):
                if Elist[r] > E0 and densStates[r] != 0:
                    k[r] = A * densStates[r - s] / densStates[r]
                    
        elif n > 0.0:
            import scipy.special
            # Evaluate the inverse Laplace transform of the T**n piece, which only
            # exists for n >= 0
            phi = numpy.zeros(len(Elist), numpy.float64)
            for i, E in enumerate(Elist):
                if E == 0.0:
                    phi[i] = 0.0
                else:
                    phi[i] = E**(n-1) / (constants.R**n * scipy.special.gamma(n))
            # Evaluate the convolution
            phi = convolve(phi, densStates, Elist)
            # Apply to determine the microcanonical rate
            s = int(math.floor(Ea / dE))
            for r in range(len(Elist)):
                if Elist[r] > E0 and densStates[r] != 0:
                    k[r] = A * phi[r - s] / densStates[r]

    else:
        raise ReactionError('Unable to use inverse Laplace transform method for non-Arrhenius kinetics or for n < 0.')
    
    return k
    
Beispiel #2
0
    def calculateDensitiesOfStates(self, Elist, E0):
        """
        Calculate and return an array containing the density of states for each
        isomer and reactant channel in the network. `Elist` represents the
        array of energies in J/mol at which to compute each density of states.
        The ground-state energies `E0` in J/mol are used to shift each density
        of states for each configuration to the same zero of energy. The
        returned density of states is in units of mol/J.
        """

        Ngrains = len(Elist)
        Nisom = len(self.isomers)
        Nreac = len(self.reactants)
        densStates = numpy.zeros((Nisom+Nreac, Ngrains), numpy.float64)
        dE = Elist[1] - Elist[0]

        # Densities of states for isomers
        for i in range(Nisom):
            logging.debug('Calculating density of states for isomer "%s"' % self.isomers[i])
            densStates0 = self.isomers[i].states.getDensityOfStates(Elist)
            # Shift to common zero of energy
            r0 = int(round(E0[i] / dE))
            if r0 < 0: r0 = 0
            densStates[i,r0:] = densStates0[:-r0+len(densStates0)]

        # Densities of states for reactant channels
        # (Only if not minimizing the number of density of states calculations)
        if not settings.minimizeDensityOfStatesCalculations:
            for n in range(Nreac):
                r0 = int(round(E0[n+Nisom] / dE))
                if self.reactants[n][0].states is not None and self.reactants[n][1].states is not None:
                    logging.debug('Calculating density of states for reactant channel "%s"' % (' + '.join([str(spec) for spec in self.reactants[n]])))
                    densStates0 = self.reactants[n][0].states.getDensityOfStates(Elist)
                    densStates1 = self.reactants[n][1].states.getDensityOfStates(Elist)
                    densStates0 = states.convolve(densStates0, densStates1, Elist)
                    # Shift to common zero of energy
                    densStates[n+Nisom,r0:] = densStates0[:-r0+len(densStates0)]
                elif self.reactants[n][0].states is not None:
                    logging.debug('Calculating density of states for reactant channel "%s"' % (' + '.join([str(spec) for spec in self.reactants[n]])))
                    densStates0 = self.reactants[n][0].states.getDensityOfStates(Elist)
                    # Shift to common zero of energy
                    densStates[n+Nisom,r0:] = densStates0[:-r0+len(densStates0)]
                elif self.reactants[n][1].states is not None:
                    logging.debug('Calculating density of states for reactant channel "%s"' % (' + '.join([str(spec) for spec in self.reactants[n]])))
                    densStates0 = self.reactants[n][1].states.getDensityOfStates(Elist)
                    # Shift to common zero of energy
                    densStates[n+Nisom,r0:] = densStates0[:-r0+len(densStates0)]
                else:
                    logging.debug('NOT calculating density of states for reactant channel "%s"' % (' + '.join([str(spec) for spec in self.reactants[n]])))
            logging.debug('')

        return densStates