Sign in to follow this  
neoaikon

C# Particle-to-Particle Gravity

Recommended Posts

I have been working on creating a particle gravity simulation using C#.. Its just simple Particle2Particle interaction, no optimizations. I’m trying to make it as realistic as possible as possible in terms of simulating gravity, and thus I’m using realistic constants and formulas. G = 6.673e-11f Or G = .00000000006673 I am creating particles of random radius; I use that to calculate the mass by using the following calculation. M = (radius^2)^2 * 1.9e-22f Or M = (radius^2)^2 * 190,000,000,000,000,000,000,000 This multiplies the squared square of the mass with the mass of the moon, giving me my mass. I use the following formula to get the force F=M1A A=G * ((M1*M2) / DISTANCE) Combining the two, we can cancel out the M1, giving us F= A = G * (M2 / DISTANCE) I multiply that with a normalized vector pointing toward the particle in question, and add that into a vector, then after going through all the particles, I add that vector to the position vector to get the new position. I believe I am doing this correctly, or at least believe I am, but the system never really stabilizes and forms orbits and such. My goal is to create small systems that orbit realistically, but what happens is after the particles are spawned (providing no initial velocities have been given), they all migrate towards the center of mass for the simulation, which is how it should be, but the problem is a large portion of the particles will form tight orbits around this center. This causes any particles not part of that mass to be bound to it, and thus no orbiting pairs form, because of this mass. Is there anything else I need to be doing? or am I calculating the gravitational forces correctly? Or is their other forces I need to be taking into account here besides the acceleration due to gravity? Once I have it well commented, I will post the class file I am using, Thanks in advance.

Share this post


Link to post
Share on other sites
Wow! if I hadn't done half the math I've been learning as of late, seeing that kinda stuff would have killed me. While I've never thought of this as an n-body system, it kind of is. But my concern isn't with calculating the stability of an N body system, but to refine my system so that it tends to fall into stable orbits.

My system isn't very particle intensive, thus why I'm using particle-to-particle interactions. My system can run it up to 500 particles smoothly, but its pretty much chaos at that point, lowering the number of particles increase stability, with 2 particles almost always falling into some sort of stable orbit.

Anything above 10 particles will usually become so mass intensive at the center particles orbiting around this heavier concentration tend to ignore other nearby particles.

Share this post


Link to post
Share on other sites
Three bodies of near-equal mass are known to be chaotic in their co-gravitation, so anything above 2 bodies in your simulation seems to already be producing realistic behaviour.

Your force calculation seems to be close to correct, but I will rewrite it just to make sure:

F = GMm/r^2
a = F/m = GM/r^2

Multiplying the unit vector pointing from the gravitated body (the one with mass m) to the gravitating body (the one with mass M) by the scalar value a gives the final acceleration vector. This seems to be what you're doing already.

The sum of all gravitation is the sum of all these acceleration vectors. This seems to be what you're doing already.

You then integrate by:
new position vector = old position vector + old velocity vector
new velocity vector = old velocity vector + acceleration vector

Make sure you do not perform the integration backward by updating velocity before position. Things will break.

I'm not sure what behaviour you are expecting.

Why not start with 2 particles, and model a simplified version of the Sun-Earth system:

M = 1.9891e30 kg
m = 5.9736e24 kg (or 0 kg if you want to ignore Earth's gravitational field)
r = 149597887500 m (Earth's semi-major axis -- its average orbit distance)
v = 29789 m/s (Earth's average orbit speed)

This can be begun by placing the Sun at location {0, 0}, and the Earth at {0, 149597887500}. Then, give Earth an initial velocity vector of {-29789, 0}. You should end up with a circular orbit. If you do, then your calculations are correct.

The initial velocity above was gathered by the equation:

v = sqrt(GM/r)

You can pretty much assume that gravitational interaction is the only one worth worrying about at this large scale. Considering that electromagnetic repulsion really only comes into play when you're in direct contact with a body such as Earth or the Moon, you don't have to worry about it until the bodies are touching. Calculating contact points and collision response vectors would be things to look into.

The Sun itself emits a lot more electromagnetic energy, but the pressure is still very slight, and can most likely be ignored until the point of contact. Solar sailing runs on this principle of light pressure.

[Edited by - taby on January 31, 2008 2:23:15 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by neoaikon
Wow! if I hadn't done half the math I've been learning as of late, seeing that kinda stuff would have killed me. While I've never thought of this as an n-body system, it kind of is. But my concern isn't with calculating the stability of an N body system, but to refine my system so that it tends to fall into stable orbits.


Looking around I found this. There appear to be some number of many-body stable orbit families, but while mathematically stable, they eventually become more chaotic as floating-point rounding errors accumulate.

Share this post


Link to post
Share on other sites
Aaron, Kudo's on that simulation, although I'm surprised at how fast the floating point errors give rise to chaos in some of them. But it does show lots of stuff that my system does when my system goes into chaos, most notably particles getting stuck together and flying off into nowhere, which I used a cutoff to keep from happening.

Taby, you actually helped me figure out what was going on and why the simulation didn't seem realistic. Also, thanks for evaluating my math, that helps a lot with my confidence. When I tried to recreate an earth body system, I discovered that what was happening was, I was creating particles within a certian range on my screen, that way I can keep everything in the camera's view. The problem with this is I'm using realistic constants, and trying to generate realistic mass. But my particles are usually within a range 1000 units in all directions. so the distance between the particles is less than 1000 meter's in all directions. Not realistic at all.

Earth lies VERY far away from the sun, based on your number. So in the gravity calculation, I multiplied the distance by 100,000,000,000 (GM / (R^2 * 1e-11)). This lead to alot more realistic behavior, since now the force fall off is a lot more dramatic, it allows the particles near each other to begin to orbit and form small systems. Although these orbits and systems usually consist of more than 2 body's, so its just a localized pocket of chaos, but its better than a huge blob in the center like I was getting.

I'm still working on commenting the class file, if anyone would like to see it. But it seems i'm either going to have to calculate the best placement for the particles to form systems, and even then I'd need infinitely long floating point percision to keep it stable for long. Or I'm going to have to find some way of having particles capture other particles, and keep them in a stable orbit, with the latter seeming like a decent solution.

EDIT:
Taby, what did you mean by backwards integration? Currently in my loop, it calls a update function, that runs through the particles and updates the velocity, then after getting done with that, it updates position, then repeats. Is it wrong to do it this way?

Share this post


Link to post
Share on other sites
For all who are interested, here is the source for the n-body system generator, it seems to be working well. But if anyone spots a way to make it improvement, or an error, let me know!


using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;

namespace DirectX
{
public class Newton
{
// Newton v1.1
// Author: Mykel Ne'Oa Ikon
// Description: This class is a functional n-body system
//it requires a DirectX Based project that is setup to the point that a blank scene
// is being drawn. You can then invoke the class and use the functions
//
// Add_NBody - adds a n-body to the system
// Delete_NBody - deletes a n-body from the system
// Toggle - by passing true(On) or false (Off) you can cause the particle to be affected by other particles gravity or not, other particles will still be affected by the off particle

Int32 Max = 500; // This is the maximum number of particles we can have through newton
Int32 N = 0; // This is the particle counter, when we add a particle this increments, and decrements when we delete it
n_body[] newton = new n_body[1000]; // Our array for our particle structure
float GC = 6.673e-11f; // Our gravitational constant, .00000000006.673
float MC = 1e+22f; // We multiply this by our radius, double squared.
float GD = 1000000000000; // our galactic distance, makes the force seem like we're at large

// This method allows us to add a particle
public void Add_NBody(Mesh mesh, Vector3 position, Vector3 acceleration, Color diffuse, float radius)
{
if (N < Max)
{
newton[N].nradius = radius; // Pass the radius
newton[N].nmass = (radius * radius) * MC; // Turn the radius into mass
newton[N].ncutoff = (radius * radius) + radius;// * (newton[i].nradius + newton[i].nradius); // Set the gravity cutoff distance
newton[N].nmesh = mesh; // Set the mesh
newton[N].nposition = position; // Set the mesh position
newton[N].nacceleration += acceleration; // Define the acceleration
newton[N].nmaterial.Diffuse = diffuse; // Set the diffuse color
newton[N].ngravity = true; // Turn the particle on
N += 1; // Increase our particle counter
}
}

public void Add_NBody(Mesh mesh, Vector3 position, Vector3 acceleration, Color diffuse, float radius, Boolean status)
{
if (N < Max)
{
newton[N].nradius = radius; // Pass the radius
newton[N].nmass = (radius * radius) * MC; // Turn the radius into mass
newton[N].ncutoff = (radius * radius) + radius;// * (newton[i].nradius + newton[i].nradius); // Set the gravity cutoff distance
newton[N].nmesh = mesh; // Set the mesh
newton[N].nposition = position; // Set the mesh position
newton[N].nacceleration += acceleration; // Define the acceleration
newton[N].nmaterial.Diffuse = diffuse; // Set the diffuse color
newton[N].ngravity = status; // Turn the particle on
N += 1; // Increase our particle counter
}
}

// This method allows us to delete a particle
public void Delete_NBody(Int32 ndex)
{
if (N > 0) // Providing we have items to work with
{
for (Int32 x = ndex; x <= N; x++) // loop through each one at the position we want to delete
{
newton[x] = newton[x + 1]; // And copy the one ahead of it
}
N -= 1; // Decrement our counter
}
}

// This method allows us to turn off/on a particle by passing off(False) or on(True) to it
public void Toggle(Int32 ndex, Boolean status)
{
newton[ndex].ngravity = status;
}

// This method calculates the gravitation on each particle, then updates the position
public void Update()
{
#region process gravity
if (N > 0) // If we have particles to process
{
for (Int32 i = 0; i < N; i++) // Loop through our particles and update the positions
{
newton[i].nposition += newton[i].nacceleration;
}
for (Int32 i = 0; i < N; i++) // Go though our particles
{
// When we're ready, on this line we will move the position + acceleration bit in the loop above
for (Int32 ii = 0; ii < N; ii++) // Go through our particles
{
if (i != ii) // If the focus(i) and target(ii) particles aren't the same
{
if (newton[i].ngravity != false) // If our particle can calculate gravity
{
float d = v3dist(newton[i].nposition, newton[ii].nposition); // Get the distance between them
if (v3collision(i,ii, d) == false) // If we're greater than the cutoff distance
{
float g = v3grav(newton[ii].nmass, newton[i].nposition, newton[ii].nposition); // Get the gravitational force
Vector3 vd = v3direction(newton[i].nposition, newton[ii].nposition, d); // get a vector representing a normalized direction to our target
newton[i].nacceleration += new Vector3(vd.X * g, vd.Y * g, vd.Z * g); // calculate our acceleration
}
}
}
}
}
}
#endregion
}

// This method renders our particles
public void Render(Device device)
{
for (Int32 i = 0; i < N; i++) // Go through each particle
{
if (newton[i].nmass != 0) // Check to make sure it isn't blank
{
device.Transform.World = Matrix.Translation(newton[i].nposition); // Position our particle
device.Material = newton[i].nmaterial; // Apply its material
newton[i].nmesh.DrawSubset(0); // Draw it
}
}
}

// This method calculates the gravity
public float v3grav(float mass, Vector3 object1, Vector3 object2)
{
// this function will calculate true gravity between 2 objects
float dist = (float)v3dist(object1, object2); // Get the distance between the 2 points
float gf = (GC * mass); // Get the gravitational force
return gf / (dist * GD); // Return the gravitational force after dividing it by r2 and scaling it
}

// This method calculates a scalar vector toward our target
public Vector3 v3direction(Vector3 object1, Vector3 object2, float d)
{
float x = (object1.X - object2.X); // Get our x distance
float y = (object1.Y - object2.Y); // Get our y distance
float z = (object1.Z - object2.Z); // Get our z distance
return new Vector3(-(x / d), -(y / d), -(z / d)); // Return our vector
}

// Get the distance between 2 points
public float v3dist(Vector3 object1, Vector3 object2)
{
Double x = (object1.X - object2.X) * (object1.X - object2.X); // Get X
Double y = (object1.Y - object2.Y) * (object1.Y - object2.Y); // Get Y
Double z = (object1.Z - object2.Z) * (object1.Z - object2.Z); // Get Z
float dist = (float)(x + y + z); // Get distance
return dist; // Return distance
}

// Returns true if we have a collision with the two particles in question using sphere bound detection
public Boolean v3collision(Int32 object1, Int32 object2, float dist)
{
float collisiondistance = newton[object1].ncutoff + newton[object2].ncutoff; // The collision distance is the sum of both particles cutoffs, while not exact it works
if (dist <= collisiondistance) // If we're closer than our colision distance, we're colliding
{
return true; // return true
}
else
{
return false; // return false
}
}

public struct n_body
{
public Mesh nmesh;
public float ncutoff;
public Vector3 nposition;
public Vector3 nacceleration;
public Material nmaterial;
public float nradius;
public float nmass;
public bool ngravity;
}
}
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this