def test_hull_analysis_against_old_analyzer(self): """ Compares my decomp energies to those I used for npj paper Changes mine to Ed = Ef if Ef > 0 because this was approach for npj """ d = read_json(os.path.join(test_data_dir, 'SCAN_Hs_from_npj.json')) d['Br3Cr1'] = {'H' : -1.128072912, 'Hd' : -0.35554559} obj = GetHullInputData(d, 'H') fjson = os.path.join(test_data_dir, '_'.join(['hulls', 'npj.json'])) hull_data = obj.hull_data(fjson, True) counted_cmpds = [] for chemical_space in hull_data: obj = AnalyzeHull(hull_data, chemical_space) hull_results = obj.hull_output_data for cmpd in hull_results: if cmpd in d: Ed_current = hull_results[cmpd]['Ed'] # Old script treated Ef > 0 as decomp into elements Ef_current = hull_results[cmpd]['Ef'] if Ef_current > 0: Ed_current = Ef_current Ed_old = d[cmpd]['Hd'] self.assertAlmostEqual(Ed_current, Ed_old, places=3) counted_cmpds.append(cmpd) self.assertEqual(len(set(counted_cmpds)), len(d))
def big_query(self, fjson, criteria, props, remove_polymorphs=True, remake=False, write_it=True): """ Args: fjson (str) - where to write data (if write_it=True) criteria (dict) - MongoDB-style query input (https://github.com/materialsproject/mapidoc) props (list) - list of queryable properties (str) remove_polymorphs - if True: filter data to only include ground-state structures remake - if True: rewrite json; else: read json write_it - if True: write json; else: return dictionary Returns: dictionary of MP data corresponding with query based on criteria and props """ if (remake == True) or not os.path.exists(fjson): if 'material_id' not in props: props += ['material_id'] data = {'criteria': criteria, 'properties': props} r = requests.post('https://materialsproject.org/rest/v2/query', headers={'X-API-KEY': self.api_key}, data={k: json.dumps(v) for k,v in data.items()}) list_of_dicts = r.json()['response'] id_key_dict = list_of_dicts_to_dict(list_of_dicts, 'material_id', props) if remove_polymorphs == True: id_key_dict = self.get_ground_states_from_MP(id_key_dict) if write_it == True: return write_json(id_key_dict, fjson) else: return id_key_dict else: return read_json(fjson)
def hull_data(self, fjson=False, remake=False): """ Args: fjson (str) - file name to write hull data to remake (bool) - if True, write json; if False, read json Returns: dict of {chemical space (str) : {formula (str) : {'E' : formation energy (float), 'amts' : {el (str) : fractional amt of el in formula (float) for el in space}} for all relevant formulas including elements} elements are automatically given formation energy = 0 chemical space is now in 'el1_el2_...' format to be jsonable """ if not fjson: fjson = 'hull_input_data.json' if (remake == True) or not os.path.exists(fjson): hull_data = {} hull_spaces = self.hull_spaces compounds = self.compounds compound_to_energy = self.compound_to_energy for space in hull_spaces: for el in space: compound_to_energy[el] = 0 relevant_compounds = [c for c in compounds if set(CompAnalyzer(c).els).issubset(set(space))] + list(space) hull_data['_'.join(list(space))] = {c : {'E' : compound_to_energy[c], 'amts' : {el : CompAnalyzer(c).fractional_amt_of_el(el=el) for el in space}} for c in relevant_compounds} return write_json(hull_data, fjson) else: return read_json(fjson)
def parallel_hull_data(compound_to_energy, hull_spaces, fjson=False, remake=False, Nprocs=4, verbose=False): import multiprocessing as mp if not fjson: fjson = 'hull_input_data.json' if (remake == True) or not os.path.exists(fjson): hull_data = {} compounds = sorted(list(compound_to_energy.keys())) pool = mp.Pool(processes=Nprocs) # argss = [(compound_to_energy, compounds, space, verbose) for space in hull_spaces] # results = pool.map(_hullin_from_space, argss) results = [ r for r in pool.starmap(_hullin_from_space, [( compound_to_energy, compounds, space, verbose) for space in hull_spaces]) ] keys = ['_'.join(list(space)) for space in hull_spaces] hull_data = dict(zip(keys, results)) return write_json(hull_data, fjson) else: return read_json(fjson)
def main(): d = read_json(os.path.join('/Users/chrisbartel/Dropbox/postdoc/projects/paper-db/data/MP/MP_query_gs.json')) d = {k : d[k] for k in d if (('Ce' in k) and ('N' in k)) or (('Mn' in k) and ('N' in k))} print(len(d)) obj = GetHullInputData(d, 'H') from time import time start = time() hullin = obj.hull_data(False, False) print(len(hullin)) compounds = [list(hullin[space].keys()) for space in hullin] all_compounds = [j for i in compounds for j in i] compounds = list(set([j for i in compounds for j in i])) compound_to_smallest_space_size = {c : np.min([s.count('_') for s in hullin if c in hullin[s]]) for c in compounds} compound_to_space = {c : [s for s in hullin if c in hullin[s] if s.count('_') == compound_to_smallest_space_size[c]][0] for c in compounds} for compound in compound_to_space: print(compound) space = compound_to_space[compound] hullout = AnalyzeHull(hullin, space).cmpd_hull_output_data(compound) end = time() print(end - start) return
def smallest_spaces(hullin, compounds, fjson=False, remake=False, Nprocs=4, verbose=False): """ Args: Nprocs (int) - processors to parallelize over remake (bool) - run this (True) or read this (False) Returns: {formula (str) : chemical space (str, '_'.join(elements), convex hull) that is easiest to compute} """ import multiprocessing as mp if not fjson: fjson = 'smallest_spaces.json' if not remake and os.path.exists(fjson): return read_json(fjson) pool = mp.Pool(processes=Nprocs) # argss = [(hullin, compound, verbose) for compound in compounds] # smallest = pool.map(_smallest_space, argss) smallest = [ r for r in pool.starmap(_smallest_space, [(hullin, compound, verbose) for compound in compounds]) ] data = dict(zip(compounds, smallest)) return write_json(data, fjson)
def parallel_hullout(hullin, smallest_spaces, compounds='all', fjson=False, remake=False, Nprocs=4, verbose=False): """ Args: Nprocs (int) - processors to parallelize over remake (bool) - run this (True) or read this (False) Returns: {formula (str) : {'Ef' : formation energy (float, eV/atom), 'Ed' : decomposition energy (float, eV/atom), 'rxn' : decomposition reaction (str), 'stability' : bool (True if on hull)} } """ import multiprocessing as mp if not fjson: fjson = 'hullout.json' if not remake and os.path.exists(fjson): return read_json(fjson) pool = mp.Pool(processes=Nprocs) if compounds == 'all': compounds = sorted(list(smallest_spaces.keys())) results = [r for r in pool.starmap(_compound_stability, [(smallest_spaces, hullin, compound, verbose) for compound in compounds])] data = dict(zip(compounds, results)) return write_json(data, fjson)
def make_data(remake=False): fjson = '_data_for_RxnEngr.json' if not remake and os.path.exists(fjson): return read_json(fjson) data_file = '/Users/chrisbartel/Dropbox/postdoc/projects/synthesis/paperdb/data/mp/MP_stability.json' data = read_json(data_file) my_els = ['Li', 'Co', 'Ba', 'Ti', 'Y', 'Ba', 'Cu', 'C', 'O'] cmpds = sorted(list(data['0'].keys())) relevant_cmpds = [ c for c in cmpds if set(CompAnalyzer(c).els).issubset(set(sorted(my_els))) ] d = {T: {} for T in data} for c in relevant_cmpds: for T in d: if c in data[T]: d[T][c] = data[T][c] return write_json(d, fjson)
def hull_spaces(self, fjson=False, remake=False, write=False): """ Args: Returns: list of unique chemical spaces (set) that do define convex hull spaces """ if not fjson: fjson = 'hull_spaces.json' if not remake and os.path.exists(fjson): d = read_json(fjson) return d['hull_spaces'] chemical_spaces_and_subspaces = self.chemical_spaces_and_subspaces chemical_subspaces = self.chemical_subspaces d = {'hull_spaces' : [s for s in chemical_spaces_and_subspaces if s not in chemical_subspaces if len(s) > 1]} if write: d = write_json(d, fjson) return d['hull_spaces']
def test_hull_analysis_against_MP(self): """ Uses an MP query of the Al-Ca-Mg-O-Si space Compares my decomp energies to theirs Changes mine to 0 for stable compounds to force agreement with theirs """ d = read_json(os.path.join(test_data_dir, 'MP_Ca-Mg-Al-Si-O.json')) data_for_hulls = {CompAnalyzer(d[k]['pretty_formula']).std_formula() : {'E' : d[k]['formation_energy_per_atom']} for k in d if d[k]['is_min_ID'] == True} obj = GetHullInputData(data_for_hulls, 'E') fjson = os.path.join(test_data_dir, '_'.join(['hulls', 'Ca-Mg-Al-Si-O.json'])) hull_data = obj.hull_data(fjson, True) for chemical_space in hull_data: obj = AnalyzeHull(hull_data, chemical_space) hull_results = obj.hull_output_data for ID in d: if d[ID]['is_min_ID'] == 1: cmpd = CompAnalyzer(d[ID]['pretty_formula']).std_formula() Ed_MP = d[ID]['e_above_hull'] Ed_me = hull_results[cmpd]['Ed'] # MP shows all stables as Hd = 0 if Ed_me < 0: Ed_me = 0 self.assertAlmostEqual(Ed_me, Ed_MP, places=3)
def specific_query(self, fjson, tag, props, remove_polymorphs=True, remake=False, write_it=True): """ Args: fjson (str) - where to write data (if write_it=True) tag (str) - chemical system (el1-el2-...), formula (Al2O3), or ID (mp-1234) on which to query props (list) - list of queryable properties (str) remove_polymorphs - if True: filter data to only include ground-state structures remake - if True: rewrite json; else: read json write_it - if True: write json; else: return dictionary Returns: dictionary of MP data corresponding with query based on tag and props """ if (remake == True) or not os.path.exists(fjson): list_of_dicts = self.rester.get_data(tag, 'vasp', '') id_key_dict = list_of_dicts_to_dict(list_of_dicts, 'material_id', props) if remove_polymorphs == True: id_key_dict = self.get_ground_states_from_MP(id_key_dict) if write_it == True: return write_json(id_key_dict, fjson) else: return id_key_dict else: return read_json(fjson)
def specific_hull_query(self, fjson, elements, props, remove_polymorphs=True, remake=False, write_it=True, include_els=False): """ Args: fjson (str) - where to write data (if write_it=True) elements (list) - list of elements (str) that comprise desired chemical space props (list) - list of queryable properties (str) remove_polymorphs - if True: filter data to only include ground-state structures remake - if True: rewrite json; else: read json write_it - if True: write json; else: return dictionary include_els (bool) - if True, also retrieve the elemental phases; else: don't Returns: dictionary of MP data corresponding with stability-related query for chemical space defined by elements """ if (remake == True) or not os.path.exists(fjson): spaces = [list(combinations(elements, i)) for i in range(2, len(elements)+1)] spaces = [j for i in spaces for j in i] all_data = {} for space in spaces: space = '-'.join(sorted(list(space))) space_data = self.specific_query('blah.json', space, props, remove_polymorphs, remake=True, write_it=False) all_data[space] = space_data if include_els: for el in elements: all_data[el] = self.specific_query('blah.json', el, props, remove_polymorphs, True, False) id_key_dict = {} for k in all_data: for ID in all_data[k]: id_key_dict[ID] = all_data[k][ID] # if remove_polymorphs == True: # id_key_dict = self.get_ground_states_from_MP(id_key_dict) if write_it == True: return write_json(id_key_dict, fjson) else: return id_key_dict else: return read_json(fjson)
def LiNaMnCO(): d = read_json( '/Users/chrisbartel/Dropbox/postdoc/projects/synthesis/LiNaMnCO/data/hulls.json' ) d = { T: {c: d[c]['stability'][T] for c in d} for T in d['Mn1O2']['stability'] } obj = RxnEngr( d, '1_Na2O|2_MnO', 1000, el_order_for_rxns=['Li', 'Co', 'Ba', 'Ti', 'Y', 'Ba', 'Cu', 'C', 'O']) print('INTERFACE:') print(obj.interface) print('EQ:') print(obj.eq) print('RXN:') print(obj.rxn) print('dGr:') print('%.2f eV/at' % obj.dGrxn['eV/at']) return d, obj
def make_json(remake=False): fjson = os.path.join(test_dir, 'test_data', 'perovskite_test_data.json') return read_json(fjson)