diff --git a/corner-sharing/data/31468.cif b/corner-sharing/data/31468.cif new file mode 100644 index 0000000..cac7bce --- /dev/null +++ b/corner-sharing/data/31468.cif @@ -0,0 +1,38 @@ +# generated using pymatgen +data_LiCaN +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 3.64796900 +_cell_length_b 5.52501055 +_cell_length_c 8.47816147 +_cell_angle_alpha 90.00000000 +_cell_angle_beta 90.00000000 +_cell_angle_gamma 90.00000000 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural LiCaN +_chemical_formula_sum 'Li4 Ca4 N4' +_cell_volume 170.87791425 +_cell_formula_units_Z 4 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Li Li0 1 0.25000000 0.57470608 0.04709782 1 + Li Li1 1 0.75000000 0.42529392 0.95290218 1 + Li Li2 1 0.75000000 0.07470608 0.45290218 1 + Li Li3 1 0.25000000 0.92529392 0.54709782 1 + Ca Ca4 1 0.25000000 0.47404325 0.65602265 1 + Ca Ca5 1 0.75000000 0.97404325 0.84397735 1 + Ca Ca6 1 0.25000000 0.02595675 0.15602265 1 + Ca Ca7 1 0.75000000 0.52595675 0.34397735 1 + N N8 1 0.75000000 0.73867475 0.09223915 1 + N N9 1 0.75000000 0.76132525 0.59223915 1 + N N10 1 0.25000000 0.26132525 0.90776085 1 + N N11 1 0.25000000 0.23867475 0.40776085 1 diff --git a/corner-sharing/data/31960.cif b/corner-sharing/data/31960.cif new file mode 100644 index 0000000..0375b3c --- /dev/null +++ b/corner-sharing/data/31960.cif @@ -0,0 +1,48 @@ +# generated using pymatgen +data_LiMnP2O7 +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 5.25142097 +_cell_length_b 7.02679723 +_cell_length_c 8.10844188 +_cell_angle_alpha 67.45244204 +_cell_angle_beta 91.00449580 +_cell_angle_gamma 94.92721598 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural LiMnP2O7 +_chemical_formula_sum 'Li2 Mn2 P4 O14' +_cell_volume 275.27628245 +_cell_formula_units_Z 2 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Li Li0 1 0.29423100 0.84940800 0.98967300 1 + Li Li1 1 0.72912400 0.05829500 0.44408000 1 + Mn Mn2 1 0.21163500 0.24645200 0.73057400 1 + Mn Mn3 1 0.77433900 0.77679000 0.26788900 1 + P P4 1 0.76538900 0.88233400 0.82926500 1 + P P5 1 0.71702000 0.54643400 0.69361300 1 + P P6 1 0.25244500 0.12414800 0.17347900 1 + P P7 1 0.27754500 0.46668700 0.30356000 1 + O O8 1 0.26490100 0.36116500 0.15736200 1 + O O9 1 0.87078800 0.36209700 0.75555500 1 + O O10 1 0.05215500 0.95840100 0.79506700 1 + O O11 1 0.13267600 0.65874000 0.21631800 1 + O O12 1 0.15482500 0.30259200 0.47566800 1 + O O13 1 0.97235900 0.04141700 0.23366200 1 + O O14 1 0.30350700 0.13962100 0.98191200 1 + O O15 1 0.45463100 0.00906700 0.29681400 1 + O O16 1 0.42714800 0.49615000 0.68292000 1 + O O17 1 0.81361200 0.72810700 0.51905700 1 + O O18 1 0.59076200 0.00704300 0.68713100 1 + O O19 1 0.67292400 0.85485100 0.01791400 1 + O O20 1 0.75280800 0.64575700 0.84373300 1 + O O21 1 0.56472700 0.51694900 0.32641200 1 diff --git a/corner-sharing/utils/analyze_env_st.py b/corner-sharing/utils/analyze_env_st.py new file mode 100644 index 0000000..ab7f5db --- /dev/null +++ b/corner-sharing/utils/analyze_env_st.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python +# This code extracts the lithium environment of all of lithium sites provided in a structure file. +import os, sys +import numpy as np +import scipy +import argparse +from scipy.spatial import ConvexHull +from itertools import permutations +from pymatgen.core.structure import Structure +from pymatgen.core.periodic_table import * +from pymatgen.core.composition import * +from pymatgen.ext.matproj import MPRester +from pymatgen.io.vasp.outputs import * +from pymatgen.analysis.chemenv.coordination_environments.coordination_geometry_finder import LocalGeometryFinder +from pymatgen.analysis.chemenv.coordination_environments.structure_environments import LightStructureEnvironments +from pymatgen.analysis.chemenv.coordination_environments.chemenv_strategies import SimplestChemenvStrategy +from pymatgen.analysis.chemenv.coordination_environments.coordination_geometries import * + +__author__ = "KyuJung Jun" +__version__ = "0.1" +__maintainer__ = "KyuJung Jun" +__email__ = "kjun@berkeley.edu" +__status__ = "Development" + +''' +Input for the script : path to the structure file supported by Pymatgen +Structures with partial occupancy should be ordered or modified to full occupancy by Pymatgen. +''' +parser = argparse.ArgumentParser() +parser.add_argument('structure', help='path to the structure file supported by Pymatgen', nargs='?') +parser.add_argument('envtype', help='both, tet, oct, choosing which perfect environment to reference to', nargs='?') +args = parser.parse_args() + + +class HiddenPrints: + ''' + class to reduce the output lines + ''' + + def __enter__(self): + self._original_stdout = sys.stdout + sys.stdout = open(os.devnull, 'w') + + def __exit__(self, exc_type, exc_val, exc_tb): + sys.stdout.close() + sys.stdout = self._original_stdout + + +def non_elements(struct, sp='Li'): + ''' + struct : structure object from Pymatgen + sp : the mobile specie + returns the structure with all of the mobile specie (Li) removed + ''' + num_li = struct.species.count(Element(sp)) + species = list(set(struct.species)) + try: + species.remove(Element("O")) + except ValueError: + print("没有O") + try: + species.remove(Element("S")) + except ValueError: + print("没有S") + try: + species.remove(Element("N")) + except ValueError: + print("没有N") + stripped = struct.copy() + stripped.remove_species(species) + stripped = stripped.get_sorted_structure(reverse=True) + return stripped + + +def site_env(coord, struct, sp="Li", envtype='both'): + ''' + coord : Fractional coordinate of the target atom + struct : structure object from Pymatgen + sp : the mobile specie + envtype : This sets the reference perfect structure. 'both' compares CSM_tet and CSM_oct and assigns to the lower one. + 'tet' refers to the perfect tetrahedron and 'oct' refers to the perfect octahedron + result : a dictionary of environment information + ''' + stripped = non_elements(struct) + with_li = stripped.copy() + with_li.append(sp, coord, coords_are_cartesian=False, validate_proximity=False) + with_li = with_li.get_sorted_structure() + tet_oct_competition = [] + if envtype == 'both' or envtype == 'tet': + for dist in np.linspace(1, 4, 601): + neigh = with_li.get_neighbors(with_li.sites[0], dist) + if len(neigh) < 4: + continue + elif len(neigh) > 4: + break + neigh_coords = [i.coords for i in neigh] + with HiddenPrints(): + lgf = LocalGeometryFinder(only_symbols=["T:4"]) + lgf.setup_structure(structure=with_li) + lgf.setup_local_geometry(isite=0, coords=neigh_coords) + try: + site_volume = ConvexHull(neigh_coords).volume + tet_env_list = [] + for i in range(20): + tet_env = {'csm': lgf.get_coordination_symmetry_measures()['T:4']['csm'], 'vol': site_volume, + 'type': 'tet'} + tet_env_list.append(tet_env) + tet_env = min(tet_env_list, key=lambda x: x['csm']) + tet_oct_competition.append(tet_env) + + except Exception as e: + print(e) + print("This site cannot be recognized as tetrahedral site") + if len(neigh) == 4: + break + if envtype == 'both' or envtype == 'oct': + for dist in np.linspace(1, 4, 601): + neigh = with_li.get_neighbors(with_li.sites[0], dist) + if len(neigh) < 6: + continue + elif len(neigh) > 6: + break + neigh_coords = [i.coords for i in neigh] + with HiddenPrints(): + lgf = LocalGeometryFinder(only_symbols=["O:6"], permutations_safe_override=False) + lgf.setup_structure(structure=with_li) + lgf.setup_local_geometry(isite=0, coords=neigh_coords) + try: + site_volume = ConvexHull(neigh_coords).volume + oct_env_list = [] + for i in range(20): + ''' + 20 times sampled in case of the algorithm "APPROXIMATE_FALLBACK" is used. Large number of permutations + are performed, but the default value in the function "coordination_geometry_symmetry_measures_fallback_random" + (NRANDOM=10) is often too small. This is not a problem if algorithm of "SEPARATION_PLANE" is used. + ''' + oct_env = {'csm': lgf.get_coordination_symmetry_measures()['O:6']['csm'], 'vol': site_volume, + 'type': 'oct'} + oct_env_list.append(oct_env) + oct_env = min(oct_env_list, key=lambda x: x['csm']) + tet_oct_competition.append(oct_env) + + except Exception as e: + print(e) + print("This site cannot be recognized as octahedral site") + if len(neigh) == 6: + break + + if len(tet_oct_competition) == 0: + return {'csm': np.nan, 'vol': np.nan, 'type': 'Non_' + envtype} + elif len(tet_oct_competition) == 1: + return tet_oct_competition[0] + elif len(tet_oct_competition) == 2: + csm1 = tet_oct_competition[0] + csm2 = tet_oct_competition[1] + if csm1['csm'] > csm2['csm']: + return csm2 + else: + return csm1 + + +def extract_sites(struct, sp="Li", envtype='both'): + ''' + struct : structure object from Pymatgen + envtype : 'tet', 'oct', or 'both' + sp : target element to analyze environment + + ''' + envlist = [] + for i in range(len(struct.sites)): + if struct.sites[i].specie != Element(sp): + continue + site = struct.sites[i] + singleenv = site_env(site.frac_coords, struct, sp, envtype) + envlist.append({'frac_coords': site.frac_coords, 'type': singleenv['type'], 'csm': singleenv['csm'], + 'volume': singleenv['vol']}) + return envlist + + +def export_envs(envlist, sp='Li', envtype='both', fname=None): + ''' + envlist : list of dictionaries of environment information + fname : Output file name + ''' + if not fname: + fname = "extracted_environment_info" + "_" + sp + "_" + envtype + ".dat" + with open(fname, 'w') as f: + + f.write('List of environment information\n') + f.write('Species : ' + sp + "\n") + f.write('Envtype : ' + envtype + "\n") + for index, i in enumerate(envlist): + f.write("Site index " + str(index) + ": " + str(i) + '\n') + + +struct = Structure.from_file("../data/31960.cif") +site_info = extract_sites(struct, envtype="both") +export_envs(site_info, sp="Li", envtype="both") \ No newline at end of file