def getKinetics(self): """ Extracts the kinetic data from the chemkin file for plotting purposes. """ from rmgpy.chemkin import loadChemkinFile from rmgpy.kinetics import ArrheniusEP, Chebyshev from rmgpy.reaction import Reaction from rmgpy.data.base import Entry kineticsDataList = [] chemkinPath = self.path + "/chemkin/chem.inp" dictionaryPath = self.path + "RMG_Dictionary.txt" speciesList, reactionList = loadChemkinFile(chemkinPath, dictionaryPath) for reaction in reactionList: # If the kinetics are ArrheniusEP, replace them with Arrhenius if isinstance(reaction.kinetics, ArrheniusEP): reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298)) reactants = " + ".join([moleculeToInfo(reactant) for reactant in reaction.reactants]) arrow = "⇔" if reaction.reversible else "→" products = " + ".join([moleculeToInfo(reactant) for reactant in reaction.products]) source = str(reaction).replace("<=>", "=") href = reaction.getURL() entry = Entry() entry.result = reactionList.index(reaction) + 1 forwardKinetics = reaction.kinetics forward = True chemkin = reaction.toChemkin(speciesList) reverseKinetics = reaction.generateReverseRateCoefficient() reverseKinetics.comment = "Fitted reverse reaction. " + reaction.kinetics.comment rev_reaction = Reaction(reactants=reaction.products, products=reaction.reactants, kinetics=reverseKinetics) chemkin_rev = rev_reaction.toChemkin(speciesList) kineticsDataList.append( [ reactants, arrow, products, entry, forwardKinetics, source, href, forward, chemkin, reverseKinetics, chemkin_rev, ] ) return kineticsDataList
def getKinetics(self): """ Extracts the kinetic data from the chemkin file for plotting purposes. """ from rmgpy.chemkin import loadChemkinFile from rmgpy.kinetics import ArrheniusEP, Chebyshev from rmgpy.reaction import Reaction from rmgpy.data.base import Entry kineticsDataList = [] chemkinPath= self.path + '/chemkin/chem.inp' dictionaryPath = self.path + 'RMG_Dictionary.txt' if self.Foreign: readComments = False else: readComments = True if os.path.exists(dictionaryPath): speciesList, reactionList = loadChemkinFile(chemkinPath, dictionaryPath, readComments=readComments) else: speciesList, reactionList = loadChemkinFile(chemkinPath, readComments=readComments) for reaction in reactionList: # If the kinetics are ArrheniusEP, replace them with Arrhenius if isinstance(reaction.kinetics, ArrheniusEP): reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298)) if os.path.exists(dictionaryPath): reactants = ' + '.join([moleculeToInfo(reactant) for reactant in reaction.reactants]) arrow = '⇔' if reaction.reversible else '→' products = ' + '.join([moleculeToInfo(product) for product in reaction.products]) href = reaction.getURL() else: reactants = ' + '.join([reactant.label for reactant in reaction.reactants]) arrow = '⇔' if reaction.reversible else '→' products = ' + '.join([product.label for product in reaction.products]) href = '' source = str(reaction).replace('<=>','=') entry = Entry() entry.result = reactionList.index(reaction)+1 forwardKinetics = reaction.kinetics forward = True chemkin = reaction.toChemkin(speciesList) reverseKinetics = reaction.generateReverseRateCoefficient() reverseKinetics.comment = 'Fitted reverse reaction. ' + reaction.kinetics.comment rev_reaction = Reaction(reactants = reaction.products, products = reaction.reactants, kinetics = reverseKinetics) chemkin_rev = rev_reaction.toChemkin(speciesList) kineticsDataList.append([reactants, arrow, products, entry, forwardKinetics, source, href, forward, chemkin, reverseKinetics, chemkin_rev]) return kineticsDataList
def loadOld(self, path): """ Load an old-style RMG kinetics library from the location `path`. """ path = os.path.abspath(path) self.loadOldDictionary( os.path.join(path, 'species.txt'), pattern=False) species = dict([(label, Species(label=label, molecule=[entry.item])) for label, entry in self.entries.iteritems()]) # Add common bath gases (Ar, Ne, He, N2) if not already present for label, smiles in [('Ar', '[Ar]'), ('He', '[He]'), ('Ne', '[Ne]'), ('N2', 'N#N')]: if label not in species: molecule = Molecule().fromSMILES(smiles) spec = Species(label=label, molecule=[molecule]) species[label] = spec reactions = [] reactions.extend( self.__loadOldReactions( os.path.join(path, 'reactions.txt'), species)) if os.path.exists(os.path.join(path, 'pdepreactions.txt')): pdep_reactions = self.__loadOldReactions( os.path.join(path, 'pdepreactions.txt'), species) # RMG-Py likes otherwise equivalent PDep and non-pdep reactions to be marked as duplicates self.markValidDuplicates(reactions, pdep_reactions) reactions.extend(pdep_reactions) self.entries = {} for index, reaction in enumerate(reactions): entry = Entry( index=index + 1, item=reaction, data=reaction.kinetics, ) entry.longDesc = reaction.kinetics.comment reaction.kinetics.comment = '' self.entries[index + 1] = entry reaction.kinetics = None self.checkForDuplicates() self.convertDuplicatesToMulti()
label = species.label, molecule = species.molecule[0].toAdjacencyList(removeH = removeH), thermo = species.thermo, shortDesc = species.thermo.comment ) else: logging.warning('Species {0} did not contain any thermo data and was omitted from the thermo library.'.format(str(species))) # load kinetics library entries kineticsLibrary = KineticsLibrary() kineticsLibrary.entries = {} for i in range(len(reactionList)): reaction = reactionList[i] entry = Entry( index = i+1, item = reaction, data = reaction.kinetics, ) entry.longDesc = reaction.kinetics.comment kineticsLibrary.entries[i+1] = entry kineticsLibrary.checkForDuplicates() kineticsLibrary.convertDuplicatesToMulti() # Assign history to all entries user = getUsername() # Pulls username from current git repository #user = '******'.format(name, email) # If not in git repository, then enter user information manually event = [time.asctime(),user,'action','{0} imported this entry from the old RMG database.'.format(user)] for label, entry in thermoLibrary.entries.iteritems(): entry.history.append(event) for label, entry in kineticsLibrary.entries.iteritems():
def kineticsGroupEstimateEntry( request, family, reactant1, product1, reactant2="", reactant3="", product2="", product3="" ): """ View a kinetics group estimate as an entry. """ # Load the kinetics database if necessary loadDatabase("kinetics", "families") # Also load the thermo database so we can generate reverse kinetics if necessary loadDatabase("thermo") # we need 'database' to reference the top level object that we pass to generateReactions from tools import database # check the family exists try: getKineticsDatabase("families", family + "/groups") except ValueError: raise Http404 reactantList = [] reactantList.append(moleculeFromURL(reactant1)) if reactant2 != "": reactantList.append(moleculeFromURL(reactant2)) if reactant3 != "": reactantList.append(moleculeFromURL(reactant3)) productList = [] productList.append(moleculeFromURL(product1)) if product2 != "": productList.append(moleculeFromURL(product2)) if product3 != "": productList.append(moleculeFromURL(product3)) # Search for the corresponding reaction(s) reactionList, empty_list = generateReactions(database, reactantList, productList, only_families=[family]) kineticsDataList = [] # discard all the rates from depositories and rules reactionList = [reaction for reaction in reactionList if isinstance(reaction, TemplateReaction)] # if there are still two, only keep the forward direction if len(reactionList) == 2: reactionList = [reaction for reaction in reactionList if reactionHasReactants(reaction, reactantList)] assert len(reactionList) == 1, "Was expecting one group estimate rate, not {0}".format(len(reactionList)) reaction = reactionList[0] # Generate the thermo data for the species involved for reactant in reaction.reactants: generateSpeciesThermo(reactant, database) for product in reaction.products: generateSpeciesThermo(product, database) # If the kinetics are ArrheniusEP, replace them with Arrhenius if isinstance(reaction.kinetics, ArrheniusEP): reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298)) reactants = " + ".join([moleculeToInfo(reactant) for reactant in reaction.reactants]) arrow = "⇔" if reaction.reversible else "→" products = " + ".join([moleculeToInfo(reactant) for reactant in reaction.products]) assert isinstance(reaction, TemplateReaction), "Expected group additive kinetics to be a TemplateReaction" source = "%s (RMG-Py Group additivity)" % (reaction.family.name) entry = Entry( item=reaction, data=reaction.kinetics, longDesc=reaction.kinetics.comment, shortDesc="Estimated by RMG-Py Group Additivity", ) # Get the entry as a entry_string, to populate the New Entry form # first, replace the kinetics with a fitted arrhenius form with no comment entry.data = reaction.kinetics.toArrhenius() entry.data.comment = "" entry_buffer = StringIO.StringIO(u"") rmgpy.data.kinetics.saveEntry(entry_buffer, entry) entry_string = entry_buffer.getvalue() entry_buffer.close() # replace the kinetics with the original ones entry.data = reaction.kinetics entry_string = re.sub("^entry\(\n", "", entry_string) # remove leading entry( entry_string = re.sub("\s*index = -?\d+,\n", "", entry_string) # remove the 'index = 23,' (or -1)line entry_string = re.sub( "\s+history = \[.*", "", entry_string, flags=re.DOTALL ) # remove the history and everything after it (including the final ')' ) new_entry_form = KineticsEntryEditForm(initial={"entry": entry_string}) forwardKinetics = reaction.kinetics reverseKinetics = reaction.generateReverseRateCoefficient() forward = reactionHasReactants(reaction, reactantList) # boolean: true if template reaction in forward direction reactants = " + ".join([moleculeToInfo(reactant) for reactant in reaction.reactants]) products = " + ".join([moleculeToInfo(reactant) for reactant in reaction.products]) reference = rmgpy.data.reference.Reference( url=request.build_absolute_uri( reverse(kinetics, kwargs={"section": "families", "subsection": family + "/groups"}) ) ) referenceType = "" entry.index = -1 reactionUrl = getReactionUrl(reaction) return render_to_response( "kineticsEntry.html", { "section": "families", "subsection": family, "databaseName": family, "entry": entry, "reactants": reactants, "arrow": arrow, "products": products, "reference": reference, "referenceType": referenceType, "kinetics": reaction.kinetics, "reactionUrl": reactionUrl, "reaction": reaction, "new_entry_form": new_entry_form, }, context_instance=RequestContext(request), )
def getLibraries(self): name = 'kineticsjobs' speciesList = self.speciesDict.values() reactionList = self.reactionDict.values() # remove duplicate species for rxn in reactionList: for i,rspc in enumerate(rxn.reactants): for spc in speciesList: if spc.isIsomorphic(rspc): rxn.reactants[i] = spc break for i,rspc in enumerate(rxn.products): for spc in speciesList: if spc.isIsomorphic(rspc): rxn.products[i] = spc break del_inds = [] for i,spc1 in enumerate(speciesList): for j,spc2 in enumerate(speciesList): if j>i and spc1.isIsomorphic(spc2): del_inds.append(j) for j in sorted(del_inds)[::-1]: del speciesList[j] thermoLibrary = ThermoLibrary(name=name) for i,species in enumerate(speciesList): if species.thermo: thermoLibrary.loadEntry(index = i + 1, label = species.label, molecule = species.molecule[0].toAdjacencyList(), thermo = species.thermo, shortDesc = species.thermo.comment ) else: logging.warning('Species {0} did not contain any thermo data and was omitted from the thermo library.'.format(str(species))) # load kinetics library entries kineticsLibrary = KineticsLibrary(name=name,autoGenerated=True) kineticsLibrary.entries = {} for i,reaction in enumerate(reactionList): entry = Entry( index = i+1, label = reaction.toLabeledStr(), item = reaction, data = reaction.kinetics, ) if reaction.kinetics is not None: if hasattr(reaction,'library') and reaction.library: entry.longDesc = 'Originally from reaction library: ' +\ reaction.library + "\n" + reaction.kinetics.comment else: entry.longDesc = reaction.kinetics.comment kineticsLibrary.entries[i+1] = entry kineticsLibrary.label = name return thermoLibrary,kineticsLibrary,speciesList
def loadEntry( self, index, group1=None, group2=None, group3=None, group4=None, kinetics=None, degeneracy=1, label='', duplicate=False, reversible=True, reference=None, referenceType='', shortDesc='', longDesc='', rank=None, ): reactants = [] if group1[0:3].upper() == 'OR{' or group1[0:4].upper( ) == 'AND{' or group1[0:7].upper() == 'NOT OR{' or group1[0:8].upper( ) == 'NOT AND{': reactants.append(makeLogicNode(group1)) else: reactants.append(Group().fromAdjacencyList(group1)) if group2 is not None: if group2[0:3].upper() == 'OR{' or group2[0:4].upper( ) == 'AND{' or group2[0:7].upper( ) == 'NOT OR{' or group2[0:8].upper() == 'NOT AND{': reactants.append(makeLogicNode(group2)) else: reactants.append(Group().fromAdjacencyList(group2)) if group3 is not None: if group3[0:3].upper() == 'OR{' or group3[0:4].upper( ) == 'AND{' or group3[0:7].upper( ) == 'NOT OR{' or group3[0:8].upper() == 'NOT AND{': reactants.append(makeLogicNode(group3)) else: reactants.append(Group().fromAdjacencyList(group3)) if group4 is not None: if group4[0:3].upper() == 'OR{' or group4[0:4].upper( ) == 'AND{' or group4[0:7].upper( ) == 'NOT OR{' or group4[0:8].upper() == 'NOT AND{': reactants.append(makeLogicNode(group4)) else: reactants.append(Group().fromAdjacencyList(group4)) reaction = Reaction(reactants=reactants, products=[]) entry = Entry( index=index, label=label, item=reaction, data=kinetics, reference=reference, referenceType=referenceType, shortDesc=shortDesc, longDesc=longDesc.strip(), rank=rank, ) try: self.entries[label].append(entry) except KeyError: self.entries[label] = [entry] return entry
def fillRulesByAveragingUp(self, rootTemplate, alreadyDone): """ Fill in gaps in the kinetics rate rules by averaging child nodes. """ rootLabel = ';'.join([g.label for g in rootTemplate]) if rootLabel in alreadyDone: return alreadyDone[rootLabel] # See if we already have a rate rule for this exact template entry = self.getRule(rootTemplate) if entry is not None and entry.rank > 0: # We already have a rate rule for this exact template # If the entry has rank of zero, then we have so little faith # in it that we'd rather use an averaged value if possible # Since this entry does not have a rank of zero, we keep its # value alreadyDone[rootLabel] = entry.data return entry.data # Recursively descend to the child nodes childrenList = [[group] for group in rootTemplate] for group in childrenList: parent = group.pop(0) if len(parent.children) > 0: group.extend(parent.children) else: group.append(parent) childrenList = getAllCombinations(childrenList) kineticsList = [] for template in childrenList: label = ';'.join([g.label for g in template]) if template == rootTemplate: continue if label in alreadyDone: kinetics = alreadyDone[label] else: kinetics = self.fillRulesByAveragingUp(template, alreadyDone) if kinetics is not None: kineticsList.append([kinetics, template]) if len(kineticsList) > 0: # We found one or more results! Let's average them together kinetics = self.__getAverageKinetics([k for k, t in kineticsList]) kinetics.comment += 'Average of ({0}). '.format( ' + '.join([ k.comment if k.comment != '' else ','.join([g.label for g in t]) for k, t in kineticsList ]), ) entry = Entry( index=0, label=rootLabel, item=rootTemplate, data=kinetics, rank=10, # Indicates this is an averaged estimate ) self.entries[entry.label] = [entry] alreadyDone[rootLabel] = entry.data return entry.data alreadyDone[rootLabel] = None return None
label = species.label, molecule = species.molecule[0].toAdjacencyList(), thermo = species.thermo, shortDesc = species.thermo.comment ) else: logging.warning('Species {0} did not contain any thermo data and was omitted from the thermo library.'.format(str(species))) # load kinetics library entries kineticsLibrary = KineticsLibrary(name=name) kineticsLibrary.entries = {} for i in range(len(reactionList)): reaction = reactionList[i] entry = Entry( index = i+1, label = str(reaction), item = reaction, data = reaction.kinetics, ) try: entry.longDesc = 'Originally from reaction library: ' + reaction.library + "\n" + reaction.kinetics.comment except AttributeError: entry.longDesc = reaction.kinetics.comment kineticsLibrary.entries[i+1] = entry # Mark as duplicates where there are mixed pressure dependent and non-pressure dependent duplicate kinetics # Even though CHEMKIN does not require a duplicate flag, RMG needs it. # Using flag markDuplicates = True kineticsLibrary.checkForDuplicates(markDuplicates=True) kineticsLibrary.convertDuplicatesToMulti() # Save in Py format
def save_kinetics_lib(rxn_list, path, name, lib_long_desc): """ Save an RMG kinetics library of all reactions in `rxn_list` in the supplied `path`. `rxn_list` is a list of ARCReaction objects. `name` is the library's name (or project's name). `long_desc` is a multiline string with level of theory description. """ entries = dict() if rxn_list: for i, rxn in enumerate(rxn_list): if rxn.kinetics is not None: if len(rxn.rmg_reaction.reactants): reactants = rxn.rmg_reaction.reactants products = rxn.rmg_reaction.products elif rxn.r_species.mol_list is not None: reactants = [ Species(molecule=arc_spc.mol_list) for arc_spc in rxn.r_species ] products = [ Species(molecule=arc_spc.mol_list) for arc_spc in rxn.p_species ] elif rxn.r_species.mol is not None: reactants = [ Species(molecule=[arc_spc.mol]) for arc_spc in rxn.r_species ] products = [ Species(molecule=[arc_spc.mol]) for arc_spc in rxn.p_species ] else: reactants = [ Species(molecule=[arc_spc.xyz_mol]) for arc_spc in rxn.r_species ] products = [ Species(molecule=[arc_spc.xyz_mol]) for arc_spc in rxn.p_species ] rxn.rmg_reaction.reactants = reactants rxn.rmg_reaction.products = products entry = Entry(index=i, item=rxn.rmg_reaction, data=rxn.kinetics, label=rxn.label) rxn.ts_species.make_ts_report() entry.longDesc = rxn.ts_species.ts_report + '\n\nOptimized TS geometry:\n' + rxn.ts_species.final_xyz rxn.rmg_reaction.kinetics = rxn.kinetics rxn.rmg_reaction.kinetics.comment = str('') entries[i + 1] = entry else: logger.warning( 'Reaction {0} did not contain any kinetic data and was omitted from the kinetics' ' library.'.format(rxn.label)) kinetics_library = KineticsLibrary(name=name, longDesc=lib_long_desc, autoGenerated=True) kinetics_library.entries = entries lib_path = os.path.join(path, 'kinetics', '') if os.path.exists(lib_path): shutil.rmtree(lib_path) try: os.makedirs(lib_path) except OSError: pass kinetics_library.save(os.path.join(lib_path, 'reactions.py')) kinetics_library.saveDictionary( os.path.join(lib_path, 'dictionary.txt'))
def generateAdditionalRateRules(family, database): """ For a given reaction `family` label, generate additional rate rules from the corresponding depository training set. This function does automatically what users used to do by hand to construct a rate rule from reaction kinetics found in the literature, i.e. determine the groups involved, adjust to a per-site basis, etc. """ # Find the database components we will need rules = database.kinetics.depository['{0}/rules'.format(family)] groups = database.kinetics.groups[family] index = max([entry.index for entry in rules.entries.values()]) + 1 for depositoryLabel in ['training']: depository = database.kinetics.depository['{0}/{1}'.format(family, depositoryLabel)] entries = depository.entries.values() entries.sort(key=lambda x: (x.index, x.label)) for entry0 in entries: reaction, template = database.kinetics.getForwardReactionForFamilyEntry(entry=entry0, family=family, thermoDatabase=database.thermo) # We must convert the kinetics to ArrheniusEP to finish our rate rule kinetics = reaction.kinetics # If kinetics are KineticsData, then first convert to Arrhenius if isinstance(kinetics, KineticsData): kinetics = Arrhenius().fitToData( Tdata=kinetics.Tdata.values, kdata=kinetics.kdata.values, kunits=kinetics.kdata.units, T0=1, ) # Now convert from Arrhenius to ArrheniusEP # If not Arrhenius (or KineticsData), then skip this entry if isinstance(kinetics, Arrhenius): if kinetics.T0.value != 1: kinetics.changeT0(1) kinetics = ArrheniusEP( A = kinetics.A, n = kinetics.n, alpha = 0, E0 = kinetics.Ea, Tmin = kinetics.Tmin, Tmax = kinetics.Tmax, ) else: break # Put the kinetics on a per-site basis kinetics.A.value /= reaction.degeneracy # Construct a new entry for the new rate rule label = ';'.join([group.label for group in template]) item = Reaction( reactants = template[:], products = None, ) entry = Entry( index = index, label = label, item = item, data = kinetics, reference = entry0.reference, rank = entry0.rank, shortDesc = entry0.shortDesc, longDesc = entry0.longDesc, history = entry0.history, ) # Add the new rate rule to the depository of rate rules rules.entries[entry.index] = entry index += 1
def get_libraries(self): """Get RMG kinetics and thermo libraries""" name = 'kineticsjobs' species_list = list(self.species_dict.values()) reaction_list = list(self.reaction_dict.values()) # remove duplicate species for rxn in reaction_list: for i, rspc in enumerate(rxn.reactants): for spc in species_list: if spc.is_isomorphic(rspc): rxn.reactants[i] = spc break for i, rspc in enumerate(rxn.products): for spc in species_list: if spc.is_isomorphic(rspc): rxn.products[i] = spc break del_inds = [] for i, spc1 in enumerate(species_list): for j, spc2 in enumerate(species_list): if j > i and spc1.is_isomorphic(spc2): del_inds.append(j) for j in sorted(del_inds)[::-1]: del species_list[j] thermo_library = ThermoLibrary(name=name) for i, species in enumerate(species_list): if species.thermo: thermo_library.load_entry( index=i + 1, label=species.label, molecule=species.molecule[0].to_adjacency_list(), thermo=species.thermo, shortDesc=species.thermo.comment) else: logging.warning( 'Species {0} did not contain any thermo data and was omitted from the thermo library.' .format(str(species))) # load kinetics library entries kinetics_library = KineticsLibrary(name=name, auto_generated=True) kinetics_library.entries = {} for i, reaction in enumerate(reaction_list): entry = Entry(index=i + 1, label=reaction.to_labeled_str(), item=reaction, data=reaction.kinetics) if reaction.kinetics is not None: if hasattr(reaction, 'library') and reaction.library: entry.long_desc = 'Originally from reaction library: ' + \ reaction.library + "\n" + reaction.kinetics.comment else: entry.long_desc = reaction.kinetics.comment kinetics_library.entries[i + 1] = entry kinetics_library.label = name return thermo_library, kinetics_library, species_list
def fillRulesByAveragingUp(self, rootTemplate, alreadyDone, verbose=False): """ Fill in gaps in the kinetics rate rules by averaging child nodes. If verbose is set to True, then exact sources of kinetics are saved in the kinetics comments (warning: this uses up a lot of memory due to the extensively long comments) """ rootLabel = ';'.join([g.label for g in rootTemplate]) if rootLabel in alreadyDone: return alreadyDone[rootLabel] # Generate the distance 1 pairings which must be averaged for this root template. # The distance 1 template is created by taking the parent node from one or more trees # and creating the combinations with children from a single remaining tree. # i.e. for some node (A,B), we want to fetch all combinations for the pairing of (A,B's children) and # (A's children, B). For node (A,B,C), we would retrieve all combinations of (A,B,C's children) # (A,B's children,C) etc... # If a particular node has no children, it is skipped from the children expansion altogether. childrenList = [] distanceList = [] for i, parent in enumerate(rootTemplate): # Start with the root template, and replace the ith member with its children if parent.children: childrenSet = [[group] for group in rootTemplate] childrenSet[i] = parent.children childrenList.extend(getAllCombinations(childrenSet)) distanceList.extend([k.nodalDistance for k in parent.children]) if distanceList != []: #average the minimum distance neighbors minDist = min(distanceList) closeChildrenList = [ childrenList[i] for i in xrange(len(childrenList)) if distanceList[i] == minDist ] else: closeChildrenList = [] kineticsList = [] for template in childrenList: label = ';'.join([g.label for g in template]) if label in alreadyDone: kinetics = alreadyDone[label] else: kinetics = self.fillRulesByAveragingUp(template, alreadyDone, verbose) if template in closeChildrenList and kinetics is not None: kineticsList.append([kinetics, template]) # See if we already have a rate rule for this exact template instead # and return it now that we have finished searching its children entry = self.getRule(rootTemplate) if entry is not None and entry.rank > 0: # We already have a rate rule for this exact template # If the entry has rank of zero, then we have so little faith # in it that we'd rather use an averaged value if possible # Since this entry does not have a rank of zero, we keep its # value alreadyDone[rootLabel] = entry.data return entry.data if len(kineticsList) > 0: if len(kineticsList) > 1: # We found one or more results! Let's average them together kinetics = self.__getAverageKinetics( [k for k, t in kineticsList]) if verbose: kinetics.comment = 'Average of [{0}]'.format(' + '.join( k.comment if k.comment != '' else ';'.join(g.label for g in t) for k, t in kineticsList)) else: kinetics.comment = 'Average of [{0}]'.format(' + '.join( ';'.join(g.label for g in t) for k, t in kineticsList)) else: k, t = kineticsList[0] kinetics = deepcopy(k) # Even though we are using just a single set of kinetics, it's still considered # an average. It just happens that the other distance 1 children had no data. if verbose: kinetics.comment = 'Average of [{0}]'.format( k.comment if k.comment != '' else ';'.join(g.label for g in t)) else: kinetics.comment = 'Average of [{0}]'.format(';'.join( g.label for g in t)) entry = Entry( index=0, label=rootLabel, item=rootTemplate, data=kinetics, rank=10, # Indicates this is an averaged estimate ) self.entries[entry.label] = [entry] alreadyDone[rootLabel] = entry.data return entry.data alreadyDone[rootLabel] = None return None
def generateRules(family, database): """ For a given reaction `family` label, generate additional rate rules from the corresponding depository training set. This function does automatically what users used to do by hand to construct a rate rule from reaction kinetics found in the literature, i.e. determine the groups involved, adjust to a per-site basis, etc. """ # Load rules and determine starting index rules = family.rules index = max([entry.index for entry in rules.entries.values()] or [0]) + 1 # Load training entries for depository in family.depositories: if 'training' in depository.name: entries = sorted(depository.entries.values(), key=lambda entry: (entry.index, entry.label)) break # Generate a rate rule for each training entry for entry in entries: # Load entry's reaction, template, and kinetics reaction, template = database.kinetics.getForwardReactionForFamilyEntry( entry=entry, family=family.name, thermoDatabase=database.thermo) kinetics = reaction.kinetics # Convert KineticsData to Arrhenius if isinstance(kinetics, KineticsData): kinetics = Arrhenius().fitToData(Tdata=kinetics.Tdata.values, kdata=kinetics.kdata.values, kunits=kinetics.kdata.units, T0=1) # Ignore other kinetics types if not isinstance(kinetics, Arrhenius): continue # Change reference temperature to 1 K if necessary if kinetics.T0.value != 1: kinetics = kinetics.changeT0(1) # Convert kinetics to a per-site basis kinetics.A.value /= reaction.degeneracy # Convert to ArrheniusEP kinetics = ArrheniusEP(A=kinetics.A, n=kinetics.n, alpha=0, E0=kinetics.Ea, Tmin=kinetics.Tmin, Tmax=kinetics.Tmax) # Add new rate rule rules.entries[index] = Entry(index=index, label=';'.join( [group.label for group in template]), item=Reaction(reactants=template[:], products=None), data=kinetics, reference=entry.reference, rank=entry.rank, shortDesc=entry.shortDesc, longDesc=entry.longDesc, history=entry.history) index += 1
molecule=species.molecule[0].toAdjacencyList(removeH=removeH), thermo=species.thermo, shortDesc=species.thermo.comment) else: logging.warning( 'Species {0} did not contain any thermo data and was omitted from the thermo library.' .format(str(species))) # load kinetics library entries kineticsLibrary = KineticsLibrary() kineticsLibrary.entries = {} for i in range(len(reactionList)): reaction = reactionList[i] entry = Entry( index=i + 1, item=reaction, data=reaction.kinetics, ) entry.longDesc = reaction.kinetics.comment kineticsLibrary.entries[i + 1] = entry kineticsLibrary.checkForDuplicates() kineticsLibrary.convertDuplicatesToMulti() # Assign history to all entries user = getUsername() # Pulls username from current git repository #user = '******'.format(name, email) # If not in git repository, then enter user information manually event = [ time.asctime(), user, 'action', '{0} imported this entry from the old RMG database.'.format(user) ]
def getKinetics(self): """ Extracts the kinetic data from the chemkin file for plotting purposes. """ from rmgpy.chemkin import loadChemkinFile from rmgpy.kinetics import ArrheniusEP, Chebyshev from rmgpy.reaction import Reaction from rmgpy.data.base import Entry kineticsDataList = [] chemkinPath = self.path + '/chemkin/chem.inp' dictionaryPath = self.path + 'RMG_Dictionary.txt' if self.Foreign: readComments = False else: readComments = True if os.path.exists(dictionaryPath): speciesList, reactionList = loadChemkinFile( chemkinPath, dictionaryPath, readComments=readComments) else: speciesList, reactionList = loadChemkinFile( chemkinPath, readComments=readComments) for reaction in reactionList: # If the kinetics are ArrheniusEP, replace them with Arrhenius if isinstance(reaction.kinetics, ArrheniusEP): reaction.kinetics = reaction.kinetics.toArrhenius( reaction.getEnthalpyOfReaction(298)) if os.path.exists(dictionaryPath): reactants = ' + '.join([ moleculeToInfo(reactant) for reactant in reaction.reactants ]) arrow = '⇔' if reaction.reversible else '→' products = ' + '.join( [moleculeToInfo(product) for product in reaction.products]) href = reaction.getURL() else: reactants = ' + '.join( [reactant.label for reactant in reaction.reactants]) arrow = '⇔' if reaction.reversible else '→' products = ' + '.join( [product.label for product in reaction.products]) href = '' source = str(reaction).replace('<=>', '=') entry = Entry() entry.result = reactionList.index(reaction) + 1 forwardKinetics = reaction.kinetics forward = True chemkin = reaction.toChemkin(speciesList) reverseKinetics = reaction.generateReverseRateCoefficient() reverseKinetics.comment = 'Fitted reverse reaction. ' + reaction.kinetics.comment rev_reaction = Reaction(reactants=reaction.products, products=reaction.reactants, kinetics=reverseKinetics) chemkin_rev = rev_reaction.toChemkin(speciesList) kineticsDataList.append([ reactants, arrow, products, entry, forwardKinetics, source, href, forward, chemkin, reverseKinetics, chemkin_rev ]) return kineticsDataList