def test_generate(self):
        autots_input = TSInput([self.reactant_1, self.reactant_2],
                                   [self.product],
                                   self.autots_variables,
                                   self.gen_variables)

        self.assertEqual(
            metal_edge_extender(
                MoleculeGraph.with_local_env_strategy(
                    self.reactant_1, OpenBabelNN()
                )
            ),
            autots_input.reactants[0])
        self.assertEqual(
            metal_edge_extender(
                MoleculeGraph.with_local_env_strategy(
                    self.reactant_2, OpenBabelNN()
                )
            ),
            autots_input.reactants[1])
        self.assertEqual(
            metal_edge_extender(
                MoleculeGraph.with_local_env_strategy(
                    self.product, OpenBabelNN()
                )
            ),
            autots_input.products[0])
        self.assertDictEqual(self.autots_variables, autots_input.autots_variables)
        self.assertDictEqual(self.gen_variables, autots_input.gen_variables)
    def setUpClass(cls):
        if ob:
            EC_mg = MoleculeGraph.with_local_env_strategy(
                Molecule.from_file(os.path.join(test_dir, "EC.xyz")),
                OpenBabelNN())
            cls.EC_mg = metal_edge_extender(EC_mg)

            LiEC_mg = MoleculeGraph.with_local_env_strategy(
                Molecule.from_file(os.path.join(test_dir, "LiEC.xyz")),
                OpenBabelNN())
            cls.LiEC_mg = metal_edge_extender(LiEC_mg)

            LEDC_mg = MoleculeGraph.with_local_env_strategy(
                Molecule.from_file(os.path.join(test_dir, "LEDC.xyz")),
                OpenBabelNN())
            cls.LEDC_mg = metal_edge_extender(LEDC_mg)

            LEMC_mg = MoleculeGraph.with_local_env_strategy(
                Molecule.from_file(os.path.join(test_dir, "LEMC.xyz")),
                OpenBabelNN())
            cls.LEMC_mg = metal_edge_extender(LEMC_mg)

            cls.LiEC_reextended_entries = []
            entries = loadfn(
                os.path.join(test_dir, "LiEC_reextended_entries.json"))
            for entry in entries:
                if "optimized_molecule" in entry["output"]:
                    mol = entry["output"]["optimized_molecule"]
                else:
                    mol = entry["output"]["initial_molecule"]
                E = float(entry["output"]["final_energy"])
                H = float(entry["output"]["enthalpy"])
                S = float(entry["output"]["entropy"])
                mol_entry = MoleculeEntry(
                    molecule=mol,
                    energy=E,
                    enthalpy=H,
                    entropy=S,
                    entry_id=entry["task_id"],
                )
                if mol_entry.formula == "Li1":
                    if mol_entry.charge == 1:
                        cls.LiEC_reextended_entries.append(mol_entry)
                else:
                    cls.LiEC_reextended_entries.append(mol_entry)

            # dumpfn(cls.LiEC_reextended_entries, "unittest_input_molentries.json")

            with open(os.path.join(test_dir, "unittest_RN_build.pkl"),
                      "rb") as input:
                cls.RN_build = pickle.load(input)

            with open(os.path.join(test_dir, "unittest_RN_pr_solved.pkl"),
                      "rb") as input:
                cls.RN_pr_solved = pickle.load(input)
Exemple #3
0
    def __init__(
        self,
        molecule: Molecule,
        energy: float,
        correction: float = 0.0,
        enthalpy: Optional[float] = None,
        entropy: Optional[float] = None,
        parameters: Optional[Dict] = None,
        entry_id: Optional[Any] = None,
        attribute=None,
        mol_graph: Optional[MoleculeGraph] = None,
    ):
        self.uncorrected_energy = energy
        self.correction = correction
        self.enthalpy = enthalpy
        self.entropy = entropy
        self.parameters = parameters if parameters else {}
        self.entry_id = entry_id
        self.attribute = attribute

        if not mol_graph:
            mol_graph = MoleculeGraph.with_local_env_strategy(
                molecule, OpenBabelNN())
            self.mol_graph = metal_edge_extender(mol_graph)
        else:
            self.mol_graph = mol_graph
    def setUpClass(cls):
        EC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "EC.xyz")),
            OpenBabelNN())
        EC_mg = metal_edge_extender(EC_mg)

        LiEC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "LiEC.xyz")),
            OpenBabelNN())
        LiEC_mg = metal_edge_extender(LiEC_mg)

        LEDC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "LEDC.xyz")),
            OpenBabelNN())
        LEDC_mg = metal_edge_extender(LEDC_mg)

        LEMC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "LEMC.xyz")),
            OpenBabelNN())
        LEMC_mg = metal_edge_extender(LEMC_mg)

        cls.LiEC_reextended_entries = []
        entries = loadfn(os.path.join(test_dir,
                                      "LiEC_reextended_entries.json"))
        for entry in entries:
            if "optimized_molecule" in entry["output"]:
                mol = entry["output"]["optimized_molecule"]
            else:
                mol = entry["output"]["initial_molecule"]
            E = float(entry["output"]["final_energy"])
            H = float(entry["output"]["enthalpy"])
            S = float(entry["output"]["entropy"])
            mol_entry = MoleculeEntry(
                molecule=mol,
                energy=E,
                enthalpy=H,
                entropy=S,
                entry_id=entry["task_id"],
            )
            if mol_entry.formula == "Li1":
                if mol_entry.charge == 1:
                    cls.LiEC_reextended_entries.append(mol_entry)
            else:
                cls.LiEC_reextended_entries.append(mol_entry)

        cls.entries_box = EntriesBox(cls.LiEC_reextended_entries,
                                     remove_complexes=False)

        cls.RI = ReactionIterator(cls.entries_box)
        cls.RN = ReactionNetwork(cls.RI, add_concerteds=False)

        # set up input variables
        cls.LEDC_ind = None
        cls.LiEC_ind = None
        cls.EC_ind = None

        for entry in cls.entries_box.entries_dict["C3 H4 O3"][10][0]:
            if EC_mg.isomorphic_to(entry.mol_graph):
                cls.EC_ind = entry.parameters["ind"]
                break

        for entry in cls.entries_box.entries_dict["C4 H4 Li2 O6"][17][0]:
            if LEDC_mg.isomorphic_to(entry.mol_graph):
                cls.LEDC_ind = entry.parameters["ind"]
                break

        for entry in cls.entries_box.entries_dict["C3 H4 Li1 O3"][12][1]:
            if LiEC_mg.isomorphic_to(entry.mol_graph):
                cls.LiEC_ind = entry.parameters["ind"]
                break

        cls.Li1_ind = cls.entries_box.entries_dict["Li1"][0][1][0].parameters[
            "ind"]

        print("LEDC_ind:", cls.LEDC_ind)
        print("LiEC_ind:", cls.LiEC_ind)
        print("EC_ind:", cls.EC_ind)
        print("Li1_ind:", cls.Li1_ind)

        cls.RN_solved = copy.deepcopy(cls.RN)
        cls.RN_solved.solve_prerequisites([cls.EC_ind, cls.Li1_ind],
                                          weight="softplus")
Exemple #5
0
    def __init__(self,
                 molecule=None,
                 bonds_formed=None,
                 bonds_broken=None,
                 angles=None,
                 torsions=None,
                 out_of_planes=None,
                 use_graph=False):
        self.molecule = molecule
        self.bonds_formed = bonds_formed or list()
        self.bonds_broken = bonds_broken or list()
        self.angles = angles or list()
        self.torsions = torsions or list()
        self.out_of_planes = out_of_planes or list()
        self.use_graph = use_graph

        # First, check that there are not too many coordinates given
        # We do not allow more than 4 driving coordinates
        num_coords = 0
        all_coords = list()

        if self.bonds_formed is not None:
            num_coords += len(self.bonds_formed)
            all_coords += self.bonds_formed
        if self.bonds_broken is not None:
            num_coords += len(self.bonds_broken)
            all_coords += self.bonds_broken
        if self.angles is not None:
            num_coords += len(self.angles)
            all_coords += self.angles
        if self.torsions is not None:
            num_coords += len(self.torsions)
            all_coords += self.torsions
        if self.out_of_planes is not None:
            num_coords += len(self.out_of_planes)
            all_coords += self.out_of_planes

        if num_coords > 4:
            raise ValueError("Too many driving coordinates given! At most 4 "
                             "driving coordinates may be used with "
                             "GSMIsomerInput.")
        else:
            self.num_coords = num_coords
            self.all_coords = all_coords

        # Verify that all coordinates are tuples including only valid indices
        for coord in all_coords:
            for index in coord:
                if isinstance(index, int):
                    if self.molecule is not None:
                        if index >= len(self.molecule):
                            raise ValueError(
                                "Invalid index given for coordinate {}!".
                                format(coord))
                else:
                    raise ValueError(
                        "Non-integer index given for coordinate {}!".format(
                            coord))

        # Verify that coordinates are of appropriate length for their type
        for coord in self.bonds_broken + self.bonds_formed:
            if len(set(coord)) != 2:
                raise ValueError(
                    "All bond coordinates should involve 2 indices!")
        for coord in self.angles:
            if len(set(coord)) != 3:
                raise ValueError(
                    "All angle coordinates should involve 3 indices!")
        for coord in self.torsions + self.out_of_planes:
            if len(set(coord)) != 4:
                raise ValueError(
                    "All angle coordinates should involve 4 indices!")

        # If allowed, use graph methods to verify the coordinates
        if self.use_graph and self.molecule is not None:
            self.molecule_graph = MoleculeGraph.with_local_env_strategy(
                self.molecule, OpenBabelNN())
            self.molecule_graph = metal_edge_extender(self.molecule_graph)

            self._verify_two_atom_coords()
            self._verify_three_atom_coords()
            self._verify_four_atom_coords()

        else:
            self.molecule_graph = None
Exemple #6
0
def get_entries():
    if ob:
        LiEC_reextended_entries = []
        entries = loadfn(os.path.join(test_dir,
                                      "LiEC_reextended_entries.json"))
        for entry in entries:
            if "optimized_molecule" in entry["output"]:
                mol = entry["output"]["optimized_molecule"]
            else:
                mol = entry["output"]["initial_molecule"]
            E = float(entry["output"]["final_energy"])
            H = float(entry["output"]["enthalpy"])
            S = float(entry["output"]["entropy"])
            mol_entry = MoleculeEntry(
                molecule=mol,
                energy=E,
                enthalpy=H,
                entropy=S,
                entry_id=entry["task_id"],
            )
            if mol_entry.formula == "Li1":
                if mol_entry.charge == 1:
                    LiEC_reextended_entries.append(mol_entry)
            else:
                LiEC_reextended_entries.append(mol_entry)

        RN = ReactionNetwork.from_input_entries(LiEC_reextended_entries)

        EC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "EC.xyz")),
            OpenBabelNN())
        EC_mg = metal_edge_extender(EC_mg)

        LiEC_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "LiEC.xyz")),
            OpenBabelNN())
        LiEC_mg = metal_edge_extender(LiEC_mg)

        LiEC_RO_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "LiEC_RO.xyz")),
            OpenBabelNN())
        LiEC_RO_mg = metal_edge_extender(LiEC_RO_mg)

        C2H4_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "C2H4.xyz")),
            OpenBabelNN())
        C2H4_mg = metal_edge_extender(C2H4_mg)

        C1Li1O3_mg = MoleculeGraph.with_local_env_strategy(
            Molecule.from_file(os.path.join(test_dir, "C1Li1O3.xyz")),
            OpenBabelNN())
        C1Li1O3_mg = metal_edge_extender(C1Li1O3_mg)

        LiEC_entry = None
        LiEC_plus_entry = None
        EC_minus_entry = None
        EC_0_entry = None
        EC_1_entry = None
        LiEC_RO_entry = None
        C2H4_entry = None
        C1Li1O3_entry = None
        Li_entry = None

        for entry in RN.entries_list:
            if (entry.formula == "C3 H4 O3" and entry.num_bonds == 10
                    and EC_mg.isomorphic_to(entry.mol_graph)):
                if entry.charge == -1:
                    if EC_minus_entry is not None:
                        if EC_minus_entry.get_free_energy(
                        ) >= entry.get_free_energy():
                            EC_minus_entry = entry
                    else:
                        EC_minus_entry = entry
                elif entry.charge == 0:
                    if EC_0_entry is not None:
                        if EC_0_entry.get_free_energy(
                        ) >= entry.get_free_energy():
                            EC_0_entry = entry
                    else:
                        EC_0_entry = entry
                elif entry.charge == 1:
                    if EC_1_entry is not None:
                        if EC_1_entry.get_free_energy(
                        ) >= entry.get_free_energy():
                            EC_1_entry = entry
                    else:
                        EC_1_entry = entry
            elif (entry.formula == "C3 H4 Li1 O3" and entry.num_bonds == 12
                  and LiEC_mg.isomorphic_to(entry.mol_graph)):
                if entry.charge == 0:
                    if LiEC_entry is not None:
                        if LiEC_entry.get_free_energy(
                        ) >= entry.get_free_energy():
                            LiEC_entry = entry
                    else:
                        LiEC_entry = entry
                elif entry.charge == 1:
                    if LiEC_plus_entry is not None:
                        if LiEC_plus_entry.get_free_energy(
                        ) >= entry.get_free_energy():
                            LiEC_plus_entry = entry
                    else:
                        LiEC_plus_entry = entry
            elif (entry.formula == "C3 H4 Li1 O3" and entry.charge == 0
                  and entry.num_bonds == 11
                  and LiEC_RO_mg.isomorphic_to(entry.mol_graph)):
                if LiEC_RO_entry is not None:
                    if LiEC_RO_entry.get_free_energy(
                    ) >= entry.get_free_energy():
                        LiEC_RO_entry = entry
                else:
                    LiEC_RO_entry = entry

            elif (entry.formula == "C2 H4" and entry.charge == 0
                  and entry.num_bonds == 5
                  and C2H4_mg.isomorphic_to(entry.mol_graph)):
                if C2H4_entry is not None:
                    if C2H4_entry.get_free_energy() >= entry.get_free_energy():
                        C2H4_entry = entry
                else:
                    C2H4_entry = entry

            elif (entry.formula == "C1 Li1 O3" and entry.charge == 0
                  and entry.num_bonds == 5
                  and C1Li1O3_mg.isomorphic_to(entry.mol_graph)):
                if C1Li1O3_entry is not None:
                    if C1Li1O3_entry.get_free_energy(
                    ) >= entry.get_free_energy():
                        C1Li1O3_entry = entry
                else:
                    C1Li1O3_entry = entry
            elif entry.formula == "Li1" and entry.charge == 1 and entry.num_bonds == 0:
                if Li_entry is not None:
                    if Li_entry.get_free_energy() >= entry.get_free_energy():
                        Li_entry = entry
                else:
                    Li_entry = entry

        return {
            "entries": LiEC_reextended_entries,
            "RN": RN,
            "LiEC": LiEC_entry,
            "LiEC_plus": LiEC_plus_entry,
            "EC_1": EC_1_entry,
            "EC_0": EC_0_entry,
            "EC_-1": EC_minus_entry,
            "LiEC_RO": LiEC_RO_entry,
            "C2H4": C2H4_entry,
            "C1Li1O3": C1Li1O3_entry,
            "Li": Li_entry,
        }

    else:
        return None
Exemple #7
0
    def __init__(
        self,
        molecule,
        edges=None,
        depth=1,
        open_rings=False,
        use_metal_edge_extender=False,
        opt_steps=10000,
        prev_unique_frag_dict=None,
        assume_previous_thoroughness=True,
    ):
        """
        Standard constructor for molecule fragmentation

        Args:
            molecule (Molecule): The molecule to fragment.
            edges (list): List of index pairs that define graph edges, aka molecule bonds. If not set,
                edges will be determined with OpenBabel. Defaults to None.
            depth (int): The number of levels of iterative fragmentation to perform, where each level
                will include fragments obtained by breaking one bond of a fragment one level up.
                Defaults to 1. However, if set to 0, instead all possible fragments are generated
                using an alternative, non-iterative scheme.
            open_rings (bool): Whether or not to open any rings encountered during fragmentation.
                Defaults to False. If true, any bond that fails to yield disconnected graphs when
                broken is instead removed and the entire structure is optimized with OpenBabel in
                order to obtain a good initial guess for an opened geometry that can then be put
                back into QChem to be optimized without the ring just reforming.
            use_metal_edge_extender (bool): Whether or not to attempt to add additional edges from
                O, N, F, or Cl to any Li or Mg atoms present that OpenBabel may have missed. Defaults
                to False. Most important for ionic bonding. Note that additional metal edges may yield
                new "rings" (e.g. -C-O-Li-O- in LiEC) that will not play nicely with ring opening.
            opt_steps (int): Number of optimization steps when opening rings. Defaults to 10000.
            prev_unique_frag_dict (dict): A dictionary of previously identified unique fragments.
                Defaults to None. Typically only used when trying to find the set of unique fragments
                that come from multiple molecules.
            assume_previous_thoroughness (bool): Whether or not to assume that a molecule / fragment
                provided in prev_unique_frag_dict has all of its unique subfragments also provided in
                prev_unique_frag_dict. Defaults to True. This is an essential optimization when trying
                to find the set of unique fragments that come from multiple molecules if all of those
                molecules are being fully iteratively fragmented. However, if you're passing a
                prev_unique_frag_dict which includes a molecule and its fragments that were generated
                at insufficient depth to find all possible subfragments to a fragmentation calculation
                of a different molecule that you aim to find all possible subfragments of and which has
                common subfragments with the previous molecule, this optimization will cause you to
                miss some unique subfragments.
        """
        self.assume_previous_thoroughness = assume_previous_thoroughness
        self.open_rings = open_rings
        self.opt_steps = opt_steps

        if edges is None:
            self.mol_graph = MoleculeGraph.with_local_env_strategy(molecule, OpenBabelNN())
        else:
            edges = {(e[0], e[1]): None for e in edges}
            self.mol_graph = MoleculeGraph.with_edges(molecule, edges)

        if ("Li" in molecule.composition or "Mg" in molecule.composition) and use_metal_edge_extender:
            self.mol_graph = metal_edge_extender(self.mol_graph)

        self.prev_unique_frag_dict = prev_unique_frag_dict or {}
        self.new_unique_frag_dict = {}  # new fragments from the given molecule not contained in prev_unique_frag_dict
        self.all_unique_frag_dict = {}  # all fragments from just the given molecule
        self.unique_frag_dict = {}  # all fragments from both the given molecule and prev_unique_frag_dict

        if depth == 0:  # Non-iterative, find all possible fragments:

            # Find all unique fragments besides those involving ring opening
            self.all_unique_frag_dict = self.mol_graph.build_unique_fragments()

            # Then, if self.open_rings is True, open all rings present in self.unique_fragments
            # in order to capture all unique fragments that require ring opening.
            if self.open_rings:
                self._open_all_rings()

        else:  # Iterative fragment generation:
            self.fragments_by_level = {}

            # Loop through the number of levels,
            for level in range(depth):
                # If on the first level, perform one level of fragmentation on the principle molecule graph:
                if level == 0:
                    self.fragments_by_level["0"] = self._fragment_one_level(
                        {
                            str(self.mol_graph.molecule.composition.alphabetical_formula)
                            + " E"
                            + str(len(self.mol_graph.graph.edges())): [self.mol_graph]
                        }
                    )
                else:
                    num_frags_prev_level = 0
                    for key in self.fragments_by_level[str(level - 1)]:
                        num_frags_prev_level += len(self.fragments_by_level[str(level - 1)][key])
                    if num_frags_prev_level == 0:
                        # Nothing left to fragment, so exit the loop:
                        break
                    # If not on the first level, and there are fragments present in the previous level, then
                    # perform one level of fragmentation on all fragments present in the previous level:
                    self.fragments_by_level[str(level)] = self._fragment_one_level(
                        self.fragments_by_level[str(level - 1)]
                    )

        if self.prev_unique_frag_dict == {}:
            self.new_unique_frag_dict = copy.deepcopy(self.all_unique_frag_dict)
        else:
            for frag_key in self.all_unique_frag_dict:
                if frag_key not in self.prev_unique_frag_dict:
                    self.new_unique_frag_dict[frag_key] = copy.deepcopy(self.all_unique_frag_dict[frag_key])
                else:
                    for fragment in self.all_unique_frag_dict[frag_key]:
                        found = False
                        for prev_frag in self.prev_unique_frag_dict[frag_key]:
                            if fragment.isomorphic_to(prev_frag):
                                found = True
                        if not found:
                            if frag_key not in self.new_unique_frag_dict:
                                self.new_unique_frag_dict[frag_key] = [fragment]
                            else:
                                self.new_unique_frag_dict[frag_key].append(fragment)

        self.new_unique_fragments = 0
        for frag_key in self.new_unique_frag_dict:
            self.new_unique_fragments += len(self.new_unique_frag_dict[frag_key])

        if self.prev_unique_frag_dict == {}:
            self.unique_frag_dict = self.new_unique_frag_dict
            self.total_unique_fragments = self.new_unique_fragments
        else:
            self.unique_frag_dict = copy.deepcopy(self.prev_unique_frag_dict)
            for frag_key in self.new_unique_frag_dict:
                if frag_key in self.unique_frag_dict:
                    for new_frag in self.new_unique_frag_dict[frag_key]:
                        self.unique_frag_dict[frag_key].append(new_frag)
                else:
                    self.unique_frag_dict[frag_key] = copy.deepcopy(self.new_unique_frag_dict[frag_key])

            self.total_unique_fragments = 0
            for frag_key in self.unique_frag_dict:
                self.total_unique_fragments += len(self.unique_frag_dict[frag_key])