JavaScript中的N体重力模拟

sup*_*per 5 javascript physics vector

所以,我正在尝试用JavaScript创建一个N-Body Gravity模拟:

http://jsfiddle.net/4M94x/

var Circle = function(c, r, cor, cof) { // Fix CoR & CoF // Had to add code for JSFiddle link :P
    this.c = c
    this.r = r
    this.m = r * r * Math.PI
    this.v = new Vector()
    this.cor = cor
    this.cof = cof
}
Run Code Online (Sandbox Code Playgroud)

问题在于,当你产生(点击)并将2个球(意外地重命名为"粒子")彼此相邻时,它们开始产生速度并且更快更快地推动彼此.我如何解决这个问题,顺便说一句,我的重力实现是否正确?

Dr.*_*ann 21

这很容易解释:您正在将Euler前向实现为ODE的求解器,而在机械系统中,Euler前向的系统误差会增加能量.欧拉向后减少能量,因此交替显式和隐式欧拉方法的组合将使能量更加恒定.

不过,你可以用相同或更少的努力实现第二阶辛方法,其节约能源和其他物理不变,无论是(隐含的)中点法或Verlet-(Stoermer - 克罗默-...-牛顿)方法.

甚至更高阶的Runge-Kutta,尽管不是辛,但它也能将能量保持在更高的阶数.

请参阅Stoermer-Verlet上的Hairer -...- Newton方法,postprintpreprint以及使用C++Ruby的"Moving stars around" 教程文本.


关于物理学的一个注释:总而言之,这些实现非常简单且可读性很好.但引力是

g*m1*m2*(p2-p1)/norm(p2-p1)^3
Run Code Online (Sandbox Code Playgroud)

作为负梯度

g*m1*m2/norm(p2-p1)
Run Code Online (Sandbox Code Playgroud)

你只使用标准的平方,其中力将是重力势能的负梯度

 g*m1*m2*ln(norm(p2-p1))
Run Code Online (Sandbox Code Playgroud)

这适用于平地物理,但不适用于3D空间的2D部分.


工作代码

速度Verlet和能量保存:

将新字段a = Vector()添加到圆形对象,并使用以下专用函数集合替换作为update()函数的厨房接收器

function compute_forces() {
    for (var i = 0; i < particles.length; i++) {
        var p = particles[i];
        p.a.set(0);

        for (var j = 0; j < i; j++) {
            var p2 = particles[j];

            var d = p.c.sub(p2.c);
            var norm = Math.sqrt(100.0 + d.lengthSq());
            var mag = gravity / (norm * norm * norm);

            p.a.set(p.a.sub(d.mul(mag * p2.m)));
            p2.a.set(p2.a.add(d.mul(mag * p.m)));

        }
    }

}


function do_collisions() {
    for (var i = 0; i < particles.length; i++) {
        var p = particles[i];
        for (var j = 0; j < i; j++) {
            var p2 = particles[j];

            if (checkCCCol(p, p2)) {
                resCCCol(p, p2);
            }
        }
    }
}


function do_physics(dt) {
    // do velocity Verlet 
    // with consistent state at interval half points
    // x += 0.5*v*dt
    for (var i1 = 0; i1 < particles.length; i1++) {
        var p1 = particles[i1];
        p1.c.set(p1.c.add(p1.v.mul(0.5 * dt)));
    }
    // a = A(x)
    compute_forces();
    // v += a*dt
    for (var i2 = 0; i2 < particles.length; i2++) {
        var p2 = particles[i2];
        p2.v.set(p2.v.add(p2.a.mul(dt)));
    }
    // x += 0.5*v*dt
    for (var i3 = 0; i3 < particles.length; i3++) {
        var p3 = particles[i3];
        p3.c.set(p3.c.add(p3.v.mul(0.5 * dt)));
    }
    do_collisions();
}

function update() {

    for (var k = 0; k < 4; k++) {
        do_physics(1.0 / 4);
    }

    render();

    RAF(update);
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/4XVPH/


更改了基于质量着色的粒子的示例(希望更好地显示它们的交互),修复了一个错误,以及一些其他注释:http://jsfiddle.net/24mg6ctg/12/