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('')
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('')
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