【发布时间】:2017-03-17 02:26:52
【问题描述】:
我已经用 Java 实现了本文所述的 Runge-Kutta 4 算法。 http://spiff.rit.edu/richmond/nbody/OrbitRungeKutta4.pdf
但是,动作不稳定。即使只有两个物体,也没有周期性运动。
protected void integrateRK4(double time) {
final double H = time;
final double HO2 = H/2;
final double HO6 = H/6;
Vector2[] currentVelocities = new Vector2[objects.length];
Vector2[] currentPositions = new Vector2[objects.length];
Vector2[] vk1 = new Vector2[objects.length];
Vector2[] vk2 = new Vector2[objects.length];
Vector2[] vk3 = new Vector2[objects.length];
Vector2[] vk4 = new Vector2[objects.length];
Vector2[] rk1 = new Vector2[objects.length];
Vector2[] rk2 = new Vector2[objects.length];
Vector2[] rk3 = new Vector2[objects.length];
Vector2[] rk4 = new Vector2[objects.length];
for (int i=0; i<objects.length; i++) {
currentVelocities[i] = objects[i].velocity().clone();
currentPositions[i] = objects[i].position().clone();
}
vk1 = computeAccelerations(objects);
for (int i=0; i<objects.length; i++) {
rk1[i] = currentVelocities[i].clone();
}
for (int i=0; i<objects.length; i++) {
objects[i].setPosition(Vectors2.add(currentPositions[i], Vectors2.prod(rk1[i], HO2)));
}
vk2 = computeAccelerations(objects);
for (int i=0; i<objects.length; i++) {
rk2[i] = Vectors2.prod(vk1[i], HO2);
}
for (int i=0; i<objects.length; i++) {
objects[i].setPosition(Vectors2.add(currentPositions[i], Vectors2.prod(rk2[i], HO2)));
}
vk3 = computeAccelerations(objects);
for (int i=0; i<objects.length; i++) {
rk3[i] = Vectors2.prod(vk2[i], HO2);
}
for (int i=0; i<objects.length; i++) {
objects[i].setPosition(Vectors2.add(currentPositions[i], Vectors2.prod(rk3[i], H)));
}
vk4 = computeAccelerations(objects);
for (int i=0; i<objects.length; i++) {
rk4[i] = Vectors2.prod(vk3[i], H);
}
for (int i=0; i<objects.length; i++) {
objects[i].setVelocity(Vectors2.add(currentVelocities[i], Vectors2.prod(Vectors2.add(vk1[i], Vectors2.prod(vk2[i], 2), Vectors2.prod(vk3[i], 2), vk4[i]), HO6)));
objects[i].setPosition(Vectors2.add(currentPositions[i], Vectors2.prod(Vectors2.add(rk1[i], Vectors2.prod(rk2[i], 2), Vectors2.prod(rk3[i], 2), rk4[i]), HO6)));
}
}
我的实现不正确吗?
注意:
Vectors2 是我自己实现的向量,它是大小为 2 的一阶张量。
所有的静态方法 Vectors2.* 返回一个向量的副本。
在 Vector2 的实例上调用的所有非静态方法都会修改向量,objects[i].addVelocity() 和 objects[i].addPosition() 也是如此
Vectors2.add(Vector2... vectors2) 进行元素加法。Vectors2.prod(Vector2... vectors2) 进行元素乘法。Vectors2.prod(Vector2 vector2, double c) 进行元素乘法。
computeAccelerations(PointBody[] objects) 返回一个加速度向量数组。
变量objects 是类NBodyIntegrator 的一个属性,这些函数是该类的一部分。它是PointBody[] 的数组。
为了确保不是其他错误,我通过删除 k2、k3 和 k4 将 RK4 算法简化为显式欧拉算法。 这个按预期工作。
protected void integrateRK1(double time) {
final double H = time;
final double HO2 = H/2;
Vector2[] currentVelocities = new Vector2[objects.length];
Vector2[] currentPositions = new Vector2[objects.length];
Vector2[] vk1;
Vector2[] rk1 = new Vector2[objects.length];
for (int i=0; i<objects.length; i++) {
currentVelocities[i] = objects[i].velocity().clone();
currentPositions[i] = objects[i].position().clone();
}
vk1 = computeAccelerations(objects);
for (int i=0; i<objects.length; i++) {
rk1[i] = currentVelocities[i].clone();
}
for (int i=0; i<objects.length; i++) {
objects[i].setVelocity(Vectors2.add(currentVelocities[i], Vectors2.prod(Vectors2.add(vk1[i]), H)));
objects[i].setPosition(Vectors2.add(currentPositions[i], Vectors2.prod(Vectors2.add(rk1[i]), H)));
}
}
【问题讨论】:
-
考虑一个四阶symplectic integrator,这将更好地保留系统的总能量。
-
使用 runge-kutta 与辛积分器的含义是什么?我知道辛积分器是时间可逆的,但还有什么其他优势?
-
人们仍然使用 RK4 甚至更高阶的 RK 算法的原因是什么? RK 有一些固有的优势吗?
标签: java algorithm math runge-kutta