Exemplo n.º 1
0
    def compute(self):
        """
        Compute the pressure-dependent rate coefficients :math:`k(T,P)` for
        the loaded MEASURE calculation.
        """
        
        # Only proceed if the input network is valid
        if self.network is None or self.network.errorString != '':
            raise PDepError('Attempted to run MEASURE calculation with invalid input.')
    
        Nisom = len(self.network.isomers)
        Nreac = len(self.network.reactants)
        Nprod = len(self.network.products)

        network = self.network   
        Tmin = self.Tmin.value
        Tmax = self.Tmax.value
        Tlist = self.Tlist.values
        Pmin = self.Pmin.value
        Pmax = self.Pmax.value
        Plist = self.Plist.values
        method = self.method
        model = self.model
        
        # Calculate the rate coefficients
        K = network.calculateRateCoefficients(Tlist, Plist, method, grainCount=self.grainCount, grainSize=self.grainSize.value)

        # Fit interpolation model
        from rmgpy.reaction import Reaction
        from rmgpy.measure.reaction import fitInterpolationModel
        if model[0] != '':
            logging.info('Fitting {0} interpolation models...'.format(model[0]))
        configurations = []
        configurations.extend([[isom] for isom in network.isomers])
        configurations.extend([reactants for reactants in network.reactants])
        configurations.extend([products for products in network.products])
        for i in range(Nisom+Nreac+Nprod):
            for j in range(Nisom+Nreac):
                if i != j:
                    # Check that we have nonzero k(T,P) values
                    if (numpy.any(K[:,:,i,j]) and not numpy.all(K[:,:,i,j])):
                        raise NetworkError('Zero rate coefficient encountered while updating network {0}.'.format(network))

                    # Make a new net reaction
                    netReaction = Reaction(
                        reactants=configurations[j],
                        products=configurations[i],
                        kinetics=None,
                        reversible=(i<Nisom+Nreac),
                    )
                    network.netReactions.append(netReaction)
                    
                    # Set/update the net reaction kinetics using interpolation model
                    netReaction.kinetics = fitInterpolationModel(netReaction, Tlist, Plist,
                        K[:,:,i,j],
                        model, Tmin, Tmax, Pmin, Pmax, errorCheck=True)
        logging.info('')
Exemplo n.º 2
0
    def compute(self):
        """
        Compute the pressure-dependent rate coefficients :math:`k(T,P)` for
        the loaded MEASURE calculation.
        """
        
        # Only proceed if the input network is valid
        if self.network is None or self.network.errorString != '':
            raise PDepError('Attempted to run MEASURE calculation with invalid input.')
    
        Nisom = len(self.network.isomers)
        Nreac = len(self.network.reactants)
        Nprod = len(self.network.products)

        network = self.network   
        Tmin = self.Tmin.value_si
        Tmax = self.Tmax.value_si
        Tlist = self.Tlist.value_si
        Pmin = self.Pmin.value_si
        Pmax = self.Pmax.value_si
        Plist = self.Plist.value_si
        method = self.method
        model = self.model
        
        # Calculate the rate coefficients
        K = network.calculateRateCoefficients(Tlist, Plist, method, grainCount=self.grainCount, grainSize=self.grainSize.value_si)

        # Fit interpolation model
        from rmgpy.reaction import Reaction
        from rmgpy.measure.reaction import fitInterpolationModel
        if model[0] != '':
            logging.info('Fitting {0} interpolation models...'.format(model[0]))
        configurations = []
        configurations.extend([[isom] for isom in network.isomers])
        configurations.extend([reactants for reactants in network.reactants])
        configurations.extend([products for products in network.products])
        for i in range(Nisom+Nreac+Nprod):
            for j in range(Nisom+Nreac):
                if i != j:
                    # Check that we have nonzero k(T,P) values
                    if (numpy.any(K[:,:,i,j]) and not numpy.all(K[:,:,i,j])):
                        raise NetworkError('Zero rate coefficient encountered while updating network {0}.'.format(network))

                    # Make a new net reaction
                    netReaction = Reaction(
                        reactants=configurations[j],
                        products=configurations[i],
                        kinetics=None,
                        reversible=(i<Nisom+Nreac),
                    )
                    network.netReactions.append(netReaction)
                    
                    # Set/update the net reaction kinetics using interpolation model
                    netReaction.kinetics = fitInterpolationModel(netReaction, Tlist, Plist,
                        K[:,:,i,j],
                        model, Tmin, Tmax, Pmin, Pmax, errorCheck=True)
        logging.info('')
Exemplo n.º 3
0
    def update(self, reactionModel, database, pdepSettings):
        """
        Regenerate the :math:`k(T,P)` values for this partial network if the
        network is marked as invalid.
        """
        from rmgpy.kinetics import Arrhenius, KineticsData
        from rmgpy.measure.collision import SingleExponentialDown
        from rmgpy.measure.reaction import fitInterpolationModel
        from rmgpy.measure.main import MEASURE
        import rmgpy.measure.settings
        
        # Get the parameters for the pressure dependence calculation
        measure = pdepSettings.copy()
        measure.network = self
        outputDirectory = measure.outputFile
        
        Tmin = measure.Tmin.value
        Tmax = measure.Tmax.value
        Pmin = measure.Pmin.value
        Pmax = measure.Pmax.value
        Tlist = measure.Tlist.values
        Plist = measure.Plist.values
        grainSize = measure.grainSize.value
        grainCount = measure.grainCount
        method = measure.method
        model = measure.model
        
        # Figure out which configurations are isomers, reactant channels, and product channels
        self.updateConfigurations(reactionModel)

        # Make sure we have high-P kinetics for all path reactions
        for rxn in self.pathReactions:
            if rxn.kinetics is None and rxn.reverse.kinetics is None:
                raise PressureDependenceError('Path reaction {0} with no high-pressure-limit kinetics encountered in PDepNetwork #{1:d}.'.format(rxn, self.index))
            elif rxn.kinetics is not None and rxn.kinetics.isPressureDependent():
                raise PressureDependenceError('Pressure-dependent kinetics encountered for path reaction {0} in PDepNetwork #{1:d}.'.format(rxn, self.index))
        
        # Do nothing if the network is already valid
        if self.valid: return
        # Do nothing if there are no explored wells
        if len(self.explored) == 0 and len(self.source) > 1: return

        # Generate states data for unimolecular isomers and reactants if necessary
        for spec in self.isomers:
            if spec.states is None: spec.generateStatesData(database)
        for reactants in self.reactants:
            for spec in reactants:
                if spec.states is None: spec.generateStatesData(database)
        # Also generate states data for any path reaction reactants, so we can
        # always apply the ILT method in the direction the kinetics are known
        for reaction in self.pathReactions:
            for spec in reaction.reactants:
                if spec.states is None: spec.generateStatesData(database)
        
        # Determine transition state energies on potential energy surface
        # In the absence of any better information, we simply set it to
        # be the reactant ground-state energy + the activation energy
        # Note that we need Arrhenius kinetics in order to do this
        for rxn in self.pathReactions:
            if rxn.kinetics is None:
                raise Exception('Path reaction "{0}" in PDepNetwork #{1:d} has no kinetics!'.format(rxn, self.index))
            elif isinstance(rxn.kinetics, KineticsData):
                if len(rxn.reactants) == 1:
                    kunits = 's^-1'
                elif len(rxn.reactants) == 2:
                    kunits = 'm^3/(mol*s)'
                elif len(rxn.reactants) == 3:
                    kunits = 'm^6/(mol^2*s)'
                else:
                    kunits = ''
                rxn.kinetics = Arrhenius().fitToData(Tlist=rxn.kinetics.Tdata.values, klist=rxn.kinetics.kdata.values, kunits=kunits)
            elif not isinstance(rxn.kinetics, Arrhenius):
                raise Exception('Path reaction "{0}" in PDepNetwork #{1:d} has invalid kinetics type "{2!s}".'.format(rxn, self.index, rxn.kinetics.__class__))
            rxn.transitionState = rmgpy.species.TransitionState(
                E0=((sum([spec.E0.value for spec in rxn.reactants]) + rxn.kinetics.Ea.value)/1000.,"kJ/mol"),
            )

        # Set collision model
        bathGas = [spec for spec in reactionModel.core.species if not spec.reactive]
        self.bathGas = {}
        for spec in bathGas:
            # is this really the only/best way to weight them? And what is alpha0?
            self.bathGas[spec] = 1.0 / len(bathGas)
            spec.collisionModel = SingleExponentialDown(alpha0=4.86 * 4184)

        # Save input file
        measure.saveInput(os.path.join(outputDirectory, 'pdep', 'network{0:d}_{1:d}.py'.format(self.index, len(self.isomers))))
        
        self.printSummary(level=logging.INFO)

        # Calculate the rate coefficients
        K = self.calculateRateCoefficients(Tlist, Plist, method, grainSize=grainSize, grainCount=grainCount)

        # Generate PDepReaction objects
        configurations = []
        configurations.extend([[isom] for isom in self.isomers])
        configurations.extend([reactants for reactants in self.reactants])
        configurations.extend([products for products in self.products])
        j = configurations.index(self.source)

        for i in range(K.shape[2]):
            if i != j:
                # Find the path reaction
                netReaction = None
                for r in self.netReactions:
                    if r.hasTemplate(configurations[j], configurations[i]):
                        netReaction = r
                # If net reaction does not already exist, make a new one
                if netReaction is None:
                    netReaction = PDepReaction(
                        reactants=configurations[j],
                        products=configurations[i],
                        network=self,
                        kinetics=None
                    )
                    netReaction = reactionModel.makeNewPDepReaction(netReaction)
                    self.netReactions.append(netReaction)

                    # Place the net reaction in the core or edge if necessary
                    # Note that leak reactions are not placed in the edge
                    if all([s in reactionModel.core.species for s in netReaction.reactants]) and all([s in reactionModel.core.species for s in netReaction.products]):
                        reactionModel.addReactionToCore(netReaction)
                    else:
                        reactionModel.addReactionToEdge(netReaction)

                # Set/update the net reaction kinetics using interpolation model
                netReaction.kinetics = fitInterpolationModel(netReaction, Tlist, Plist, K[:,:,i,j], model, Tmin, Tmax, Pmin, Pmax, errorCheck=True)

                # Check: For each net reaction that has a path reaction, make
                # sure the k(T,P) values for the net reaction do not exceed
                # the k(T) values of the path reaction
                # Only check the k(T,P) value at the highest P and lowest T,
                # as this is the one most likely to be in the high-pressure 
                # limit
                t = 0; p = len(Plist) - 1
                for pathReaction in self.pathReactions:
                    if pathReaction.isIsomerization():
                        # Don't check isomerization reactions, since their
                        # k(T,P) values potentially contain both direct and
                        # well-skipping contributions, and therefore could be
                        # significantly larger than the direct k(T) value
                        # (This can also happen for association/dissocation
                        # reactions, but the effect is generally not too large)
                        continue
                    if pathReaction.reactants == netReaction.reactants and pathReaction.products == netReaction.products:
                        kinf = pathReaction.kinetics.getRateCoefficient(Tlist[t])
                        if K[t,p,i,j] > 2 * kinf: # To allow for a small discretization error
                            logging.warning('k(T,P) for net reaction {0} exceeds high-P k(T) by {1:g} at {2:g} K, {3:g} bar'.format(netReaction, K[t,p,i,j] / kinf, Tlist[t], Plist[p]/1e5))
                            logging.info('    k(T,P) = {0:9.2e}    k(T) = {1:9.2e}'.format(K[t,p,i,j], kinf))
                        break
                    elif pathReaction.products == netReaction.reactants and pathReaction.reactants == netReaction.products:
                        kinf = pathReaction.kinetics.getRateCoefficient(Tlist[t]) / pathReaction.getEquilibriumConstant(Tlist[t])
                        if K[t,p,i,j] > 2 * kinf: # To allow for a small discretization error
                            logging.warning('k(T,P) for net reaction {0} exceeds high-P k(T) by {1:g} at {2:g} K, {3:g} bar'.format(netReaction, K[t,p,i,j] / kinf, Tlist[t], Plist[p]/1e5))           
                            logging.info('    k(T,P) = {0:9.2e}    k(T) = {1:9.2e}'.format(K[t,p,i,j], kinf))
                        break
        
        # We're done processing this network, so mark it as valid
        self.valid = True