N-body Simulations-Code Part 2

Using our Body object

Recall that by creating a new class, we have a Body object that can be called using:

Body b = new Body(double rx, double ry, double vx, double vy, double mass, Color color)

Now, we want to use the brute-force method to update the positions and velocities of the bodies. Here's the code for an applet that we'll see at the end of this tutorial.


BruteForce.java


// tell the compiler where to find the methods you will use.
// required when you create an applet
import java.applet.*;
// required to paint on screen
import java.awt.*;
import java.awt.event.*;


//Start the applet and define a few necessary variables
public class BruteForce extends Applet {
    public int N = 100;
    public Body bodies[]= new Body[10000];
    public TextField t1;
    public Label l1;
    public Button b1;
    public Button b2;
    public boolean shouldrun=false;
    

    
// The first time we call the applet, this function will start
  public void init()
  {
        startthebodies(N);
        t1=new TextField("100",5);
        b2=new Button("Restart");
        b1=new Button("Stop");
        l1=new Label("Number of bodies:");
        ButtonListener myButtonListener = new ButtonListener();
        b1.addActionListener(myButtonListener);
        b2.addActionListener(myButtonListener);
        add(l1);
        add(t1);
        add(b2);
        add(b1);
  }
  
  
// This method gets called when the applet is terminated. It stops the code
  public void stop()
  {
    shouldrun=false;
  }
  
  
//Called by the applet initally. It can be executed again by calling repaint();
  public void paint(Graphics g)
  {
    g.translate(250,250); //Originally the origin is in the top right. Put it in its normal place
    
//check if we stopped the applet, and if not, draw the particles where they are
    if (shouldrun) {
      for(int i=0; i<N; i++) {
        g.setColor(bodies[i].color);
        g.fillOval((int) Math.round(bodies[i].rx*250/1e18),(int) Math.round(bodies[i].ry*250/1e18),8,8);
      }
      //go through the Brute Force algorithm (see the function below)
      addforces(N);
      //go through the same process again until applet is stopped
      repaint();
    }
  }
  
  //the bodies are initialized in circular orbits around the central mass.
  //This is just some physics to do that
  public static double circlev(double rx, double ry) {
    double solarmass=1.98892e30;
    double r2=Math.sqrt(rx*rx+ry*ry);
    double numerator=(6.67e-11)*1e6*solarmass;
    return Math.sqrt(numerator/r2);
  }
  
  //Initialize N bodies with random positions and circular velocities
  public void startthebodies(int N) {
    double radius = 1e18;        // radius of universe
    double solarmass=1.98892e30;
    for (int i = 0; i < N; i++) {
      double px = 1e18*exp(-1.8)*(.5-Math.random());
      double py = 1e18*exp(-1.8)*(.5-Math.random());
      double magv = circlev(px,py);
      
      double absangle = Math.atan(Math.abs(py/px));
      double thetav= Math.PI/2-absangle;
      double phiv = Math.random()*Math.PI;
      double vx   = -1*Math.signum(py)*Math.cos(thetav)*magv;
      double vy   = Math.signum(px)*Math.sin(thetav)*magv;
      //Orient a random 2D circular orbit
     
           if (Math.random() <=.5) {
              vx=-vx;
              vy=-vy;
            } 
           
      double mass = Math.random()*solarmass*10+1e20;
      //Color the masses in green gradients by mass
      int red     = (int) Math.floor(mass*254/(solarmass*10+1e20));
      int blue   = (int) Math.floor(mass*254/(solarmass*10+1e20));
      int green    = 255;
      Color color = new Color(red, green, blue);
      bodies[i]   = new Body(px, py, vx, vy, mass, color);
    }
    //Put the central mass in
    bodies[0]= new Body(0,0,0,0,1e6*solarmass,Color.red);//put a heavy body in the center
    
  }
  
  //Use the method in Body to reset the forces, then add all the new forces
  public void addforces(int N) {
    for (int i = 0; i < N; i++) {
      bodies[i].resetForce();
      //Notice-2 loops-->N^2 complexity
      for (int j = 0; j < N; j++) {
        if (i != j) bodies[i].addForce(bodies[j]);
      }
    }
    //Then, loop again and update the bodies using timestep dt
    for (int i = 0; i < N; i++) {
      bodies[i].update(1e11);
    }
  }
   public static double exp(double lambda) {
        return -Math.log(1 - Math.random()) / lambda;
    }
   public boolean action(Event e,Object o)
   {
     N = Integer.parseInt(t1.getText());
     if (N>1000) {
       t1.setText("1000");
       N=1000;
     }
     
       startthebodies(N);
       repaint();
     
     return true;
   }
   public class ButtonListener implements ActionListener{

    public void actionPerformed(ActionEvent evt) 
    {
        // Get label of the button clicked in event passed in
        String arg = evt.getActionCommand();    
        if (arg.equals("Restart"))
        {
          shouldrun=true;
               N = Integer.parseInt(t1.getText());
     if (N>1000) {
       t1.setText("1000");
       N=1000;
     }
     
       startthebodies(N);
       repaint();
        }
        else if (arg.equals("Stop")) 
            stop();
    }
}

}

And that's it! It's pretty simple once we have the Body object defined. This is easily embedded in a webpage using the <applet code=BruteForce.classs> HTML tag.

You can skip to the Applets page to see this one in action, or head to the Next section of programming, where we will look at the Barnes-Hut algorithm.