我翻译了一个模拟阻尼驱动线性振荡器的旧Fortran程序。这是JS:
/*jslint browser: true, devel: true */
/*global VERLET */
/*global FORCE */
/*global $ */
function driven() {
"use strict";
//MODULE shared
//USE, INTRINSIC :: ISO_FORTRAN_ENV,dp=>REAL64!modern DOUBLE PRECISION
//INTEGER :: i
//INTEGER, PARAMETER :: i_max=5000
//REAL(dp) :: x_read,v_read,const0,gamma,A_o,dt
//REAL(dp), DIMENSION(:), ALLOCATABLE :: x,v,a,E,dE,time
//REAL(dp), PARAMETER :: m=1.0
var i_max,
i_max_read,
i,
x_read,
v_read,
const0,
const0_read,
gamma,
gamma_read,
A_o,
A_o_read,
dt,
dt_read,
x,
x_plot,
v,
v_plot,
a,
a_plot,
time,
f_osc,
sim,
result,
nonlinear;
//i_max = 5000;
x = [];
x_plot = [];//new combined array for Flot plotting
v = [];
v_plot = [];//new combined array for Flot plotting
a = [];
a_plot = [];//new combined array for Flot plotting
time = [];
f_osc = [];//unlike Fortran, this needs to be an array
//END MODULE shared
//PROGRAM nonlinear
nonlinear = document.forms.nonlinear;
//USE shared
//IMPLICIT NONE
//EXTERNAL VERLET
//ALLOCATE(x(i_max + 1))
//ALLOCATE(v(i_max + 1))
//ALLOCATE(a(i_max + 1))
//ALLOCATE(E(i_max + 1))
//ALLOCATE(dE(i_max + 1))
//ALLOCATE(time(i_max + 1))
//PRINT *, ' '
//PRINT *, 'Initial position of the mass? [m]'
//PRINT *, ' '
//READ *, x_read
x_read = nonlinear.elements.x_read;
//x(1) = x_read
x[0] = parseFloat(x_read.value);
//PRINT *, ' '
//PRINT *, 'Initial velocity of the mass? [m/sec]'
//PRINT *, ' '
//READ *, v_read
v_read = nonlinear.elements.v_read;
//v(1) = v_read
v[0] = parseFloat(v_read.value);
//PRINT *, ' '
//PRINT *, 'Value of k/m? [1/sec^2]'
//PRINT *, ' '
//READ *, const0
const0_read = nonlinear.elements.const0_read;
const0 = parseFloat(const0_read.value);
//PRINT *, ' '
//PRINT *, 'Value of the damping coefficient? [kg/sec]'
//PRINT *, ' '
//READ *, gamma
gamma_read = nonlinear.elements.gamma_read;
gamma = parseFloat(gamma_read.value);
//PRINT *, ' '
//PRINT *, 'Amplitude of the external force? [N]'
//PRINT *, ' '
//READ *, A_o
A_o_read = nonlinear.elements.A_o_read;
A_o = parseFloat(A_o_read.value);
i_max_read = nonlinear.elements.i_max_read;
i_max = parseFloat(i_max_read.value);
//PRINT *, ' '
//PRINT *, 'Time-step of the system? [sec]'
//PRINT *, ' '
//READ *, dt
//PRINT *, ' '
dt_read = nonlinear.elements.dt_read;
dt = parseFloat(dt_read.value);
sim = i_max * dt;
result = sim.toFixed(1);
document.getElementById('output').innerHTML = result;
//time(1) = 0.0
time[0] = 0.0;
//i = 1
i = 0;
//DO
do {
//IF(i > i_max) EXIT
//CALL VERLET
VERLET(i, x, v, a, time, f_osc, dt, A_o, const0, gamma);
x_plot[i] = [time[i], x[i]];
v_plot[i] = [time[i], v[i]];
a_plot[i] = [time[i], a[i]];
//time(i + 1) = time(i) + dt
time[i + 1] = time[i] + dt;
//i = i + 1
i = i + 1;
//END DO
} while (i < i_max);
//OPEN(7, file='xt.dat', status='unknown')
//WRITE(7,'(2f16.6)') (time(i),x(i),i=1,i_max)
//CLOSE(7)
//DEALLOCATE(x)
//DEALLOCATE(v)
//DEALLOCATE(a)
//DEALLOCATE(E)
//DEALLOCATE(dE)
//DEALLOCATE(time)
function doPlot(position) {//Flot
$.plot("#placeholder", [//data
{
data: x_plot,
label: "Position (m)",
yaxis: 1,
color: "red"
},
{
data: v_plot,
label: "Velocity (m/sec)",
yaxis: 2,
color: "green"
},
{
data: a_plot,
label: "Acceleration (m/sec/sec)",
yaxis: 3,
color: "blue"
}
],//options
{
xaxis: { axisLabel: "Time (sec)" },
yaxes: [
{ font: { color: "red" } },
{ font: { color: "green" } },
{ font: { color: "blue" } },
{ alignTicksWithAxis: position === "left" ? 1 : null }
],
legend: {
position: "nw",
labelBoxBorderColor: null
}
}
);
}
doPlot("left");
//END PROGRAM nonlinear
}
//SUBROUTINE VERLET()
function VERLET(i, x_temp, v_temp, a_temp, t_temp, f_osc_temp, dt, A_o, const0, gamma) {
"use strict";
//USE shared
//IMPLICIT NONE
//REAL(dp) :: x_temp,v_temp,t_temp,f_osc
//EXTERNAL FORCE,ENERGY
var m;
m = 1.0;
//x_temp = x(i)
//v_temp = v(i)
//t_temp = time(i)
//CALL FORCE(x_temp,v_temp,t_temp,f_osc)
FORCE(i, x_temp, v_temp, t_temp, f_osc_temp, A_o, const0, gamma);
//x_temp = x(i)
//v_temp = v(i)
//CALL ENERGY!don't think I'm actually using this; no INTENT(OUT)
//a(i) = f_osc/m
a_temp[i] = f_osc_temp[i] / m;
//x(i + 1) = x(i) + v(i)*dt + 0.5*a(i)*dt*dt
x_temp[i + 1] = x_temp[i] + v_temp[i] * dt + 0.5 * a_temp[i] * dt * dt;
//x_temp = x(i + 1)
//v_temp = v(i)
//t_temp = time(i + 1)
//CALL FORCE(x_temp,v_temp,t_temp,f_osc)
FORCE(i, x_temp, v_temp, t_temp, f_osc_temp, A_o, const0, gamma);
//a(i + 1) = f_osc/m
a_temp[i + 1] = f_osc_temp[i] / m;
//v(i + 1) = v(i) + 0.5*(a(i + 1) + a(i))*dt
v_temp[i + 1] = v_temp[i] + 0.5 * (a_temp[i + 1] + a_temp[i]) * dt;
//x_temp = x(i + 1)
//v_temp = v(i + 1)
//CALL ENERGY!don't think I'm actually using this; no INTENT(OUT)
return [x_temp, v_temp, a_temp, t_temp];
//END
}
//SUBROUTINE FORCE(xs,vs,ts,f_oscs)
function FORCE(i, xs, vs, ts, f_oscs, A_o, const0, gamma) {
"use strict";
//USE shared
//IMPLICIT NONE
//REAL(dp), INTENT(IN) :: xs,vs,ts
//REAL(dp), INTENT(OUT) :: f_oscs
//REAL(dp) :: f_t
var f_t;
//f_t = A_o*DCOS(2.0*ts)
f_t = A_o * Math.cos(2.0 * ts[i]);
//f_oscs = -const0*xs - gamma*vs + f_t
f_oscs[i] = -const0 * xs[i] - gamma * vs[i] + f_t;
return f_oscs;
//END
}
//SUBROUTINE ENERGY()
//USE shared
//IMPLICIT NONE
//!REAL(dp), INTENT(OUT) ::
//E(i) = 0.5*(v(i)**2 + const0*x(i)**2)
//E(1) = 0.5*(v(1)**2 + const0*x(1)**2)
//dE(i) = E(i) - E(1)
//END
原始Fortran源显示在注释中。比较原始Fortran程序中位置与时间的输出:
0.000000 0.100000
0.010000 0.129930
0.020000 0.159693
...
...来自翻译的JavaScript:
0.000000 0.100000
0.010000 0.129930
0.020000 0.159707
...
结果从那里变得更糟。在5000步之后,结果不同意0.01的差异。我不习惯在JS中使用数组,所以错误可能在某处。这是我第一次遇到这样的事情。有没有人对这里发生的事情有所了解?
JS本身:
/*jslint browser: true, devel: true */
/*global VERLET */
/*global FORCE */
/*global $ */
function driven() {
"use strict";
var i_max,
i_max_read,
i,
x_read,
v_read,
const0,
const0_read,
gamma,
gamma_read,
A_o,
A_o_read,
dt,
dt_read,
x,
x_plot,
v,
v_plot,
a,
a_plot,
time,
f_osc,
sim,
result,
nonlinear;
x = [];
v = [];
a = [];
time = [];
f_osc = [];//unlike Fortran, this needs to be an array
time[0] = 0.0;
i = 0;
do {
VERLET(i, x, v, a, time, f_osc, dt, A_o, const0, gamma);
time[i + 1] = time[i] + dt;
i = i + 1;
} while (i < i_max);
}
function VERLET(i, x_temp, v_temp, a_temp, t_temp, f_osc_temp, dt, A_o, const0, gamma) {
"use strict";
var m;
m = 1.0;
FORCE(i, x_temp, v_temp, t_temp, f_osc_temp, A_o, const0, gamma);
a_temp[i] = f_osc_temp[i] / m;
x_temp[i + 1] = x_temp[i] + v_temp[i] * dt + 0.5 * a_temp[i] * dt * dt;
FORCE(i, x_temp, v_temp, t_temp, f_osc_temp, A_o, const0, gamma);
a_temp[i + 1] = f_osc_temp[i] / m;
v_temp[i + 1] = v_temp[i] + 0.5 * (a_temp[i + 1] + a_temp[i]) * dt;
return [x_temp, v_temp, a_temp, t_temp];
}
function FORCE(i, xs, vs, ts, f_oscs, A_o, const0, gamma) {
"use strict";
var f_t;
f_t = A_o * Math.cos(2.0 * ts[i]);
f_oscs[i] = -const0 * xs[i] - gamma * vs[i] + f_t;
return f_oscs;
}
这是一个类似的JS,不表现出这种症状:
/*jslint browser: true, devel: true */
/*global $ */
function amp() {
"use strict";
var i_max,
i,
m,
f_osc,
theta,
theta_plot,
omega,
omega_plot,
a,
e,
e_plot,
de,
time,
theta0,
read_ratio,
const0,
T,
result,
omega_read,
dt_read,
dt,
amplitude;
i_max = 500;
m = 1.0;
f_osc = 0.0;
theta = [];
omega = [];
a = [];
e = [];
de = [];
time = [];
e[0] = 0.5 * (Math.pow(omega[0], 2) + const0 * Math.pow(theta[0], 2));
time[0] = 0.0;
i = 0;
do {
f_osc = -const0 * Math.sin(theta[i]);
a[i] = f_osc / m;
e[i] = 0.5 * (Math.pow(omega[i], 2) + const0 * Math.pow(theta[i], 2));
de[i] = e[i] - e[0];
theta[i + 1] = theta[i] + omega[i] * dt + 0.5 * a[i] * dt * dt;
f_osc = -const0 * Math.sin(theta[i + 1]);
a[i + 1] = f_osc / m;
omega[i + 1] = omega[i] + 0.5 * (a[i + 1] + a[i]) * dt;
e[i] = 0.5 * (Math.pow(omega[i + 1], 2) + const0 * Math.pow(theta[i + 1], 2));
de[i] = e[i] - e[0];
time[i + 1] = time[i] + dt;
i = i + 1;
} while (i < i_max);
}
最大的区别在于,这个不包含我像子程序一样对待的函数。我在这方面做了非法的事吗?
答案 0 :(得分:2)
对FORCE()的第二次调用与FORTRAN对应的做法不同......
在FORTRAN,您可以这样做:
a(i) = FORCE( x(i) , v(i) , time(i) ) / m
a(i+1) = FORCE( x(i) + v(i)*dt + 0.5*a(i)*dt*dt , v(i) , time(i+1) ) / m
在JS中,你做了另一件事:
a(i) = FORCE( x(i) , v(i) , time(i) ) / m
a(i+1) = FORCE( x(i) , v(i) , time(i) ) / m
由于FORTRAN a(i + 1)的中间结果需要混合x(i + 1)和v(i)...,因此处理索引真的很困难 因此,仅仅将i作为参数传递听起来并不合适 您可以设置v [i + 1] = v [i]并尝试FORCE(i + 1,...)但这听起来太棘手了。
要么坚持更接近翻译,要么尝试完全重写。