CSM计算
This commit is contained in:
134
corner-sharing/utils/CS_analyse.py
Normal file
134
corner-sharing/utils/CS_analyse.py
Normal file
@@ -0,0 +1,134 @@
|
||||
from pymatgen.core.structure import Structure
|
||||
from pymatgen.analysis.local_env import VoronoiNN
|
||||
import numpy as np
|
||||
|
||||
def check_real(nearest):
|
||||
real_nearest = []
|
||||
for site in nearest:
|
||||
if np.all((site.frac_coords >= 0) & (site.frac_coords <= 1)):
|
||||
real_nearest.append(site)
|
||||
|
||||
return real_nearest
|
||||
|
||||
def special_check_for_3(site, nearest):
|
||||
real_nearest = []
|
||||
distances = []
|
||||
for site2 in nearest:
|
||||
distance = np.linalg.norm(np.array(site.frac_coords) - np.array(site2.frac_coords))
|
||||
distances.append(distance)
|
||||
|
||||
sorted_indices = np.argsort(distances)
|
||||
for index in sorted_indices[:3]:
|
||||
real_nearest.append(nearest[index])
|
||||
|
||||
return real_nearest
|
||||
|
||||
|
||||
def CS_catulate(struct, sp='Li', anion=['O'], tol=0, cutoff=3.0,notice=False,ID=None):
|
||||
"""
|
||||
计算结构中目标元素与最近阴离子的共享关系。
|
||||
|
||||
参数:
|
||||
struct (Structure): 输入结构。
|
||||
sp (str): 目标元素符号,默认为 'Li'。
|
||||
anion (list): 阴离子列表,默认为 ['O']。
|
||||
tol (float): VoronoiNN 的容差,默认为 0。
|
||||
cutoff (float): VoronoiNN 的截断距离,默认为 3.0。
|
||||
|
||||
返回:
|
||||
list: 包含每个目标位点及其最近阴离子索引的列表。
|
||||
"""
|
||||
# 初始化 VoronoiNN 对象
|
||||
if sp=='Li':
|
||||
tol = 0
|
||||
cutoff = 3.0
|
||||
voro_nn = VoronoiNN(tol=tol, cutoff=cutoff)
|
||||
# 初始化字典,用于统计共享关系
|
||||
shared_count = {"2": 0, "3": 0,"4":0,"5":0,"6":0}
|
||||
# 存储结果的列表
|
||||
atom_dice = []
|
||||
|
||||
# 遍历结构中的每个位点
|
||||
for index,site in enumerate(struct.sites):
|
||||
# 跳过阴离子位点
|
||||
if site.specie.symbol in anion:
|
||||
continue
|
||||
# 跳过Li原子
|
||||
if site.specie.symbol == sp:
|
||||
continue
|
||||
# 获取 Voronoi 多面体信息
|
||||
voro_info = voro_nn.get_voronoi_polyhedra(struct, index)
|
||||
|
||||
# 找到最近的阴离子位点
|
||||
nearest_anions = [
|
||||
nn_info["site"] for nn_info in voro_info.values()
|
||||
if nn_info["site"].specie.symbol in anion
|
||||
]
|
||||
|
||||
# 如果没有找到最近的阴离子,跳过
|
||||
if not nearest_anions:
|
||||
print(f"No nearest anions found for {ID} site {index}.")
|
||||
continue
|
||||
if site.specie.symbol == 'B' or site.specie.symbol == 'N':
|
||||
nearest_anions = special_check_for_3(site,nearest_anions)
|
||||
nearest_anions = check_real(nearest_anions)
|
||||
# 将结果添加到 atom_dice 列表中
|
||||
atom_dice.append({
|
||||
'index': index,
|
||||
'nearest_index': [nn.index for nn in nearest_anions]
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 枚举 atom_dice 中的所有原子对
|
||||
for i, atom_i in enumerate(atom_dice):
|
||||
for j, atom_j in enumerate(atom_dice[i + 1:], start=i + 1):
|
||||
# 获取两个原子的最近阴离子索引
|
||||
nearest_i = set(atom_i['nearest_index'])
|
||||
nearest_j = set(atom_j['nearest_index'])
|
||||
|
||||
# 比较最近阴离子的交集大小
|
||||
shared_count_key = str(len(nearest_i & nearest_j))
|
||||
|
||||
# 更新字典中的计数
|
||||
if shared_count_key in shared_count:
|
||||
shared_count[shared_count_key] += 1
|
||||
if notice:
|
||||
if shared_count_key=='2':
|
||||
print(f"{atom_j['index']}与{atom_i['index']}之间存在共线")
|
||||
print(f"共线的阴离子为{nearest_i & nearest_j}")
|
||||
if shared_count_key=='3':
|
||||
print(f"{atom_j['index']}与{atom_i['index']}之间存在共面")
|
||||
print(f"共面的阴离子为{nearest_i & nearest_j}")
|
||||
|
||||
# # 最后将字典中的值除以 2,因为每个共享关系被计算了两次
|
||||
# for key in shared_count.keys():
|
||||
# shared_count[key] //= 2
|
||||
|
||||
return shared_count
|
||||
|
||||
|
||||
def CS_count(struct, shared_count, sp='Li'):
|
||||
count = 0
|
||||
for site in struct.sites:
|
||||
if site.specie.symbol == sp:
|
||||
count += 1 # 累加符合条件的原子数量
|
||||
|
||||
CS_count = 0
|
||||
for i in range(2, 7): # 遍历范围 [2, 3, 4, 5]
|
||||
if str(i) in shared_count: # 检查键是否存在
|
||||
CS_count += shared_count[str(i)] * i # 累加计算结果
|
||||
|
||||
if count > 0: # 防止除以零
|
||||
CS_count /= count # 平均化结果
|
||||
else:
|
||||
CS_count = 0 # 如果 count 为 0,直接返回 0
|
||||
|
||||
return CS_count
|
||||
|
||||
structure = Structure.from_file("data/CS_Table1/Li3Al(BO3)2_mp-6097_computed.cif")
|
||||
a = CS_catulate(structure,notice=True)
|
||||
b = CS_count(structure,a)
|
||||
print(f"{a}\n{b}")
|
||||
@@ -47,28 +47,19 @@ class HiddenPrints:
|
||||
|
||||
|
||||
def non_elements(struct, sp='Li'):
|
||||
'''
|
||||
struct : structure object from Pymatgen
|
||||
"""
|
||||
struct : 必须是一个有序结构
|
||||
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")
|
||||
returns a new structure containing only the framework anions (O, S, N).
|
||||
"""
|
||||
anions_to_keep = {"O", "S", "N"}
|
||||
stripped = struct.copy()
|
||||
stripped.remove_species(species)
|
||||
stripped = stripped.get_sorted_structure(reverse=True)
|
||||
species_to_remove = [el.symbol for el in stripped.composition.elements
|
||||
if el.symbol not in anions_to_keep]
|
||||
|
||||
if species_to_remove:
|
||||
stripped.remove_species(species_to_remove)
|
||||
|
||||
return stripped
|
||||
|
||||
|
||||
@@ -160,22 +151,43 @@ def site_env(coord, struct, sp="Li", envtype='both'):
|
||||
|
||||
|
||||
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
|
||||
|
||||
# --- 关键修改:直接遍历原始结构,即使它是无序的 ---
|
||||
# 我们不再调用 get_sorted_structure()
|
||||
# 我们只关心那些含有目标元素 sp 的位点
|
||||
|
||||
# 遍历每一个位点 (site)
|
||||
for i, site in enumerate(struct):
|
||||
# 检查当前位点的组分(site.species)中是否包含我们感兴趣的元素(sp)
|
||||
# site.species.elements 返回该位点上的元素列表,例如 [Element Li, Element Fe]
|
||||
# [el.symbol for el in site.species.elements] 将其转换为符号列表 ['Li', 'Fe']
|
||||
site_elements = [el.symbol for el in site.species.elements]
|
||||
|
||||
if sp in site_elements:
|
||||
# 如果找到了Li,我们就对这个位点进行环境分析
|
||||
# 注意:我们将原始的、可能无序的 struct 传递给 site_env
|
||||
# 因为 site_env 内部的函数 (如 LocalGeometryFinder) 知道如何处理它
|
||||
|
||||
# 为了让下游函数(特别是 non_elements)能够工作,
|
||||
# 我们在这里创建一个一次性的、临时的有序结构副本给它
|
||||
# 这可以避免我们之前遇到的所有 'ordered structures only' 错误
|
||||
temp_ordered_struct = struct.get_sorted_structure()
|
||||
|
||||
singleenv = site_env(site.frac_coords, temp_ordered_struct, sp, envtype)
|
||||
|
||||
envlist.append({'frac_coords': site.frac_coords, 'type': singleenv['type'], 'csm': singleenv['csm'],
|
||||
'volume': singleenv['vol']})
|
||||
|
||||
if not envlist:
|
||||
print(f"警告: 在结构中未找到元素 {sp} 的占位。")
|
||||
|
||||
return envlist
|
||||
|
||||
def export_envs(envlist, sp='Li', envtype='both', fname=None):
|
||||
'''
|
||||
@@ -193,6 +205,6 @@ def export_envs(envlist, sp='Li', envtype='both', fname=None):
|
||||
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")
|
||||
# struct = Structure.from_file("../data/0921/wjy_475.cif")
|
||||
# site_info = extract_sites(struct, envtype="both")
|
||||
# export_envs(site_info, sp="Li", envtype="both")
|
||||
Reference in New Issue
Block a user