fix: driven atoms now oscillate around their initial equilibrium position

Previously, apply_driving_force set absolute position to A*cos(2π f t + φ),
ignoring the atom's initial coordinates. For atoms not at the origin (e.g.,
atom 120 at x=119), this incorrectly forced them back toward the origin each
step, causing severe distortion and numerical explosion.

Fix: store each driven atom's initial position as eq_pos/eq_x/eq_y/eq_z at
load time; position is now eq + A*cos(2π f t + φ) in all four engines
(Python, C, C++, Fortran).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 07:23:25 +08:00
parent e62e536cee
commit d489222eaf
4 changed files with 98 additions and 14 deletions
+12 -4
View File
@@ -84,6 +84,7 @@ typedef struct {
double *phi_x, *phi_y, *phi_z; /* radians */
int *has_period; /* 0=all, 1=limited cycles */
double *period_cycles; /* number of cycles */
double *eq_x, *eq_y, *eq_z; /* 平衡位置(初始坐标) */
double *freeze_x, *freeze_y, *freeze_z;
} DriverData;
@@ -129,12 +130,16 @@ static DriverData read_driver(const char *input_dir, const AtomData *atoms) {
d.phi_z = (double*)xmalloc(n_lines * sizeof(double));
d.has_period = (int*)xmalloc(n_lines * sizeof(int));
d.period_cycles = (double*)xmalloc(n_lines * sizeof(double));
d.eq_x = (double*)xmalloc(n_lines * sizeof(double));
d.eq_y = (double*)xmalloc(n_lines * sizeof(double));
d.eq_z = (double*)xmalloc(n_lines * sizeof(double));
d.freeze_x = (double*)xmalloc(n_lines * sizeof(double));
d.freeze_y = (double*)xmalloc(n_lines * sizeof(double));
d.freeze_z = (double*)xmalloc(n_lines * sizeof(double));
/* 初始化 freeze 数组 */
/* 初始化 freeze/eq 数组 */
for (int i = 0; i < n_lines; i++) {
d.eq_x[i] = d.eq_y[i] = d.eq_z[i] = 0.0;
d.freeze_x[i] = d.freeze_y[i] = d.freeze_z[i] = 0.0;
}
@@ -177,6 +182,9 @@ static DriverData read_driver(const char *input_dir, const AtomData *atoms) {
if (ii < 0) continue;
d.atom_idx[idx] = ii;
d.eq_x[idx] = atoms->pos_0[ii*3+0];
d.eq_y[idx] = atoms->pos_0[ii*3+1];
d.eq_z[idx] = atoms->pos_0[ii*3+2];
d.amp_x[idx] = amp_x;
d.amp_y[idx] = amp_y;
d.amp_z[idx] = amp_z;
@@ -738,9 +746,9 @@ static void apply_driving_force(
}
}
double px = drivers->amp_x[d] * cos(2*M_PI*drivers->freq_x[d]*t + drivers->phi_x[d]);
double py = drivers->amp_y[d] * cos(2*M_PI*drivers->freq_y[d]*t + drivers->phi_y[d]);
double pz = drivers->amp_z[d] * cos(2*M_PI*drivers->freq_z[d]*t + drivers->phi_z[d]);
double px = drivers->eq_x[d] + drivers->amp_x[d] * cos(2*M_PI*drivers->freq_x[d]*t + drivers->phi_x[d]);
double py = drivers->eq_y[d] + drivers->amp_y[d] * cos(2*M_PI*drivers->freq_y[d]*t + drivers->phi_y[d]);
double pz = drivers->eq_z[d] + drivers->amp_z[d] * cos(2*M_PI*drivers->freq_z[d]*t + drivers->phi_z[d]);
double vpx = -drivers->amp_x[d]*2*M_PI*drivers->freq_x[d]*sin(2*M_PI*drivers->freq_x[d]*t + drivers->phi_x[d]);
double vpy = -drivers->amp_y[d]*2*M_PI*drivers->freq_y[d]*sin(2*M_PI*drivers->freq_y[d]*t + drivers->phi_y[d]);
double vpz = -drivers->amp_z[d]*2*M_PI*drivers->freq_z[d]*sin(2*M_PI*drivers->freq_z[d]*t + drivers->phi_z[d]);