【问题标题】:Runge-Kutta N-Body Implementation not workingRunge-Kutta N-Body 实施不起作用
【发布时间】: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


【解决方案1】:

你正在设置

rk1 = v0
pos2 = pos0 + rk1*h/2
vk2 = acc(pos2)

这是正确的。然后你继续

rk2 = vk1*h/2

它应该在哪里

rk2 = v0 + vk1*h/2

等等。当然那么累积位置更新也是错误的。

【讨论】:

  • 应该是 rk3 = v0 + vk2 h/2 and rk4 = v0 + vk3 h/2 or rk3 = v1 + vk2 h/2 and rk4 = v2 + vk3 h/2 ?
  • 它是从基点的所有偏移量,因此是第一个变体。与您对职位所做的相同。
  • 好很多了,但是轨道还是错了,二元系统在显式欧拉、中点和越级中是稳定的,但是使用RK4就不稳定,两个物体会互相靠近。跨度>
【解决方案2】:

这不是 RK 集成的良好实现。

您正在使用共享的可变数据。这不是线程安全的。

我见过的任何正确的数值积分实现都会将要积分的函数抽象为传递给积分方案的方法。您应该能够通过将函数传递给新例程来更改集成方案。

从一个以函数和初始条件为参数的集成接口开始。

【讨论】:

  • 我不太明白,我所有的属性都是私有的,包括 Vector2,因为它扩展了具有私有属性的 Tensor。 Vector2 对所有内容进行检查以确保它是 1 阶张量,大小为 2。
  • 对象未传入;我假设它是类中的私有共享数据成员。如果它是可变的,则它不是线程安全的。
  • 我应该将集成转移到抽象类中的静态方法吗?出于性能原因,我将 objects[i] 作为此集成器的属性。
  • 不。我担心你对集成和对象的理解。
  • 我接受建议,但我不明白我做错了什么。你能举个例子或给出一个线程会导致问题的具体案例吗?
猜你喜欢
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 2023-02-18
  • 1970-01-01
  • 2015-11-17
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多