modified: CMakeLists.txt

modified:   INSTALL.md
	modified:   README.md
	modified:   build_release_zip.py
	modified:   compute.py
	new file:   doc/index.html
	modified:   dynamics.py
	modified:   engines/c/main.c
	modified:   engines/cpp/main.cpp
	modified:   engines/fortran/main.f90
	modified:   examples/case01/input/coord.txt
	renamed:    examples/case01/input/parameters.yaml -> examples/case01/input/input.txt
	modified:   examples/case01/run_dynamics.py
	new file:   examples/case02/input/bond.txt
	new file:   examples/case02/input/connection.txt
	new file:   examples/case02/input/coord.txt
	new file:   examples/case02/input/input.txt
	new file:   examples/case02/run_dynamics.py
This commit is contained in:
2026-05-20 16:03:59 +08:00
parent 45513fe334
commit 5de80d4f7e
18 changed files with 3058 additions and 233 deletions
+322 -84
View File
@@ -2,13 +2,15 @@
* engines/c/main.c
* -----------------
* C 语言动力学模拟引擎。
* 与 Python 版 (compute.py) 算法保持一致。
*
* 输入: param.json 数值参数(Python 从 YAML 转换得来)
* <input_dir>/coord.txt
* <input_dir>/connection.txt
* <input_dir>/bond.txt
* 输出: <output_dir>/trajectory.txt (JSON 格式,与 Python 版兼容)
*
* 编译: make
* 编译: cmake --build build --target dynamics_c
* 用法: ./build/dynamics_c <input_dir> <output_dir> <param_json_path>
*/
@@ -27,8 +29,14 @@ typedef struct {
double DT; /* 时间步长 */
int NSTEP; /* 抽帧间隔 */
int warmup_steps; /* 预热步数 */
char method[32]; /* 算法名称 */
double G[3]; /* 重力分量 */
double B[3]; /* 阻尼分量 */
int gravity_field; /* 均匀重力场开关 */
int gravity_interaction; /* 原子间万有引力开关 */
int elastic_force; /* 弹簧键力开关 */
int damping_force; /* 阻尼开关 */
double gravity_strength; /* 万有引力强度 */
} SimParams;
/* ========================================================================
@@ -79,7 +87,7 @@ static void *xmalloc(size_t sz) {
return p;
}
/* 从 JSON 中读取 double 值。简单实现:搜索 key 并解析 */
/* 从 JSON 中读取 double 值 */
static double json_read_double(const char *json, const char *key) {
char search[256];
snprintf(search, sizeof(search), "\"%s\"", key);
@@ -96,6 +104,23 @@ static int json_read_int(const char *json, const char *key) {
return (int)json_read_double(json, key);
}
/* 从 JSON 中读取字符串值(写入 dst,最多 dst_sz 字节) */
static void json_read_string(const char *json, const char *key, char *dst, int dst_sz) {
char search[256];
snprintf(search, sizeof(search), "\"%s\"", key);
const char *p = strstr(json, search);
if (!p) { dst[0] = '\0'; return; }
p = strchr(p, ':');
if (!p) { dst[0] = '\0'; return; }
p++;
while (*p == ' ' || *p == '\t' || *p == '\n') p++;
if (*p != '"') { dst[0] = '\0'; return; }
p++;
int i = 0;
while (*p && *p != '"' && i < dst_sz - 1) { dst[i++] = *p++; }
dst[i] = '\0';
}
/* 读取 JSON 数组 (如 "G": [0, 0, -9.8]) 到 double[3] */
static void json_read_double3(const char *json, const char *key, double out[3]) {
char search[256];
@@ -112,6 +137,12 @@ static void json_read_double3(const char *json, const char *key, double out[3])
}
/* 读取 param.json */
static int g_gravity_field = 1;
static int g_gravity_interaction = 0;
static int g_elastic_force = 1;
static int g_damping_force = 0;
static double g_gravity_strength = 1.0;
static SimParams read_params(const char *path) {
FILE *f = fopen(path, "rb");
if (!f) die("无法打开 param.json");
@@ -129,8 +160,20 @@ static SimParams read_params(const char *path) {
p.DT = json_read_double(buf, "DT");
p.NSTEP = json_read_int(buf, "NSTEP");
p.warmup_steps = json_read_int(buf, "warmup_steps");
strcpy(p.method, "leapfrog"); /* 默认 */
json_read_string(buf, "method", p.method, sizeof(p.method));
json_read_double3(buf, "G", p.G);
json_read_double3(buf, "B", p.B);
p.gravity_field = json_read_int(buf, "gravity_field");
p.gravity_interaction = json_read_int(buf, "gravity_interaction");
p.elastic_force = json_read_int(buf, "elastic_force");
p.damping_force = json_read_int(buf, "damping_force");
p.gravity_strength = json_read_double(buf, "gravity_strength");
g_gravity_field = p.gravity_field;
g_gravity_interaction = p.gravity_interaction;
g_elastic_force = p.elastic_force;
g_damping_force = p.damping_force;
g_gravity_strength = p.gravity_strength;
free(buf);
return p;
@@ -147,7 +190,6 @@ static AtomData read_coord(const char *input_dir) {
char line[1024];
if (!fgets(line, sizeof(line), f)) die("coord.txt 为空");
/* 先读入所有行到内存 */
int capacity = 16;
AtomData a;
a.n_atoms = 0;
@@ -173,10 +215,9 @@ static AtomData read_coord(const char *input_dir) {
int n_parsed = sscanf(line, "%d %lf %lf %lf %lf %lf %lf %lf %lf %d %d %d",
&id, &mass, &rad, &px, &py, &pz, &vx, &vy, &vz, &fx, &fy, &fz);
if (n_parsed == 9) {
/* 无固定约束列 */
fx = fy = fz = 0;
} else if (n_parsed != 12) {
continue; /* 跳过空行/格式不符的行 */
continue;
}
int i = a.n_atoms;
a.atom_ids[i] = id;
@@ -204,13 +245,11 @@ static BondData read_bonds(const char *input_dir, const AtomData *atoms) {
snprintf(path, sizeof(path), "%s/connection.txt", input_dir);
FILE *f = fopen(path, "r");
if (!f) return b; /* 无成键 */
if (!f) return b;
/* 跳过第一行表头 */
char line[256];
if (!fgets(line, sizeof(line), f)) { fclose(f); return b; }
/* 先数行数 */
int n_lines = 0, tmp_a, tmp_b;
char bond_name[256];
while (fscanf(f, "%d %d %s", &tmp_a, &tmp_b, bond_name) == 3) n_lines++;
@@ -223,24 +262,21 @@ static BondData read_bonds(const char *input_dir, const AtomData *atoms) {
b.stiffness = (double*)xmalloc(n_lines * sizeof(double));
b.rest_lengths = (double*)xmalloc(n_lines * sizeof(double));
/* 读取 bond.txt 获取劲度系数和平衡长度 */
char bond_path[512];
snprintf(bond_path, sizeof(bond_path), "%s/bond.txt", input_dir);
FILE *fb = fopen(bond_path, "r");
/* bond.txt 格式: name stiffness rest_length */
for (int i = 0; i < n_lines; i++) {
fscanf(f, "%d %d %s", &tmp_a, &tmp_b, bond_name);
/* 转换原子编号为 0-based 索引 */
b.pairs[i*2+0] = tmp_a - 1;
b.pairs[i*2+1] = tmp_b - 1;
/* 查找 bond.txt 中对应的参数 */
b.stiffness[i] = 1.0;
b.rest_lengths[i] = 2.0; /* 默认值 */
b.rest_lengths[i] = 2.0;
if (fb) {
char name[256];
char name[256], header[256];
double k, r0;
rewind(fb);
fgets(header, sizeof(header), fb); // 跳过表头行
while (fscanf(fb, "%s %lf %lf", name, &k, &r0) == 3) {
if (strcmp(name, bond_name) == 0) {
b.stiffness[i] = k;
@@ -256,9 +292,10 @@ static BondData read_bonds(const char *input_dir, const AtomData *atoms) {
}
/* ========================================================================
* 物理核心
* 物理核心(与 Python compute.py 对应)
* ======================================================================== */
/* 加速度计算(各力独立开关控制) */
static void compute_acceleration(
int n, const double *x, const double *y, const double *z,
const double *vx, const double *vy, const double *vz,
@@ -266,50 +303,124 @@ static void compute_acceleration(
const BondData *bonds,
double *ax, double *ay, double *az)
{
/* 先清零 */
for (int i = 0; i < n; i++) {
double inv_m = 1.0 / m[i];
ax[i] = (m[i] * G[0] - B[0] * vx[i]) * inv_m;
ay[i] = (m[i] * G[1] - B[1] * vy[i]) * inv_m;
az[i] = (m[i] * G[2] - B[2] * vz[i]) * inv_m;
ax[i] = 0.0; ay[i] = 0.0; az[i] = 0.0;
}
/* 弹簧力 */
for (int b = 0; b < bonds->n_bonds; b++) {
int i = bonds->pairs[b*2+0];
int j = bonds->pairs[b*2+1];
double dx = x[j] - x[i];
double dy = y[j] - y[i];
double dz = z[j] - z[i];
double dist = sqrt(dx*dx + dy*dy + dz*dz);
if (dist < 1e-12) continue;
double stretch = dist - bonds->rest_lengths[b];
double fmag = bonds->stiffness[b] * stretch;
double ux = dx / dist, uy = dy / dist, uz = dz / dist;
double fx = fmag * ux, fy = fmag * uy, fz = fmag * uz;
ax[i] += fx / m[i]; ay[i] += fy / m[i]; az[i] += fz / m[i];
ax[j] -= fx / m[j]; ay[j] -= fy / m[j]; az[j] -= fz / m[j];
/* 均匀重力场 */
if (g_gravity_field) {
for (int i = 0; i < n; i++) {
ax[i] += G[0];
ay[i] += G[1];
az[i] += G[2];
}
}
/* 阻尼 */
if (g_damping_force) {
for (int i = 0; i < n; i++) {
ax[i] -= B[0] * vx[i] / m[i];
ay[i] -= B[1] * vy[i] / m[i];
az[i] -= B[2] * vz[i] / m[i];
}
}
/* 弹簧键力 */
if (g_elastic_force) {
for (int b = 0; b < bonds->n_bonds; b++) {
int i = bonds->pairs[b*2+0];
int j = bonds->pairs[b*2+1];
double dx = x[j] - x[i];
double dy = y[j] - y[i];
double dz = z[j] - z[i];
double dist = sqrt(dx*dx + dy*dy + dz*dz);
if (dist < 1e-12) continue;
double stretch = dist - bonds->rest_lengths[b];
double fmag = bonds->stiffness[b] * stretch;
double ux = dx / dist, uy = dy / dist, uz = dz / dist;
double fx = fmag * ux, fy = fmag * uy, fz = fmag * uz;
ax[i] += fx / m[i]; ay[i] += fy / m[i]; az[i] += fz / m[i];
ax[j] -= fx / m[j]; ay[j] -= fy / m[j]; az[j] -= fz / m[j];
}
}
/* 万有引力(所有原子对之间) */
if (g_gravity_interaction) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double dx = x[j] - x[i];
double dy = y[j] - y[i];
double dz = z[j] - z[i];
double r2 = dx*dx + dy*dy + dz*dz;
if (r2 <= 1e-12) continue;
double r = sqrt(r2);
double f_mag = g_gravity_strength * m[i] * m[j] / r2;
double fx_g = f_mag * dx / r;
double fy_g = f_mag * dy / r;
double fz_g = f_mag * dz / r;
ax[i] += fx_g / m[i]; ay[i] += fy_g / m[i]; az[i] += fz_g / m[i];
ax[j] -= fx_g / m[j]; ay[j] -= fy_g / m[j]; az[j] -= fz_g / m[j];
}
}
}
}
/* clamp */
static double clamp(double v, double lo, double hi) {
return fmin(fmax(v, lo), hi);
/* 边界条件:clamp 位置 + 速度反转 ——与 Python Limit_in_box 一致 */
static void limit_in_box(double *pos, double *vel, double lo, double hi) {
if (*pos > hi) { *pos = hi; *vel = -*vel; }
if (*pos < lo) { *pos = lo; *vel = -*vel; }
}
/* 蛙跳法一步 */
static void leapfrog_step(
/* ── 显式欧拉法 ──────────── */
static void explicit_euler_step(
int n, double *x, double *y, double *z,
double *vx, double *vy, double *vz,
const double *m, const double G[3], const double B[3],
const BondData *bonds, const int *fixed,
double box_a, double dt)
const BondData *bonds, const int *fixed, double dt)
{
double *ax = (double*)alloca(n * sizeof(double));
double *ay = (double*)alloca(n * sizeof(double));
double *az = (double*)alloca(n * sizeof(double));
compute_acceleration(n, x, y, z, vx, vy, vz, m, G, B, bonds, ax, ay, az);
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
x[i] += vx[i] * dt;
y[i] += vy[i] * dt;
z[i] += vz[i] * dt;
vx[i] += ax[i] * dt;
vy[i] += ay[i] * dt;
vz[i] += az[i] * dt;
}
}
/* ── 隐式欧拉法 ──────────── */
static void implicit_euler_step(
int n, double *x, double *y, double *z,
double *vx, double *vy, double *vz,
const double *m, const double G[3], const double B[3],
const BondData *bonds, const int *fixed, double dt)
{
double *vxn = (double*)alloca(n * sizeof(double));
double *vyn = (double*)alloca(n * sizeof(double));
double *vzn = (double*)alloca(n * sizeof(double));
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) {
vxn[i] = 0; vyn[i] = 0; vzn[i] = 0; continue;
}
double gx = B[0] / m[i], gy = B[1] / m[i], gz = B[2] / m[i];
vxn[i] = (vx[i] + G[0] * dt) / (1.0 + gx * dt);
vyn[i] = (vy[i] + G[1] * dt) / (1.0 + gy * dt);
vzn[i] = (vz[i] + G[2] * dt) / (1.0 + gz * dt);
}
double *ax = (double*)alloca(n * sizeof(double));
double *ay = (double*)alloca(n * sizeof(double));
double *az = (double*)alloca(n * sizeof(double));
compute_acceleration(n, x, y, z, vxn, vyn, vzn, m, G, B, bonds, ax, ay, az);
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
vx[i] += ax[i] * dt;
@@ -318,16 +429,148 @@ static void leapfrog_step(
x[i] += vx[i] * dt;
y[i] += vy[i] * dt;
z[i] += vz[i] * dt;
/* wrap */
x[i] = clamp(x[i], -box_a, box_a);
y[i] = clamp(y[i], -box_a, box_a);
z[i] = clamp(z[i], -box_a, box_a);
}
}
/* ========================================================================
* JSON 输出
* ======================================================================== */
/* ── 中点法 ──────────── */
static void midpoint_step(
int n, double *x, double *y, double *z,
double *vx, double *vy, double *vz,
const double *m, const double G[3], const double B[3],
const BondData *bonds, const int *fixed, double dt)
{
double *ax = (double*)alloca(n * sizeof(double));
double *ay = (double*)alloca(n * sizeof(double));
double *az = (double*)alloca(n * sizeof(double));
compute_acceleration(n, x, y, z, vx, vy, vz, m, G, B, bonds, ax, ay, az);
double *xm = (double*)alloca(n * sizeof(double));
double *ym = (double*)alloca(n * sizeof(double));
double *zm = (double*)alloca(n * sizeof(double));
double *vxm = (double*)alloca(n * sizeof(double));
double *vym = (double*)alloca(n * sizeof(double));
double *vzm = (double*)alloca(n * sizeof(double));
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) {
xm[i]=ym[i]=zm[i]=vxm[i]=vym[i]=vzm[i]=0; continue;
}
xm[i] = x[i] + 0.5 * vx[i] * dt;
ym[i] = y[i] + 0.5 * vy[i] * dt;
zm[i] = z[i] + 0.5 * vz[i] * dt;
vxm[i] = vx[i] + 0.5 * ax[i] * dt;
vym[i] = vy[i] + 0.5 * ay[i] * dt;
vzm[i] = vz[i] + 0.5 * az[i] * dt;
x[i] = x[i] + vxm[i] * dt;
y[i] = y[i] + vym[i] * dt;
z[i] = z[i] + vzm[i] * dt;
}
compute_acceleration(n, xm, ym, zm, vxm, vym, vzm, m, G, B, bonds, ax, ay, az);
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
vx[i] += ax[i] * dt;
vy[i] += ay[i] * dt;
vz[i] += az[i] * dt;
}
}
/* ── 蛙跳法(Velocity-Verlet)── */
static void leapfrog_step(
int n, double *x, double *y, double *z,
double *vx, double *vy, double *vz,
const double *m, const double G[3], const double B[3],
const BondData *bonds, const int *fixed, double dt)
{
double *ax = (double*)alloca(n * sizeof(double));
double *ay = (double*)alloca(n * sizeof(double));
double *az = (double*)alloca(n * sizeof(double));
compute_acceleration(n, x, y, z, vx, vy, vz, m, G, B, bonds, ax, ay, az);
/* 半推速度:v_half = v + 0.5*a*dt */
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
vx[i] += ax[i] * dt * 0.5;
vy[i] += ay[i] * dt * 0.5;
vz[i] += az[i] * dt * 0.5;
}
/* 全推位置(不含边界)*/
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
x[i] += vx[i] * dt; /* vx 此时是 v_half */
y[i] += vy[i] * dt;
z[i] += vz[i] * dt;
}
/* 显式预测器:v_pred = v_half + 0.5*a_old*dt,用第一次加速度外推半步
包含重力+阻尼+弹簧的所有贡献(标准 Velocity-Verlet 预测步)*/
double *pred_vx = (double*)alloca(n * sizeof(double));
double *pred_vy = (double*)alloca(n * sizeof(double));
double *pred_vz = (double*)alloca(n * sizeof(double));
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
pred_vx[i] = vx[i] + 0.5 * ax[i] * dt;
pred_vy[i] = vy[i] + 0.5 * ay[i] * dt;
pred_vz[i] = vz[i] + 0.5 * az[i] * dt;
}
/* 用新位置 + 预测速度重算加速度 */
compute_acceleration(n, x, y, z, pred_vx, pred_vy, pred_vz, m, G, B, bonds, ax, ay, az);
/* 速度后半步:v = v_half + 0.5*a_next*dt
vx 仍为 v_half(未被覆盖)*/
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
vx[i] += ax[i] * dt * 0.5;
vy[i] += ay[i] * dt * 0.5;
vz[i] += az[i] * dt * 0.5;
}
}
/* ── 分发器:调用对应积分方法 + 边界条件 + 自由度约束(与 Python 一致)── */
static void apply_step(
const char *method,
int n, double *x, double *y, double *z,
double *vx, double *vy, double *vz,
const double *m, const double G[3], const double B[3],
const BondData *bonds, const int *fixed,
const double *pos_0,
double box_a, double dt)
{
if (strcmp(method, "explicit_euler") == 0) {
explicit_euler_step(n, x, y, z, vx, vy, vz, m, G, B, bonds, fixed, dt);
} else if (strcmp(method, "implicit_euler") == 0) {
implicit_euler_step(n, x, y, z, vx, vy, vz, m, G, B, bonds, fixed, dt);
} else if (strcmp(method, "midpoint") == 0) {
midpoint_step(n, x, y, z, vx, vy, vz, m, G, B, bonds, fixed, dt);
} else if (strcmp(method, "leapfrog") == 0) {
leapfrog_step(n, x, y, z, vx, vy, vz, m, G, B, bonds, fixed, dt);
} else {
fprintf(stderr, "[C-engine] 未知算法: %s\n", method);
exit(1);
}
/* 边界条件(与 Python Limit_in_box 一致) */
for (int i = 0; i < n; i++) {
if (fixed[i*3+0] && fixed[i*3+1] && fixed[i*3+2]) continue;
limit_in_box(&x[i], &vx[i], -box_a, box_a);
limit_in_box(&y[i], &vy[i], -box_a, box_a);
limit_in_box(&z[i], &vz[i], -box_a, box_a);
}
/* 逐自由度固定约束(与 Python apply_fixed_constraints 一致) */
for (int i = 0; i < n; i++) {
if (fixed[i*3+0]) { x[i] = pos_0[i*3+0]; vx[i] = 0.0; }
if (fixed[i*3+1]) { y[i] = pos_0[i*3+1]; vy[i] = 0.0; }
if (fixed[i*3+2]) { z[i] = pos_0[i*3+2]; vz[i] = 0.0; }
}
}
// ========================================================================
// JSON 输出
// ========================================================================
static void write_trajectory_json(const char *path, const Trajectory *traj,
const SimParams *params, const AtomData *atoms,
@@ -338,7 +581,6 @@ static void write_trajectory_json(const char *path, const Trajectory *traj,
fprintf(f, "{\n");
/* traj_x, traj_y, ... */
const char *names[] = {"traj_x","traj_y","traj_z","traj_vx","traj_vy","traj_vz"};
double *arrs[] = {traj->x, traj->y, traj->z, traj->vx, traj->vy, traj->vz};
@@ -355,7 +597,6 @@ static void write_trajectory_json(const char *path, const Trajectory *traj,
fputc('\n', f);
}
fprintf(f, " ]");
// 每个轨迹数组后加逗号(后面还有标量参数)
fputc(',', f);
fputc('\n', f);
}
@@ -364,45 +605,43 @@ static void write_trajectory_json(const char *path, const Trajectory *traj,
fprintf(f, " \"NT\": %d,\n", params->NT);
fprintf(f, " \"DT\": %.15g,\n", params->DT);
fprintf(f, " \"NSTEP\": %d,\n", params->NSTEP);
fprintf(f, " \"method\": \"leapfrog\",\n");
fprintf(f, " \"method\": \"%s\",\n", params->method);
fprintf(f, " \"warmup_steps\": %d,\n", params->warmup_steps);
fprintf(f, " \"G\": [%.15g, %.15g, %.15g],\n", params->G[0], params->G[1], params->G[2]);
fprintf(f, " \"B\": [%.15g, %.15g, %.15g],\n", params->B[0], params->B[1], params->B[2]);
/* 原子信息 */
fprintf(f, " \"atom_ids\": [");
for (int i = 0; i < atoms->n_atoms; i++) {
if (i > 0) fputc(',', f);
fprintf(f, "%d", atoms->atom_ids[i]);
if (i < atoms->n_atoms - 1) fputc(',', f);
}
fprintf(f, "],\n");
fprintf(f, " \"atom_masses\": [");
for (int i = 0; i < atoms->n_atoms; i++) {
if (i > 0) fputc(',', f);
fprintf(f, "%.15g", atoms->masses[i]);
if (i < atoms->n_atoms - 1) fputc(',', f);
}
fprintf(f, "],\n");
/* 成键 */
fprintf(f, " \"bond_pairs\": [");
for (int b = 0; b < bonds->n_bonds; b++) {
if (b > 0) fputc(',', f);
fprintf(f, "[%d, %d]", bonds->pairs[b*2], bonds->pairs[b*2+1]);
if (b < bonds->n_bonds - 1) fputc(',', f);
}
fprintf(f, "],\n");
fprintf(f, " \"bond_stiffness\": [");
for (int b = 0; b < bonds->n_bonds; b++) {
if (b > 0) fputc(',', f);
fprintf(f, "%.15g", bonds->stiffness[b]);
if (b < bonds->n_bonds - 1) fputc(',', f);
}
fprintf(f, "],\n");
fprintf(f, " \"bond_rest_lengths\": [");
for (int b = 0; b < bonds->n_bonds; b++) {
if (b > 0) fputc(',', f);
fprintf(f, "%.15g", bonds->rest_lengths[b]);
if (b < bonds->n_bonds - 1) fputc(',', f);
}
fprintf(f, "]\n");
@@ -410,9 +649,9 @@ static void write_trajectory_json(const char *path, const Trajectory *traj,
fclose(f);
}
/* ========================================================================
* 主函数
* ======================================================================== */
// ========================================================================
// 主函数
// ========================================================================
int main(int argc, char **argv) {
if (argc < 4) {
@@ -425,15 +664,13 @@ int main(int argc, char **argv) {
clock_t t0 = clock();
/* 读取参数和输入 */
SimParams params = read_params(param_path);
AtomData atoms = read_coord(input_dir);
BondData bonds = read_bonds(input_dir, &atoms);
printf("[C-engine] 原子数=%d, 键数=%d, NT=%d, DT=%.6g\n",
atoms.n_atoms, bonds.n_bonds, params.NT, params.DT);
printf("[C-engine] 原子数=%d, 键数=%d, NT=%d, DT=%.6g, method=%s\n",
atoms.n_atoms, bonds.n_bonds, params.NT, params.DT, params.method);
/* 初始化位置/速度 */
int n = atoms.n_atoms;
double *x = (double*)xmalloc(n * sizeof(double));
double *y = (double*)xmalloc(n * sizeof(double));
@@ -450,30 +687,28 @@ int main(int argc, char **argv) {
vz[i] = atoms.vel_0[i*3+2];
}
/* 分配轨迹缓冲区 */
/* 分配轨迹缓冲区:改用 record_steps */
int record_steps = params.NT - params.warmup_steps;
Trajectory traj;
traj.n_steps = params.NT;
traj.n_steps = record_steps;
traj.n_atoms = n;
traj.x = (double*)xmalloc(params.NT * n * sizeof(double) * 6);
traj.y = traj.x + params.NT * n;
traj.z = traj.y + params.NT * n;
traj.vx = traj.z + params.NT * n;
traj.vy = traj.vx + params.NT * n;
traj.vz = traj.vy + params.NT * n;
traj.x = (double*)xmalloc(record_steps * n * sizeof(double) * 6);
traj.y = traj.x + record_steps * n;
traj.z = traj.y + record_steps * n;
traj.vx = traj.z + record_steps * n;
traj.vy = traj.vx + record_steps * n;
traj.vz = traj.vy + record_steps * n;
/* 预热 */
for (int s = 0; s < params.warmup_steps; s++) {
leapfrog_step(n, x, y, z, vx, vy, vz,
atoms.masses, params.G, params.B, &bonds, atoms.fixed,
params.box_a, params.DT);
apply_step(params.method, n, x, y, z, vx, vy, vz,
atoms.masses, params.G, params.B, &bonds, atoms.fixed,
atoms.pos_0,
params.box_a, params.DT);
}
/* 记录 */
for (int s = 0; s < params.NT; s++) {
leapfrog_step(n, x, y, z, vx, vy, vz,
atoms.masses, params.G, params.B, &bonds, atoms.fixed,
params.box_a, params.DT);
/* 保存这一帧 */
for (int s = 0; s < record_steps; s++) {
for (int i = 0; i < n; i++) {
traj.x[ s * n + i] = x[i];
traj.y[ s * n + i] = y[i];
@@ -482,16 +717,19 @@ int main(int argc, char **argv) {
traj.vy[s * n + i] = vy[i];
traj.vz[s * n + i] = vz[i];
}
apply_step(params.method, n, x, y, z, vx, vy, vz,
atoms.masses, params.G, params.B, &bonds, atoms.fixed,
atoms.pos_0,
params.box_a, params.DT);
}
/* 输出轨迹 */
char out_path[512];
snprintf(out_path, sizeof(out_path), "%s/trajectory.txt", output_dir);
write_trajectory_json(out_path, &traj, &params, &atoms, &bonds);
clock_t t1 = clock();
double elapsed = (double)(t1 - t0) / CLOCKS_PER_SEC;
printf("[C-engine] 计算完成: %d 步, %.3f s\n", params.NT, elapsed);
printf("[C-engine] 计算完成: %d 步, %.3f s\n", record_steps, elapsed);
/* 清理 */
free(traj.x);