feat: C/C++ 引擎支持 save_trajectory=0 时直接写 display.txt
所有引擎(Python/C/C++)在 save_trajectory=0 时行为一致: - 计算时按 NSTEP 抽帧,只存 sampled 缓冲区 - 直接写入 display.txt(新文本格式) - 不生成 trajectory.txt Python 引擎:run_simulation 已支持 ✅ C 引擎:采样缓冲区 + write_display_txt ✅ C++ 引擎:采样缓冲区 + write_display_txt ✅ Fortran 引擎:待完成 compute.py run_engine:save_trajectory=0 时跳过 trajectory.txt 加载 dynamics.py:引擎直接输出 display.txt 时跳过抽帧步骤
This commit is contained in:
+84
-17
@@ -43,6 +43,7 @@ struct SimParams {
|
||||
int damping_force = 0;
|
||||
double gravity_strength = 1.0;
|
||||
int driving_force = 0;
|
||||
int save_trajectory = 1;
|
||||
};
|
||||
|
||||
// ========================================================================
|
||||
@@ -131,6 +132,11 @@ static std::string json_read_string(const std::string &json, const std::string &
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 检查 JSON 中是否存在某个 key */
|
||||
static bool json_has_key(const std::string &json, const std::string &key) {
|
||||
return json.find("\"" + key + "\"") != std::string::npos;
|
||||
}
|
||||
|
||||
/* 读取 JSON 数组 (如 "G": [0, 0, -9.8]) 到 double[3] */
|
||||
static void json_read_double3(const std::string &json, const std::string &key, double out[3]) {
|
||||
auto pos = json.find("\"" + key + "\"");
|
||||
@@ -165,6 +171,9 @@ static SimParams read_params(const std::string &path) {
|
||||
p.damping_force = json_read_int(buf, "damping_force");
|
||||
p.gravity_strength = json_read_double(buf, "gravity_strength");
|
||||
p.driving_force = json_read_int(buf, "driving_force");
|
||||
// save_trajectory 默认 1(全量),仅在 JSON 中存在该 key 时覆盖
|
||||
if (json_has_key(buf, "save_trajectory"))
|
||||
p.save_trajectory = json_read_int(buf, "save_trajectory");
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -681,6 +690,52 @@ static void apply_driving_force(
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// display.txt 输出(save_trajectory=0 时使用)
|
||||
// ========================================================================
|
||||
|
||||
static void write_display_txt(
|
||||
const std::string &path,
|
||||
const std::vector<double> &x, const std::vector<double> &y,
|
||||
const std::vector<double> &z, const std::vector<double> &vx,
|
||||
const std::vector<double> &vy, const std::vector<double> &vz,
|
||||
int n_steps, int n_atoms,
|
||||
const SimParams ¶ms, const AtomData &atoms)
|
||||
{
|
||||
std::ofstream f(path);
|
||||
if (!f) die("无法写入 " + path);
|
||||
std::cout << "[Cpp-engine] 正在写入显示数据…" << std::endl;
|
||||
|
||||
double T_total = params.NT * params.DT;
|
||||
|
||||
f << "number of frames: " << n_steps << "\n";
|
||||
f << "number of particles: " << n_atoms << "\n";
|
||||
f << "DT: " << params.DT << "\n";
|
||||
f << "NSTEP: " << params.NSTEP << "\n";
|
||||
f << "method: " << params.method << "\n";
|
||||
f << "warmup_steps: " << params.warmup_steps << "\n";
|
||||
f << "dynamic_steps: " << (params.NT - params.warmup_steps) << "\n";
|
||||
f << "T_total: " << T_total << "\n";
|
||||
f << "box_a: " << params.box_a << "\n";
|
||||
f << "driving_force: " << params.driving_force << "\n\n";
|
||||
|
||||
f << std::fixed << std::setprecision(6);
|
||||
for (int t = 0; t < n_steps; t++) {
|
||||
f << "frame: " << (t + 1) << "\n";
|
||||
f << "n x y z vx vy vz\n";
|
||||
for (int i = 0; i < n_atoms; i++) {
|
||||
int base = t * n_atoms + i;
|
||||
f << std::setw(3) << atoms.ids[i]
|
||||
<< std::setw(12) << x[base]
|
||||
<< std::setw(12) << y[base]
|
||||
<< std::setw(12) << z[base]
|
||||
<< std::setw(12) << vx[base]
|
||||
<< std::setw(12) << vy[base]
|
||||
<< std::setw(12) << vz[base] << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// JSON 输出
|
||||
// ========================================================================
|
||||
@@ -817,12 +872,14 @@ int main(int argc, char **argv) {
|
||||
|
||||
// 分配轨迹缓冲区
|
||||
int record_steps = params.NT - params.warmup_steps;
|
||||
std::vector<double> traj_x(record_steps * n);
|
||||
std::vector<double> traj_y(record_steps * n);
|
||||
std::vector<double> traj_z(record_steps * n);
|
||||
std::vector<double> traj_vx(record_steps * n);
|
||||
std::vector<double> traj_vy(record_steps * n);
|
||||
std::vector<double> traj_vz(record_steps * n);
|
||||
int nstep_sampling = (params.save_trajectory == 0) ? params.NSTEP : 1;
|
||||
int buf_steps = (params.save_trajectory == 0) ? (record_steps / nstep_sampling) : record_steps;
|
||||
std::vector<double> traj_x(buf_steps * n);
|
||||
std::vector<double> traj_y(buf_steps * n);
|
||||
std::vector<double> traj_z(buf_steps * n);
|
||||
std::vector<double> traj_vx(buf_steps * n);
|
||||
std::vector<double> traj_vy(buf_steps * n);
|
||||
std::vector<double> traj_vz(buf_steps * n);
|
||||
|
||||
// 预热
|
||||
// 初始时刻 t=0 驱动力(与 Python run_simulation 一致)
|
||||
@@ -846,6 +903,7 @@ int main(int argc, char **argv) {
|
||||
// 记录
|
||||
int _prog_int = record_steps / 100;
|
||||
if (_prog_int < 1) _prog_int = 1;
|
||||
int si = 0; // 采样帧索引
|
||||
for (int s = 0; s < record_steps; s++) {
|
||||
if (s % _prog_int == 0 && s > 0) {
|
||||
std::cout << "[Cpp-engine] progress: " << s << "/" << record_steps << std::endl;
|
||||
@@ -853,14 +911,17 @@ int main(int argc, char **argv) {
|
||||
double t = (s + params.warmup_steps) * params.DT;
|
||||
if (params.driving_force)
|
||||
apply_driving_force(n, x.data(), y.data(), z.data(), vx.data(), vy.data(), vz.data(), t, s, params.DT, drivers);
|
||||
// 保存当前帧
|
||||
for (int i = 0; i < n; i++) {
|
||||
traj_x[s * n + i] = x[i];
|
||||
traj_y[s * n + i] = y[i];
|
||||
traj_z[s * n + i] = z[i];
|
||||
traj_vx[s * n + i] = vx[i];
|
||||
traj_vy[s * n + i] = vy[i];
|
||||
traj_vz[s * n + i] = vz[i];
|
||||
// 保存当前帧(采样模式仅每 NSTEP 步保存一次)
|
||||
if (s % nstep_sampling == 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
traj_x[si * n + i] = x[i];
|
||||
traj_y[si * n + i] = y[i];
|
||||
traj_z[si * n + i] = z[i];
|
||||
traj_vx[si * n + i] = vx[i];
|
||||
traj_vy[si * n + i] = vy[i];
|
||||
traj_vz[si * n + i] = vz[i];
|
||||
}
|
||||
si++;
|
||||
}
|
||||
|
||||
apply_step(params.method, n, x.data(), y.data(), z.data(),
|
||||
@@ -874,9 +935,15 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
// 输出轨迹
|
||||
std::string out_path = output_dir + "/trajectory.txt";
|
||||
write_trajectory_json(out_path, traj_x, traj_y, traj_z, traj_vx, traj_vy, traj_vz,
|
||||
record_steps, n, params, atoms, bonds);
|
||||
if (params.save_trajectory == 0) {
|
||||
std::string out_path = output_dir + "/display.txt";
|
||||
write_display_txt(out_path, traj_x, traj_y, traj_z, traj_vx, traj_vy, traj_vz,
|
||||
si, n, params, atoms);
|
||||
} else {
|
||||
std::string out_path = output_dir + "/trajectory.txt";
|
||||
write_trajectory_json(out_path, traj_x, traj_y, traj_z, traj_vx, traj_vy, traj_vz,
|
||||
record_steps, n, params, atoms, bonds);
|
||||
}
|
||||
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
double elapsed = std::chrono::duration<double>(t1 - t0).count();
|
||||
|
||||
Reference in New Issue
Block a user