nep框架搭建

This commit is contained in:
2025-12-08 22:05:06 +08:00
parent 5057d18e98
commit cba2afb403
9 changed files with 498 additions and 5 deletions

View File

@@ -0,0 +1,116 @@
import shutil
import glob
from pathlib import Path
from nep_auto.modules.base_module import BaseModule
class MDModule(BaseModule):
def __init__(self, driver, iter_id):
super().__init__(driver, iter_id)
self.template_subdir = "00_md"
# 预热目录 (输入源)
self.preheat_dir = self.iter_dir / "00.md" / "preheat"
# MD 目录 (工作区)
self.work_dir = self.iter_dir / "00.md" / "md"
def get_work_dir(self):
return self.work_dir
def run(self):
self.logger.info(f"🌪️ [MD] Starting Sampling Phase Iter {self.iter_id}...")
self.initialize()
# ----------------------------------------
# 1. 从预热轨迹中采样 (dump.xyz -> sampled_structures.xyz)
# ----------------------------------------
preheat_dump = self.preheat_dir / "dump.xyz"
if not preheat_dump.exists():
raise FileNotFoundError(f"Preheat dump not found: {preheat_dump}")
# 调用 sample_structures.py
# 假设参数: input_file method number
kit_root = self.driver.config_param['env']['gpumdkit_root']
script = f"{kit_root}/Scripts/sample_structures/sample_structures.py"
# 复制 dump 到当前目录以便处理
local_dump = self.work_dir / "preheat_dump.xyz"
shutil.copy(preheat_dump, local_dump)
self.logger.info(" -> Sampling structures from preheat trajectory...")
# 按照你的描述: sample_structures.py dump.xyz uniform 4
# 这里 "4" 可以放到 param.yaml 里配置,暂时写死或读取默认
self.runner.run(
"python_script", # 这里可以用 local runner 直接跑 python
cwd=self.work_dir,
extra_args=f"{script} preheat_dump.xyz uniform 4"
)
# 产物通常叫 sampled_structures.xyz我们需要把它作为后续 MD 的起始结构
# 但注意GPUMD MD 通常读取 model.xyz 或者 restart。
# 如果你的 run.in 里写的是 load_xyz sampled_structures.xyz那就没问题。
# 如果不是,通常做法是把 sampled_structures.xyz 切分成多个文件夹。
# --- 修正逻辑:根据你的描述 "生成 sample_1-4 文件夹" ---
# 我们遍历 template/00_md/md_run_*.in
tpl_path = Path("template") / self.template_subdir
run_templates = sorted(list(tpl_path.glob("md_run_*.in")))
if not run_templates:
self.logger.warning(f"⚠️ No 'md_run_*.in' found in {tpl_path}, looking for 'run.in'...")
run_templates = list(tpl_path.glob("run.in"))
sub_tasks = []
nep_source = self.preheat_dir / "nep.txt" # 沿用预热阶段的势函数
for idx, tpl in enumerate(run_templates, start=1):
task_name = f"sample_{idx}"
task_dir = self.work_dir / task_name
task_dir.mkdir(exist_ok=True)
sub_tasks.append(task_dir)
# 1. 复制 run.in
shutil.copy(tpl, task_dir / "run.in")
# 2. 复制 nep.txt
shutil.copy(nep_source, task_dir / "nep.txt")
# 3. 复制结构 (假设所有 sample 都从预热的最后一帧或 sampled_structures 开始)
# 这里简化处理:复制 model.xyz (初始结构) 或者 使用 preheat 的最后状态
# 根据你的流程,通常需要把 sampled_structures.xyz 里的某一帧放进去
# 或者 GPUMD 支持直接读取 exyz。
# 这里我们假设 run.in 里配置好了读取方式,我们只负责给文件。
if (self.preheat_dir / "model.xyz").exists():
shutil.copy(self.preheat_dir / "model.xyz", task_dir / "model.xyz")
# ----------------------------------------
# 2. 执行所有 Sample 任务
# ----------------------------------------
self.logger.info(f" -> Submitting {len(sub_tasks)} MD tasks...")
for task_dir in sub_tasks:
self.logger.info(f" -> Running {task_dir.name}...")
self.runner.run("gpumd", cwd=task_dir)
# ----------------------------------------
# 3. 合并结果
# ----------------------------------------
self.logger.info(" -> Merging dump files...")
# cat sample_*/dump.xyz >> dump.xyz
# 使用 python 实现 cat 以跨平台安全
target_dump = self.work_dir / "dump.xyz"
with open(target_dump, 'wb') as outfile:
for task_dir in sub_tasks:
src = task_dir / "dump.xyz"
if src.exists():
with open(src, 'rb') as infile:
shutil.copyfileobj(infile, outfile)
else:
self.logger.warning(f"⚠️ {task_dir.name} generated no dump.xyz")
self.check_done()
def check_done(self):
if (self.work_dir / "dump.xyz").exists():
self.logger.info("✅ MD Sampling finished.")
return True
raise RuntimeError("MD failed: dump.xyz not created.")