Exemple #1
0
    def test_rmg_reaction(self):
        test_reaction = RMGReaction(
            reactants=[RMGMolecule(smiles="CC"),
                       RMGMolecule(smiles="[O]O")],
            products=[RMGMolecule(smiles="[CH2]C"),
                      RMGMolecule(smiles="OO")])

        self.assertTrue(
            test_reaction.is_isomorphic(self.reaction.get_rmg_reaction()))
        self.assertTrue(
            test_reaction.is_isomorphic(self.reaction2.get_rmg_reaction()))
Exemple #2
0
    def test_remove_isotope_for_reactions(self):
        """
        Test that remove isotope algorithm works with Reaction objects.
        """

        eth = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")

        ethi = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 i13 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")
        unlabeled_rxn = Reaction(reactants=[eth], products=[eth])
        labeled_rxn = Reaction(reactants=[ethi], products=[ethi])
        stripped = remove_isotope(labeled_rxn)

        self.assertTrue(unlabeled_rxn.is_isomorphic(stripped))
Exemple #3
0
def determine_rmg_kinetics(
    rmgdb: RMGDatabase,
    reaction: Reaction,
    dh_rxn298: float,
) -> List[Reaction]:
    """
    Determine kinetics for `reaction` (an RMG Reaction object) from RMG's database, if possible.
    Assigns a list of all matching entries from both libraries and families.

    Args:
        rmgdb (RMGDatabase): The RMG database instance.
        reaction (Reaction): The RMG Reaction object.
        dh_rxn298 (float): The heat of reaction at 298 K in J/mol.

    Returns: List[Reaction]
        All matching RMG reactions (both libraries and families) with a populated ``.kinetics`` attribute.
    """
    reaction = reaction.copy(
    )  # use a copy to avoid changing atom order in the molecules by RMG
    rmg_reactions = list()
    # Libraries:
    for library in rmgdb.kinetics.libraries.values():
        library_reactions = library.get_library_reactions()
        for library_reaction in library_reactions:
            if reaction.is_isomorphic(library_reaction):
                library_reaction.comment = f'Library: {library.label}'
                rmg_reactions.append(library_reaction)
                break
    # Families:
    fam_list = loop_families(rmgdb, reaction)
    for family, degenerate_reactions in fam_list:
        for deg_rxn in degenerate_reactions:
            template = family.retrieve_template(deg_rxn.template)
            kinetics = family.estimate_kinetics_using_rate_rules(template)[0]
            kinetics.change_rate(deg_rxn.degeneracy)
            kinetics = kinetics.to_arrhenius(
                dh_rxn298
            )  # Convert ArrheniusEP to Arrhenius using the dHrxn at 298K
            deg_rxn.kinetics = kinetics
            deg_rxn.comment = f'Family: {deg_rxn.family}'
            deg_rxn.reactants = reaction.reactants
            deg_rxn.products = reaction.products
        rmg_reactions.extend(degenerate_reactions)
    worked_through_nist_fams = []
    # NIST:
    for family, degenerate_reactions in fam_list:
        if family not in worked_through_nist_fams:
            worked_through_nist_fams.append(family)
            for depo in family.depositories:
                if 'NIST' in depo.label:
                    for entry in depo.entries.values():
                        rxn = entry.item
                        rxn.kinetics = entry.data
                        rxn.comment = f'NIST: {entry.index}'
                        if entry.reference is not None:
                            rxn.comment += f'{entry.reference.authors[0]} {entry.reference.year}'
                        rmg_reactions.append(rxn)
    return rmg_reactions
Exemple #4
0
    def test_labeled_reaction(self):
        test_reaction = RMGReaction(
            reactants=[RMGMolecule(smiles="CC"),
                       RMGMolecule(smiles="[O]O")],
            products=[RMGMolecule(smiles="[CH2]C"),
                      RMGMolecule(smiles="OO")])
        labeled_reaction, reaction_family = self.reaction.get_labeled_reaction(
        )

        self.assertEquals(reaction_family.lower(), "h_abstraction")
        self.assertTrue(test_reaction.is_isomorphic(labeled_reaction))

        merged = labeled_reaction.reactants[0].merge(
            labeled_reaction.reactants[1])
        self.assertTrue(merged.get_labeled_atoms("*1")[0].is_carbon())
        self.assertTrue(merged.get_labeled_atoms("*2")[0].is_hydrogen())
        self.assertTrue(merged.get_labeled_atoms("*3")[0].is_oxygen)

        merged = labeled_reaction.products[0].merge(
            labeled_reaction.products[1])
        self.assertTrue(merged.get_labeled_atoms("*3")[0].is_carbon())
        self.assertTrue(merged.get_labeled_atoms("*2")[0].is_hydrogen())
        self.assertTrue(merged.get_labeled_atoms("*1")[0].is_oxygen)

        labeled_reaction, reaction_family = self.reaction2.get_labeled_reaction(
        )

        self.assertEquals(reaction_family.lower(), "h_abstraction")
        self.assertTrue(test_reaction.is_isomorphic(labeled_reaction))

        merged = labeled_reaction.reactants[0].merge(
            labeled_reaction.reactants[1])
        self.assertTrue(merged.get_labeled_atoms("*1")[0].is_carbon())
        self.assertTrue(merged.get_labeled_atoms("*2")[0].is_hydrogen())
        self.assertTrue(merged.get_labeled_atoms("*3")[0].is_oxygen)

        merged = labeled_reaction.products[0].merge(
            labeled_reaction.products[1])
        self.assertTrue(merged.get_labeled_atoms("*3")[0].is_carbon())
        self.assertTrue(merged.get_labeled_atoms("*2")[0].is_hydrogen())
        self.assertTrue(merged.get_labeled_atoms("*1")[0].is_oxygen)
Exemple #5
0
    def test_inplace_remove_isotope_for_reactions(self):
        """
        Test that removeIsotope and redoIsotope works with reactions
        """

        eth = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")

        ethi = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 i13 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")
        unlabeled_rxn = Reaction(reactants=[eth], products=[eth])
        labeled_rxn = Reaction(reactants=[ethi], products=[ethi])
        stored_labeled_rxn = labeled_rxn.copy()
        modified_atoms = remove_isotope(labeled_rxn, inplace=True)

        self.assertTrue(unlabeled_rxn.is_isomorphic(labeled_rxn))

        redo_isotope(modified_atoms)

        self.assertTrue(stored_labeled_rxn.is_isomorphic(labeled_rxn))
Exemple #6
0
    def get_labeled_reaction(self):
        """
        A method that will return a labeled reaction given a reaction label or rmg_reaction
        A label or an rmg_reaction needs to be provided in order for this method to work.
        If both are provided, we assert that the label matches the reaction.

        Variables:
        - label (str): the reaction label of interest
        - rmg_reaction (RMGReaction): the reaction of interest

        Returns:
        - reaction (RMGReaction): An RMGReaction with labeled reactants and products
        - name (str): The string corresponding to the reaction family matched to the reaction of interest
        """
        if not (self.rmg_database or self.ts_databases):
            self.rmg_database, self.ts_databases = self.load_databases()

        assert (self.label or self.rmg_reaction
                ), "You must provide a reaction or a reaction label"

        match = False  # We have not found a labeled reaction that matches the one provided.
        if self.label:  # A reaction label was provided

            # Generating lists of lists. Main list is the reactans or products
            # Secondary list is composed of the resonance structures for that species
            r, p = self.label.split("_")
            rmg_reactants = [
                RMGMolecule(smiles=smile).generate_resonance_structures()
                for smile in r.split("+")
            ]
            rmg_products = [
                RMGMolecule(smiles=smile).generate_resonance_structures()
                for smile in p.split("+")
            ]

            combos_to_try = list(
                itertools.product(list(itertools.product(*rmg_reactants)),
                                  list(itertools.product(*rmg_products))))

            # looping though each reaction family and each combination of reactants and products
            for name, family in list(
                    self.rmg_database.kinetics.families.items()):
                logging.info("Trying to match reacction to {}".format(family))
                for rmg_reactants, rmg_products in combos_to_try:
                    # Making a test reaction
                    test_reaction = RMGReaction(reactants=list(rmg_reactants),
                                                products=list(rmg_products))

                    try:  # Trying to label the reaction
                        labeled_r, labeled_p = family.get_labeled_reactants_and_products(
                            test_reaction.reactants, test_reaction.products)
                    except:  # Failed to match a reaction to the family
                        logging.error(
                            "Couldn't match {} to {}, trying different combination..."
                            .format(test_reaction, name))
                        continue

                    if not (labeled_r and labeled_p):
                        # Catching an error where it matched the reaction but the reactants and products we not return...
                        # A weird bug in RMG that I can explain
                        continue

                    if ((len(labeled_r) > 0)
                            and (len(labeled_p) > 0)):  # We found a match.
                        if match:
                            # We found a match already, but we were able to label the reaction again...
                            # This would happen if different combinations of resonance structures match up
                            logging.warning(
                                "This reaction has been already labeled... \
                                it seems that resonance structures \for reactants and products exist."
                            )
                            logging.warning("Skipping this duplicate for now")
                            continue

                        logging.info(
                            "Matched reaction to {} family".format(name))

                        # Copying labed reactions and saving them for later
                        labeled_reactants = deepcopy(labeled_r)
                        labeled_products = deepcopy(labeled_p)
                        match_reaction = RMGReaction(
                            reactants=deepcopy(labeled_r),
                            products=deepcopy(labeled_p))
                        # Setting it true that we matche the reaction and remembering the
                        # RMG reaction family and family name
                        match = True
                        final_family = family
                        final_name = name

        elif self.rmg_reaction:  #RMGReaction but no label
            rmg_reactants = []
            rmg_products = []
            for react in self.rmg_reaction.reactants:
                if isinstance(react, RMGSpecies):
                    rmg_reactants.append(react.molecule)
                elif isinstance(react, RMGMolecule):
                    rmg_reactants.append(react.generate_resonance_structures())

            for prod in self.rmg_reaction.products:
                if isinstance(prod, RMGSpecies):
                    rmg_products.append(prod.molecule)
                elif isinstance(prod, RMGMolecule):
                    rmg_products.append(prod.generate_resonance_structures())

            combos_to_try = list(
                itertools.product(list(itertools.product(*rmg_reactants)),
                                  list(itertools.product(*rmg_products))))

            for name, family in list(
                    self.rmg_database.kinetics.families.items()):
                logging.info("Trying to match reaction to {}".format(name))
                for rmg_reactants, rmg_products in combos_to_try:
                    # Making a test reaction
                    test_reaction = RMGReaction(reactants=list(rmg_reactants),
                                                products=list(rmg_products))

                    try:  # Trying to label the reaction
                        labeled_r, labeled_p = family.get_labeled_reactants_and_products(
                            test_reaction.reactants, test_reaction.products)
                        if not (labeled_r and labeled_p):
                            logging.error(
                                "Unable to determine a reaction for the forward direction. Trying the reverse direction."
                            )
                            raise ActionError
                    except:
                        try:
                            # Trying the reverse reaction if the forward reaction doesn't work
                            # This is useful for R_Addition reactions
                            labeled_r, labeled_p = family.get_labeled_reactants_and_products(
                                test_reaction.products,
                                test_reaction.reactants)
                        except:
                            logging.error(
                                "Couldn't match {} to {}, trying different combination..."
                                .format(test_reaction, name))
                            continue

                    if not (labeled_r and labeled_p):
                        # Catching an error where it matched the reaction but the reactants and products we not return...
                        # A weird bug in RMG that I can explain
                        continue

                    if ((len(labeled_r) > 0)
                            and (len(labeled_p) > 0)):  # We found a match.
                        if match:
                            # We found a match already, but we were able to label the reaction again...
                            # This would happen if different combinations of resonance structures match up
                            logging.warning(
                                "This reaction has been already labeled... \
                                it seems that resonance structures \for reactants and products exist."
                            )
                            logging.warning("Skipping this duplicate for now")
                            continue

                        logging.info(
                            "Matched reaction to {} family".format(name))

                        # Copying labed reactions and saving them for later
                        labeled_reactants = deepcopy(labeled_r)
                        labeled_products = deepcopy(labeled_p)
                        match_reaction = RMGReaction(
                            reactants=deepcopy(labeled_r),
                            products=deepcopy(labeled_p))
                        # Setting it true that we matche the reaction and remembering the
                        # RMG reaction family and family name
                        match = True
                        final_family = family
                        final_name = name

        assert match, "Could not idetify labeled reactants and products"

        reaction_list = final_family.generate_reactions(
            match_reaction.reactants, match_reaction.products)

        assert reaction_list, "Could not match a reaction to a reaction family..."

        for reaction in reaction_list:
            if match_reaction.is_isomorphic(reaction):
                reaction.reactants = labeled_reactants
                reaction.products = labeled_products
                break
        self.rmg_reaction = reaction
        self.reaction_family = final_name
        return self.rmg_reaction, self.reaction_family
Exemple #7
0
    def validate_irc(self):
        """
        A method to verify an IRC calc
        """

        logging.info("Validating IRC file...")
        irc_path = os.path.join(
            self.directory, "ts", self.conformer.reaction_label, "irc",
            self.conformer.reaction_label + "_irc_" +
            self.conformer.direction + "_" + str(self.conformer.index) +
            ".log")

        complete, converged = self.verify_output_file(irc_path)
        if not complete:
            logging.info("It seems that the IRC claculation did not complete")
            return False
        if not converged:
            logging.info("The IRC calculation did not converge...")
            return False

        pth1 = list()
        steps = list()
        with open(irc_path) as output_file:
            for line in output_file:
                line = line.strip()

                if line.startswith('Point Number:'):
                    if int(line.split()[2]) > 0:
                        if int(line.split()[-1]) == 1:
                            pt_num = int(line.split()[2])
                            pth1.append(pt_num)
                        else:
                            pass
                elif line.startswith('# OF STEPS ='):
                    num_step = int(line.split()[-1])
                    steps.append(num_step)
        # This indexes the coordinate to be used from the parsing
        if steps == []:
            logging.error('No steps taken in the IRC calculation!')
            return False
        else:
            pth1End = sum(steps[:pth1[-1]])
            # Compare the reactants and products
            irc_parse = ccread(irc_path)

            atomcoords = irc_parse.atomcoords
            atomnos = irc_parse.atomnos

            mol1 = RMGMolecule()
            mol1.from_xyz(atomnos, atomcoords[pth1End])
            mol2 = RMGMolecule()
            mol2.from_xyz(atomnos, atomcoords[-1])

            test_reaction = RMGReaction(
                reactants=mol1.split(),
                products=mol2.split(),
            )

            r, p = self.conformer.reaction_label.split("_")

            reactants = []
            products = []

            for react in r.split("+"):
                react = RMGMolecule(smiles=react)
                reactants.append(react)

            for prod in p.split("+"):
                prod = RMGMolecule(smiles=prod)
                products.append(prod)

            possible_reactants = []
            possible_products = []
            for reactant in reactants:
                possible_reactants.append(
                    reactant.generate_resonance_structures())

            for product in products:
                possible_products.append(
                    product.generate_resonance_structures())

            possible_reactants = list(itertools.product(*possible_reactants))
            possible_products = list(itertools.product(*possible_products))

            for possible_reactant in possible_reactants:
                reactant_list = []
                for react in possible_reactant:
                    reactant_list.append(react.to_single_bonds())

                for possible_product in possible_products:
                    product_list = []
                    for prod in possible_product:
                        product_list.append(prod.to_single_bonds())

                    target_reaction = RMGReaction(
                        reactants=list(reactant_list),
                        products=list(product_list))

                    if target_reaction.is_isomorphic(test_reaction):
                        logging.info("IRC calculation was successful!")
                        return True
            logging.info("IRC calculation failed for {} :(".format(irc_path))
            return False