import os import sys import subprocess import re import csv import argparse from pathlib import Path # --- 配置区 --- # softBV.x 可执行文件的路径,请根据你的实际情况修改 SOFTBV_EXECUTABLE = Path.home() / "tool/softBV-GUI_linux/bin/softBV.x" # 固定的命令参数 MOBILE_ION = "Li" ION_VALENCE = "1" # 输出CSV文件的名称 OUTPUT_CSV_FILE = "conductivity_results.csv" # --- 配置区结束 --- def check_executable(): """检查 softBV.x 文件是否存在且可执行""" if not SOFTBV_EXECUTABLE.is_file(): print(f"错误: 可执行文件未找到: {SOFTBV_EXECUTABLE}") print("请检查脚本中的 SOFTBV_EXECUTABLE 路径是否正确。") sys.exit(1) if not os.access(SOFTBV_EXECUTABLE, os.X_OK): print(f"错误: 文件存在但不可执行: {SOFTBV_EXECUTABLE}") print("请使用 'chmod +x' 命令赋予其执行权限。") 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 的输出文本中解析并格式化电导率""" pattern = re.compile(r"^\s*MD: conductivity\s*=\s*([-\d.eE+]+)", re.MULTILINE) match = pattern.search(output_text) if match: 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: return None def main(): """主函数""" 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(args.folder) temperature = str(args.temperature) if not target_folder.is_dir(): print(f"错误: 文件夹 '{target_folder}' 不存在。") sys.exit(1) check_executable() cif_files = sorted(list(target_folder.glob("*.cif"))) if not cif_files: print(f"警告: 在文件夹 '{target_folder}' 中没有找到任何 .cif 文件。") return print(f"在 '{target_folder}' 中找到 {len(cif_files)} 个 .cif 文件,开始处理...") print(f"模拟温度设置为: {temperature} K") results = [] 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, temperature ] try: process_result = subprocess.run( 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, formula, conductivity]) print(f" 成功, Formula: {formula}, Conductivity: {conductivity} (x10^-3 S/m)") else: print(" 失败 (无法在输出中找到conductivity)") results.append([cif_file.name, formula, "NotFound"]) except subprocess.CalledProcessError as e: print(f" 失败 (命令执行错误)") 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, formula, "Timeout"]) except Exception as e: print(f" 失败 (发生未知错误: {e})", file=sys.stderr) results.append([cif_file.name, formula, "UnknownError"]) if not results: print("没有成功处理任何文件,不生成CSV。") return print(f"\n处理完成,正在将 {len(results)} 条结果写入 {OUTPUT_CSV_FILE} ...") try: with open(OUTPUT_CSV_FILE, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(['filename', 'formula', 'conductivity(e-3S/m)']) writer.writerows(results) print("CSV文件已成功生成!") except IOError as e: print(f"错误: 无法写入CSV文件: {e}") if __name__ == "__main__": main()