示例#1
0
文件: rules.py 项目: canh-thu/RMG-Py
    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
                molecule=species.molecule[0].to_adjacency_list(),
                thermo=species.thermo,
            )
        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)
    kinetics_library.entries = {}
    for i in range(len(reaction_list)):
        reaction = reaction_list[i]
        entry = Entry(
            index=i + 1,
            label=reaction.to_labeled_str(),
            item=reaction,
            data=reaction.kinetics,
        )
        try:
            entry.long_desc = 'Originally from reaction library: ' + reaction.library + "\n" + reaction.kinetics.comment
        except AttributeError:
            entry.long_desc = reaction.kinetics.comment
        kinetics_library.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 mark_duplicates = True
    kinetics_library.check_for_duplicates(mark_duplicates=True)
    kinetics_library.convert_duplicates_to_multi()

    # Save in Py format
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
示例#4
0
                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)
    ]
示例#5
0
    def getLibraries(self):
        """Get RMG kinetics and thermo libraries"""
        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
示例#6
0
                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,
        )
        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
    databaseDirectory = settings['database.directory']
    try:
        os.makedirs(
示例#7
0
    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
示例#8
0
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'))