一些小修改

This commit is contained in:
2025-11-19 12:23:17 +08:00
parent 95d719cc1e
commit 80ae03c8c1
25 changed files with 2291 additions and 17 deletions

View File

@@ -0,0 +1,79 @@
from pymatgen.core import Structure
from pymatgen.io.vasp import Poscar
def create_supercell_poscar(cif_path, supercell_matrix, output_filename="POSCAR_supercell"):
"""
从CIF文件读取晶体结构根据指定的矩阵进行扩胞并生成VASP POSCAR文件。
Args:
cif_path (str): 输入的CIF文件路径。
supercell_matrix (list or tuple): 3x3的扩胞矩阵。
- 对于简单的对角扩胞 (例如 2x2x4),使用: [[2, 0, 0], [0, 2, 0], [0, 0, 4]]
- 对于非对角扩胞 (例如 a_s=3a, b_s=2a+4b, c_s=6c),使用: [[3, 0, 0], [2, 4, 0], [0, 0, 6]]
output_filename (str): 输出的POSCAR文件名。默认为 "POSCAR_supercell"
Returns:
bool: 如果成功生成文件则返回 True否则返回 False。
"""
try:
# 1. 从CIF文件加载结构
# 使用 from_file 静态方法直接读取
# primitive=False 确保我们使用CIF中定义的晶胞而不是其原胞
original_structure = Structure.from_file(cif_path, primitive=False)
print("--- 原始晶胞信息 ---")
print(f" 原子数: {original_structure.num_sites}")
print(f" 化学式: {original_structure.composition.reduced_formula}")
print(f" 晶格参数 (a, b, c, α, β, γ):")
lat = original_structure.lattice
print(f" {lat.a:.4f}, {lat.b:.4f}, {lat.c:.4f}, {lat.alpha:.2f}, {lat.beta:.2f}, {lat.gamma:.2f}")
# 2. 进行扩胞操作
# 注意pymatgen 会自动处理原子坐标的映射
supercell_structure = original_structure * supercell_matrix
print("\n--- 扩胞后信息 ---")
print(f" 扩胞矩阵: {supercell_matrix}")
print(f" 新原子数: {supercell_structure.num_sites}")
print(f" 新化学式: {supercell_structure.composition.reduced_formula}")
print(f" 新晶格参数 (a, b, c, α, β, γ):")
super_lat = supercell_structure.lattice
print(f" {super_lat.a:.4f}, {super_lat.b:.4f}, {super_lat.c:.4f}, {super_lat.alpha:.2f}, {super_lat.beta:.2f}, {super_lat.gamma:.2f}")
# 3. 创建Poscar对象并写入文件
# comment 参数可以设置POSCAR文件的第一行注释
poscar = Poscar(supercell_structure, comment=f"Supercell from {cif_path}")
poscar.write_file(output_filename)
print(f"\n成功!已将扩胞结构写入文件: {output_filename}")
return True
except Exception as e:
print(f"发生错误: {e}")
return False
# --- 使用示例 ---
# 假设您的CIF文件名为 "origin.cif",并且与此脚本在同一目录下。
# 如果您在复现 Wang Shuo 的工作,他们可能使用了不同的扩胞方案。
# 例如用于MD模拟的大超胞是 2x2x4 [source_id: 3]。
# 而用于DP-GEN探索的小超胞是 1x1x2 [source_id: 3]。
# 示例1生成用于DP-GEN探索的 1x1x2 小超胞 (60个原子)
print("="*40)
print("正在生成 1x1x2 超胞 (用于 DP-GEN 探索)...")
matrix_1x1x2 = [[1, 0, 0], [0, 1, 0], [0, 0, 2]]
create_supercell_poscar("data/P3ma/origin.cif", matrix_1x1x2, "data/P3ma/output/POSCAR_1x1x2_60atoms")
# 示例2生成用于LAMMPS MD模拟的 2x2x4 大超胞 (480个原子)
# print("\n" + "="*40)
# print("正在生成 2x2x4 超胞 (用于 LAMMPS MD 模拟)...")
# matrix_2x2x4 = [[2, 0, 0], [0, 2, 0], [0, 0, 4]]
# create_supercell_poscar("origin.cif", matrix_2x2x4, "POSCAR_2x2x4_480atoms")
#
# # 示例3生成 Geng 等人研究中使用的大超胞 (2160个原子) [source_id: 1]
# # 这个扩胞矩阵 a_s = 3a_0, b_s = 2a_0 + 4b_0, c_s = 6c_0 [source_id: 1]
# print("\n" + "="*40)
# print("正在生成非对角扩胞超胞 (Geng et al.)...")
# matrix_geng = [[3, 0, 0], [2, 4, 0], [0, 0, 6]]
# create_supercell_poscar("origin.cif", matrix_geng, "POSCAR_Geng_2160atoms")

View File

@@ -147,5 +147,5 @@ def make_pnma_poscar_from_cif(cif_path: str,
print(f"写出 {out_poscar};总原子数 = {len(s)};组成 = {comp}")
if __name__=="__main__":
# make_model3_poscar_from_cif("data/P3ma/model3.cif","data/P3ma/supercell_model4.poscar")
make_pnma_poscar_from_cif("data/Pnma/origin.cif","data/Pnma/supercell_pnma.poscar",seed=42)
# make_model3_poscar_from_cif("raw/P3ma/model3.cif","raw/P3ma/supercell_model4.poscar")
make_pnma_poscar_from_cif("data/Pnma/origin.cif","raw/Pnma/supercell_pnma.poscar",seed=42)

View File

@@ -0,0 +1,240 @@
import pymatgen.core as mg
from pymatgen.io.cif import CifParser
from pymatgen.transformations.standard_transformations import SupercellTransformation
import random
import os
def create_ordered_structure_from_disordered(disordered_structure):
"""
手动将包含部分占位的无序结构转换为有序结构借鉴plus.py的思路。
"""
s = disordered_structure.copy()
# 识别需要处理的部分占位
# 根据 model3.cif, Y2(z≈0.488, occ=0.75), Y3(z≈-0.065, occ=0.25), Li2(z≈0.5, occ=0.5) [model3.cif]
y2_indices, y3_indices, li2_indices = [], [], []
for i, site in enumerate(s.sites):
# 使用z坐标来识别特定的部分占位
z = site.frac_coords[2]
if site.species_string == "Y":
if abs(z - 0.488) < 0.05:
y2_indices.append(i)
elif abs(z - (-0.065)) < 0.05 or abs(z - (1 - 0.065)) < 0.05:
y3_indices.append(i)
elif site.species_string == "Li":
if abs(z - 0.5) < 0.05:
li2_indices.append(i)
# 根据占位率随机选择要保留的原子
def choose_keep(indices, keep_fraction):
num_to_keep = int(round(len(indices) * keep_fraction))
return set(random.sample(indices, num_to_keep))
keep_y2 = choose_keep(y2_indices, 0.75)
keep_y3 = choose_keep(y3_indices, 0.25)
keep_li2 = choose_keep(li2_indices, 0.50)
# 找出所有需要删除的原子索引
to_remove_indices = [i for i in y2_indices if i not in keep_y2]
to_remove_indices.extend([i for i in y3_indices if i not in keep_y3])
to_remove_indices.extend([i for i in li2_indices if i not in keep_li2])
# 从后往前删除,避免索引错位
s.remove_sites(sorted(to_remove_indices, reverse=True))
# --- 关键修复步骤 ---
# 最终清理,确保所有位点都是有序的
for i, site in enumerate(s.sites):
if not site.is_ordered:
# 将Composition对象转换为字典然后找到占位率最高的元素 [plus.py]
species_dict = site.species.as_dict()
main_specie = max(species_dict.items(), key=lambda item: item[1])[0]
s.replace(i, main_specie)
return s
def create_supercells_from_file(cif_path, output_path="."):
"""
根据给定的CIF文件路径生成三种不同尺寸和缺陷的超胞并保存为POSCAR文件。
"""
if not os.path.exists(cif_path):
print(f"错误: 文件 '{cif_path}' 不存在。")
return
print(f"正在从 {cif_path} 读取结构...")
parser = CifParser(cif_path)
disordered_structure = parser.parse_structures(primitive=False)[0]
structure = create_ordered_structure_from_disordered(disordered_structure)
print(f"成功将无序结构转换为一个包含 {len(structure)} 个原子的有序单胞。")
os.makedirs(output_path, exist_ok=True)
# 任务一生成60原子超胞 (无缺陷)
print("\n--- 正在生成 60原子无缺陷超胞 (1x1x2) ---")
tf_60 = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 2]])
sc_60_no_defect = tf_60.apply_transformation(structure)
print(f"原子总数: {len(sc_60_no_defect)}, 化学式: {sc_60_no_defect.composition.reduced_formula}")
sc_60_no_defect.to(fmt="poscar", filename=os.path.join(output_path, "POSCAR_60_no_defect"))
print(f"已保存文件: {os.path.join(output_path, 'POSCAR_60_no_defect')}")
# 任务二生成60原子超胞 (含一对反位缺陷)
print("\n--- 正在生成 60原子含一对反位缺陷超胞 ---")
sc_60_defect = sc_60_no_defect.copy()
li_indices = [i for i, site in enumerate(sc_60_defect.sites) if site.species_string == 'Li']
y_indices = [i for i, site in enumerate(sc_60_defect.sites) if site.species_string == 'Y']
if li_indices and y_indices:
li_swap_idx, y_swap_idx = random.choice(li_indices), random.choice(y_indices)
sc_60_defect.replace(li_swap_idx, "Y")
sc_60_defect.replace(y_swap_idx, "Li")
print(f"成功引入一对反位缺陷。浓度: {2 / (len(li_indices) + len(y_indices)) * 100:.2f}%")
sc_60_defect.to(fmt="poscar", filename=os.path.join(output_path, "POSCAR_60_antisite_defect"))
print(f"已保存文件: {os.path.join(output_path, 'POSCAR_60_antisite_defect')}")
# 任务三生成90原子超胞 (含一对反位缺陷)
print("\n--- 正在生成 90原子含一对反位缺陷超胞 ---")
tf_90 = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 3]])
sc_90_no_defect = tf_90.apply_transformation(structure)
sc_90_defect = sc_90_no_defect.copy()
li_indices = [i for i, site in enumerate(sc_90_defect.sites) if site.species_string == 'Li']
y_indices = [i for i, site in enumerate(sc_90_defect.sites) if site.species_string == 'Y']
if li_indices and y_indices:
li_swap_idx, y_swap_idx = random.choice(li_indices), random.choice(y_indices)
sc_90_defect.replace(li_swap_idx, "Y")
sc_90_defect.replace(y_swap_idx, "Li")
print(f"原子总数: {len(sc_90_defect)}, 浓度: {2 / (len(li_indices) + len(y_indices)) * 100:.2f}%")
sc_90_defect.to(fmt="poscar", filename=os.path.join(output_path, "POSCAR_90_antisite_defect"))
print(f"已保存文件: {os.path.join(output_path, 'POSCAR_90_antisite_defect')}")
def create_ordered_p3ma_structure(disordered_structure):
"""
手动将P3ma相的无序结构包含Y2, Y3, Li2的部分占位转换为有序结构。
"""
s = disordered_structure.copy()
# 根据 model3.cif, 识别Y2(z≈0.488, occ=0.75), Y3(z≈-0.065, occ=0.25), Li2(z≈0.5, occ=0.5) [model3.cif]
y2_indices, y3_indices, li2_indices = [], [], []
for i, site in enumerate(s.sites):
z = site.frac_coords[2]
if site.species_string == "Y":
if abs(z - 0.488) < 0.05:
y2_indices.append(i)
elif abs(z - (-0.065)) < 0.05 or abs(z - (1 - 0.065)) < 0.05:
y3_indices.append(i)
elif site.species_string == "Li":
if abs(z - 0.5) < 0.05:
li2_indices.append(i)
# 根据占位率随机选择要保留的原子
def choose_keep(indices, keep_fraction):
num_to_keep = int(round(len(indices) * keep_fraction))
return set(random.sample(indices, num_to_keep))
keep_y2 = choose_keep(y2_indices, 0.75)
keep_y3 = choose_keep(y3_indices, 0.25)
keep_li2 = choose_keep(li2_indices, 0.50)
# 找出所有需要删除的原子索引
to_remove_indices = [i for i in y2_indices if i not in keep_y2]
to_remove_indices.extend([i for i in y3_indices if i not in keep_y3])
to_remove_indices.extend([i for i in li2_indices if i not in keep_li2])
s.remove_sites(sorted(to_remove_indices, reverse=True))
# 最终清理,确保所有位点都是有序的
for i, site in enumerate(s.sites):
if not site.is_ordered:
species_dict = site.species.as_dict()
main_specie = max(species_dict.items(), key=lambda item: item[1])[0]
s.replace(i, main_specie)
return s
def create_multiple_p3ma_supercells(cif_path, num_configs=5, output_path="."):
"""
读取P3ma相CIF为不同尺寸的超胞生成多个具有不同反位缺陷位置的构型。
"""
if not os.path.exists(cif_path):
print(f"错误: 文件 '{cif_path}' 不存在。")
return
print(f"正在从 {cif_path} 读取P3ma结构...")
parser = CifParser(cif_path)
disordered_structure = parser.parse_structures(primitive=False)[0]
structure = create_ordered_p3ma_structure(disordered_structure)
print(f"成功将无序P3ma结构转换为一个包含 {len(structure)} 个原子的有序单胞。")
os.makedirs(output_path, exist_ok=True)
target_sizes = [60, 90]
for size in target_sizes:
print(f"\n--- 正在为约 {size} 原子的版本生成 {num_configs} 个不同构型 ---")
# 1. 构建基准超胞
if size == 60:
tf = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 2]])
filename_suffix = "60_approx"
else: # size == 90
tf = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 3]])
filename_suffix = "90_approx"
base_supercell = tf.apply_transformation(structure)
print(f"已生成基准超胞,实际原子数: {len(base_supercell)}")
li_indices = [i for i, site in enumerate(base_supercell.sites) if site.species_string == 'Li']
y_indices = [i for i, site in enumerate(base_supercell.sites) if site.species_string == 'Y']
if not li_indices or not y_indices:
print("错误在超胞中未找到足够的Li或Y原子来引入缺陷。")
continue
# 2. 循环生成多个独特的缺陷构型
used_pairs = set()
for i in range(num_configs):
defect_supercell = base_supercell.copy()
# 确保随机选择的交换对是全新的
# 增加一个尝试次数上限,防止在原子数很少时陷入死循环
max_tries = len(li_indices) * len(y_indices)
for _ in range(max_tries):
li_swap_idx = random.choice(li_indices)
y_swap_idx = random.choice(y_indices)
pair = tuple(sorted((li_swap_idx, y_swap_idx)))
if pair not in used_pairs:
used_pairs.add(pair)
break
else:
print(f" 警告: 未能找到更多独特的交换对,已停止在第 {i} 个构型。")
break
# 引入缺陷
defect_supercell.replace(li_swap_idx, "Y")
defect_supercell.replace(y_swap_idx, "Li")
print(f" 配置 {i}: 成功引入一对反位缺陷 (Li at index {li_swap_idx} <-> Y at index {y_swap_idx})。")
# 3. 保存为带编号的POSCAR文件
poscar_filename = f"POSCAR_P3ma_{filename_suffix}_antisite_defect_{i}"
poscar_path = os.path.join(output_path, poscar_filename)
defect_supercell.to(fmt="poscar", filename=poscar_path)
print(f" 已保存文件: {poscar_path}")
if __name__ == '__main__':
# --- 使用方法 ---
# 1. 将您的CIF文件保存例如命名为 "Li3YCl6.cif"
# 2. 将文件名作为参数传递给函数
cif_file_path = "data/P3ma/model3.cif" # 修改为您的CIF文件名
output_directory = "raw/P3ma/output" # 可以指定一个输出目录
# create_supercells_from_file(cif_file_path, output_directory)
create_multiple_p3ma_supercells(cif_file_path,output_path=output_directory)
print("所有任务完成!")

View File

@@ -0,0 +1,115 @@
import pymatgen.core as mg
from pymatgen.io.cif import CifParser
from pymatgen.transformations.standard_transformations import SupercellTransformation
import random
import os
def create_ordered_pnma_structure(disordered_structure):
"""
手动将Pnma相的无序结构主要为Li的部分占位转换为有序结构。
"""
s = disordered_structure.copy()
# 根据origin.cif, Li位点的占位率为0.75 [5]
partial_li_indices = [i for i, site in enumerate(s.sites) if "Li" in site.species and not site.is_ordered]
# 根据0.75的占位率随机选择要保留的Li原子
num_to_keep = int(round(len(partial_li_indices) * 0.75))
keep_indices = set(random.sample(partial_li_indices, num_to_keep))
# 找出需要删除的原子索引
to_remove_indices = [i for i in partial_li_indices if i not in keep_indices]
s.remove_sites(sorted(to_remove_indices, reverse=True))
# 重新创建一个新的、完全有序的结构,避免任何副作用
ordered_species = []
ordered_coords = []
for site in s.sites:
# 只取每个位点的主要元素
main_specie = site.species.elements[0]
ordered_species.append(main_specie)
ordered_coords.append(site.frac_coords)
final_structure = mg.Structure(s.lattice, ordered_species, ordered_coords)
return final_structure
def create_multiple_pnma_supercells(cif_path, num_configs=3, output_path="."):
"""
读取Pnma相CIF为不同尺寸的超胞生成多个具有不同反位缺陷位置的构型。
"""
if not os.path.exists(cif_path):
print(f"错误: 文件 '{cif_path}' 不存在。")
return
print(f"正在从 {cif_path} 读取Pnma结构...")
parser = CifParser(cif_path)
disordered_structure = parser.parse_structures(primitive=False)[0]
structure = create_ordered_pnma_structure(disordered_structure)
print(f"成功将无序Pnma结构转换为一个包含 {len(structure)} 个原子的有序单胞。")
os.makedirs(output_path, exist_ok=True)
target_sizes = [60, 90]
for size in target_sizes:
print(f"\n--- 正在为约 {size} 原子的版本生成 {num_configs} 个不同构型 ---")
# 1. 构建基准超胞
if size == 60:
tf = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 2]])
filename_suffix = "60_approx"
else: # size == 90
tf = SupercellTransformation([[1, 0, 0], [0, 1, 0], [0, 0, 3]])
filename_suffix = "90_approx"
base_supercell = tf.apply_transformation(structure)
print(f"已生成基准超胞,实际原子数: {len(base_supercell)}")
li_indices = [i for i, site in enumerate(base_supercell.sites) if site.species_string == 'Li']
y_indices = [i for i, site in enumerate(base_supercell.sites) if site.species_string == 'Y']
if not li_indices or not y_indices:
print("错误在超胞中未找到足够的Li或Y原子来引入缺陷。")
continue
# 2. 循环生成多个独特的缺陷构型
used_pairs = set()
for i in range(num_configs):
defect_supercell = base_supercell.copy()
# 确保随机选择的交换对是全新的
while True:
li_swap_idx = random.choice(li_indices)
y_swap_idx = random.choice(y_indices)
# 使用排序后的元组作为键,确保(a,b)和(b,a)被视为相同
pair = tuple(sorted((li_swap_idx, y_swap_idx)))
if pair not in used_pairs:
used_pairs.add(pair)
break
# 引入缺陷
defect_supercell.replace(li_swap_idx, "Y")
defect_supercell.replace(y_swap_idx, "Li")
print(f" 配置 {i}: 成功引入一对反位缺陷 (Li at index {li_swap_idx} <-> Y at index {y_swap_idx})。")
# 3. 保存为带编号的POSCAR文件
poscar_filename = f"POSCAR_Pnma_{filename_suffix}_antisite_defect_{i}"
poscar_path = os.path.join(output_path, poscar_filename)
defect_supercell.to(fmt="poscar", filename=poscar_path)
print(f" 已保存文件: {poscar_path}")
if __name__ == '__main__':
# 请将您的Pnma相CIF文件保存并修改此路径
# 这里我们使用您提供的参考文件名 'origin.cif'
cif_file_path = "data/Pnma/origin.cif"
output_directory = "raw/Pnma/output"
create_multiple_pnma_supercells(cif_file_path, num_configs=3, output_path=output_directory)
print("\nPnma相处理完成")

View File

@@ -0,0 +1,197 @@
import random
from collections import defaultdict, Counter
from pymatgen.core import Structure, Element
from pymatgen.io.lammps.data import LammpsData
# ASE 兜底(可选)
try:
from ase.io import write as ase_write
from ase import Atoms as ASEAtoms
HAS_ASE = True
except Exception:
HAS_ASE = False
# ===== 用户参数 =====
cif_filename = "data/P3ma/origin.cif" # 你的输入 CIF含部分占位[5]
supercell_matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 2]] # 2×2×4 超胞(总复制数=16[3]
out_lammps = "lyc_P3m1_1x1x2_from_cif_ordered.vasp" # 输出 LAMMPS raw
seed = 2025
strict_count = True # 严格配额:每个父位点在超胞内按占位概率分配整数个原子/空位
# ====================
random.seed(seed)
def species_to_probs(site):
"""
将站点的物种占位转换为 [(species or None(vac), prob)] 列表prob 归一化为和=1。
若总占位 < 1补一个 vacancy(None)。
去掉氧化态,仅保留元素。
"""
sp_items = site.species.items()
total = 0.0
pairs = []
for spc, occ in sp_items:
# 转成 Element剔除氧化态
try:
e = Element(spc.symbol) if hasattr(spc, "symbol") else Element(str(spc))
except Exception:
e = Element(str(spc))
pairs.append((e, float(occ)))
total += float(occ)
if total < 1.0 - 1e-10:
pairs.append((None, 1.0 - total)) # vacancy
total = 1.0
# 归一化
if abs(total - 1.0) > 1e-10:
pairs = [(e, p / total) for (e, p) in pairs]
return pairs
def draw_counts_from_probs(n, probs):
"""
给定复制数 n 和概率 probs返回 {species/None: count},使计数和为 n。
先按四舍五入,再用残差修正到总和= n。
"""
# 初分配
counts = {sp: int(round(p * n)) for sp, p in probs}
s = sum(counts.values())
if s == n:
return counts
# 残差排序:需要增加则按概率大的优先加;需要减少则按概率小的优先减
if n > s:
need = n - s
probs_sorted = sorted(probs, key=lambda x: x[1], reverse=True)
for i in range(need):
sp = probs_sorted[i % len(probs_sorted)][0]
counts[sp] = counts.get(sp, 0) + 1
else:
need = s - n
probs_sorted = sorted(probs, key=lambda x: x[1]) # 先减概率小的
idx = 0
while need > 0 and idx < 50 * len(probs_sorted):
sp = probs_sorted[idx % len(probs_sorted)][0]
if counts.get(sp, 0) > 0:
counts[sp] -= 1
need -= 1
idx += 1
return counts
def collapse_disorder_to_ordered_supercell(struct, M, strict=True):
"""
处理步骤:
1) 给原胞每个位点打 parent_id
2) 扩胞到 M
3) 以父位点为组,在组内(复制数 n按占位概率分配整数个 species/空位到每个复制位点
- 有序位点:所有复制直接保留
- 无序位点/部分占位:严格配额或独立抽样
4) 返回完全有序的超胞 Structure
"""
s0 = struct.copy()
s0.add_site_property("parent_id", list(range(s0.num_sites)))
sc = s0.copy()
sc.make_supercell(M)
# 按父位点分组
groups = defaultdict(list)
for i, site in enumerate(sc.sites):
pid = sc.site_properties["parent_id"][i]
groups[pid].append(i)
new_species = []
new_fracs = []
new_lat = sc.lattice
for pid, idx_list in groups.items():
# 用该组第一个复制的站点定义占位
site0 = sc[idx_list[0]]
# 有序站点直接全部保留只有一种元素且占位为1
if site0.is_ordered:
species_elem = list(site0.species.keys())[0]
for i in idx_list:
new_species.append(species_elem)
new_fracs.append(sc[i].frac_coords)
continue
# 无序/部分占位:概率分配
probs = species_to_probs(site0)
n = len(idx_list)
if strict:
counts = draw_counts_from_probs(n, probs)
# 构造分配池并打乱
pool = []
for sp, c in counts.items():
pool += [sp] * c
random.shuffle(pool)
# 分配到每个复制位点
for i, sp in zip(idx_list, pool):
if sp is None:
continue # vacancy -> 删除该位点
new_species.append(sp)
new_fracs.append(sc[i].frac_coords)
else:
# 独立抽样
import bisect
species_list = [sp for sp, p in probs]
cum = []
ssum = 0.0
for _, p in probs:
ssum += p
cum.append(ssum)
for i in idx_list:
r = random.random()
j = bisect.bisect_left(cum, r)
sp = species_list[j]
if sp is None:
continue
new_species.append(sp)
new_fracs.append(sc[i].frac_coords)
ordered_sc = Structure(new_lat, new_species, new_fracs, to_unit_cell=True, coords_are_cartesian=False)
# 去除可能残留的氧化态LAMMPS atomic 不需要)
try:
ordered_sc.remove_oxidation_states()
except Exception:
pass
return ordered_sc
# 1) 读取 CIF含部分占位
s_in = Structure.from_file(cif_filename, primitive=False)
print(f"读入: {cif_filename}, 原胞位点: {s_in.num_sites}, 有序?: {s_in.is_ordered}")
# 2) 在 2×2×4 超胞上固化部分占位 -> 完全有序超胞
ordered_sc = collapse_disorder_to_ordered_supercell(s_in, supercell_matrix, strict=strict_count)
print(f"生成有序超胞: 位点数={ordered_sc.num_sites}, 有序?: {ordered_sc.is_ordered}")
# 3) 打印元素计数,核对化学计量
elem_count = Counter([sp.symbol for sp in ordered_sc.species])
print("元素计数:", dict(elem_count))
# 4) 写 LAMMPS rawpymatgen失败则 ASE 兜底)
wrote = False
try:
ldata = LammpsData.from_structure(ordered_sc, atom_style="atomic")
ldata.write_file(out_lammps)
wrote = True
print(f"已写出 LAMMPS raw: {out_lammps} (pymatgen)")
except Exception as e:
print("pymatgen 写 LAMMPS raw 失败:", e)
if not wrote and HAS_ASE:
try:
ase_atoms = ASEAtoms(
symbols=[sp.symbol for sp in ordered_sc.species],
positions=ordered_sc.cart_coords,
cell=ordered_sc.lattice.matrix,
pbc=True
)
ase_write(out_lammps, ase_atoms, format="lammps-raw", atom_style="atomic")
wrote = True
print(f"已写出 LAMMPS raw: {out_lammps} (ASE)")
except Exception as e:
print("ASE 写 LAMMPS raw 也失败:", e)
if not wrote:
print("写 LAMMPS raw 失败,请把错误信息发我。")