def setUp(self): entrylist = list() weights = list() comp = Composition("Mn2O3") entry = PDEntry(comp, 49) entrylist.append(PourbaixEntry(entry)) weights.append(1.0) comp = Ion.from_formula("MnO4[-]") entry = IonEntry(comp, 25) entrylist.append(PourbaixEntry(entry)) weights.append(0.25) comp = Composition("Fe2O3") entry = PDEntry(comp, 50) entrylist.append(PourbaixEntry(entry)) weights.append(0.5) comp = Ion.from_formula("Fe[2+]") entry = IonEntry(comp, 15) entrylist.append(PourbaixEntry(entry)) weights.append(2.5) comp = Ion.from_formula("Fe[3+]") entry = IonEntry(comp, 20) entrylist.append(PourbaixEntry(entry)) weights.append(1.5) self.weights = weights self.entrylist = entrylist self.multientry = MultiEntry(entrylist, weights)
def __init__(self, entry_list, weights=None): """ Initializes a MultiEntry. Args: entry_list: List of component PourbaixEntries weights: Weights associated with each entry. Default is None """ if weights is None: self.weights = [1.0] * len(entry_list) else: self.weights = weights self.entrylist = entry_list self.correction = 0.0 self.uncorrected_energy = 0.0 self.npH = 0.0 self.nPhi = 0.0 self.nH2O = 0.0 self.nM = 0.0 self.name = "" self.entry_id = list() self.total_composition = Composition() for w, e in zip(self.weights, entry_list): self.uncorrected_energy += w * \ e.uncorrected_energy self.correction += w * e.correction self.npH += w * e.npH self.nPhi += w * e.nPhi self.nH2O += w * e.nH2O self.nM += w * e.nM self.name += e.name + " + " self.entry_id.append(e.entry_id) self.total_composition += w * e.composition self.name = self.name[:-3]
def test_read_write_csv(self): Zn_solids = ["Zn", "ZnO", "ZnO2"] sol_g = [0.0, -3.338, -1.315] Zn_ions = ["Zn[2+]", "ZnOH[+]", "HZnO2[-]", "ZnO2[2-]", "ZnO"] liq_g = [-1.527, -3.415, -4.812, -4.036, -2.921] liq_conc = [1e-6, 1e-6, 1e-6, 1e-6, 1e-6] solid_entry = list() for sol in Zn_solids: comp = Composition(sol) delg = sol_g[Zn_solids.index(sol)] solid_entry.append(PourbaixEntry(PDEntry(comp, delg))) ion_entry = list() for ion in Zn_ions: comp_ion = Ion.from_formula(ion) delg = liq_g[Zn_ions.index(ion)] conc = liq_conc[Zn_ions.index(ion)] PoE = PourbaixEntry(IonEntry(comp_ion, delg)) PoE.conc = conc ion_entry.append(PoE) entries = solid_entry + ion_entry PourbaixEntryIO.to_csv("pourbaix_test_entries.csv", entries) (elements, entries) = PourbaixEntryIO.from_csv("pourbaix_test_entries.csv") self.assertEqual( elements, [Element('Zn'), Element('H'), Element('O')], "Wrong elements!") self.assertEqual(len(entries), 8, "Wrong number of entries!") os.remove("pourbaix_test_entries.csv")
def test_parse_criteria(self): crit = MPRester.parse_criteria("mp-1234 Li-*") self.assertIn("Li-O", crit["$or"][1]["chemsys"]["$in"]) self.assertIn({"task_id": "mp-1234"}, crit["$or"]) crit = MPRester.parse_criteria("Li2*") self.assertIn("Li2O", crit["pretty_formula"]["$in"]) self.assertIn("Li2I", crit["pretty_formula"]["$in"]) self.assertIn("CsLi2", crit["pretty_formula"]["$in"]) crit = MPRester.parse_criteria("Li-*-*") self.assertIn("Li-Re-Ru", crit["chemsys"]["$in"]) self.assertNotIn("Li-Li", crit["chemsys"]["$in"]) comps = MPRester.parse_criteria("**O3")["pretty_formula"]["$in"] for c in comps: self.assertEqual(len(Composition(c)), 3, "Failed in %s" % c) chemsys = MPRester.parse_criteria("{Fe,Mn}-O")["chemsys"]["$in"] self.assertEqual(len(chemsys), 2) comps = MPRester.parse_criteria("{Fe,Mn,Co}O")["pretty_formula"]["$in"] self.assertEqual(len(comps), 3, comps) #Let's test some invalid symbols self.assertRaises(ValueError, MPRester.parse_criteria, "li-fe") self.assertRaises(ValueError, MPRester.parse_criteria, "LO2") crit = MPRester.parse_criteria("POPO2") self.assertIn("P2O3", crit["pretty_formula"]["$in"])
def test_get_data(self): props = ["energy", "energy_per_atom", "formation_energy_per_atom", "nsites", "unit_cell_formula", "pretty_formula", "is_hubbard", "elements", "nelements", "e_above_hull", "hubbards", "is_compatible", "task_ids", "density", "icsd_ids", "total_magnetization"] expected_vals = [-191.3359011, -6.833425039285714, -2.5515769497278913, 28, {'P': 4, 'Fe': 4, 'O': 16, 'Li': 4}, "LiFePO4", True, ['Li', 'O', 'P', 'Fe'], 4, 0.0, {'Fe': 5.3, 'Li': 0.0, 'O': 0.0, 'P': 0.0}, True, {'mp-19017', 'mp-540081', 'mp-601412'}, 3.464840709092822, [159107, 154117, 160776, 99860, 181272, 166815, 260571, 92198, 165000, 155580, 38209, 161479, 153699, 260569, 260570, 200155, 260572, 181341, 181342, 72545, 56291, 97764, 162282, 155635], 3.999999999] for (i, prop) in enumerate(props): if prop not in ['hubbards', 'unit_cell_formula', 'elements', 'icsd_ids', 'task_ids']: val = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertAlmostEqual(expected_vals[i], val, 2, "Failed with property %s" % prop) elif prop in ["elements", "icsd_ids", "task_ids"]: upstream_vals = set( self.rester.get_data("mp-19017", prop=prop)[0][prop]) self.assertLessEqual(set(expected_vals[i]), upstream_vals) else: self.assertEqual(expected_vals[i], self.rester.get_data("mp-19017", prop=prop)[0][prop]) props = ['structure', 'initial_structure', 'final_structure', 'entry'] for prop in props: obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] if prop.endswith("structure"): self.assertIsInstance(obj, Structure) elif prop == "entry": obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertIsInstance(obj, ComputedEntry) # Test chemsys search data = self.rester.get_data('Fe-Li-O', prop='unit_cell_formula') self.assertTrue(len(data) > 1) elements = {Element("Li"), Element("Fe"), Element("O")} for d in data: self.assertTrue( set(Composition(d['unit_cell_formula']).elements).issubset( elements)) self.assertRaises(MPRestError, self.rester.get_data, "Fe2O3", "badmethod") # Test getting supported properties self.assertNotEqual(self.rester.get_task_data("mp-30"), []) # Test aliasing data = self.rester.get_task_data("mp-30", "energy") self.assertAlmostEqual(data[0]["energy"], -4.09929227, places=2)
def _get_int_removals_helper(self, spec_amts_oxi, redox_el, redox_els, numa): """ This is a helper method for get_removals_int_oxid! Args: spec_amts_oxi - a dict of species to their amounts in the structure redox_el - the element to oxidize or reduce redox_els - the full list of elements that might be oxidized or reduced numa - a running set of numbers of A ion at integer oxidation steps Returns: a set of numbers A; steps for for oxidizing oxid_el first, then the other oxid_els in this list """ # If a given redox_el has multiple oxidation states present in the structure, we want # to oxidize the lowest state or reduce the highest state if self.working_ion_charge < 0: oxid_old = max(spec.oxi_state for spec in spec_amts_oxi if spec.symbol == redox_el.symbol) oxid_new = math.ceil(oxid_old - 1) lowest_oxid = defaultdict(lambda: 2, {"Cu": 1}) # if this is not a valid solution, break out of here and don't add anything to the list if oxid_new < min( os for os in Element(redox_el.symbol).oxidation_states if os >= lowest_oxid[redox_el.symbol]): return numa else: oxid_old = min(spec.oxi_state for spec in spec_amts_oxi if spec.symbol == redox_el.symbol) oxid_new = math.floor(oxid_old + 1) # if this is not a valid solution, break out of here and don't add anything to the list if oxid_new > redox_el.max_oxidation_state: return numa # update the spec_amts_oxi map to reflect that the redox took place spec_old = Species(redox_el.symbol, oxid_old) spec_new = Species(redox_el.symbol, oxid_new) specamt = spec_amts_oxi[spec_old] spec_amts_oxi = { sp: amt for sp, amt in spec_amts_oxi.items() if sp != spec_old } spec_amts_oxi[spec_new] = specamt spec_amts_oxi = Composition(spec_amts_oxi) # determine the amount of ion A in the structure needed for charge balance and add it to the list oxi_noA = sum(spec.oxi_state * spec_amts_oxi[spec] for spec in spec_amts_oxi if spec.symbol not in self.working_ion.symbol) a = max(0, -oxi_noA / self.working_ion_charge) numa = numa.union({a}) # recursively try the other oxidation states if a == 0: return numa for red in redox_els: numa = numa.union( self._get_int_removals_helper(spec_amts_oxi.copy(), red, redox_els, numa)) return numa
def setUp(self): comp = Composition("Mn2O3") self.solentry = PDEntry(comp, 49) ion = Ion.from_formula("MnO4-") self.ionentry = IonEntry(ion, 25) self.PxIon = PourbaixEntry(self.ionentry) self.PxSol = PourbaixEntry(self.solentry) self.PxIon.conc = 1e-4
def ion_or_solid_comp_object(formula): """ Returns either an ion object or composition object given a formula. Args: formula: String formula. Eg. of ion: NaOH(aq), Na[+]; Eg. of solid: Fe2O3(s), Fe(s), Na2O Returns: Composition/Ion object """ m = re.search(r"\[([^\[\]]+)\]|\(aq\)", formula) if m: comp_obj = Ion.from_formula(formula) elif re.search(r"\(s\)", formula): comp_obj = Composition(formula[:-3]) else: comp_obj = Composition(formula) return comp_obj
def test_get_data(self): props = ["energy", "energy_per_atom", "formation_energy_per_atom", "nsites", "unit_cell_formula", "pretty_formula", "is_hubbard", "elements", "nelements", "e_above_hull", "hubbards", "is_compatible", "task_ids", "density", "icsd_ids", "total_magnetization"] # unicode literals have been reintroduced in py>3.2 expected_vals = [-191.33812137, -6.833504334642858, -2.551358929370749, 28, {k: v for k, v in {'P': 4, 'Fe': 4, 'O': 16, 'Li': 4}.items()}, "LiFePO4", True, ['Li', 'O', 'P', 'Fe'], 4, 0.0, {k: v for k, v in {'Fe': 5.3, 'Li': 0.0, 'O': 0.0, 'P': 0.0}.items()}, True, [u'mp-601412', u'mp-19017', u'mp-796535', u'mp-797820', u'mp-540081', u'mp-797269'], 3.4662026991351147, [159107, 154117, 160776, 99860, 181272, 166815, 260571, 92198, 165000, 155580, 38209, 161479, 153699, 260569, 260570, 200155, 260572, 181341, 181342, 72545, 56291, 97764, 162282, 155635], 16.0002716] for (i, prop) in enumerate(props): if prop not in ['hubbards', 'unit_cell_formula', 'elements', 'icsd_ids', 'task_ids']: val = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertAlmostEqual(expected_vals[i], val) elif prop in ["elements", "icsd_ids", "task_ids"]: self.assertEqual(set(expected_vals[i]), set(self.rester.get_data("mp-19017", prop=prop)[0][prop])) else: self.assertEqual(expected_vals[i], self.rester.get_data("mp-19017", prop=prop)[0][prop]) props = ['structure', 'initial_structure', 'final_structure', 'entry'] for prop in props: obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] if prop.endswith("structure"): self.assertIsInstance(obj, Structure) elif prop == "entry": obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertIsInstance(obj, ComputedEntry) #Test chemsys search data = self.rester.get_data('Fe-Li-O', prop='unit_cell_formula') self.assertTrue(len(data) > 1) elements = {Element("Li"), Element("Fe"), Element("O")} for d in data: self.assertTrue( set(Composition(d['unit_cell_formula']).elements).issubset( elements)) self.assertRaises(MPRestError, self.rester.get_data, "Fe2O3", "badmethod")
def _get_int_removals_helper(self, spec_amts_oxi, oxid_el, oxid_els, numa): """ This is a helper method for get_removals_int_oxid! Args: spec_amts_oxi - a dict of species to their amounts in the structure oxid_el - the element to oxidize oxid_els - the full list of elements that might be oxidized numa - a running set of numbers of A cation at integer oxidation steps Returns: a set of numbers A; steps for for oxidizing oxid_el first, then the other oxid_els in this list """ # If Mn is the oxid_el, we have a mixture of Mn2+, Mn3+, determine the minimum oxidation state for Mn #this is the state we want to oxidize! oxid_old = min([ spec.oxi_state for spec in spec_amts_oxi if spec.symbol == oxid_el.symbol ]) oxid_new = math.floor(oxid_old + 1) #if this is not a valid solution, break out of here and don't add anything to the list if oxid_new > oxid_el.max_oxidation_state: return numa #update the spec_amts_oxi map to reflect that the oxidation took place spec_old = Specie(oxid_el.symbol, oxid_old) spec_new = Specie(oxid_el.symbol, oxid_new) specamt = spec_amts_oxi[spec_old] spec_amts_oxi = { sp: amt for sp, amt in spec_amts_oxi.items() if sp != spec_old } spec_amts_oxi[spec_new] = specamt spec_amts_oxi = Composition(spec_amts_oxi) #determine the amount of cation A in the structure needed for charge balance and add it to the list oxi_noA = sum([ spec.oxi_state * spec_amts_oxi[spec] for spec in spec_amts_oxi if spec.symbol not in self.cation.symbol ]) a = max(0, -oxi_noA / self.cation_charge) numa = numa.union({a}) #recursively try the other oxidation states if a == 0: return numa else: for oxid_el in oxid_els: numa = numa.union( self._get_int_removals_helper(spec_amts_oxi.copy(), oxid_el, oxid_els, numa)) return numa
def get_only_sites(self): """ Get a copy of the structure with only the sites Args: Returns: Structure: Structure with all possible migrating ion sites """ migrating_ion_sites = list( filter( lambda site: site.species == Composition( {self.migrating_specie: 1}), self.structure.sites)) return Structure.from_sites(migrating_ion_sites)
def test_get_data(self): props = ["energy", "energy_per_atom", "formation_energy_per_atom", "nsites", "unit_cell_formula", "pretty_formula", "is_hubbard", "elements", "nelements", "e_above_hull", "hubbards", "is_compatible", "task_ids", "density", "icsd_id", "total_magnetization"] expected_vals = [-191.33812137, -6.833504334642858, -2.5532843405078913, 28, {u'P': 4, u'Fe': 4, u'O': 16, u'Li': 4}, "LiFePO4", True, [u'Li', u'O', u'P', u'Fe'], 4, 0.0, {u'Fe': 5.3, u'Li': 0.0, u'O': 0.0, u'P': 0.0}, True, [540081, 19017], 3.4662026991351147, 56291, 16.0001687] for (i, prop) in enumerate(props): if prop not in ['hubbards', 'unit_cell_formula', 'elements']: val = self.rester.get_data(540081, prop=prop)[0][prop] self.assertAlmostEqual(expected_vals[i], val) elif prop == "elements": self.assertEqual(set(expected_vals[i]), set(self.rester.get_data(540081, prop=prop)[0][prop])) else: self.assertEqual(expected_vals[i], self.rester.get_data(540081, prop=prop)[0][prop]) props = ['structure', 'initial_structure', 'final_structure', 'entry'] for prop in props: obj = self.rester.get_data(540081, prop=prop)[0][prop] if prop.endswith("structure"): self.assertIsInstance(obj, Structure) elif prop == "entry": obj = self.rester.get_data(540081, prop=prop)[0][prop] self.assertIsInstance(obj, ComputedEntry) #Test chemsys search data = self.rester.get_data('Fe-Li-O', prop='unit_cell_formula') self.assertTrue(len(data) > 1) elements = {Element("Li"), Element("Fe"), Element("O")} for d in data: self.assertTrue( set(Composition(d['unit_cell_formula']).elements).issubset( elements)) self.assertRaises(MPRestError, self.rester.get_data, "Fe2O3", "badmethod")
def from_csv(filename): """ Imports PourbaixEntries from a csv. Args: filename - Filename to import from. Returns: List of Entries """ import csv reader = csv.reader(open(filename, "rb"), delimiter=",", quotechar="\"", quoting=csv.QUOTE_MINIMAL) entries = list() header_read = False for row in reader: if not header_read: elements = row[1:(len(row) - 4)] header_read = True else: name = row[0] energy = float(row[-4]) conc = float(row[-1]) comp = dict() for ind in range(1, len(row) - 4): if float(row[ind]) > 0: comp[Element(elements[ind - 1])] = float(row[ind]) phase_type = row[-3] if phase_type == "Ion": PoE = PourbaixEntry( IonEntry(Ion.from_formula(name), energy)) PoE.set_conc(conc) PoE.set_name(name) entries.append(PoE) else: entries.append( PourbaixEntry(PDEntry(Composition(comp), energy))) elements = [Element(el) for el in elements] return elements, entries
def test_get_data(self): props = { "energy", "energy_per_atom", "formation_energy_per_atom", "nsites", "unit_cell_formula", "pretty_formula", "is_hubbard", "elements", "nelements", "e_above_hull", "hubbards", "is_compatible", "task_ids", "density", "icsd_ids", "total_magnetization", } mpid = "mp-1143" vals = requests.get( f"http://legacy.materialsproject.org/materials/{mpid}/json/") expected_vals = vals.json() for prop in props: if prop not in [ "hubbards", "unit_cell_formula", "elements", "icsd_ids", "task_ids", ]: val = self.rester.get_data(mpid, prop=prop)[0][prop] if prop in ["energy", "energy_per_atom"]: prop = "final_" + prop self.assertAlmostEqual(expected_vals[prop], val, 2, f"Failed with property {prop}") elif prop in ["elements", "icsd_ids", "task_ids"]: upstream_vals = set( self.rester.get_data(mpid, prop=prop)[0][prop]) self.assertLessEqual(set(expected_vals[prop]), upstream_vals) else: self.assertEqual( expected_vals[prop], self.rester.get_data(mpid, prop=prop)[0][prop], ) props = ["structure", "initial_structure", "final_structure", "entry"] for prop in props: obj = self.rester.get_data(mpid, prop=prop)[0][prop] if prop.endswith("structure"): self.assertIsInstance(obj, Structure) elif prop == "entry": obj = self.rester.get_data(mpid, prop=prop)[0][prop] self.assertIsInstance(obj, ComputedEntry) # Test chemsys search data = self.rester.get_data("Fe-Li-O", prop="unit_cell_formula") self.assertTrue(len(data) > 1) elements = {Element("Li"), Element("Fe"), Element("O")} for d in data: self.assertTrue( set(Composition( d["unit_cell_formula"]).elements).issubset(elements)) self.assertRaises(MPRestError, self.rester.get_data, "Fe2O3", "badmethod")
def test_get_data(self): props = [ "energy", "energy_per_atom", "formation_energy_per_atom", "nsites", "unit_cell_formula", "pretty_formula", "is_hubbard", "elements", "nelements", "e_above_hull", "hubbards", "is_compatible", "task_ids", "density", "icsd_ids", "total_magnetization", ] expected_vals = [ -191.7661349, -6.848790532142857, -2.5571951564625857, 28, { "P": 4, "Fe": 4, "O": 16, "Li": 4 }, "LiFePO4", True, ["Li", "O", "P", "Fe"], 4, 0.0, { "Fe": 5.3, "Li": 0.0, "O": 0.0, "P": 0.0 }, True, {"mp-19017", "mp-540081", "mp-601412"}, 3.4708958823634912, [ 159107, 154117, 160776, 99860, 181272, 166815, 260571, 92198, 165000, 155580, 38209, 161479, 153699, 260569, 260570, 200155, 260572, 181341, 181342, 72545, 56291, 97764, 162282, 155635, ], 0, ] for (i, prop) in enumerate(props): if prop not in [ "hubbards", "unit_cell_formula", "elements", "icsd_ids", "task_ids", ]: val = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertAlmostEqual(expected_vals[i], val, 2, "Failed with property %s" % prop) elif prop in ["elements", "icsd_ids", "task_ids"]: upstream_vals = set( self.rester.get_data("mp-19017", prop=prop)[0][prop]) self.assertLessEqual(set(expected_vals[i]), upstream_vals) else: self.assertEqual( expected_vals[i], self.rester.get_data("mp-19017", prop=prop)[0][prop], ) props = ["structure", "initial_structure", "final_structure", "entry"] for prop in props: obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] if prop.endswith("structure"): self.assertIsInstance(obj, Structure) elif prop == "entry": obj = self.rester.get_data("mp-19017", prop=prop)[0][prop] self.assertIsInstance(obj, ComputedEntry) # Test chemsys search data = self.rester.get_data("Fe-Li-O", prop="unit_cell_formula") self.assertTrue(len(data) > 1) elements = {Element("Li"), Element("Fe"), Element("O")} for d in data: self.assertTrue( set(Composition( d["unit_cell_formula"]).elements).issubset(elements)) self.assertRaises(MPRestError, self.rester.get_data, "Fe2O3", "badmethod") # Test getting supported properties self.assertNotEqual(self.rester.get_task_data("mp-30"), []) # Test aliasing data = self.rester.get_task_data("mp-30", "energy") self.assertAlmostEqual(data[0]["energy"], -4.09929227, places=2)
def curate_cifstring(cifstring): """ :return integrity_class 3 can run all calculations 2 can only run geometric analyses 1 do not run any calculations (exception) outputs files written by this function structural_schemas structural_schemas['configuration']: the major config structural_schemas['molgraphs']: a list of unique molgraphs from the major config, rsorted by # of atoms structural_schemas['molsmiles']: a list of unique molecular smiles from the major config, rsorted by # of atoms identifier hashconfig(major_config) """ integrity_class = 3 outputs = [] structural_schemas = OrderedDict() dp = DisParser(cifstring) try: print('--- begin DisParser.to_configs ---') dis_pstructure, dis_unwrap_str, dis_mols, config_infos = dp.to_configs( write_files=True, vanilla=True ) # if True writes conf_x.cif, configs is a list of pmg Structure except: emsg = 'ERROR: dp.to_configs failed!' print(emsg) raise CuratorError(emsg) if len(config_infos) not in [1, 2]: emsg = 'ERROR: vanilla to_configs found too many configs' print(emsg) raise CuratorError(emsg) disorder_class = dp.classification print('disorder class: {}'.format(disorder_class)) print('--- end DisParser.to_configs ---\n') print('--- begin composition check ---') try: cif_comp = Composition(dp.cifdata['_chemical_formula_sum']) print('_chemical_formula_sum: {}'.format(cif_comp)) except (KeyError, CompositionError) as e: cif_comp = None print( WEAK_WMSG.format( '_chemical_formula_sum does not exist or cannot be parsed')) try: comp_str = dp.cifdata['_chemical_formula_moiety'] moiety_comps = [Composition(s) for s in comp_str.split(',')] moiety_comps = sorted(moiety_comps, key=lambda x: len(x), reverse=True) print('_chemical_formula_moiety:') for moiety_comp in moiety_comps: print('-- {}'.format(moiety_comp)) except (KeyError, CompositionError) as e: print( WEAK_WMSG.format( '_chemical_formula_moiety does not exist or cannot be parsed')) major_config_structure, major_occu = config_infos[0] print('major config comps: {}'.format(major_config_structure.composition)) print('major config occu: {}'.format(major_occu)) if isinstance(cif_comp, Composition): if not major_config_structure.composition == cif_comp: print( WEAK_WMSG.format( 'major comps does not match _chemical_formula_sum')) try: minor_config_structure, minor_occu = config_infos[1] print('minor config comps: {}'.format( minor_config_structure.composition)) print('minor config occu: {}'.format(minor_occu)) major_minor_comps_match = minor_config_structure.composition == major_config_structure if major_minor_comps_match: print(WEAK_WMSG.format('minor and major comps do not match')) except IndexError: pass print('--- end composition check ---\n') print('--- begin major config check ---') try: major_config = Config.from_labeled_clean_pstructure( major_config_structure, major_occu) except: emsg = 'ERROR: cannot parse major config structure into a config!' print(emsg) raise CuratorError(emsg) structural_schemas['configuration'] = major_config.as_dict() major_config_cif = 'curated_major_config.cif' major_config.pstructure.to('cif', major_config_cif) outputs.append('{}/{}'.format(os.getcwd(), major_config_cif)) if not major_config.molconformers_all_legit(): emsg = 'ERROR: cannot convert all molconformers to rdkit mol' print(emsg) raise CuratorError(emsg) print('major config moiety comps:') mc: MolConformer max_nradicals = 0 imc = 0 for mc in major_config.molconformers: print(' -- imc {}: {}'.format(imc, mc.composition)) try: rdmol, smiles, _, _ = mc.to_rdmol(charged_fragments=False) Chem.SanitizeMol(rdmol) except: print( WMSG.format( 'rdmol sanitize failed, integrity_class is set to 2')) if integrity_class > 2: integrity_class = 2 nradicals = mc.is_missing_hydrogen() print(' missing hydrogen: {}'.format(nradicals)) mc_xyzfils = 'curated_molconformer_{}_{}.xyz'.format(imc, nradicals) mc.to('xyz', mc_xyzfils) outputs.append(mc_xyzfils) if nradicals > max_nradicals: max_nradicals = nradicals imc += 1 molsmiles = [] for mc in sorted(major_config.molconformers, key=lambda x: len(x), reverse=True): # imol == imc, imol is not assigned based on len(mc), so use another for loop to do this molsmiles.append(mc.smiles) structural_schemas['molsmiles'] = list(set(molsmiles)) if max_nradicals: print( WMSG.format( 'major config missing hydrogen, integrity_class is set to 2')) if integrity_class > 2: integrity_class = 2 unique_molgraphs = major_config.molgraph_set() structural_schemas['molgraphs'] = [ umg.as_dict() for umg in sorted(list(unique_molgraphs), key=lambda x: len(x)) ] if len(unique_molgraphs) > 1: emsg = 'ERROR: more than one unique molecule in the major config!' print(emsg) raise CuratorError(emsg) print('--- end major config check ---\n') print('integrity_class: {}'.format(integrity_class)) return integrity_class, outputs, structural_schemas, major_config.hashconfig( )
def read(self): dis_pstructure, dis_unwrap_str, dis_mols, config_infos = self.dp.to_configs(write_files=False, vanilla=True) # if True writes conf_x.cif, configs is a list of pmg Structure self.disorder_class = self.dp.classification self.results['disordered_pstructure'] = dis_unwrap_str self.results['disordered_pmgmols'] = dis_mols config_structures = [] config_occupancies = [] for item in config_infos: config_structures.append(item[0]) config_occupancies.append(item[1]) self.results['config_sturcutures'] = config_structures self.results['config_occupancies'] = config_occupancies configs = [] missh = [] for i in range(len(config_structures)): structure = config_structures[i] conf = Config.from_labeled_clean_pstructure(structure, occu=config_occupancies[i]) config_missingh = False for conformer in conf.molconformers: if conformer.is_missing_hydrogen(): config_missingh = True break if config_missingh: conf.pstructure.to('cif', '{}_mhconf_{}.cif'.format(self.identifier, i)) warnings.warn('missing hydrogens in {}_mhconf_{}.cif'.format(self.identifier, i)) configs.append(conf) missh.append(config_missingh) self.results['configurations'] = configs self.results['missingh'] = missh # these are checked against to configs[0] check_config = configs[0] try: self.results['n_unique_molecule'] = len(check_config.molgraph_set()) self.results['n_molconformers'] = len(check_config.molconformers) self.results['all_molconformers_legit'] = check_config.molconformers_all_legit() self.results['disorder_location'] = self.where_is_disorder(check_config) except: warnings.warn('there are problems in readcif.results, some fileds will be missing!') try: comp = Composition(self.dp.cifdata['_chemical_formula_sum']) self.results['cif_sum_composition'] = comp if not all(self.results['cif_sum_composition'] == mc.composition for mc in check_config.molconformers): self.results['sum_composition_match'] = False print('cif_sum_composition: {}'.format(self.results['cif_sum_composition'])) for mc in check_config.molconformers: print('mc composition: {}'.format(mc.composition)) warnings.warn('moiety sum composition does not match that specified in cif file!') else: self.results['sum_composition_match'] = True except (KeyError, CompositionError) as e: self.results['cif_sum_composition'] = None self.results['sum_composition_match'] = None try: comp_str = self.dp.cifdata['_chemical_formula_moiety'] comps = [Composition(s) for s in comp_str.split(',')] comps = sorted(comps, key=lambda x:len(x), reverse=True) if len(comps) > 1: warnings.warn('more than 1 moiety from cif file! only the largest one is checked!') self.results['cif_moiety_composition'] = comps[0] if not all(self.results['cif_moiety_composition'] == mc.composition for mc in check_config.molconformers): self.results['moiety_composition_match'] = False print('cif_moiety_composition: {}'.format(self.results['cif_moiety_composition'])) for mc in check_config.molconformers: print('mc composition: {}'.format(mc.composition)) warnings.warn('moiety composition does not match that specified in cif file!') else: self.results['moiety_composition_match'] = True except (KeyError, CompositionError) as e: self.results['cif_moiety_composition'] = None self.results['moiety_composition_match'] = None
def apply_transformation(self, structure, return_ranked_list=False): # Make a mutable structure first mods = Structure.from_sites(structure) for sp, spin in self.mag_species_spin.items(): sp = get_el_sp(sp) oxi_state = getattr(sp, "oxi_state", 0) if spin: up = Specie(sp.symbol, oxi_state, {"spin": abs(spin)}) down = Specie(sp.symbol, oxi_state, {"spin": -abs(spin)}) mods.replace_species({ sp: Composition({ up: self.order_parameter, down: 1 - self.order_parameter }) }) else: mods.replace_species( {sp: Specie(sp.symbol, oxi_state, {"spin": spin})}) if mods.is_ordered: return [mods] if return_ranked_list > 1 else mods enum_args = self.kwargs enum_args["min_cell_size"] = max( int( MagOrderingTransformation.determine_min_cell( structure, self.mag_species_spin, self.order_parameter)), enum_args.get("min_cell_size", 1)) max_cell = enum_args.get('max_cell_size') if max_cell: if enum_args["min_cell_size"] > max_cell: raise ValueError('Specified max cell size is smaller' ' than the minimum enumerable cell size') else: enum_args["max_cell_size"] = enum_args["min_cell_size"] t = EnumerateStructureTransformation(**enum_args) alls = t.apply_transformation(mods, return_ranked_list=return_ranked_list) try: num_to_return = int(return_ranked_list) except ValueError: num_to_return = 1 if num_to_return == 1 or not return_ranked_list: return alls[0]["structure"] if num_to_return else alls m = StructureMatcher(comparator=SpinComparator()) key = lambda x: SpacegroupAnalyzer(x, 0.1).get_space_group_number() out = [] for _, g in groupby(sorted([d["structure"] for d in alls], key=key), key): g = list(g) grouped = m.group_structures(g) out.extend([{ "structure": g[0], "energy": self.energy_model.get_energy(g[0]) } for g in grouped]) self._all_structures = sorted(out, key=lambda d: d["energy"]) return self._all_structures[0:num_to_return]
Created on Wed Feb 28 15:40:02 2018 @author: jherfson """ from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry #, MultiEntry from pymatgen.analysis.pourbaix.entry import PourbaixEntryIO from pymatgen.analysis.phase_diagram import PDEntry from pymatgen.core.ion import Ion from pymatgen.core.structure import Composition Zn_solids = ["Zn", "ZnO", "ZnO2"] sol_g = [0.0, -3.338, -1.315] Zn_ions = ["Zn[2+]", "ZnOH[+]", "HZnO2[-]", "ZnO2[2-]", "ZnO"] liq_g = [-1.527, -3.415, -4.812, -4.036, -2.921] liq_conc = [1e-6, 1e-6, 1e-6, 1e-6, 1e-6] solid_entry = list() for sol in Zn_solids: comp = Composition(sol) delg = sol_g[Zn_solids.index(sol)] solid_entry.append(PourbaixEntry(PDEntry(comp, delg))) ion_entry = list() for ion in Zn_ions: comp_ion = Ion.from_formula(ion) delg = liq_g[Zn_ions.index(ion)] conc = liq_conc[Zn_ions.index(ion)] PoE = PourbaixEntry(IonEntry(comp_ion, delg)) PoE.conc = conc ion_entry.append(PoE) entries = solid_entry + ion_entry PourbaixEntryIO.to_csv("pourbaix_test_entries.csv", entries)