feat: 增加驱动力系统、Marker渲染模式、动画防闪退、案例文档
- 新增 driving_force 驱动力系统(driver.txt 定义,支持周期控制) - 新增 use_marker 渲染开关(GPU实例化点精灵,提升大量原子性能) - 修复动画闪退:独立控制台、错误日志、启动存活检测 - 重绘 draw.py 架构:双渲染模式 + 预分配键线缓冲区 - 修复 raw trajectory 采样时间变量遮蔽 bug - 重构 case05: 60原子一维链 + 驱动力 + 完整案例文档 - 修复所有案例 Readme.md 编码(GBK → UTF-8) - 所有 input.txt 新增 driver_file / driving_force / use_marker 参数
This commit is contained in:
+43
-20
@@ -12,6 +12,7 @@ dynamics.py
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import time
|
||||
import argparse
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
@@ -316,6 +317,8 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
"elastic_force": int(data.get("elastic_force", 1)),
|
||||
"damping_force": int(data.get("damping_force", 0)),
|
||||
"gravity_strength": float(data.get("gravity_strength", 1.0)),
|
||||
"driving_force": int(config.get("driving_force", 0)),
|
||||
"use_marker": int(config.get("use_marker", 0)),
|
||||
}
|
||||
save_display_txt(disp_data, str(runtime_base))
|
||||
print(f"[run] 抽帧完成: {sample_end - sample_start} 步 -> {n_frames} 帧")
|
||||
@@ -331,7 +334,7 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei', 'DejaVu Sans']
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
time = np.arange(NT) * DT
|
||||
time_arr = np.arange(NT) * DT
|
||||
n_atoms = all_x.shape[1]
|
||||
atom_ids_list = data.get("atom_ids", np.arange(n_atoms) + 1)
|
||||
|
||||
@@ -353,7 +356,7 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
for ax, data_arr, title in plot_configs:
|
||||
for i in range(n_atoms):
|
||||
atom_id = int(atom_ids_list[i])
|
||||
ax.plot(time, data_arr[:, i], color=colors[i], linewidth=1.5, label=f"原子 {atom_id}")
|
||||
ax.plot(time_arr, data_arr[:, i], color=colors[i], linewidth=1.5, label=f"原子 {atom_id}")
|
||||
ax.set_title(title)
|
||||
ax.set_xlabel("时间 (s)")
|
||||
ax.grid(True, alpha=0.3)
|
||||
@@ -423,7 +426,7 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
ax_e = axes[2, 0]
|
||||
for i in range(n_atoms):
|
||||
aid = int(atom_ids_list[i])
|
||||
ax_e.plot(time, e_total[:, i], color=colors[i], linewidth=1.5, label=f"原子 {aid}")
|
||||
ax_e.plot(time_arr, e_total[:, i], color=colors[i], linewidth=1.5, label=f"原子 {aid}")
|
||||
ax_e.set_title("各原子总能量")
|
||||
ax_e.set_xlabel("时间 (s)")
|
||||
ax_e.set_ylabel("能量")
|
||||
@@ -432,13 +435,13 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
|
||||
# ── 第 3 行右:系统总能量 ──
|
||||
ax_sys = axes[2, 1]
|
||||
ax_sys.plot(time, ek_sys, 'b-', linewidth=1.5, label="系统动能")
|
||||
ax_sys.plot(time, ug_sys, 'g-', linewidth=1.5, label="均匀重力势能")
|
||||
ax_sys.plot(time_arr, ek_sys, 'b-', linewidth=1.5, label="系统动能")
|
||||
ax_sys.plot(time_arr, ug_sys, 'g-', linewidth=1.5, label="均匀重力势能")
|
||||
if elastic_force_enabled and bond_pairs is not None and len(bond_pairs) > 0:
|
||||
ax_sys.plot(time, us_sys, color='orange', linewidth=1.5, label="系统弹性势能")
|
||||
ax_sys.plot(time_arr, us_sys, color='orange', linewidth=1.5, label="系统弹性势能")
|
||||
if gravity_interaction_enabled:
|
||||
ax_sys.plot(time, ug_grav_sys, color='purple', linewidth=1.5, label="万有引力势能")
|
||||
ax_sys.plot(time, e_sys, 'r--', linewidth=1.5, label="系统总能量")
|
||||
ax_sys.plot(time_arr, ug_grav_sys, color='purple', linewidth=1.5, label="万有引力势能")
|
||||
ax_sys.plot(time_arr, e_sys, 'r--', linewidth=1.5, label="系统总能量")
|
||||
ax_sys.set_title("系统总能量")
|
||||
ax_sys.set_xlabel("时间 (s)")
|
||||
ax_sys.set_ylabel("能量")
|
||||
@@ -461,19 +464,39 @@ def run_case(config_path, runtime_base, input_dir="input", output_dir="output",
|
||||
# 5. 自动播放动画(可选)
|
||||
if config.get("step_animation", 0):
|
||||
draw_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "draw.py")
|
||||
if os.path.exists(draw_script):
|
||||
try:
|
||||
print("[run] 正在启动 VisPy 3D 动画窗口…")
|
||||
subprocess.Popen(
|
||||
[sys.executable, draw_script],
|
||||
cwd=runtime_base,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[run] 启动动画失败: {e}")
|
||||
else:
|
||||
if not os.path.exists(draw_script):
|
||||
print(f"[run] 未找到动画脚本: {draw_script}")
|
||||
else:
|
||||
# 检查 display.txt 是否存在(step_sample=0 时可能没有)
|
||||
disp_path = os.path.join(output_dir_abs, "display.txt")
|
||||
if not os.path.exists(disp_path):
|
||||
print(f"[run] 错误: 找不到 {disp_path}")
|
||||
print(f"[run] 启动动画需要先运行抽帧(step_sample: 1),或手动保留 output/display.txt")
|
||||
else:
|
||||
try:
|
||||
print("[run] 正在启动 VisPy 3D 动画窗口…")
|
||||
ansi_log = os.path.join(output_dir_abs, "animation.log")
|
||||
if sys.platform == "win32":
|
||||
# Windows 上给子进程独立控制台,避免父进程退出时连带关闭
|
||||
creation_flags = subprocess.CREATE_NEW_CONSOLE
|
||||
else:
|
||||
creation_flags = 0
|
||||
proc = subprocess.Popen(
|
||||
[sys.executable, draw_script, output_dir_abs],
|
||||
cwd=runtime_base,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=open(ansi_log, "w", encoding="utf-8"),
|
||||
creationflags=creation_flags,
|
||||
)
|
||||
# 等待半秒检查子进程是否成功启动(未立即崩溃)
|
||||
time.sleep(0.5)
|
||||
if proc.poll() is not None:
|
||||
print(f"[run] ⚠ 动画进程已退出,返回码={proc.returncode}")
|
||||
print(f"[run] 请查看错误日志: {ansi_log}")
|
||||
else:
|
||||
print(f"[run] VisPy 动画窗口已启动(PID={proc.pid})")
|
||||
except Exception as e:
|
||||
print(f"[run] 启动动画失败: {e}")
|
||||
else:
|
||||
print("[run] 运行 python draw.py 查看动画。")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user