1

I have many particles in space.

Each particle knows its position in space as well as some things like mass, velocity, and acceleration.

public class Particle
{
    float mass;
    float velocity;
    float acceleration;
}

I have a class that controls the gravity. This class has a List of all Particles. I can calculate the force of gravity of two Particles using the formula below.

F1 = F2 = G*M1*M2/d^2

How do I calculate this when I have 5 particles in my List? There will be more in the future.

Element 0 with 1, Element 1 with 2, Element 2 with 3, Element 3 with 4, and Element 4 with 0? (This doesn't seem to be a good idea).

J_Strauton
  • 2,270
  • 3
  • 28
  • 70
  • 1
    I thought there were many stars in Space! Just kidding! :) – Afzaal Ahmad Zeeshan May 26 '14 at 21:01
  • The problem is that each body has to interact with all other bodies. What you are looking for is a N-Body Problem (http://en.wikipedia.org/wiki/N-body_problem) or N-Body Simulation (http://en.wikipedia.org/wiki/N-body_simulation). Maybe start with three bodies - it's already quite complicated. – PiotrWolkowski May 26 '14 at 21:06
  • @PiotrWolkowski Cool I didn't know it was called N-body Simulation. – J_Strauton May 26 '14 at 21:11
  • You'll need to calculate the sum of all gravitational forces acting on each particle in each time frame, likely as a set of vectors. There are faster approximations but under these situations I don't think you'd need it. – scragar May 26 '14 at 21:11
  • 1
    NASA's approach to this when calculating orbital trajectories is to calculate the gravitational force on each body from every other body. For each body the sum of the vectors is applied to the motion as an acceleration for some period and a new position calculated. Then the exercise is repeated. They use Newtonian gravity for the outer planets. For Mercury they have to use General Relativity, but you probably don't need that. –  May 26 '14 at 21:17
  • Your positions, velocities and accelerations cannot be scalars. You need to create vector objects, or track each component separately. – John Alexiou May 28 '14 at 00:36
  • PS. Do **not** use `float` as the precision is terrible. Did you know `1 + x == x` for `x=1.677722E+07f`. But with double precision `x=9.00719925474099E+15`. – John Alexiou May 28 '14 at 01:15
  • Related questions: http://stackoverflow.com/q/22104128/3088138, http://stackoverflow.com/q/2182609/3088138. Also have a look at "Moving stars around", http://www.artcompsci.org/#msa provided in answers to both questions. – Lutz Lehmann Jun 06 '14 at 13:47

3 Answers3

1

At each timestep in your simulation, calculate the total vector force on each particle, and move that particle with an acceleration equal to the total force divided by the mass of the particle.

To find the total force on each particle, calculate the gravitational forces between a particle and each of the other particles, and add these all up. Note than when you calculate each force, it must be the vector force, that is, a force with a magnitude as in your equation, and the the direction towards the other particle. (That is, use this version of Newton's law of gravity: http://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation#Vector_form )

Along with the force, everything here should be done using vectors: position, velocity, acceleration, and force, all as vectors. The masses are your only scalars as you've described the problem. (That is, in your Particle class, the mass can be a float, but velocity and acceleration need to be vectors, with x, y, and z components.)

tom10
  • 67,082
  • 10
  • 127
  • 137
1

This should be a good starting point:

namespace SO.NBody
{
    public class Particle
    {
        public double mass;
        public double[] position;
        public double[] velocity;
        public double[] acceleration;

        public Particle(double mass)
        {
            this.mass=mass;
            this.position=new double[Simulation.DOF];
            this.velocity=new double[Simulation.DOF];
            this.acceleration=new double[Simulation.DOF];
        }
    }

    public class Simulation
    {
        // Degrees of Freedom, Planar Simulation = 2, Spatial Simulation = 3
        public static int DOF=2;
        // Set Universal Gravity as Needed here
        public const double G=100;

        public Simulation()
        {
            Bodies=new List<Particle>();
            Time=0;
        }
        public List<Particle> Bodies { get; private set; }
        public double Time { get; set; }

        public void CalculateAllAccelerations()
        {
            for (int i=0; i<Bodies.Count; i++)
            {
                Bodies[i].acceleration=new double[DOF];
                for (int j=0; j<i; j++)
                {
                    // Find relative position, which is needed for
                    //   a) Distance
                    //   b) Direction
                    double[] step=new double[DOF];
                    double distance=0;
                    for (int k=0; k<DOF; k++)
                    {
                        step[k]=Bodies[i].position[k]-Bodies[j].position[k];
                        // distance is |x^2+y^2+..|
                        distance+=step[k]*step[k];
                    }
                    distance=Math.Sqrt(distance);
                    // Law of gravity
                    double force=G*Bodies[i].mass*Bodies[j].mass/(distance*distance);
                    // direction vector from [j] to [i]
                    double[] direction=new double[DOF];
                    for (int k=0; k<DOF; k++)
                    {
                        direction[k]=step[k]/distance;
                    }
                    // Add equal and opposite acceleration components
                    for (int k=0; k<DOF; k++)
                    {
                        Bodies[i].acceleration[k]-=direction[k]*(force/Bodies[i].mass);
                        Bodies[j].acceleration[k]+=direction[k]*(force/Bodies[j].mass);
                    }
                }
            }

        }

        public void UpdatePositions(double time_step)
        {
            CalculateAllAccelerations();
            // Use symplectic integration
            for (int i=0; i<Bodies.Count; i++)
            {
                for (int k=0; k<DOF; k++)
                {
                    Bodies[i].velocity[k]+=time_step*Bodies[i].acceleration[k];
                    Bodies[i].position[k]+=time_step*Bodies[i].velocity[k];
                }
            }
            Time+=time_step;
        }

        public void RunSimulation(double end_time, int steps)
        {
            double h=(end_time-Time)/steps;
            while (Time<end_time)
            {
                // Trim last step if needed so the sim ends when specified
                if (Time+h>end_time) { h=end_time-Time; }
                UpdatePositions(h);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var world=new Simulation();
            var sun=new Particle(1000);
            var p1=new Particle(1.15)
            {
                position=new double[] { 100, 0 },
                velocity = new double[] { 0, 10 }
            };
            var p2=new Particle(1.05)
            {
                position=new double[] { 120, 0 },
                velocity=new double[] { 0, 6 }
            };
            // ...

            world.Bodies.Add(sun);
            world.Bodies.Add(p1);
            world.Bodies.Add(p2);
            //...

            // Run for t=10.0, with 100 steps
            world.RunSimulation(10.0, 100);
        }
    }
}
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • The Euler method as integrator will steadily increase the energy of the system until something reaches escape velocity. One should use a symplectic integrator, like the Verlet method that Newton used or an higher order method. See http://stackoverflow.com/a/23671054/3088138 and http://jsfiddle.net/4XVPH/ (not entirely correctly initialized, center of mass does not stay in center of screen). And compare to the original implementation provided with the question. – Lutz Lehmann Jun 05 '14 at 17:25
  • Yes, I know very well this. This discussion is beyond the scope of the original question. As I said, it is a starting point and not a final solution. – John Alexiou Jun 06 '14 at 12:50
  • I should have started with "If you got the simulation running that far, you will observe that..." and "you can improve on it by ..." An easier improvement is to reduce the time step in the Euler method, especially if the simulation is displayed as frame-based animation, one should take multiple simulation steps per frame. – Lutz Lehmann Jun 06 '14 at 13:56
  • Note that I update the velocities first, before the position in order to reduce the artificial energy input of the explicit Euler method. This is almost as good as a Verlet method. See http://en.wikipedia.org/wiki/Semi-implicit_Euler_method – John Alexiou Jun 08 '14 at 14:39
  • Note that I found and error and fixed it in `Bodies[i].acceleration[k]-=direction[k]...` Somehow I had `=-` instead of `-=`. – John Alexiou Jun 10 '14 at 04:46
0

Actually the Law of Gravitation applies to only 2 objects. Which was as general studied for Earth and Object in space or on surface.

https://en.wikipedia.org/wiki/Newton's_law_of_universal_gravitation

Here if you have 5 masses, what you can do is to make one mass stationary or relative. Which would be M1 then test all of the masses relative to it finding each ones gravity. Maybe here you would require some sort of foreach looping too.

Working with 5 bodies all in space, is difficult even from Mister Newton, that's why he gave you an equation for 2 bodies. With are inter-relatable to each other. You can use these 2 bodies, and check each body's gravity. Relate them to each other, because initially they are not related.

Afzaal Ahmad Zeeshan
  • 15,669
  • 12
  • 55
  • 103