This commit is contained in:
2025-10-09 09:43:34 +08:00
parent e6141689c1
commit 5d1a4d04f2
4 changed files with 179 additions and 59 deletions

View File

@@ -3,17 +3,16 @@ import sys
import subprocess
import re
import csv
import argparse
from pathlib import Path
# --- 配置区 ---
# softBV.x 可执行文件的路径,请根据你的实际情况修改
# 使用 Path.home() 来自动获取用户家目录,比 '~' 更可靠
SOFTBV_EXECUTABLE = Path.home() / "tool/softBV-GUI_linux/bin/softBV.x"
# 固定的命令参数
MOBILE_ION = "Li"
ION_VALENCE = "1"
SF_VALUE = "1000"
# 输出CSV文件的名称
OUTPUT_CSV_FILE = "conductivity_results.csv"
@@ -33,47 +32,73 @@ def check_executable():
sys.exit(1)
def get_formula_from_cif_line2(cif_path):
"""
通过读取CIF文件的第二行来提取化学式。
期望的格式是 'data_FORMULA'
"""
try:
with open(cif_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
if len(lines) > 1:
second_line = lines[1].strip() # .strip() 去除首尾空白和换行符
if second_line.lower().startswith('data_'):
# 提取 'data_' 之后的内容作为化学式
return second_line[5:]
else:
print(f"\n警告: 文件 {cif_path.name} 的第二行格式不正确 (不是以'data_'开头)。", file=sys.stderr)
return "FormatError"
else:
print(f"\n警告: 文件 {cif_path.name} 行数不足2行。", file=sys.stderr)
return "FileTooShort"
except Exception as e:
print(f"\n警告: 读取文件 {cif_path.name} 时发生错误: {e}", file=sys.stderr)
return "ReadError"
def parse_conductivity(output_text):
"""
从 softBV.x 的输出文本中解析电导率(conductivity)。
使用正则表达式来匹配 'MD: conductivity = <value>' 格式的行。
"""
# 正则表达式解释:
# ^ - 匹配行首
# \s* - 匹配任意数量的空白字符
# MD: conductivity - 匹配字面字符串
# \s*=\s* - 匹配等号,前后可以有任意空白
# ([-\d.eE+]+) - 捕获组1: 匹配并捕获一个或多个数字、点、'e'/'E'、'+'/'-' (科学计数法)
"""从 softBV.x 的输出文本中解析并格式化电导率"""
pattern = re.compile(r"^\s*MD: conductivity\s*=\s*([-\d.eE+]+)", re.MULTILINE)
match = pattern.search(output_text)
if match:
# 返回捕获到的第一个组 (也就是数值部分)
return match.group(1)
conductivity_str = match.group(1)
try:
conductivity_val = float(conductivity_str)
# 将单位从 S/m 转换为 1e-3 S/m (mS/m), 需要乘以 1000
conductivity_ms_m = conductivity_val * 1000
# 格式化为两位小数的字符串
return f"{conductivity_ms_m:.2f}"
except ValueError:
return "ValueError"
else:
# 如果没有找到匹配的行,返回 None
return None
def main():
"""主函数"""
# 1. 检查命令行参数
if len(sys.argv) != 2:
print(f"用法: python {sys.argv[0]} <cif_folder_name>")
print(f"例如: python {sys.argv[0]} Br")
sys.exit(1)
parser = argparse.ArgumentParser(
description="运行 softBV.x 计算电导率并汇总到CSV文件。",
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument("folder", type=str, help="包含CIF文件的目标文件夹路径。")
parser.add_argument(
"-t", "--temperature",
type=int,
default=1000,
help="模拟温度 (K),对应 softBV.x 的最后一个参数。\n默认值: 1000"
)
args = parser.parse_args()
target_folder = Path(sys.argv[1])
target_folder = Path(args.folder)
temperature = str(args.temperature)
# 检查目标文件夹是否存在
if not target_folder.is_dir():
print(f"错误: 文件夹 '{target_folder}' 不存在。")
sys.exit(1)
# 检查 softBV.x 是否配置正确
check_executable()
# 2. 查找所有 .cif 文件
cif_files = sorted(list(target_folder.glob("*.cif")))
if not cif_files:
@@ -81,61 +106,45 @@ def main():
return
print(f"'{target_folder}' 中找到 {len(cif_files)} 个 .cif 文件,开始处理...")
print(f"模拟温度设置为: {temperature} K")
results = [] # 用于存储 (文件名, 电导率)
results = []
# 3. 遍历文件,执行命令并提取数据
for cif_file in cif_files:
print(f" -> 正在处理: {cif_file} ...", end="", flush=True)
# 构建命令
# 使用新的函数获取化学式
formula = get_formula_from_cif_line2(cif_file)
command = [
str(SOFTBV_EXECUTABLE),
"--md",
str(cif_file),
MOBILE_ION,
ION_VALENCE,
SF_VALUE
str(SOFTBV_EXECUTABLE), "--md", str(cif_file),
MOBILE_ION, ION_VALENCE, temperature
]
try:
# 执行命令并捕获输出
# capture_output=True 将 stdout 和 stderr 分别捕获
# text=True (或 encoding='utf-8') 将输出解码为字符串
# check=True 如果命令返回非零退出码 (表示错误),则会抛出异常
process_result = subprocess.run(
command,
capture_output=True,
text=True,
check=True,
timeout=300 # 设置一个超时时间例如300秒防止程序卡死
command, capture_output=True, text=True, check=True, timeout=300
)
# 从标准输出中解析数据
conductivity = parse_conductivity(process_result.stdout)
if conductivity is not None:
results.append((cif_file.name, conductivity))
print(f" 成功, conductivity = {conductivity}")
results.append([cif_file.name, formula, conductivity])
print(f" 成功, Formula: {formula}, Conductivity: {conductivity} (x10^-3 S/m)")
else:
print(" 失败 (无法在输出中找到conductivity)")
# 你也可以选择将错误信息记录下来
# results.append((cif_file.name, "Error: Not Found"))
results.append([cif_file.name, formula, "NotFound"])
except subprocess.CalledProcessError as e:
# 命令执行失败
print(f" 失败 (命令执行错误)")
print(f" 错误信息: {e.stderr.strip()}")
# results.append((cif_file.name, "Error: Execution Failed"))
print(f" 错误信息: {e.stderr.strip()}", file=sys.stderr)
results.append([cif_file.name, formula, "ExecError"])
except subprocess.TimeoutExpired:
print(f" 失败 (命令执行超时)")
# results.append((cif_file.name, "Error: Timeout"))
results.append([cif_file.name, formula, "Timeout"])
except Exception as e:
# 其他未知错误
print(f" 失败 (发生未知错误: {e})")
# results.append((cif_file.name, f"Error: {e}"))
print(f" 失败 (发生未知错误: {e})", file=sys.stderr)
results.append([cif_file.name, formula, "UnknownError"])
# 4. 将结果写入CSV文件
if not results:
print("没有成功处理任何文件不生成CSV。")
return
@@ -145,9 +154,7 @@ def main():
try:
with open(OUTPUT_CSV_FILE, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
# 写入表头
writer.writerow(['filename', 'conductivity'])
# 写入数据
writer.writerow(['filename', 'formula', 'conductivity(e-3S/m)'])
writer.writerows(results)
print("CSV文件已成功生成")
except IOError as e: