diff --git a/src/workflow.py b/src/workflow.py index 0d7146f..56617fa 100644 --- a/src/workflow.py +++ b/src/workflow.py @@ -48,59 +48,77 @@ class Workflow: # Step: 00.md # ========================== if step_name == "00.md": - # 1. 【修正点】先定义 step_dir,确保后续都能访问到 step_dir = os.path.join(iter_path, "00.md") - # --- 第一轮初始化:POSCAR -> model.xyz --- + # --- A. 第一轮初始化:POSCAR -> model.xyz --- if iter_id == 0: - # 2. 现在使用 step_dir 是安全的 os.makedirs(step_dir, exist_ok=True) - - # 获取文件名和路径 poscar_name = self.param['files']['poscar'] poscar_src = os.path.join(self.data_dir, poscar_name) - # 复制原始 POSCAR - if not os.path.exists(poscar_src): - self.logger.error(f"Initial POSCAR not found: {poscar_src}") - return - shutil.copy(poscar_src, os.path.join(step_dir, poscar_name)) + if os.path.exists(poscar_src): + shutil.copy(poscar_src, os.path.join(step_dir, poscar_name)) - # 获取标签 - atom_labels = self.param['files'].get('label', '') - if not atom_labels: - self.logger.error("Missing 'label' in param.yaml files section.") - return + atom_labels = self.param['files'].get('label', '') + kit_path = self.machine.config['paths'].get('gpumdkit', 'gpumdkit.sh') - # 执行转换 - kit_path = self.machine.config['paths'].get('gpumdkit', 'gpumdkit.sh') - # 确保使用绝对路径,防止 subprocess 找不到 - if not os.path.isabs(kit_path): - # 假设相对于项目根目录,或者在 PATH 中 - pass - - cmd = f"{kit_path} -addlabel {poscar_name} {atom_labels}" - - self.logger.info(f"Initializing model.xyz with command: {cmd}") - try: + cmd = f"{kit_path} -addlabel {poscar_name} {atom_labels}" + self.logger.info(f"Initializing model.xyz: {cmd}") subprocess.check_call(cmd, shell=True, cwd=step_dir) - except subprocess.CalledProcessError as e: - self.logger.error(f"Failed to convert POSCAR: {e}") - return - - if not os.path.exists(os.path.join(step_dir, "model.xyz")): - self.logger.error("model.xyz was not generated.") - return else: - self.logger.info("Successfully generated model.xyz") + self.logger.error(f"POSCAR missing: {poscar_src}") + continue # 跳过这一步 - # --- 遍历子任务 (preheat, production...) --- - for sub in step_conf.get('sub_tasks', []): - template_sub_name = sub['template_sub'] + # 检查 model.xyz 是否存在 (无论是刚生成的,还是上一轮传过来的) + # 注意:如果是 Iter > 0,这里需要逻辑从上一轮获取,目前先保证 Iter 0 + current_model_xyz = os.path.join(step_dir, "model.xyz") + if not os.path.exists(current_model_xyz): + self.logger.error(f"Critical: model.xyz not found in {step_dir}") + continue + + # --- B. 执行子任务 (Preheat / Production) --- + sub_tasks = step_conf.get('sub_tasks', []) + if not sub_tasks: + self.logger.warning("No sub_tasks defined for 00.md in param.yaml!") + + for sub in sub_tasks: + template_sub_name = sub.get('template_sub') + if not template_sub_name: continue + + # 1. 定义子目录 (e.g., iter_00/00.md/preheat) sub_work_dir = os.path.join(step_dir, template_sub_name) - template_path = os.path.join(self.template_dir, "00.md", template_sub_name) + os.makedirs(sub_work_dir, exist_ok=True) - # ========================== + self.logger.info(f"--> Setup Sub-task: {template_sub_name}") + + # 2. 【关键】将 model.xyz 分发到子目录 + shutil.copy(current_model_xyz, os.path.join(sub_work_dir, "model.xyz")) + + # 3. 准备 Template (run.in) + # 路径: template/00.md/preheat/ + template_path = os.path.join(self.template_dir, "00.md", template_sub_name) + if not os.path.exists(template_path): + self.logger.error(f"Template not found: {template_path}") + continue + + # 4. 实例化 MD 任务 + # 这里的 name 仅仅是日志用的标识 + md_task = MDStep(f"MD-{template_sub_name}", sub_work_dir, self.machine, self.config) + + # 5. 运行 (传入势函数路径 和 模板路径) + # run() 方法内部会处理 nep.txt 的复制和 run.in 的复制 + success = md_task.run(self.current_nep_pot, template_path) + + if success: + # 记录最新的 dump.xyz 位置,供下一步 Select 使用 + self.last_dump_path = os.path.join(sub_work_dir, "dump.xyz") + # 同时也把最新的 model.xyz (如果MD改变了结构) 或 dump 更新为下一次的起点? + # 目前逻辑:Select 步会用 self.last_dump_path + else: + self.logger.error(f"MD Sub-task {template_sub_name} Failed.") + # 根据策略决定是否中断,这里暂时中断 + break + # ========================== # Step: 01.select # ========================== elif step_name == "01.select":