def check_neutrality_4(formula): charge_neutral_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) max_num = max(reduce_formula.values()) for i, ele_a in enumerate(list_of_elements): for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i+1:]): for ox_b in smact.Element(ele_b).oxidation_states: for k, ele_c in enumerate(list_of_elements[i+j+2:]): for ox_c in smact.Element(ele_c).oxidation_states: for m, ele_d in enumerate(list_of_elements[i+j+k+3:]): for ox_d in smact.Element(ele_d).oxidation_states: # Checks if the combination is charge neutral before printing it out! # cn_e, cn_r = neutral_ratios([ox_a, ox_b, ox_c, ox_d], threshold = int(max_num)) if cn_e: for num in cn_r: if tuple(reduce_formula.values()) == num: return True # print(cn_e) # print(cn_r) # print(ox_a, ox_b, ox_c) # charge_neutral_count = charge_neutral_count + 1 # print('{0:3s} {1:3s} {2:3s}'.format(ele_a, ele_b, ele_c)) print('Number of combinations = {0}'.format(charge_neutral_count)) print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def check_electronegativity_2(formula): pauling_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) max_num = max(reduce_formula.values()) for i, ele_a in enumerate(list_of_elements): paul_a = smact.Element(ele_a).pauling_eneg for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i + 1:]): paul_b = smact.Element(ele_b).pauling_eneg for ox_b in smact.Element(ele_b).oxidation_states: # Puts elements, oxidation states and electronegativites into lists for convenience # elements = [ele_a, ele_b] oxidation_states = [ox_a, ox_b] pauling_electro = [paul_a, paul_b] # Checks if the electronegativity makes sense and if the combination is charge neutral # electroneg_makes_sense = pauling_test( oxidation_states, pauling_electro, elements) cn_e, cn_r = neutral_ratios([ox_a, ox_b], threshold=int(max_num)) if cn_e: if electroneg_makes_sense: pauling_count = pauling_count + 1 for num in cn_r: if tuple(reduce_formula.values()) == num: # print('{0:2s}{1:3d} {2:2s}{3:3d} {4:2s}{5:3d}'.format(ele_a, ox_a, ele_b, # ox_b, ele_c, ox_c)) return True print('Number of combinations = {0}'.format(pauling_count)) print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def check_neutrality_2(formula): charge_neutral_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) # stoichs = np.array(list(reduce_formula.values())).astype(np.int32)[:,np.newaxis] max_num = max(reduce_formula.values()) for i, ele_a in enumerate(list_of_elements): for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i+1:]): for ox_b in smact.Element(ele_b).oxidation_states: # Checks if the combination is charge neutral before printing it out! # # neutral_ratios(oxidations, stoichs=False, threshold=5) #speed up by providing stoichs # cn_e, cn_r = neutral_ratios([ox_a, ox_b], threshold = int(max_num)) cn_e, cn_r = neutral_ratios([ox_a, ox_b], threshold = int(max_num)) if cn_e: for num in cn_r: if tuple(reduce_formula.values()) == num: return True # print(cn_e) # print(cn_r) # print(ox_a, ox_b, ox_c) # charge_neutral_count = charge_neutral_count + 1 # print('{0:3s} {1:3s} {2:3s}'.format(ele_a, ele_b, ele_c)) print('Number of combinations = {0}'.format(charge_neutral_count)) print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def ternary_smact_combos(position1, position2, position3, threshold=8): """ Combinatorially generate Pymatgen Species compositions using SMACT when up to three different lists are needed to draw species from (e.g. Ternary metal halides.) Args: position(n) (list of species): Species to be considered iteratively for each position. threshold (int): Max stoichiometry threshold. Returns: species_comps (list): Compositions as tuples of Pymatgen Species objects. """ initial_comps_list = [] for sp1, sp2, an in tqdm(itertools.product(position1, position2, position3)): e1, oxst1 = sp1.symbol, int(sp1.oxi_state) eneg1 = Element(e1).pauling_eneg e2, oxst2 = sp2.symbol, int(sp2.oxi_state) eneg2 = Element(e2).pauling_eneg e3, oxst3 = an.symbol, int(an.oxi_state) eneg3 = Element(e3).pauling_eneg symbols = [e1, e2, e3] ox_states = [oxst1, oxst2, oxst3] cn_e, cn_r = neutral_ratios(ox_states, threshold=threshold) if cn_e: enegs = [eneg1, eneg2, eneg3] eneg_ok = pauling_test(ox_states, enegs, symbols=symbols, repeat_cations=False) if eneg_ok: for ratio in cn_r: comp = (symbols, ox_states, list(ratio)) initial_comps_list.append(comp) print('Number of compositions before reduction: {}'.format( len(initial_comps_list))) # Create a list of pymatgen species for each comp print('Converting to Pymatgen Species...') species_comps = [] for i in tqdm(initial_comps_list): comp = {} for sym, ox, ratio in zip(i[0], i[1], i[2]): comp[Specie(sym, ox)] = ratio comp_list = [[key] * val for key, val in comp.items()] comp_list = [item for sublist in comp_list for item in sublist] species_comps.append(comp_list) # Sort and ditch duplicates print( 'Ditching duplicates (sorry to have got your hopes up with the big numbers)...' ) for i in species_comps: i.sort() i.sort(key=lambda x: x.oxi_state, reverse=True) species_comps = list(set([tuple(i) for i in species_comps])) print('Total number of new compounds unique compositions: {0}'.format( len(species_comps))) return species_comps
def check_electronegativity_4(formula): pauling_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) stoichs = list( np.array(list(reduce_formula.values())).astype(np.int32)[:, np.newaxis]) max_num = max(reduce_formula.values()) for i, ele_a in enumerate(list_of_elements): paul_a = smact.Element(ele_a).pauling_eneg for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i + 1:]): paul_b = smact.Element(ele_b).pauling_eneg for ox_b in smact.Element(ele_b).oxidation_states: for k, ele_c in enumerate(list_of_elements[i + j + 2:]): paul_c = smact.Element(ele_c).pauling_eneg for ox_c in smact.Element(ele_c).oxidation_states: for m, ele_d in enumerate( list_of_elements[i + j + k + 3:]): paul_d = smact.Element(ele_d).pauling_eneg for ox_d in smact.Element( ele_d).oxidation_states: # Puts elements, oxidation states and electronegativites into lists for convenience # elements = [ele_a, ele_b, ele_c, ele_d] oxidation_states = [ox_a, ox_b, ox_c, ox_d] pauling_electro = [ paul_a, paul_b, paul_c, paul_d ] if None in pauling_electro: print( "No pauling electronegativity data" ) return False # Checks if the electronegativity makes sense and if the combination is charge neutral # electroneg_makes_sense = pauling_test( oxidation_states, pauling_electro, elements) cn_e, cn_r = neutral_ratios( [ox_a, ox_b, ox_c, ox_d], stoichs=stoichs, threshold=int(max_num)) if cn_e: if electroneg_makes_sense: pauling_count = pauling_count + 1 for num in cn_r: if tuple(reduce_formula.values( )) == num: # print('{0:2s}{1:3d} {2:2s}{3:3d} {4:2s}{5:3d}'.format(ele_a, ox_a, ele_b, # ox_b, ele_c, ox_c)) return True # print('Number of combinations = {0}'.format(pauling_count)) # print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def check_electronegativity_8(formula): pauling_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) max_num = max(reduce_formula.values()) # for element in reduce_formula.keys(): # print(len(smact.Element(element).oxidation_states), end = ",") for i, ele_a in enumerate(list_of_elements): paul_a = smact.Element(ele_a).pauling_eneg for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i+1:]): paul_b = smact.Element(ele_b).pauling_eneg for ox_b in smact.Element(ele_b).oxidation_states: for k, ele_c in enumerate(list_of_elements[i+j+2:]): paul_c = smact.Element(ele_c).pauling_eneg for ox_c in smact.Element(ele_c).oxidation_states: for m, ele_d in enumerate(list_of_elements[i+j+k+3:]): paul_d = smact.Element(ele_d).pauling_eneg for ox_d in smact.Element(ele_d).oxidation_states: for n, ele_e in enumerate(list_of_elements[i+j+k+m+4:]): paul_e = smact.Element(ele_e).pauling_eneg for ox_e in smact.Element(ele_e).oxidation_states: for p, ele_f in enumerate(list_of_elements[i+j+k+m+n+5:]): paul_f = smact.Element(ele_f).pauling_eneg for ox_f in smact.Element(ele_f).oxidation_states: for q, ele_g in enumerate(list_of_elements[i+j+k+m+n+p+6:]): paul_g = smact.Element(ele_g).pauling_eneg for ox_g in smact.Element(ele_g).oxidation_states: for s, ele_h in enumerate(list_of_elements[i+j+k+m+n+p+q+7:]): paul_h = smact.Element(ele_h).pauling_eneg for ox_h in smact.Element(ele_h).oxidation_states: # Puts elements, oxidation states and electronegativites into lists for convenience # elements = [ele_a, ele_b, ele_c, ele_d, ele_e, ele_f, ele_g, ele_h] oxidation_states = [ox_a, ox_b, ox_c, ox_d, ox_e, ox_f, ox_g, ox_h] pauling_electro = [paul_a, paul_b, paul_c, paul_d, paul_e, paul_f, paul_g, paul_h] if None in pauling_electro: print("No pauling electronegativity data") return False # Checks if the electronegativity makes sense and if the combination is charge neutral # electroneg_makes_sense = pauling_test(oxidation_states, pauling_electro, elements) cn_e, cn_r = neutral_ratios([ox_a, ox_b, ox_c, ox_d, ox_e, ox_f, ox_g, ox_h], threshold = int(max_num)) if cn_e: if electroneg_makes_sense: pauling_count = pauling_count + 1 for num in cn_r: if tuple(reduce_formula.values()) == num: # print('{0:2s}{1:3d} {2:2s}{3:3d} {4:2s}{5:3d}'.format(ele_a, ox_a, ele_b, # ox_b, ele_c, ox_c)) return True # print('Number of combinations = {0}'.format(pauling_count)) # print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def check_neutrality_8(formula): charge_neutral_count = 0 comp = mg.Composition(formula) reduce_formula = comp.get_el_amt_dict() list_of_elements = list(reduce_formula.keys()) stoichs = list( np.array(list(reduce_formula.values())).astype(np.int32)[:,np.newaxis] ) max_num = max(reduce_formula.values()) for element in reduce_formula.keys(): print(len(smact.Element(element).oxidation_states), end = ",") for i, ele_a in enumerate(list_of_elements): for ox_a in smact.Element(ele_a).oxidation_states: for j, ele_b in enumerate(list_of_elements[i+1:]): for ox_b in smact.Element(ele_b).oxidation_states: for k, ele_c in enumerate(list_of_elements[i+j+2:]): for ox_c in smact.Element(ele_c).oxidation_states: for m, ele_d in enumerate(list_of_elements[i+j+k+3:]): for ox_d in smact.Element(ele_d).oxidation_states: for n, ele_e in enumerate(list_of_elements[i+j+k+m+4:]): for ox_e in smact.Element(ele_e).oxidation_states: for p, ele_f in enumerate(list_of_elements[i+j+k+m+n+5:]): for ox_f in smact.Element(ele_f).oxidation_states: for q, ele_g in enumerate(list_of_elements[i+j+k+m+n+p+6:]): for ox_g in smact.Element(ele_g).oxidation_states: for s, ele_h in enumerate(list_of_elements[i+j+k+m+n+p+q+7:]): for ox_h in smact.Element(ele_h).oxidation_states: # Checks if the combination is charge neutral before printing it out! # cn_e, cn_r = neutral_ratios([ox_a, ox_b, ox_c, ox_d, ox_e, ox_f, ox_g, ox_h], stoichs = stoichs, threshold = int(max_num)) if cn_e: for num in cn_r: if tuple(reduce_formula.values()) == num: return True # print(cn_e) # print(cn_r) # print(ox_a, ox_b, ox_c) # charge_neutral_count = charge_neutral_count + 1 # print('{0:3s} {1:3s} {2:3s}'.format(ele_a, ele_b, ele_c)) print('Number of combinations = {0}'.format(charge_neutral_count)) print("--- {0} seconds to run ---".format(time.time() - start_time)) return False
def smact_test(els, threshold=8, species_unique=True): """Function that applies the charge neutrality and electronegativity tests in one go for simple application in external scripts that wish to apply the general 'smact test'. Args: els (tuple/list): A list of smact.Element objects threshold (int): Threshold for stoichiometry limit, default = 8 species_unique (bool): Whether or not to consider elements in different oxidation states as unique in the results. Returns: allowed_comps (list): Allowed compositions for that chemical system in the form [(elements), (oxidation states), (ratios)] if species_unique=True or in the form [(elements), (ratios)] if species_unique=False. """ compositions = [] # Get symbols and electronegativities # print(els) # exit() symbols = tuple(e.symbol for e in els) electronegs = [e.pauling_eneg for e in els] ox_combos = [e.oxidation_states for e in els] for i, ox_states in enumerate(itertools.product(*ox_combos)): # Test for charge balance # print(i) cn_e, cn_r = neutral_ratios(ox_states, threshold=threshold) # Electronegativity test if cn_e: electroneg_OK = pauling_test(ox_states, electronegs) if electroneg_OK: for ratio in cn_r: compositions.append(tuple([symbols, ox_states, ratio])) # exit() # Return list depending on whether we are interested in unique species combinations # or just unique element combinations. if species_unique: return (compositions) else: compositions = [(i[0], i[2]) for i in compositions] compositions = list(set(compositions)) return compositions
def smact_test(els, threshold=8, include=None): """Function that applies the charge neutrality and electronegativity tests in one go for simple application in external scripts that wish to apply the general 'smact test'. Args: els (tuple): A list of Element objects or symbols. threshold (int): Threshold for stoichiometry limit, default = 8. include (list): (optional) List of Element objects that must be in every composition. Returns: allowed_comps (list): Allowed compositions for that chemical system in the form [[elements], [ratios]] Note: Info on oxidation states is not returned, only the list of elements and unique allowed ratios. """ ratios = [] els = list(els) els = els + include if include != None else els # Get symbols and electronegativities symbols = [e.symbol for e in els] electronegs = [e.pauling_eneg for e in els] ox_combos = [e.oxidation_states for e in els] for ox_states in itertools.product(*ox_combos): # Test for charge balance cn_e, cn_r = neutral_ratios(ox_states, threshold=threshold) # Electronegativity test if cn_e: electroneg_OK = pauling_test(ox_states, electronegs) if electroneg_OK: ratios.append(cn_r) ratios = [item for sublist in ratios for item in sublist] ratios = list(set(ratios)) compositions = [[symbols, x] for x in ratios] return compositions
def test_neutral_ratios(self): ox = [1, -2, 1] is_neutral, neutral_combos = smact.neutral_ratios(ox) self.assertTrue((is_neutral)) self.assertEqual(len(neutral_combos), 9) self.assertTrue((3, 2, 1) in neutral_combos)
paul_A = smact.Element(ele_A).pauling_eneg for ox_A in smact.Element(ele_A).oxidation_states: for j, ele_B in enumerate(B_elements): paul_B = smact.Element(ele_B).pauling_eneg for ox_B in smact.Element(ele_B).oxidation_states: for k, ele_C in enumerate(C_elements): paul_C = smact.Element(ele_C).pauling_eneg for ox_C in smact.Element(ele_C).oxidation_states: raw_ion_count = raw_ion_count + 1 elements = [ele_A, ele_B, ele_C] ox_states = [ox_A, ox_B, ox_C] electronegativities = [paul_A, paul_B, paul_C] # Test for charge balance cn_e, cn_r = smact.neutral_ratios( ox_states, threshold=stoichiometry_limit) if cn_e: charge_balanced_count = charge_balanced_count + len( cn_r) # Electronegativity test electroneg_OK = screening.pauling_test( ox_states, electronegativities, elements, threshold=0.0) if electroneg_OK: electroneg_OK_count = electroneg_OK_count + len( cn_r) # Band gap test
def n_neutral_ratios(oxidation_states, threshold=8): return len(smact.neutral_ratios(oxidation_states, threshold=threshold)[1])
paul_A = smact.Element(ele_A).pauling_eneg for ox_A in smact.Element(ele_A).oxidation_states: for j, ele_B in enumerate(B_elements): paul_B = smact.Element(ele_B).pauling_eneg for ox_B in smact.Element(ele_B).oxidation_states: for k, ele_C in enumerate(C_elements): paul_C = smact.Element(ele_C).pauling_eneg for ox_C in smact.Element(ele_C).oxidation_states: raw_ion_count = raw_ion_count + 1 elements = [ele_A, ele_B, ele_C] ox_states = [ox_A, ox_B, ox_C] electronegativities = [paul_A, paul_B, paul_C] # Test for charge balance cn_e, cn_r = smact.neutral_ratios(ox_states,threshold = stoichiometry_limit) if cn_e: charge_balanced_count = charge_balanced_count + len(cn_r) # Electronegativity test electroneg_OK = screening.pauling_test(ox_states, electronegativities, elements, threshold = 0.0) if electroneg_OK: electroneg_OK_count = electroneg_OK_count + len(cn_r) # Band gap test SSE_A = smact.Element(ele_A).SSE SSE_B = smact.Element(ele_B).SSE SSE_C = smact.Element(ele_C).SSE BG_1 = abs(SSE_A - SSE_B) BG_2 = abs(SSE_A - SSE_C) if (BG_1 <= BG_max) and (BG_1 >= BG_min):