0

私は Java クラスで Nbody の例に取り組もうとしています (これは Java での最初の学期です)。

プログラムの詳細は次のとおりです。

Scanner を使用して標準入力からユニバースを読み取り、上記のリープフロッグ スキームを使用してそのダイナミクスをシミュレートし、StdDraw を使用してアニメーション化するプログラム Nbody.java を作成します。データを格納するためにいくつかの配列を維持します。コンピューター シミュレーションを行うには、粒子の位置と速度を繰り返し更新する無限ループを記述します。プロットするときは、StdDraw.setXscale(-R, +R) および StdDraw.setYscale(-R, +R) を使用して、物理座標を画面座標にスケーリングすることを検討してください。

背景画像、曲、惑星を正しい配置でコンパイルしてロードする次のコードを作成しました。ただし、植物を本来のように回転させることはできません。

これが私のコードです:

import java.util.Scanner;

public class Nbody {

// method dist calculates distance between two points
// it accepts four double values (x1, y1, x2, y2)
// it returns a double value
private static double dist(double x1, double y1, double x2, double y2)

{

     double r;
     r = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
     return r;
} 


public static void main(String[] args) {

    final double G = 6.67e-11; // constant value G

    final double deltaT = 25000.0; // constant value delta T, which determines animation interval

    // ax and ay are accerlations on x axis and y axis
    double ax;
    double ay;


    Scanner scan = new Scanner (System.in); // define a keyboard object: scan

    int bodyNum = scan.nextInt(); // read in the first integer, which specify how many particles
    double radius = scan.nextDouble(); // read in radius of universe


    // define arrays to save x values and y values of each particle
    double[] x = new double[bodyNum];
    double[] y = new double[bodyNum];

    // define arrays to save velocity of each particle
    double[] vx = new double[bodyNum];
    double[] vy = new double[bodyNum];

    double[] m = new double[bodyNum];  // array stores mass of each particle
    String[] name = new String[bodyNum]; // array stores file name of each particles
    double[] Fx = new double[bodyNum]; // force on X axis
    double[] Fy = new double[bodyNum]; // force on Y axis

    StdDraw.setXscale(-radius, radius); // Set the X scale
    StdDraw.setYscale(-radius, radius); // Set the Y scale
    StdDraw.picture(0, 0, "starfield.jpg"); // Display background pic centered at (0,0)

    // read in inital location values and velocity values for each particle

    for (int i = 0; i < bodyNum; i++)

    {
       x[i] = scan.nextDouble();
       y[i] = scan.nextDouble();
       vx[i] = scan.nextDouble();
       vy[i] = scan.nextDouble();
       m[i] = scan.nextDouble();
       name[i] = scan.next();
       StdDraw.picture(x[i], y[i], name[i]); // display particle pic on screen
    }

    // This following line play background music, uncomment it in lab
    // If you work from a remote location via VNC, comment it
    StdAudio.play("2001.mid");

    // main animation loop
    while(true){

        // array Fx and Fy store net force acting on each body
        // initialize these two arrays to zeros

        for (int n = 0; n<bodyNum; n++)

        {
           Fx[n] = 0.0;
           Fy[n] = 0.0;
        }

         //  for loop to process all bodies
         for(int body = 0; body<bodyNum; body++)

            {

            // calculate the gravitational attraction between current body
            // and all other bodies

            Fx[body] = (m[body] * m[body+1])  / (x[body+1] -x[body])*G;

            Fy[body] = (m[body] * m[body+1]) / (y[body+1] -y[body])*G;

                for (int j = 0; j < bodyNum; j++)

                {

                 // calculate only when two bodies are different
                 // Please fill out the following if statement body                 

                 if(body != j)

                 {

                 Fx[j] = (m[j] * m[j+1]) / (y[j+1] -y[j])*G;
                 Fy[j] = (m[j] * m[j+1]) / (y[j+1] -y[j])*G;


                 }


                }
            }

         // update vleocity value and location value for each particle
         // please fill out the for loop
         for (int j = 0; j < bodyNum; j++)

            {

             // calculate accleration rate
             ax = Fx[j] / m[j];
             ay = Fy[j] / m[j];

             // update vleocity value 

            vx[j] = vx[j] + deltaT * ax;
            vy[j] = vy[j] + deltaT * ay;

            // update location value

            x[j] = x[j] + deltaT * vx[j];
            y[j] = y[j] + deltaT * vy[j];


            } 

         // redraw background
         StdDraw.setXscale(-radius, radius);
         StdDraw.setYscale(-radius, radius);
         StdDraw.picture(0, 0, "starfield.jpg");

         for (int i = 0; i < bodyNum; i++){
             // display the particle           
             StdDraw.picture(x[i], y[i], name[i]);
         }

         // display and pause for 30ms      
         StdDraw.show(30);        
    }
}
}

何かご意見は?

4

1 に答える 1

2

あなたの力の計算は私にはかなりずれているようです。私は次のようにします:

Arrays.fill(Fx, 0.0);
Arrays.fill(Fy, 0.0);
for (int body = 0; body < bodyNum - 1; body++) {
    for (int body2 = body + 1; body2 < bodyNum; body2++) {
        double dx = x[body2] - x[body];
        double dy = y[body2] - y[body];
        double d2 = dx * dx + dy * dy;
        double d = Math.sqrt(d2);
        double f = G * m[body] * m[body2] / d2;
        double fx = f * dx / d;
        double fy = f * dy / d;
        Fx[body] += fx;
        Fy[body] += fy;
        Fx[body2] -= fx;
        Fy[body2] -= fy;
    }
}
// then update positions and velocities based on Fx and Fy arrays

これは、 に作用する力の x および y 成分を計算し、bodyそれbody2を の x および y 力成分にbody加算し、 から減算しますbody2。からインデックスを作成するbody + 1ことで、同じ内部ループ パス内の 2 つのボディに対する同等かつ反対の力を考慮することができ、計算回数を半分に減らすことができます。

位置を更新するために、デルタの最後の速度で物体がデルタ全体にわたって移動しているかのように、時間デルタの最後の速度を使用しています。ある種の補間を行う方がより正確かもしれませんが、それは二次的な効果であるはずです。

于 2012-10-21T22:04:52.680 に答える