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)
def setUpClass(cls) -> None: if ob: 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) 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) LiEC_RO_mg = MoleculeGraph.with_local_env_strategy( Molecule.from_file(os.path.join(test_dir, "LiEC_RO.xyz")), OpenBabelNN()) cls.LiEC_RO_mg = metal_edge_extender(LiEC_RO_mg) cls.LiEC_entry = None cls.LiEC_RO_entry = None for entry in cls.LiEC_reextended_entries: if (entry.formula == "C3 H4 Li1 O3" and entry.charge == 0 and entry.num_bonds == 12 and cls.LiEC_mg.isomorphic_to(entry.mol_graph)): cls.LiEC_entry = entry elif (entry.formula == "C3 H4 Li1 O3" and entry.charge == 0 and entry.num_bonds == 11 and cls.LiEC_RO_mg.isomorphic_to(entry.mol_graph)): cls.LiEC_RO_entry = entry if cls.LiEC_entry is not None and cls.LiEC_RO_entry is not None: break
def __init__(self, db_entry, use_metal_edge_extender=True, optimized=True): # id identifier = str(db_entry["_id"]) # pymatgen mol if optimized: if db_entry["state"] != "successful": raise UnsuccessfulEntryError try: pymatgen_mol = pymatgen.Molecule.from_dict( db_entry["output"]["optimized_molecule"]) except KeyError: pymatgen_mol = pymatgen.Molecule.from_dict( db_entry["output"]["initial_molecule"]) print("use initial_molecule for id: {}; job type:{} ".format( db_entry["_id"], db_entry["output"]["job_type"])) else: pymatgen_mol = pymatgen.Molecule.from_dict( db_entry["input"]["initial_molecule"]) # mol graph mol_graph = MoleculeGraph.with_local_env_strategy( pymatgen_mol, OpenBabelNN(order=True)) if use_metal_edge_extender: mol_graph = metal_edge_extender(self.mol_graph) # free energy free_energy = self._get_free_energy(db_entry, self.id, self.formula) # init superclass super(MoleculeWrapperTaskCollection, self).__init__(mol_graph, free_energy, identifier)
def find_mol_entry_from_xyz_and_charge(mol_entries, xyz_file_path, charge): """ given a file 'molecule.xyz', find the mol_entry corresponding to the molecule graph with given charge """ target_mol_graph = MoleculeGraph.with_local_env_strategy( Molecule.from_file(xyz_file_path), OpenBabelNN()) # correction to the molecule graph target_mol_graph = metal_edge_extender(target_mol_graph) match = False index = -1 while not match: index += 1 mol_entry = mol_entries[index] species_mol_graph = mol_entry.mol_graph if mol_entry.charge == charge: match = target_mol_graph.isomorphic_to(species_mol_graph) if match: return mol_entry else: return None
def test_mol_to_mol_graph(self): mol = Molecule.from_file( (test_dir / "molecules" / "li2co3_1.xyz").as_posix()) mg = MoleculeGraph.with_local_env_strategy(mol, OpenBabelNN()) mg = metal_edge_extender(mg) self.assertEqual(mg, mol_to_mol_graph(mol))
def from_molecule_document( cls, mol_doc: Dict, correction: float = 0.0, parameters: Optional[Dict] = None, attribute=None, ): """ Initialize a MoleculeEntry from a molecule document. Args: mol_doc: MongoDB molecule document (nested dictionary) that contains the molecule information. correction: A correction to be applied to the energy. This is used to modify the energy for certain analyses. Defaults to 0.0. parameters: An optional dict of parameters associated with the molecule. Defaults to None. attribute: Optional attribute of the entry. This can be used to specify that the entry is a newly found compound, or to specify a particular label for the entry, or else ... Used for further analysis and plotting purposes. An attribute can be anything but must be MSONable. """ try: if isinstance(mol_doc["molecule"], Molecule): molecule = mol_doc["molecule"] else: molecule = Molecule.from_dict(mol_doc["molecule"]) energy = mol_doc["energy_Ha"] enthalpy = mol_doc["enthalpy_kcal/mol"] entropy = mol_doc["entropy_cal/molK"] entry_id = mol_doc["task_id"] except KeyError as e: raise MoleculeEntryError( "Unable to construct molecule entry from molecule document; missing " f"attribute {e} in `mol_doc`.") if "mol_graph" in mol_doc: if isinstance(mol_doc["mol_graph"], MoleculeGraph): mol_graph = mol_doc["mol_graph"] else: mol_graph = MoleculeGraph.from_dict(mol_doc["mol_graph"]) else: mol_graph = MoleculeGraph.with_local_env_strategy( molecule, OpenBabelNN()) mol_graph = metal_edge_extender(mol_graph) return cls( molecule=molecule, energy=energy, correction=correction, enthalpy=enthalpy, entropy=entropy, parameters=parameters, entry_id=entry_id, attribute=attribute, mol_graph=mol_graph, )
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_doc: Optional[Dict] = 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 self.mol_doc = mol_doc if mol_doc else {} self.mol_graph = mol_graph if self.mol_doc != {}: self.enthalpy = self.mol_doc["enthalpy_kcal/mol"] self.entropy = self.mol_doc["entropy_cal/molK"] self.entry_id = self.mol_doc["task_id"] if "mol_graph" in self.mol_doc: if isinstance(self.mol_doc["mol_graph"], MoleculeGraph): self.mol_graph = self.mol_doc["mol_graph"] else: self.mol_graph = MoleculeGraph.from_dict( self.mol_doc["mol_graph"]) else: mol_graph = MoleculeGraph.with_local_env_strategy( molecule, OpenBabelNN()) self.mol_graph = metal_edge_extender(mol_graph) else: if self.mol_graph is None: mol_graph = MoleculeGraph.with_local_env_strategy( molecule, OpenBabelNN()) self.mol_graph = metal_edge_extender(mol_graph)
def mol_to_mol_graph(molecule: Union[Molecule, MoleculeGraph]): """ Convert a Molecule to a MoleculeGraph using a default connectivity algorithm. Args: molecule (Molecule): Molecule to be converted Returns: mol_graph: MoleculeGraph """ if isinstance(molecule, MoleculeGraph): return molecule else: mol_graph = MoleculeGraph.with_local_env_strategy(molecule, OpenBabelNN()) return metal_edge_extender(mol_graph)
def test_metal_edge_extender(self): mol_graph = MoleculeGraph.with_edges(molecule=self.LiEC, edges={ (0, 2): None, (0, 1): None, (1, 3): None, (1, 4): None, (2, 7): None, (2, 5): None, (2, 8): None, (3, 6): None, (4, 5): None, (5, 9): None, (5, 10): None }) self.assertEqual(len(mol_graph.graph.edges), 11) extended_mol_graph = metal_edge_extender(mol_graph) self.assertEqual(len(mol_graph.graph.edges), 12)
def test_union_molgraph(self): with self.assertRaises(ValueError): _ = union_molgraph([]) # Test "good", well-behaved case good_one = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "molecules" / "union" / "good" / "1.xyz").as_posix()), OpenBabelNN()) good_one = metal_edge_extender(good_one) good_two = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "molecules" / "union" / "good" / "2.xyz").as_posix()), OpenBabelNN()) good_two = metal_edge_extender(good_two) good_union = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "molecules" / "union" / "good" / "union.xyz").as_posix()), OpenBabelNN()) good_union = metal_edge_extender(good_union) good = union_molgraph([good_one, good_two]) self.assertTrue(good_union.isomorphic_to(good)) # Test "bad" case where proximity might be an issue bad_one = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "molecules" / "union" / "bad" / "1.xyz").as_posix()), OpenBabelNN()) bad_one = metal_edge_extender(bad_one) bad_two = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "molecules" / "union" / "bad" / "2.xyz").as_posix()), OpenBabelNN()) bad_two = metal_edge_extender(bad_two) bad_union = MoleculeGraph.with_local_env_strategy( Molecule.from_file( (test_dir / "molecules" / "union" / "bad" / "union.xyz")), OpenBabelNN()) bad_union = metal_edge_extender(bad_union) bad = union_molgraph([bad_one, bad_two]) self.assertTrue(bad_union.isomorphic_to(bad)) with self.assertRaises(ValueError): _ = union_molgraph([bad_one, bad_two], validate_proximity=True)
def test_get_reaction_graphs(self): # Test that isomorphic graphs return themselves li2co3 = MoleculeGraph.with_local_env_strategy( Molecule.from_file( (test_dir / "molecules" / "li2co3_1.xyz").as_posix()), OpenBabelNN()) li2co3 = metal_edge_extender(li2co3) li2co3_copy = copy.deepcopy(li2co3) self.assertEqual(get_reaction_graphs(li2co3, li2co3_copy), [li2co3]) # Test for case where graphs cannot be compared (different species, etc.) ethane = MoleculeGraph.with_local_env_strategy( Molecule.from_file( (test_dir / "molecules" / "ethane.mol").as_posix()), OpenBabelNN()) self.assertEqual(get_reaction_graphs(li2co3, ethane), list()) # Test for case of a single bond-breaking break_rct = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "break" / "rct.xyz").as_posix()), OpenBabelNN()) break_rct = metal_edge_extender(break_rct) break_pro = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "break" / "pro.xyz").as_posix()), OpenBabelNN()) break_pro = metal_edge_extender(break_pro) break_rxn = get_reaction_graphs(break_rct, break_pro) self.assertEqual(len(break_rxn), 1) self.assertTrue(break_rxn[0].isomorphic_to(break_rct)) # for edge in break_rxn[0].graph.edges(data=True): # print(edge) self.assertTrue(break_rxn[0].graph[4][5][0].get("broken", False)) self.assertFalse(break_rxn[0].graph[4][5][0].get("formed", True)) # Test for case of a single bond-forming form_rct = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "form" / "rct.xyz").as_posix()), OpenBabelNN()) form_rct = metal_edge_extender(form_rct) form_pro = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "form" / "pro.xyz").as_posix()), OpenBabelNN()) form_pro = metal_edge_extender(form_pro) form_rxn = get_reaction_graphs(form_rct, form_pro) self.assertEqual(len(form_rxn), 1) self.assertTrue(form_rxn[0].isomorphic_to(form_pro)) self.assertTrue(form_rxn[0].graph[0][3][0].get("formed", False)) self.assertFalse(form_rxn[0].graph[0][3][0].get("broken", True)) # Test for case of complex bond breaking and formation bf_rct = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "break_form" / "rct.xyz").as_posix()), OpenBabelNN()) bf_rct = metal_edge_extender(bf_rct) bf_pro = MoleculeGraph.with_local_env_strategy( Molecule.from_file((test_dir / "reactions" / "isomorphism" / "break_form" / "pro.xyz").as_posix()), OpenBabelNN()) bf_pro = metal_edge_extender(bf_pro) bf_rxn = get_reaction_graphs(bf_rct, bf_pro) self.assertEqual(len(bf_rxn), 0) bf_rxn = get_reaction_graphs(bf_rct, bf_pro, allowed_break=2, allowed_form=1, stop_at_one=True) self.assertEqual(len(bf_rxn), 1) bf_rxn = get_reaction_graphs(bf_rct, bf_pro, allowed_break=2, allowed_form=1, stop_at_one=False) self.assertEqual(len(bf_rxn), 2) self.assertTrue(bf_rxn[0].graph[0][8][0].get("broken", False)) self.assertTrue(bf_rxn[0].graph[6][12][0].get("broken", False)) self.assertTrue(bf_rxn[0].graph[8][12][0].get("formed", False)) self.assertTrue(bf_rxn[1].graph[0][9][0].get("broken", False)) self.assertTrue(bf_rxn[1].graph[6][12][0].get("broken", False)) self.assertTrue(bf_rxn[1].graph[9][12][0].get("formed", False))
def convert_to_babel_mol_graph(self, use_metal_edge_extender=True): self.mol_graph = MoleculeGraph.with_local_env_strategy( self.pymatgen_mol, OpenBabelNN(order=True)) if use_metal_edge_extender: self.mol_graph = metal_edge_extender(self.mol_graph)
"..", "test_files", "reaction_network_files", ) try: import openbabel as ob except ImportError: ob = None """ Create a reaction network for testing from LiEC entries """ if ob: 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) 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"]