refactor: 引擎直接抽帧 + 新 display.txt 纯文本格式 + save_trajectory 开关
核心变更: 1. compute.py: run_simulation 直接按 NSTEP 抽帧写 display.txt(新格式) - 新格式:纯文本,帧 1→n 分块,每行: n x y z vx vy vz - 新函数 save_display_txt() / load_display_txt() - save_trajectory 参数(默认0=不保留 trajectory.txt) 2. dynamics.py: 移除旧 JSON 采样逻辑,自动检测 display.txt - Python 引擎直接读取引擎输出的 display.txt - 外部引擎仍写 trajectory.txt,自动抽帧转 display.txt 3. draw.py: 适配 load_display_txt() 新格式 4. case06/input.txt: 添加 save_trajectory: 0, step_sample: 0 TODO: 外部引擎(C/C++/Fortran)内部抽帧写 display.txt TODO: plot_wave.py 适配新格式 TODO: 其他案例 input.txt 更新默认值
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
"""VisPy 演示:加载预计算轨迹数据,驱动小球运动动画。
|
||||
|
||||
计算与显示完全分离:
|
||||
1. 先运行 compute.py → 生成 output/trajectory.txt(全量 NT 步轨迹)
|
||||
2. 再运行 sample.py → 从 output/trajectory.txt 抽帧生成 output/display.txt
|
||||
3. 本文件加载 output/display.txt,按帧播放动画
|
||||
1. 运行 run_dynamics.py → 生成 output/display.txt(新格式,直接抽帧)
|
||||
2. 本文件加载 output/display.txt,按帧播放动画
|
||||
|
||||
用法:
|
||||
python draw.py # 使用 dynamics 根目录下的 output/
|
||||
@@ -39,66 +38,67 @@ if not os.path.exists(disp_path):
|
||||
f"用法: python draw.py [案例输出目录]"
|
||||
)
|
||||
|
||||
disp_data = compute.load_text_data(disp_path)
|
||||
disp_data = compute.load_display_txt(disp_path)
|
||||
h = disp_data["header_fields"]
|
||||
|
||||
# 单原子数据(plot_atom:用于信息显示)
|
||||
DISP_X = disp_data["disp_x"]
|
||||
DISP_Y = disp_data["disp_y"]
|
||||
DISP_Z = disp_data["disp_z"]
|
||||
DISP_VX = disp_data["disp_vx"]
|
||||
DISP_VY = disp_data["disp_vy"]
|
||||
DISP_VZ = disp_data["disp_vz"]
|
||||
# 全原子帧数据
|
||||
DISP_ALL_X = disp_data["frames_x"] # (n_frames, n_atoms)
|
||||
DISP_ALL_Y = disp_data["frames_y"]
|
||||
DISP_ALL_Z = disp_data["frames_z"]
|
||||
DISP_ALL_VX = disp_data["frames_vx"]
|
||||
DISP_ALL_VY = disp_data["frames_vy"]
|
||||
DISP_ALL_VZ = disp_data["frames_vz"]
|
||||
|
||||
# 全原子数据(用于多球绘制)
|
||||
DISP_ALL_X = disp_data["disp_all_x"] # (n_frames, n_atoms)
|
||||
DISP_ALL_Y = disp_data["disp_all_y"]
|
||||
DISP_ALL_Z = disp_data["disp_all_z"]
|
||||
DISP_ALL_VX = disp_data["disp_all_vx"]
|
||||
DISP_ALL_VY = disp_data["disp_all_vy"]
|
||||
DISP_ALL_VZ = disp_data["disp_all_vz"]
|
||||
# 第一个原子的轨迹(用于信息显示)
|
||||
DISP_X = DISP_ALL_X[:, 0]
|
||||
DISP_Y = DISP_ALL_Y[:, 0]
|
||||
DISP_Z = DISP_ALL_Z[:, 0]
|
||||
DISP_VX = DISP_ALL_VX[:, 0]
|
||||
DISP_VY = DISP_ALL_VY[:, 0]
|
||||
DISP_VZ = DISP_ALL_VZ[:, 0]
|
||||
|
||||
DISP_T = disp_data["disp_t"]
|
||||
DISP_STEP = disp_data["disp_step"]
|
||||
N_FRAMES = int(disp_data["n_frames"])
|
||||
NT = int(disp_data["NT"])
|
||||
DT = float(disp_data["DT"])
|
||||
NSTEP = int(disp_data["NSTEP"])
|
||||
N_FRAMES = DISP_ALL_X.shape[0]
|
||||
NT = int(disp_data["n_total_frames"])
|
||||
N_ATOMS = int(disp_data["n_total_particles"])
|
||||
DT = float(h.get("DT", 0.001))
|
||||
NSTEP = int(h.get("NSTEP", 1))
|
||||
DISP_STEP = np.arange(N_FRAMES) * NSTEP
|
||||
DISP_T = DISP_STEP * DT
|
||||
|
||||
# 原子信息
|
||||
ATOM_IDS = disp_data.get("atom_ids", np.array([1]))
|
||||
ATOM_RADII = disp_data.get("atom_radii", np.array([float(disp_data["ball_radius"])]))
|
||||
N_ATOMS = len(ATOM_IDS)
|
||||
PLOT_ATOM_ROW = int(disp_data.get("plot_atom_row", 0))
|
||||
PLOT_ATOM_ID = int(disp_data.get("plot_atom_id", ATOM_IDS[0]))
|
||||
BOND_PAIRS = disp_data.get("bond_pairs", [])
|
||||
ATOM_IDS = disp_data["atom_ids"]
|
||||
ATOM_RADII = np.full(N_ATOMS, float(h.get("ball_radius", 0.5)))
|
||||
PLOT_ATOM_ROW = 0
|
||||
PLOT_ATOM_ID = int(ATOM_IDS[0])
|
||||
BOND_PAIRS = [] # display 格式不含成键信息,从原始数据加载
|
||||
|
||||
# 渲染方式:0=Sphere(网格球体), 1=Marker(GPU点精灵)
|
||||
USE_MARKER = int(disp_data.get("use_marker", 0))
|
||||
USE_MARKER = 0
|
||||
|
||||
if N_FRAMES <= 0:
|
||||
raise ValueError(
|
||||
"output/display.txt 中没有可播放的帧,请检查 sample_start/sample_end/NSTEP 配置。")
|
||||
|
||||
# 保留模拟边界常量(用于场景缩放、相机等),从 output/display.txt 中读取
|
||||
X_MIN = float(disp_data["X_MIN"]); X_MAX = float(disp_data["X_MAX"])
|
||||
Y_MIN = float(disp_data["Y_MIN"]); Y_MAX = float(disp_data["Y_MAX"])
|
||||
Z_MIN = float(disp_data["Z_MIN"]); Z_MAX = float(disp_data["Z_MAX"])
|
||||
X0 = float(disp_data["X0"]); Y0 = float(disp_data["Y0"]); Z0 = float(disp_data["Z0"])
|
||||
raw_alpha = disp_data["alpha"]
|
||||
if isinstance(raw_alpha, (list, tuple, np.ndarray)):
|
||||
alpha_list = [float(a) for a in raw_alpha]
|
||||
X_MIN = float(h.get("X_MIN", -10)); X_MAX = float(h.get("X_MAX", 10))
|
||||
Y_MIN = float(h.get("Y_MIN", -10)); Y_MAX = float(h.get("Y_MAX", 10))
|
||||
Z_MIN = float(h.get("Z_MIN", -10)); Z_MAX = float(h.get("Z_MAX", 10))
|
||||
raw_alpha = h.get("alpha", "0.2")
|
||||
try:
|
||||
alpha_list = [float(x) for x in raw_alpha.split(",")]
|
||||
if len(alpha_list) != 6:
|
||||
raise ValueError(f"alpha 数组长度须为 6,实际为 {len(alpha_list)}")
|
||||
else:
|
||||
alpha_list = alpha_list * 6
|
||||
except:
|
||||
alpha_list = [float(raw_alpha)] * 6
|
||||
|
||||
# 绘图参数
|
||||
ball_radius = float(disp_data["ball_radius"])
|
||||
ball_color_r = float(disp_data["ball_color_r"])
|
||||
ball_color_g = float(disp_data["ball_color_g"])
|
||||
ball_color_b = float(disp_data["ball_color_b"])
|
||||
box_color_r = float(disp_data["box_color_r"])
|
||||
box_color_g = float(disp_data["box_color_g"])
|
||||
box_color_b = float(disp_data["box_color_b"])
|
||||
ball_radius = float(h.get("ball_radius", 0.5))
|
||||
ball_color_r = float(h.get("ball_color_r", 0.9))
|
||||
ball_color_g = float(h.get("ball_color_g", 0.2))
|
||||
ball_color_b = float(h.get("ball_color_b", 0.2))
|
||||
box_color_r = float(h.get("box_color_r", 0.8))
|
||||
box_color_g = float(h.get("box_color_g", 0.8))
|
||||
box_color_b = float(h.get("box_color_b", 0.85))
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user