feat: 为 C/C++/Fortran 引擎增加驱动力(driving_force)支持
- param.json 新增 driving_force 开关 - C 引擎: 新增 DriverData 结构体、read_driver()、apply_driving_force() - C++ 引擎: 同上(C++ 风格实现) - Fortran 引擎: 同上(Fortran 90 风格实现) - 修复 JSON 输出末尾逗号导致加载失败的问题 - 编译通过并验证 C 引擎运行正常(100000步/6.6s)
This commit is contained in:
+229
-7
@@ -18,9 +18,10 @@ program dynamics_f90
|
||||
double precision :: DT, box_a
|
||||
double precision :: G(3), B(3)
|
||||
integer :: gravity_field, gravity_interaction, elastic_force, damping_force
|
||||
integer :: driving_force
|
||||
double precision :: gravity_strength
|
||||
character(len=32) :: method
|
||||
double precision :: t0, t1, elapsed
|
||||
double precision :: t0, t1, elapsed, tw
|
||||
|
||||
! 原子数据
|
||||
integer, allocatable :: atom_ids(:)
|
||||
@@ -32,6 +33,16 @@ program dynamics_f90
|
||||
integer, allocatable :: bond_pairs(:, :)
|
||||
double precision, allocatable :: bond_stiffness(:), bond_rest_lengths(:)
|
||||
|
||||
! 驱动力数据
|
||||
integer :: n_drivers
|
||||
integer, allocatable :: drv_atom_idx(:)
|
||||
double precision, allocatable :: drv_amp_x(:), drv_amp_y(:), drv_amp_z(:)
|
||||
double precision, allocatable :: drv_freq_x(:), drv_freq_y(:), drv_freq_z(:)
|
||||
double precision, allocatable :: drv_phi_x(:), drv_phi_y(:), drv_phi_z(:)
|
||||
integer, allocatable :: drv_has_period(:)
|
||||
double precision, allocatable :: drv_period_cycles(:)
|
||||
double precision, allocatable :: drv_freeze_x(:), drv_freeze_y(:), drv_freeze_z(:)
|
||||
|
||||
! 运行时位置/速度
|
||||
double precision, allocatable :: x(:), y(:), z(:)
|
||||
double precision, allocatable :: vx(:), vy(:), vz(:)
|
||||
@@ -59,7 +70,7 @@ program dynamics_f90
|
||||
! 读取 param.json
|
||||
call read_params(param_path, box_a, NT, DT, NSTEP, warmup_steps, method, G, B, &
|
||||
gravity_field, gravity_interaction, &
|
||||
elastic_force, damping_force, gravity_strength)
|
||||
elastic_force, damping_force, gravity_strength, driving_force)
|
||||
|
||||
! 读取 coord.txt
|
||||
call read_coord(input_dir, n_atoms, atom_ids, masses, radii, pos_0, vel_0, fixed)
|
||||
@@ -68,6 +79,17 @@ program dynamics_f90
|
||||
call read_bonds(input_dir, n_atoms, atom_ids, pos_0, n_bonds, &
|
||||
bond_pairs, bond_stiffness, bond_rest_lengths)
|
||||
|
||||
! 读取驱动力
|
||||
n_drivers = 0
|
||||
if (driving_force /= 0) then
|
||||
call read_driver(input_dir, n_atoms, atom_ids, n_drivers, &
|
||||
drv_atom_idx, drv_amp_x, drv_amp_y, drv_amp_z, &
|
||||
drv_freq_x, drv_freq_y, drv_freq_z, &
|
||||
drv_phi_x, drv_phi_y, drv_phi_z, &
|
||||
drv_has_period, drv_period_cycles, &
|
||||
drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
end if
|
||||
|
||||
write(*, '("[Fortran-engine] 原子数=", i0, ", 键数=", i0, &
|
||||
&", NT=", i0, ", DT=", f0.6, ", method=", a)') &
|
||||
n_atoms, n_bonds, NT, DT, trim(method)
|
||||
@@ -87,6 +109,16 @@ program dynamics_f90
|
||||
|
||||
! 预热
|
||||
do s = 1, warmup_steps
|
||||
if (driving_force /= 0 .and. n_drivers > 0) then
|
||||
tw = (s * 1.0d0) * DT
|
||||
call apply_driving(n, x, y, z, vx, vy, vz, tw, s-1, DT, &
|
||||
n_drivers, drv_atom_idx, &
|
||||
drv_amp_x, drv_amp_y, drv_amp_z, &
|
||||
drv_freq_x, drv_freq_y, drv_freq_z, &
|
||||
drv_phi_x, drv_phi_y, drv_phi_z, &
|
||||
drv_has_period, drv_period_cycles, &
|
||||
drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
end if
|
||||
call apply_step(method, n, x, y, z, vx, vy, vz, masses, G, B, &
|
||||
n_bonds, bond_pairs, bond_stiffness, bond_rest_lengths, &
|
||||
fixed, box_a, DT, &
|
||||
@@ -97,6 +129,16 @@ program dynamics_f90
|
||||
|
||||
! 记录
|
||||
do s = 1, record_steps
|
||||
if (driving_force /= 0 .and. n_drivers > 0) then
|
||||
tw = ((s-1 + warmup_steps) * 1.0d0) * DT
|
||||
call apply_driving(n, x, y, z, vx, vy, vz, tw, s-1, DT, &
|
||||
n_drivers, drv_atom_idx, &
|
||||
drv_amp_x, drv_amp_y, drv_amp_z, &
|
||||
drv_freq_x, drv_freq_y, drv_freq_z, &
|
||||
drv_phi_x, drv_phi_y, drv_phi_z, &
|
||||
drv_has_period, drv_period_cycles, &
|
||||
drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
end if
|
||||
traj_x(s, :) = x; traj_y(s, :) = y; traj_z(s, :) = z
|
||||
traj_vx(s, :) = vx; traj_vy(s, :) = vy; traj_vz(s, :) = vz
|
||||
call apply_step(method, n, x, y, z, vx, vy, vz, masses, G, B, &
|
||||
@@ -111,7 +153,8 @@ program dynamics_f90
|
||||
call write_json(output_dir, traj_x, traj_y, traj_z, traj_vx, traj_vy, traj_vz, &
|
||||
record_steps, n_atoms, atom_ids, masses, &
|
||||
NT, DT, NSTEP, warmup_steps, method, G, B, &
|
||||
n_bonds, bond_pairs, bond_stiffness, bond_rest_lengths)
|
||||
n_bonds, bond_pairs, bond_stiffness, bond_rest_lengths, &
|
||||
driving_force)
|
||||
|
||||
call cpu_time(t1)
|
||||
elapsed = t1 - t0
|
||||
@@ -121,6 +164,14 @@ program dynamics_f90
|
||||
deallocate(traj_x, traj_y, traj_z, traj_vx, traj_vy, traj_vz)
|
||||
deallocate(atom_ids, masses, radii, pos_0, vel_0, fixed)
|
||||
if (allocated(bond_pairs)) deallocate(bond_pairs, bond_stiffness, bond_rest_lengths)
|
||||
if (allocated(drv_atom_idx)) then
|
||||
deallocate(drv_atom_idx)
|
||||
deallocate(drv_amp_x, drv_amp_y, drv_amp_z)
|
||||
deallocate(drv_freq_x, drv_freq_y, drv_freq_z)
|
||||
deallocate(drv_phi_x, drv_phi_y, drv_phi_z)
|
||||
deallocate(drv_has_period, drv_period_cycles)
|
||||
deallocate(drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
end if
|
||||
|
||||
contains
|
||||
|
||||
@@ -129,11 +180,11 @@ contains
|
||||
! ========================================================================
|
||||
subroutine read_params(path, box_a, NT, DT, NSTEP, warmup_steps, method, G, B, &
|
||||
gravity_field, gravity_interaction, &
|
||||
elastic_force, damping_force, gravity_strength)
|
||||
elastic_force, damping_force, gravity_strength, driving_force)
|
||||
character(len=*), intent(in) :: path
|
||||
double precision, intent(out) :: box_a, DT, G(3), B(3), gravity_strength
|
||||
integer, intent(out) :: NT, NSTEP, warmup_steps
|
||||
integer, intent(out) :: gravity_field, gravity_interaction, elastic_force, damping_force
|
||||
integer, intent(out) :: gravity_field, gravity_interaction, elastic_force, damping_force, driving_force
|
||||
character(len=*), intent(out) :: method
|
||||
character(len=8096) :: buf
|
||||
character(len=256) :: line
|
||||
@@ -144,6 +195,7 @@ subroutine read_params(path, box_a, NT, DT, NSTEP, warmup_steps, method, G, B, &
|
||||
G = (/ 0.0d0, 0.0d0, -9.8d0 /); B = 0.0d0
|
||||
gravity_field = 1; gravity_interaction = 0
|
||||
elastic_force = 1; damping_force = 0; gravity_strength = 1.0d0
|
||||
driving_force = 0
|
||||
|
||||
open(newunit=u, file=trim(path), status='old', action='read', iostat=ios)
|
||||
if (ios /= 0) then
|
||||
@@ -173,6 +225,7 @@ subroutine read_params(path, box_a, NT, DT, NSTEP, warmup_steps, method, G, B, &
|
||||
elastic_force = json_get_int(buf, 'elastic_force', 1)
|
||||
damping_force = json_get_int(buf, 'damping_force', 0)
|
||||
gravity_strength = json_get_double(buf, 'gravity_strength', 1.0d0)
|
||||
driving_force = json_get_int(buf, 'driving_force', 0)
|
||||
end subroutine read_params
|
||||
|
||||
! ========================================================================
|
||||
@@ -685,6 +738,172 @@ subroutine apply_step(method, n, x, y, z, vx, vy, vz, m, G, B, &
|
||||
end do
|
||||
end subroutine apply_step
|
||||
|
||||
! ========================================================================
|
||||
! 读取驱动力 driver.txt
|
||||
! ========================================================================
|
||||
subroutine read_driver(input_dir, n_atoms, atom_ids, n_drivers, &
|
||||
drv_atom_idx, drv_amp_x, drv_amp_y, drv_amp_z, &
|
||||
drv_freq_x, drv_freq_y, drv_freq_z, &
|
||||
drv_phi_x, drv_phi_y, drv_phi_z, &
|
||||
drv_has_period, drv_period_cycles, &
|
||||
drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
character(len=*), intent(in) :: input_dir
|
||||
integer, intent(in) :: n_atoms, atom_ids(n_atoms)
|
||||
integer, intent(out) :: n_drivers
|
||||
integer, allocatable, intent(out) :: drv_atom_idx(:)
|
||||
double precision, allocatable, intent(out) :: drv_amp_x(:), drv_amp_y(:), drv_amp_z(:)
|
||||
double precision, allocatable, intent(out) :: drv_freq_x(:), drv_freq_y(:), drv_freq_z(:)
|
||||
double precision, allocatable, intent(out) :: drv_phi_x(:), drv_phi_y(:), drv_phi_z(:)
|
||||
integer, allocatable, intent(out) :: drv_has_period(:)
|
||||
double precision, allocatable, intent(out) :: drv_period_cycles(:)
|
||||
double precision, allocatable, intent(out) :: drv_freeze_x(:), drv_freeze_y(:), drv_freeze_z(:)
|
||||
|
||||
character(len=512) :: path, line, period_str
|
||||
integer :: u, ios, i, n, idx, n_cap
|
||||
double precision :: ax, ay, az, fx, fy, fz, px, py, pz
|
||||
integer, parameter :: MX = 256
|
||||
integer :: idx_tmp(MX), per_tmp(MX)
|
||||
double precision :: ax_tmp(MX), ay_tmp(MX), az_tmp(MX)
|
||||
double precision :: fxx_tmp(MX), fyy_tmp(MX), fzz_tmp(MX)
|
||||
double precision :: pxx_tmp(MX), pyy_tmp(MX), pzz_tmp(MX)
|
||||
double precision :: pc_tmp(MX)
|
||||
double precision :: fzx_tmp(MX), fzy_tmp(MX), fzz_tmp2(MX)
|
||||
|
||||
n_drivers = 0
|
||||
path = trim(input_dir) // '/driver.txt'
|
||||
open(newunit=u, file=trim(path), status='old', action='read', iostat=ios)
|
||||
if (ios /= 0) then
|
||||
write(*, '("[Fortran-engine] 警告: 无法打开 ", a)') trim(path)
|
||||
return
|
||||
end if
|
||||
|
||||
read(u, '(a)', iostat=ios) ! skip header
|
||||
|
||||
do
|
||||
read(u, *, iostat=ios) n, ax, ay, az, fx, fy, fz, px, py, pz, period_str
|
||||
if (ios /= 0) exit
|
||||
n_drivers = n_drivers + 1
|
||||
if (n_drivers > MX) exit
|
||||
|
||||
! Find atom index by id
|
||||
idx = -1
|
||||
do i = 1, n_atoms
|
||||
if (atom_ids(i) == n) then
|
||||
idx = i
|
||||
exit
|
||||
end if
|
||||
end do
|
||||
if (idx < 0) cycle
|
||||
|
||||
idx_tmp(n_drivers) = idx - 1 ! 0-based index
|
||||
ax_tmp(n_drivers) = ax; ay_tmp(n_drivers) = ay; az_tmp(n_drivers) = az
|
||||
fxx_tmp(n_drivers) = fx; fyy_tmp(n_drivers) = fy; fzz_tmp(n_drivers) = fz
|
||||
! degrees to radians
|
||||
pxx_tmp(n_drivers) = px * 3.141592653589793d0 / 180.0d0
|
||||
pyy_tmp(n_drivers) = py * 3.141592653589793d0 / 180.0d0
|
||||
pzz_tmp(n_drivers) = pz * 3.141592653589793d0 / 180.0d0
|
||||
|
||||
if (trim(period_str) == 'all') then
|
||||
per_tmp(n_drivers) = 0
|
||||
pc_tmp(n_drivers) = -1.0d0
|
||||
else
|
||||
per_tmp(n_drivers) = 1
|
||||
read(period_str, *) pc_tmp(n_drivers)
|
||||
end if
|
||||
fzx_tmp(n_drivers) = 0.0d0
|
||||
fzy_tmp(n_drivers) = 0.0d0
|
||||
fzz_tmp2(n_drivers) = 0.0d0
|
||||
end do
|
||||
close(u)
|
||||
|
||||
if (n_drivers <= 0) return
|
||||
|
||||
allocate(drv_atom_idx(n_drivers))
|
||||
allocate(drv_amp_x(n_drivers), drv_amp_y(n_drivers), drv_amp_z(n_drivers))
|
||||
allocate(drv_freq_x(n_drivers), drv_freq_y(n_drivers), drv_freq_z(n_drivers))
|
||||
allocate(drv_phi_x(n_drivers), drv_phi_y(n_drivers), drv_phi_z(n_drivers))
|
||||
allocate(drv_has_period(n_drivers), drv_period_cycles(n_drivers))
|
||||
allocate(drv_freeze_x(n_drivers), drv_freeze_y(n_drivers), drv_freeze_z(n_drivers))
|
||||
|
||||
drv_atom_idx = idx_tmp(1:n_drivers)
|
||||
drv_amp_x = ax_tmp(1:n_drivers); drv_amp_y = ay_tmp(1:n_drivers); drv_amp_z = az_tmp(1:n_drivers)
|
||||
drv_freq_x = fxx_tmp(1:n_drivers); drv_freq_y = fyy_tmp(1:n_drivers); drv_freq_z = fzz_tmp(1:n_drivers)
|
||||
drv_phi_x = pxx_tmp(1:n_drivers); drv_phi_y = pyy_tmp(1:n_drivers); drv_phi_z = pzz_tmp(1:n_drivers)
|
||||
drv_has_period = per_tmp(1:n_drivers)
|
||||
drv_period_cycles = pc_tmp(1:n_drivers)
|
||||
drv_freeze_x = fzx_tmp(1:n_drivers); drv_freeze_y = fzy_tmp(1:n_drivers); drv_freeze_z = fzz_tmp2(1:n_drivers)
|
||||
|
||||
write(*, '("[Fortran-engine] 已加载驱动力: ", i0, " 条定义")') n_drivers
|
||||
end subroutine read_driver
|
||||
|
||||
! 施加驱动力
|
||||
subroutine apply_driving(n, x, y, z, vx, vy, vz, t, step, dt, &
|
||||
n_drivers, drv_atom_idx, &
|
||||
drv_amp_x, drv_amp_y, drv_amp_z, &
|
||||
drv_freq_x, drv_freq_y, drv_freq_z, &
|
||||
drv_phi_x, drv_phi_y, drv_phi_z, &
|
||||
drv_has_period, drv_period_cycles, &
|
||||
drv_freeze_x, drv_freeze_y, drv_freeze_z)
|
||||
integer, intent(in) :: n, step, n_drivers
|
||||
integer, intent(in) :: drv_atom_idx(n_drivers), drv_has_period(n_drivers)
|
||||
double precision, intent(inout) :: x(n), y(n), z(n), vx(n), vy(n), vz(n)
|
||||
double precision, intent(in) :: t, dt
|
||||
double precision, intent(in) :: drv_amp_x(n_drivers), drv_amp_y(n_drivers), drv_amp_z(n_drivers)
|
||||
double precision, intent(in) :: drv_freq_x(n_drivers), drv_freq_y(n_drivers), drv_freq_z(n_drivers)
|
||||
double precision, intent(in) :: drv_phi_x(n_drivers), drv_phi_y(n_drivers), drv_phi_z(n_drivers)
|
||||
double precision, intent(in) :: drv_period_cycles(n_drivers)
|
||||
double precision, intent(inout) :: drv_freeze_x(n_drivers), drv_freeze_y(n_drivers), drv_freeze_z(n_drivers)
|
||||
|
||||
integer :: d, idx, period_steps
|
||||
double precision :: max_freq, px, py, pz, vpx, vpy, vpz, TWO_PI
|
||||
|
||||
TWO_PI = 2.0d0 * 3.141592653589793d0
|
||||
|
||||
do d = 1, n_drivers
|
||||
idx = drv_atom_idx(d) + 1 ! Fortran 1-based indexing
|
||||
|
||||
! Check period
|
||||
if (drv_has_period(d) /= 0) then
|
||||
max_freq = max(abs(drv_freq_x(d)), abs(drv_freq_y(d)), abs(drv_freq_z(d)))
|
||||
period_steps = 0
|
||||
if (max_freq > 1.0d-12) then
|
||||
period_steps = int(drv_period_cycles(d) / max_freq / dt)
|
||||
end if
|
||||
if (step > period_steps) then
|
||||
x(idx) = drv_freeze_x(d)
|
||||
y(idx) = drv_freeze_y(d)
|
||||
z(idx) = drv_freeze_z(d)
|
||||
vx(idx) = 0.0d0; vy(idx) = 0.0d0; vz(idx) = 0.0d0
|
||||
cycle
|
||||
end if
|
||||
end if
|
||||
|
||||
px = drv_amp_x(d) * cos(TWO_PI * drv_freq_x(d) * t + drv_phi_x(d))
|
||||
py = drv_amp_y(d) * cos(TWO_PI * drv_freq_y(d) * t + drv_phi_y(d))
|
||||
pz = drv_amp_z(d) * cos(TWO_PI * drv_freq_z(d) * t + drv_phi_z(d))
|
||||
vpx = -drv_amp_x(d) * TWO_PI * drv_freq_x(d) * sin(TWO_PI * drv_freq_x(d) * t + drv_phi_x(d))
|
||||
vpy = -drv_amp_y(d) * TWO_PI * drv_freq_y(d) * sin(TWO_PI * drv_freq_y(d) * t + drv_phi_y(d))
|
||||
vpz = -drv_amp_z(d) * TWO_PI * drv_freq_z(d) * sin(TWO_PI * drv_freq_z(d) * t + drv_phi_z(d))
|
||||
|
||||
x(idx) = px; y(idx) = py; z(idx) = pz
|
||||
vx(idx) = vpx; vy(idx) = vpy; vz(idx) = vpz
|
||||
|
||||
! Record freeze position
|
||||
if (drv_has_period(d) /= 0) then
|
||||
max_freq = max(abs(drv_freq_x(d)), abs(drv_freq_y(d)), abs(drv_freq_z(d)))
|
||||
period_steps = 0
|
||||
if (max_freq > 1.0d-12) then
|
||||
period_steps = int(drv_period_cycles(d) / max_freq / dt)
|
||||
end if
|
||||
if (step == period_steps) then
|
||||
drv_freeze_x(d) = px
|
||||
drv_freeze_y(d) = py
|
||||
drv_freeze_z(d) = pz
|
||||
end if
|
||||
end if
|
||||
end do
|
||||
end subroutine apply_driving
|
||||
|
||||
! ========================================================================
|
||||
! JSON 输出
|
||||
! ========================================================================
|
||||
@@ -692,9 +911,9 @@ end subroutine apply_step
|
||||
subroutine write_json(outdir, tx, ty, tz, tvx, tvy, tvz, &
|
||||
nsteps, nat, aid, amass, &
|
||||
NT, DT, NSTEP, warmup, method, G, B, &
|
||||
nb, bp, bk, br)
|
||||
nb, bp, bk, br, driving_force)
|
||||
character(len=*), intent(in) :: outdir, method
|
||||
integer, intent(in) :: nsteps, nat, NT, NSTEP, warmup, nb, bp(nb, 2), aid(nat)
|
||||
integer, intent(in) :: nsteps, nat, NT, NSTEP, warmup, nb, bp(nb, 2), aid(nat), driving_force
|
||||
double precision, intent(in) :: tx(nsteps, nat), ty(nsteps, nat), tz(nsteps, nat)
|
||||
double precision, intent(in) :: tvx(nsteps, nat), tvy(nsteps, nat), tvz(nsteps, nat)
|
||||
double precision, intent(in) :: DT, G(3), B(3), bk(nb), br(nb), amass(nat)
|
||||
@@ -798,6 +1017,9 @@ subroutine write_json(outdir, tx, ty, tz, tvx, tvy, tvz, &
|
||||
write(u, '(a)') ' "bond_rest_lengths": []'
|
||||
end if
|
||||
|
||||
write(buf, '(a, i0)') ' "driving_force": ', driving_force
|
||||
write(u, '(a)') trim(buf)
|
||||
|
||||
write(u, '(a)') '}'
|
||||
close(u)
|
||||
end subroutine write_json
|
||||
|
||||
Reference in New Issue
Block a user