JavaScript 中的 N 体重力模拟 [英] N-Body Gravity Simulation in JavaScript

查看:24
本文介绍了JavaScript 中的 N 体重力模拟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我尝试在 JavaScript 中创建 N 体重力模拟:

So, I am trying to create a N-Body Gravity simulation in JavaScript:

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
}

问题在于,当您生成(单击)并将 2 个球(意外重命名为粒子")并排放置时,它们开始产生速度并且越来越快地相互推挤.. 我该如何解决这个问题,顺便说一句是我的重力实施正确吗?

The problem's that when you spawn (click) and put 2 balls (accidentally renamed "particles") next to each other they start to generate velocity and faster and faster push eachother.. How do I fix this, btw is my gravity implementation correct?

推荐答案

这很容易解释:您正在将 Euler forward 作为 ODE 的求解器实施,并且在机械系统中,Euler forward 的系统误差会增加能量.Euler 反向降低了能量,因此交替使用显式和隐式 Euler 方法会使能量更加恒定.

This is easy to explain: You are implementing Euler forward as solver for the ODE, and in mechanical systems the systematic error of Euler forward increases the energy. Euler backward decreases the energy, so a combination of alternating the explicit and implicit Euler methods would leave the energy a little more constant.

但是你可以用同样甚至更少的努力来实现保持能量和其他物理不变量的二阶辛方法,(隐式)中点方法或 Verlet-(Stoermer-Cromer-...-Newton-)方法.

But then you can implement with the same or even less effort the second order symplectic methods which preserve energy and other physical invariants, either the (implicit) midpoint method or the Verlet-(Stoermer-Cromer-...-Newton-)method.

或者甚至更高阶的 Runge-Kutta,尽管不是辛的,它也会将能量保持到更高阶.

Or even higher order Runge-Kutta, which will also preserve the energy to a higher order, despite not being symplectic.

参见 Hairer 关于 Stoermer-Verlet-...-Newton 方法,postprint预印本 和移动的星星"使用 C++ 的教程文本Ruby.

See Hairer on the Stoermer-Verlet-...-Newton method, postprint or preprint and the "Moving stars around" tutorial text using C++ or Ruby.

物理注意事项:总而言之,实现非常小且可读性强.但是万有引力是

A note to the physics: All in all the implementation is very minimal and well readable. But the gravitational force is

g*m1*m2*(p2-p1)/norm(p2-p1)^3

作为

g*m1*m2/norm(p2-p1)

您只使用范数的平方,其中力将是重力势能的负梯度

you are only using the square of the norm, where the force would be the negative gradient of the gravitational potential energy

 g*m1*m2*ln(norm(p2-p1))

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

which is right for flatland physics, but not for a 2D section of 3D space.

具有速度 Verlet 和能量保存:

with velocity Verlet and energy preservation:

向圆对象添加一个新字段 a=Vector() 并用以下专用函数集合替换作为 update() 函数的厨房水槽

Add a new field a=Vector() to the circle object and replace the kitchen sink which is the update() function with the following collection of dedicated functions

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);
}

http://jsfiddle.net/4XVPH/

改变了粒子根据质量着色的示例(希望更好地显示它们的相互作用),修复了一个错误,以及一些额外的评论:http://jsfiddle.net/24mg6ctg/12/

Altered example with particles coloured based on their mass(hopefully better displaying their interaction), one bug fixed, and some additional comments: http://jsfiddle.net/24mg6ctg/12/

这篇关于JavaScript 中的 N 体重力模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆