def _get_valences(self): """ Computes ionic valences of elements for all sites in the structure. """ try: bv = BVAnalyzer() self._structure = bv.get_oxi_state_decorated_structure( self._structure) valences = bv.get_valences(self._structure) except: try: bv = BVAnalyzer(symm_tol=0.0) self._structure = bv.get_oxi_state_decorated_structure( self._structure) valences = bv.get_valences(self._structure) except: valences = [0] * self._structure.num_sites #raise #el = [site.specie.symbol for site in self._structure.sites] #el = [site.species_string for site in self._structure.sites] #el = [site.specie for site in self._structure.sites] #valence_dict = dict(zip(el, valences)) #print valence_dict return valences
def __init__(self, symm_tol=0.1, max_radius=4, max_permutations=100000, distance_scale_factor=1.015): self.analyzer = BVAnalyzer(symm_tol, max_radius, max_permutations, distance_scale_factor)
def __init__( self, symm_tol=0.1, max_radius=4, max_permutations=100000, distance_scale_factor=1.015, ): """ Args: symm_tol (float): Symmetry tolerance used to determine which sites are symmetrically equivalent. Set to 0 to turn off symmetry. max_radius (float): Maximum radius in Angstrom used to find nearest neighbors. max_permutations (int): Maximum number of permutations of oxidation states to test. distance_scale_factor (float): A scale factor to be applied. This is useful for scaling distances, esp in the case of calculation-relaxed structures, which may tend to under (GGA) or over bind (LDA). The default of 1.015 works for GGA. For experimental structure, set this to 1. """ self.symm_tol = symm_tol self.max_radius = max_radius self.max_permutations = max_permutations self.distance_scale_factor = distance_scale_factor self.analyzer = BVAnalyzer(symm_tol, max_radius, max_permutations, distance_scale_factor)
def from_py_struct(structure: pymatgen.core.Structure): """Create a SmactStructure from a pymatgen Structure object. Args: structure: A pymatgen Structure. Returns: :class:`~.SmactStructure` """ if not isinstance(structure, pymatgen.core.Structure): raise TypeError("Structure must be a pymatgen.core.Structure instance.") bva = BVAnalyzer() struct = bva.get_oxi_state_decorated_structure(structure) sites, species = SmactStructure.__parse_py_sites(struct) lattice_mat = struct.lattice.matrix lattice_param = 1.0 return SmactStructure( species, lattice_mat, sites, lattice_param, sanitise_species=True, )
def tersoff_potential(self, structure): """ Generate the species, tersoff potential lines for an oxide structure Args: structure: pymatgen.core.structure.Structure """ bv = BVAnalyzer() el = [site.species_string for site in structure.sites] valences = bv.get_valences(structure) el_val_dict = dict(zip(el, valences)) gin = "species \n" qerfstring = "qerfc\n" for key in el_val_dict.keys(): if key != "O" and el_val_dict[key] % 1 != 0: raise SystemError("Oxide has mixed valence on metal") specie_string = key + " core " + str(el_val_dict[key]) + "\n" gin += specie_string qerfstring += key + " " + key + " 0.6000 10.0000 \n" gin += "# noelectrostatics \n Morse \n" met_oxi_ters = Tersoff_pot().data for key in el_val_dict.keys(): if key != "O": metal = key + "(" + str(int(el_val_dict[key])) + ")" ters_pot_str = met_oxi_ters[metal] gin += ters_pot_str gin += qerfstring return gin
def __init__(self, defect): """ Args: defect(Defect): pymatgen Defect object """ self.defect = defect try: bv = BVAnalyzer() struct_valences = bv.get_valences(self.defect.bulk_structure) site_index = self.defect.bulk_structure.get_sites_in_sphere( self.defect.site.coords, 0.1, include_index=True)[0][2] def_site_valence = struct_valences[site_index] except Exception: # sometimes valences cant be assigned def_site_valence = 0 if isinstance(defect, Vacancy): self.charges = [-1 * def_site_valence] elif isinstance(defect, Substitution): #(minimize difference with host site specie) probable_chgs = [ ox - def_site_valence for ox in self.defect.site.specie.oxidation_states ] self.charges = [min(probable_chgs, key=abs)] elif isinstance(defect, Interstitial): self.charges = [0] else: raise ValueError("Defect Type not recognized.")
def predict(self, structure, ref_structure, test_isostructural=True): """ Given a structure, returns back the predicted volume. Args: structure (Structure): structure w/unknown volume ref_structure (Structure): A reference structure with a similar structure but different species. test_isostructural (bool): Whether to test that the two structures are isostructural. This algo works best for isostructural compounds. Defaults to True. Returns: a float value of the predicted volume """ if not is_ox(structure): a = BVAnalyzer() structure = a.get_oxi_state_decorated_structure(structure) if not is_ox(ref_structure): a = BVAnalyzer() ref_structure = a.get_oxi_state_decorated_structure(ref_structure) if test_isostructural: m = StructureMatcher() mapping = m.get_best_electronegativity_anonymous_mapping( structure, ref_structure) if mapping is None: raise ValueError("Input structures do not match!") comp = structure.composition ref_comp = ref_structure.composition numerator = 0 denominator = 0 # Here, the 1/3 factor on the composition accounts for atomic # packing. We want the number per unit length. # TODO: AJ doesn't understand the (1/3). It would make sense to him # if you were doing atomic volume and not atomic radius for k, v in comp.items(): numerator += k.ionic_radius * v**(1 / 3) for k, v in ref_comp.items(): denominator += k.ionic_radius * v**(1 / 3) # The scaling factor is based on lengths. We apply a power of 3. return ref_structure.volume * (numerator / denominator)**3
def add_bv_structure(doc): struc = Structure.from_dict(doc["structure"]) try: bva = BVAnalyzer() bv_struct = bva.get_oxi_state_decorated_structure(struc) doc["bv_structure"] = bv_struct.as_dict() except Exception as e: print("BVAnalyzer error: {}".format(e))
def get_basic_analysis_and_error_checks(d, max_force_threshold=0.5, volume_change_threshold=0.2): initial_vol = d["input"]["crystal"]["lattice"]["volume"] final_vol = d["output"]["crystal"]["lattice"]["volume"] delta_vol = final_vol - initial_vol percent_delta_vol = delta_vol / initial_vol coord_num = get_coordination_numbers(d) calc = d["calculations"][-1] gap = calc["output"]["bandgap"] cbm = calc["output"]["cbm"] vbm = calc["output"]["vbm"] is_direct = calc["output"]["is_gap_direct"] warning_msgs = [] error_msgs = [] if abs(percent_delta_vol) > volume_change_threshold: warning_msgs.append("Volume change > {}%" .format(volume_change_threshold * 100)) bv_struct = Structure.from_dict(d["output"]["crystal"]) try: bva = BVAnalyzer() bv_struct = bva.get_oxi_state_decorated_structure(bv_struct) except ValueError as e: logger.error("Valence cannot be determined due to {e}." .format(e=e)) except Exception as ex: logger.error("BVAnalyzer error {e}.".format(e=str(ex))) max_force = None if d["state"] == "successful" and \ d["calculations"][0]["input"]["parameters"].get("NSW", 0) > 0: # handle the max force and max force error max_force = max([np.linalg.norm(a) for a in d["calculations"][-1]["output"] ["ionic_steps"][-1]["forces"]]) if max_force > max_force_threshold: error_msgs.append("Final max force exceeds {} eV" .format(max_force_threshold)) d["state"] = "error" s = Structure.from_dict(d["output"]["crystal"]) if not s.is_valid(): error_msgs.append("Bad structure (atoms are too close!)") d["state"] = "error" return {"delta_volume": delta_vol, "max_force": max_force, "percent_delta_volume": percent_delta_vol, "warnings": warning_msgs, "errors": error_msgs, "coordination_numbers": coord_num, "bandgap": gap, "cbm": cbm, "vbm": vbm, "is_gap_direct": is_direct, "bv_structure": bv_struct.as_dict()}
def calc(self, item): s = Structure.from_dict(item["structure"]) d = { "pymatgen_version": pymatgen_version, "successful": False, "bond_valence": { "structure": item["structure"], "method": None }, } try: bva = BVAnalyzer() valences = bva.get_valences(s) possible_species = { str(Specie(s[idx].specie, oxidation_state=valence)) for idx, valence in enumerate(valences) } d["successful"] = True s.add_oxidation_state_by_site(valences) d["bond_valence"] = { "possible_species": list(possible_species), "possible_valences": valences, "method": "BVAnalyzer", "structure": s.as_dict(), } except Exception as e: self.logger.error("BVAnalyzer failed with: {}".format(e)) try: first_oxi_state_guess = s.composition.oxi_state_guesses( max_sites=-50)[0] valences = [ first_oxi_state_guess[site.species_string] for site in s ] possible_species = { str(Specie(el, oxidation_state=valence)) for el, valence in first_oxi_state_guess.items() } d["successful"] = True s.add_oxidation_state_by_site(valences) d["bond_valence"] = { "possible_species": list(possible_species), "possible_valences": valences, "method": "oxi_state_guesses", "structure": s.as_dict(), } except Exception as e: self.logger.error( "Oxidation state guess failed with: {}".format(e)) return d
def setUp(self): mgo_latt = [[4.212, 0, 0], [0, 4.212, 0], [0, 0, 4.212]] mgo_specie = ["Mg", 'O'] * 4 mgo_frac_cord = [[0, 0, 0], [0.5, 0, 0], [0.5, 0.5, 0], [0, 0.5, 0], [0.5, 0, 0.5], [0, 0, 0.5], [0, 0.5, 0.5], [0.5, 0.5, 0.5]] self.mgo_uc = Structure(mgo_latt, mgo_specie, mgo_frac_cord, True, True) bv = BVAnalyzer() val = bv.get_valences(self.mgo_uc) el = [site.species_string for site in self.mgo_uc.sites] self.val_dict = dict(zip(el, val))
def setUp(self): filepath = os.path.join(test_dir, 'POSCAR') p = Poscar.from_file(filepath) self.structure = p.structure bv = BVAnalyzer() valences = bv.get_valences(self.structure) el = [site.species_string for site in self.structure.sites] valence_dict = dict(zip(el, valences)) self.rad_dict = {} for k, v in valence_dict.items(): self.rad_dict[k] = float(Specie(k, v).ionic_radius) assert len(self.rad_dict) == len(self.structure.composition)
def setUp(self): filepath1 = os.path.join(PymatgenTest.TEST_FILES_DIR, "Li2O.cif") p = CifParser(filepath1).get_structures(False)[0] bv = BVAnalyzer() valences = bv.get_valences(p) el = [site.species_string for site in p.sites] val_dict = dict(zip(el, valences)) self._radii = {} for k, v in val_dict.items(): k1 = re.sub(r"[1-9,+,\-]", "", k) self._radii[k1] = float(Species(k1, v).ionic_radius) p.remove(0) self._vac_struct = p
def setUp(self): filepath1 = os.path.join(test_dir, 'Li2O.cif') p = CifParser(filepath1).get_structures(False)[0] bv = BVAnalyzer() valences = bv.get_valences(p) el = [site.species_string for site in p.sites] val_dict = dict(zip(el, valences)) self._radii = {} for k, v in val_dict.items(): k1 = re.sub(r'[1-9,+,\-]', '', k) self._radii[k1] = float(Specie(k1, v).ionic_radius) p.remove(0) self._vac_struct = p
def from_mp( species: List[Union[Tuple[str, int, int], Tuple[smact.Species, int]]], api_key: str, ): """Create a SmactStructure using the first Materials Project entry for a composition. Args: species: See :meth:`~.__init__`. api_key: A www.materialsproject.org API key. Returns: :class:`~.SmactStructure` """ sanit_species = SmactStructure._sanitise_species(species) with MPRester(api_key) as m: eles = SmactStructure._get_ele_stoics(sanit_species) formula = "".join(f"{ele}{stoic}" for ele, stoic in eles.items()) structs = m.query( criteria={"reduced_cell_formula": formula}, properties=["structure"], ) if len(structs) == 0: raise ValueError( "Could not find composition in Materials Project Database, " "please supply a structure.") struct = structs[0][ 'structure'] # Default to first found structure if 0 not in (spec[1] for spec in sanit_species): # If everything's charged bva = BVAnalyzer() struct = bva.get_oxi_state_decorated_structure(struct) lattice_mat = struct.lattice.matrix lattice_param = 1.0 # TODO Use actual lattice parameter sites, _ = SmactStructure.__parse_py_sites(struct) return SmactStructure( sanit_species, lattice_mat, sites, lattice_param, sanitise_species=False, )
def setUp(self): filepath = os.path.join(test_dir, 'POSCAR') p = Poscar.from_file(filepath) self.structure = p.structure bv = BVAnalyzer() self.structure = bv.get_oxi_state_decorated_structure(self.structure) valences = bv.get_valences(self.structure) radii = [] for i in range(len(valences)): el = self.structure.sites[i].specie.symbol radius = Specie(el, valences[i]).ionic_radius radii.append(radius) el = [site.species_string for site in self.structure.sites] self.rad_dict = dict(zip(el, radii)) for el in self.rad_dict.keys(): print((el, self.rad_dict[el].real))
def setUp(self): with open("mp-7000.json", "r") as f: dict_lse = json.load(f) lse = LightStructureEnvironments.from_dict(dict_lse) struct = lse.structure bva = BVAnalyzer() valences = bva.get_valences(structure=struct) lgf = LocalGeometryFinder() lgf.setup_structure(structure=struct) se = lgf.compute_structure_environments(maximum_distance_factor=1.41, only_cations=False, valences=valences) strategy = MultiWeightsChemenvStrategy.stats_article_weights_parameters() self.lse = LightStructureEnvironments.from_structure_environments(strategy=strategy, structure_environments=se) with open("mp-5634.json", "r") as f: dict_lse2 = json.load(f) self.lse2 = LightStructureEnvironments.from_dict(dict_lse2)
def _get_valences(self): """ Computes ionic valences of elements for all sites in the structure. """ bv = BVAnalyzer() try: valences = bv.get_valences(self._structure) except: err_str = "BVAnalyzer failed. The defect effective charge, and" err_str += " volume and surface area may not work" print err_str raise LookupError() el = [site.species_string for site in self.structure.sites] valence_dict = dict(zip(el, valences)) return valence_dict
def setUp(self): """ Setup MgO rocksalt structure for testing Vacancy """ mgo_latt = [[4.212, 0, 0], [0, 4.212, 0], [0, 0, 4.212]] mgo_specie = ["Mg"] * 4 + ["O"] * 4 mgo_frac_cord = [[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5], [0.5, 0, 0], [0, 0.5, 0], [0, 0, 0.5], [0.5, 0.5, 0.5]] self._mgo_uc = Structure(mgo_latt, mgo_specie, mgo_frac_cord, True, True) bv = BVAnalyzer() self._mgo_uc = bv.get_oxi_state_decorated_structure(self._mgo_uc) self._mgo_val_rad_eval = ValenceIonicRadiusEvaluator(self._mgo_uc) self._mgo_val = self._mgo_val_rad_eval.valences self._mgo_rad = self._mgo_val_rad_eval.radii self._mgo_vac = Vacancy(self._mgo_uc, self._mgo_val, self._mgo_rad)
def get_oxidation_states(stru): try: valences = BVAnalyzer().get_valences(stru) elems = [i for i in stru.species] oxids = set(zip(elems,valences)) reduced_elems = set(elems) out={i:[] for i in reduced_elems} for i in oxids: if i[1] not in out[i[0]]: out[i[0]].append(i[1]) out1 = {i:np.sign(out[i][0])*np.max(np.abs(out[i])) for i in out} return out1 except: oxi_states = {} oxi_range = {} reduc_comp = stru.composition.reduced_composition oxid_states = get_oxid_states_composition(reduc_comp) return oxid_states
def get_atomic_radii(self): if not self.pymatgen_radii: return None try: bv = BVAnalyzer() valences = bv.get_valences(self._structure) elements = [site.species_string for site in self._structure.sites] valence_dict = dict(zip(elements, valences)) radii = {} for k, v in valence_dict.items(): radii[k] = float(Specie(k, v).ionic_radius) except (ValueError, TypeError) as e: radii = None return radii
def __init__(self, structure, include_bv_charge=False): """ Initializes a Vacancy Generator Args: structure(Structure): pymatgen structure object """ self.structure = structure self.include_bv_charge = include_bv_charge # Find equivalent site list sga = SpacegroupAnalyzer(self.structure) self.symm_structure = sga.get_symmetrized_structure() self.equiv_site_seq = list(self.symm_structure.equivalent_sites) self.struct_valences = None if self.include_bv_charge: bv = BVAnalyzer() self.struct_valences = bv.get_valences(self.structure)
def get_valences(self): """ Uses Pymatgen to obtain likely valence states of every element in structure Returns vals: dictionary of average valence state for every element in composition """ struct = self.structure bv = BVAnalyzer() try: valences = bv.get_valences(struct) struct = bv.get_oxi_state_decorated_structure(struct) except: return None if isinstance(valences[0], list): valences = [item for sublist in valences for item in sublist] stoich = defaultdict(int) for site in struct.as_dict()['sites']: elem = site['species'][0]['element'] stoich[elem] += 1 vals = {} for spec in stoich.keys(): vals[spec] = 0.0 for atom in range(len(struct)): try: vals[struct.as_dict()['sites'][atom]['species'][0] ['element']] += valences[atom] except Exception as e: print("Trouble with {}".format(struct.formula)) print('Do you have partial occupancies?') return None for spec in vals: vals[spec] = vals[spec] / stoich[spec] vals[spec] = int(round(vals[spec])) return vals
def get_coordsites_min_max_charge(self, n): """ Minimum and maximum charge of sites surrounding the vacancy site. Args: n: Index of vacancy list """ bv = BVAnalyzer() struct_valences = bv.get_valences(self._structure) coordinated_site_valences = [] def _get_index(site): for i in range(len(self._structure.sites)): if site.is_periodic_image(self._structure.sites[i]): return i raise ValueError("Site not found") for site in self._defect_coord_sites[n]: ind = _get_index(site) coordinated_site_valences.append(struct_valences[ind]) coordinated_site_valences.sort() return coordinated_site_valences[0], coordinated_site_valences[-1]
def get_basic_analysis_and_error_checks(d): initial_vol = d["input"]["crystal"]["lattice"]["volume"] final_vol = d["output"]["crystal"]["lattice"]["volume"] delta_vol = final_vol - initial_vol percent_delta_vol = delta_vol / initial_vol coord_num = get_coordination_numbers(d) calc = d["calculations"][-1] gap = calc["output"]["bandgap"] cbm = calc["output"]["cbm"] vbm = calc["output"]["vbm"] is_direct = calc["output"]["is_gap_direct"] if abs(percent_delta_vol) > 0.20: warning_msgs = ["Volume change > 20%"] else: warning_msgs = [] bv_struct = Structure.from_dict(d["output"]["crystal"]) try: bva = BVAnalyzer() bv_struct = bva.get_oxi_state_decorated_structure(bv_struct) except ValueError as e: logger.error("Valence cannot be determined due to {e}.".format(e=e)) except Exception as ex: logger.error("BVAnalyzer error {e}.".format(e=str(ex))) return { "delta_volume": delta_vol, "percent_delta_volume": percent_delta_vol, "warnings": warning_msgs, "coordination_numbers": coord_num, "bandgap": gap, "cbm": cbm, "vbm": vbm, "is_gap_direct": is_direct, "bv_structure": bv_struct.to_dict }
def process_item(self, item): s = Structure.from_dict(item['structure']) try: bva = BVAnalyzer() valences = bva.get_valences(s) possible_species = { str(Specie(s[idx].specie, oxidation_state=valence)) for idx, valence in enumerate(valences) } method = "BVAnalyzer" except ValueError: try: first_oxi_state_guess = s.composition.oxi_state_guesses()[0] valences = [ first_oxi_state_guess[site.species_string] for site in s ] possible_species = { str(Specie(el, oxidation_state=valence)) for el, valence in first_oxi_state_guess.items() } method = "oxi_state_guesses" except: return { "task_id": item['task_id'], "pymatgen_version": pymatgen_version, "successful": False } return { "task_id": item['task_id'], "possible_species": list(possible_species), "possible_valences": valences, "method": method, "pymatgen_version": pymatgen_version, "successful": True }
def Calc_Ewald(pmg_struct, formal_val=[]): """ input: pmg_struct: pymatgen structure formal_val: list - list of valence for each atom TBD: use input formal valence list to decorate the structure """ # GET valence list if len(formal_val)==0: bv_analyzer=BVAnalyzer(max_radius=4) #max_radius default is 4 formal_val=bv_analyzer.get_valences(pmg_struct) # default for cutoff is set to None real_cutoff = None rec_cutoff = None # Oxidation states are decorated automatically. decorated_struct = bv_analyzer.get_oxi_state_decorated_structure(pmg_struct) NUM_sites=pmg_struct.num_sites # Per atom ewald_per_atom=1/NUM_sites*EwaldSummation(decorated_struct, real_space_cut=real_cutoff, recip_space_cut=rec_cutoff).total_energy return ewald_per_atom
def get_analysis_and_structure(self, structure, calculate_valences=True, guesstimate_spin=False, op_threshold=0.1): """ Obtain an analysis of a given structure and if it may be Jahn-Teller active or not. This is a heuristic, and may give false positives and false negatives (false positives are preferred). :param structure: input structure :param calculate_valences (bool): whether to attempt to calculate valences or not, structure should have oxidation states to perform analysis :param guesstimate_spin (bool): whether to guesstimate spin state from magnetic moments or not, use with caution :param op_threshold (float): threshold for order parameter above which to consider site to match an octahedral or tetrahedral motif, since Jahn-Teller structures can often be quite distorted, this threshold is smaller than one might expect :return (dict): analysis of structure, with key 'strength' which may be 'none', 'strong', 'weak', or 'unknown' """ structure = structure.get_primitive_structure() if calculate_valences: bva = BVAnalyzer() structure = bva.get_oxi_state_decorated_structure(structure) # no point testing multiple equivalent sites, doesn't make any difference to analysis # but makes returned symmetrized_structure = SpacegroupAnalyzer( structure).get_symmetrized_structure() # to detect structural motifs of a given site op = LocalStructOrderParams(['oct', 'tet']) # dict of site index to the Jahn-Teller analysis of that site jt_sites = [] non_jt_sites = [] for indices in symmetrized_structure.equivalent_indices: idx = indices[0] site = symmetrized_structure[idx] # only interested in sites with oxidation states if isinstance(site.specie, Specie) and site.specie.element.is_transition_metal: # get motif around site order_params = op.get_order_parameters(symmetrized_structure, idx) if order_params[0] > order_params[1] and order_params[ 0] > op_threshold: motif = 'oct' motif_order_parameter = order_params[0] elif order_params[1] > op_threshold: motif = 'tet' motif_order_parameter = order_params[1] else: motif = 'unknown' motif_order_parameter = None if motif == "oct" or motif == "tet": # guess spin of metal ion if guesstimate_spin and 'magmom' in site.properties: # estimate if high spin or low spin magmom = site.properties['magmom'] spin_state = self._estimate_spin_state( site.specie, motif, magmom) else: spin_state = "unknown" magnitude = self.get_magnitude_of_effect_from_species( site.specie, spin_state, motif) if magnitude != "none": ligands = get_neighbors_of_site_with_index( structure, idx, approach="min_dist", delta=0.15) ligand_bond_lengths = [ ligand.distance(structure[idx]) for ligand in ligands ] ligands_species = list( set([str(ligand.specie) for ligand in ligands])) ligand_bond_length_spread = max(ligand_bond_lengths) - \ min(ligand_bond_lengths) def trim(f): # avoid storing to unreasonable precision, hurts readability return float("{:.4f}".format(f)) # to be Jahn-Teller active, all ligands have to be the same if len(ligands_species) == 1: jt_sites.append({ 'strength': magnitude, 'motif': motif, 'motif_order_parameter': trim(motif_order_parameter), 'spin_state': spin_state, 'species': str(site.specie), 'ligand': ligands_species[0], 'ligand_bond_lengths': [ trim(length) for length in ligand_bond_lengths ], 'ligand_bond_length_spread': trim(ligand_bond_length_spread), 'site_indices': indices }) # store reasons for not being J-T active else: non_jt_sites.append({ 'site_indices': indices, 'strength': "none", 'reason': "Not Jahn-Teller active for this " "electronic configuration." }) else: non_jt_sites.append({ 'site_indices': indices, 'strength': "none", 'reason': "motif is {}".format(motif) }) # perform aggregation of all sites if jt_sites: analysis = {'active': True} # if any site could exhibit 'strong' Jahn-Teller effect # then mark whole structure as strong strong_magnitudes = [ site['strength'] == "strong" for site in jt_sites ] if any(strong_magnitudes): analysis['strength'] = "strong" else: analysis['strength'] = "weak" analysis['sites'] = jt_sites return analysis, structure else: return {'active': False, 'sites': non_jt_sites}, structure
def buckingham_potential(self, structure, val_dict=None): """ Generate species, buckingham, and spring options for an oxide structure using the parameters in default libraries. Ref: 1. G.V. Lewis and C.R.A. Catlow, J. Phys. C: Solid State Phys., 18, 1149-1161 (1985) 2. T.S.Bush, J.D.Gale, C.R.A.Catlow and P.D. Battle, J. Mater Chem., 4, 831-837 (1994) Args: structure: pymatgen.core.structure.Structure val_dict (Needed if structure is not charge neutral) El:valence dictionary, where El is element. """ if not val_dict: bv = BVAnalyzer() el = [site.species_string for site in structure.sites] valences = bv.get_valences(structure) val_dict = dict(zip(el, valences)) #Try bush library first bpb = BuckinghamPotBush() bpl = BuckinghamPotLewis() gin = "" for key in val_dict.keys(): use_bush = True el = re.sub('[1-9,+,\-]', '', key) if el not in bpb.species_dict.keys(): use_bush = False elif val_dict[key] != bpb.species_dict[el]['oxi']: use_bush = False if use_bush: gin += "species \n" gin += bpb.species_dict[el]['inp_str'] gin += "buckingham \n" gin += bpb.pot_dict[el] gin += "spring \n" gin += bpb.spring_dict[el] continue #Try lewis library next if element is not in bush #use_lewis = True if el != "O": # For metals the key is "Metal_OxiState+" k = el + '_' + str(int(val_dict[key])) + '+' if k not in bpl.species_dict.keys(): #use_lewis = False raise GulpError("Element {} not in library".format(k)) gin += "species\n" gin += bpl.species_dict[k] gin += "buckingham\n" gin += bpl.pot_dict[k] else: gin += "species\n" k = "O_core" gin += bpl.species_dict[k] k = "O_shel" gin += bpl.species_dict[k] gin += "buckingham\n" gin += bpl.pot_dict[key] gin += 'spring\n' gin += bpl.spring_dict[key] return gin
sites_Na = [[55, 59, 64, 68], [51, 54, 60, 63], [56, 58, 65, 67], [52, 53, 62, 64], [57, 57, 67, 67]] directories = ["c5", "c4", "c3", "c2", "c1", "relax", "t1", "t2", "t3", "t4", "t5"] o_fig = o_file = 'NaObonds' all_dist_NaO = []# (strain,layers,atom,bond) for element in directories: """ This populates the distances array with all the Na-O bonds detected by the CrystalNN routine. The innermost index varies in size as each atom in sites_Na can have more or less neigbours. The second innermost index size is always 4 due to array symmetry reasons. It registers the number of Na atoms at a layer The third innermost index is 5. It is the number of layers in the slab. The first index registers the strain steps taken. """ input_struct = Structure.from_file( element+"/CONTCAR" ) ox_struct = BVAnalyzer().get_oxi_state_decorated_structure( input_struct ) dist_NaO = [] for layer, atom_list in enumerate( sites_Na ): layer_atoms = [] for atom in atom_list: atom_neigbors = CrystalNN( cation_anion=True ).get_nn( ox_struct, atom-1 ) distances = [] for neighbor in range( len( atom_neigbors ) ): distances.append( atom_neigbors[neighbor].distance( input_struct[atom-1] ) ) layer_atoms.append( distances ) dist_NaO.append( layer_atoms ) all_dist_NaO.append( dist_NaO ) avrg_bond = np.zeros( [len(all_dist_NaO), len(all_dist_NaO[0]), len(all_dist_NaO[0][0])] ) avrg_layer = np.zeros( [len(all_dist_NaO), len(all_dist_NaO[0])] ) stdev_bond = np.zeros( [len(all_dist_NaO), len(all_dist_NaO[0]), len(all_dist_NaO[0][0])] )