# What are some algorithms that will allow me to simulate planetary physics?

I'm interested in doing a "Solar System" simulator that will allow me to simulate the rotational and gravitational forces of planets and stars.

I'd like to be able to say, simulate our solar system, and simulate it across varying speeds (ie, watch Earth and other planets rotate around the sun across days, years, etc). I'd like to be able to add planets and change planets mass, etc, to see how it would effect the system.

Does anyone have any resources that would point me in the right direction for writing this sort of simulator?

Are there any existing physics engines which are designed for this purpose?

## Answers

It's everything here and in general, everything that Jean Meeus has written.

You need to know and understand Newton's Law of Universal Gravitation and Kepler's Laws of Planetary Motion. These two are simple and I'm sure you've heard about them, if not studied them in high school. Finally, if you want your simulator to be as accurate as possible, you should familiarize yourself with the n-Body problem.

You should start out simple. Try making a Sun object and an Earth object that revolves around it. That should give you a very solid start and it's fairly easy to expand from there. A planet object would look something like:

Class Planet { float x; float y; float z; // If you want to work in 3D double velocity; int mass; }

Just remember that F = MA and the rest just just boring math :P

This is a great tutorial on N-body problems in general.

http://www.artcompsci.org/#msa

It's written using Ruby but pretty easy to map into other languages etc. It covers some of the common integration approaches; Forward-Euler, Leapfrog and Hermite.

You might want to take a look at Celestia, a free space simulator. I believe that you can use it to create fictitious solar systems and it is open source.

All you need to implement is proper differential equation (Keplers law) and using Runge-Kutta. (at lest this worked for me, but there are probably better methods)

There are loads of such simulators online.

Here is one simple one implemented in 500lines of c code. (montion algorhitm is much less) http://astro.berkeley.edu/~dperley/programs/ssms.html.

Also check this: http://en.wikipedia.org/wiki/Kepler_problem http://en.wikipedia.org/wiki/Two-body_problem http://en.wikipedia.org/wiki/N-body_problem

In physics this is known as the N-Body Problem. It is famous because you can not solve this by hand for a system with more than three planets. Luckily, you can get approximate solutions with a computer very easily.

A nice paper on writing this code from the ground up can be found here.

However, I feel **a word of warning** is important here. You may not get the results you expect. If you want to see how:

- the mass of a planet affects its orbital speed around the Sun, cool. You will see that.
- the different planets interact with each other, you will be bummed.

**The problem is this.**

Yeah, modern astronomers are concerned with how Saturn's mass changes the Earth's orbit around the Sun. But this is a VERY minor effect. If you are going to plot the path of a planet around the Sun, it will hardly matter that there are other planets in the Solar System. The Sun is so big it will drown out all other gravity. The only exceptions to this are:

- If your planets have very elliptical orbits. This will cause the planets to potentially get closer together, so they interact more.
- If your planets are almost the exact same distance from the Sun. They will interact more.
- If you make your planets so comically large they compete with the Sun for gravity in the outer Solar System.

To be clear, yes, you will be able to calculate some interactions between planets. But no, these interactions will not be significant to the naked eye if you create a realistic Solar System.

Try it though, and find out!

Check out nMod, a n-body modeling toolkit written in C++ and using OpenGL. It has a pretty well populated solar system model that comes with it and it should be easy to modify. Also, he has a pretty good wiki about n-body simulation in general. The same guy who created this is also making a new program called Moody, but it doesn't appear to be as far along.

In addition, if you are going to do n-body simulations with more than just a few objects, you should really look at the fast multipole method (also called the fast multipole algorithm). It can the reduce number of computations from O(N^2) to O(N) to really speed up your simulation. It is also one of the top ten most successful algorithms of the 20th century, according to the author of this article.

**Algorithms to simulate planetary physics.**

Here is an implementation of the Keppler parts, in my Android app. The main parts are on my web site for you can download the whole source: http://www.barrythomas.co.uk/keppler.html

This is my method for drawing the planet at the 'next' position in the orbit. Think of the steps like stepping round a circle, one degree at a time, on a circle which has the same period as the planet you are trying to track. Outside of this method I use a global double as the step counter - called dTime, which contains a number of degrees of rotation.

The key parameters passed to the method are, dEccentricty, dScalar (a scaling factor so the orbit all fits on the display), dYear (the duration of the orbit in Earth years) and to orient the orbit so that perihelion is at the right place on the dial, so to speak, dLongPeri - the Longitude of Perihelion.

**drawPlanet:**

public void drawPlanet (double dEccentricity, double dScalar, double dYear, Canvas canvas, Paint paint, String sName, Bitmap bmp, double dLongPeri) { double dE, dr, dv, dSatX, dSatY, dSatXCorrected, dSatYCorrected; float fX, fY; int iSunXOffset = getWidth() / 2; int iSunYOffset = getHeight() / 2; // get the value of E from the angle travelled in this 'tick' dE = getE (dTime * (1 / dYear), dEccentricity); // get r: the length of 'radius' vector dr = getRfromE (dE, dEccentricity, dScalar); // calculate v - the true anomaly dv = 2 * Math.atan ( Math.sqrt((1 + dEccentricity) / (1 - dEccentricity)) * Math.tan(dE / 2) ); // get X and Y coords based on the origin dSatX = dr / Math.sin(Math.PI / 2) * Math.sin(dv); dSatY = Math.sin((Math.PI / 2) - dv) * (dSatX / Math.sin(dv)); // now correct for Longitude of Perihelion for this planet dSatXCorrected = dSatX * (float)Math.cos (Math.toRadians(dLongPeri)) - dSatY * (float)Math.sin(Math.toRadians(dLongPeri)); dSatYCorrected = dSatX * (float)Math.sin (Math.toRadians(dLongPeri)) + dSatY * (float)Math.cos(Math.toRadians(dLongPeri)); // offset the origin to nearer the centre of the display fX = (float)dSatXCorrected + (float)iSunXOffset; fY = (float)dSatYCorrected + (float)iSunYOffset; if (bDrawOrbits) { // draw the path of the orbit travelled paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); // get the size of the rect which encloses the elliptical orbit dE = getE (0.0, dEccentricity); dr = getRfromE (dE, dEccentricity, dScalar); rectOval.bottom = (float)dr; dE = getE (180.0, dEccentricity); dr = getRfromE (dE, dEccentricity, dScalar); rectOval.top = (float)(0 - dr); // calculate minor axis from major axis and eccentricity // http://www.1728.org/ellipse.htm double dMajor = rectOval.bottom - rectOval.top; double dMinor = Math.sqrt(1 - (dEccentricity * dEccentricity)) * dMajor; rectOval.left = 0 - (float)(dMinor / 2); rectOval.right = (float)(dMinor / 2); rectOval.left += (float)iSunXOffset; rectOval.right += (float)iSunXOffset; rectOval.top += (float)iSunYOffset; rectOval.bottom += (float)iSunYOffset; // now correct for Longitude of Perihelion for this orbit's path canvas.save(); canvas.rotate((float)dLongPeri, (float)iSunXOffset, (float)iSunYOffset); canvas.drawOval(rectOval, paint); canvas.restore(); } int iBitmapHeight = bmp.getHeight(); canvas.drawBitmap(bmp, fX - (iBitmapHeight / 2), fY - (iBitmapHeight / 2), null); // draw planet label myPaint.setColor(Color.WHITE); paint.setTextSize(30); canvas.drawText(sName, fX+20, fY-20, paint); }

The method above calls two further methods which provide values of E (the mean anomaly) and r, the length of the vector at the end of which the planet is found.

**getE:**

public double getE (double dTime, double dEccentricity) { // we are passed the degree count in degrees (duh) // and the eccentricity value // the method returns E double dM1, dD, dE0, dE = 0; // return value E = the mean anomaly double dM; // local value of M in radians dM = Math.toRadians (dTime); int iSign = 1; if (dM > 0) iSign = 1; else iSign = -1; dM = Math.abs(dM) / (2 * Math.PI); // Meeus, p 206, line 110 dM = (dM - (long)dM) * (2 * Math.PI) * iSign; // line 120 if (dM < 0) dM = dM + (2 * Math.PI); // line 130 iSign = 1; if (dM > Math.PI) iSign = -1; // line 150 if (dM > Math.PI) dM = 2 * Math.PI - dM; // line 160 dE0 = Math.PI / 2; // line 170 dD = Math.PI / 4; // line 170 for (int i = 0; i < 33; i++) // line 180 { dM1 = dE0 - dEccentricity * Math.sin(dE0); // line 190 dE0 = dE0 + dD * Math.signum((float)(dM - dM1)); dD = dD / 2; } dE = dE0 * iSign; return dE; }

**getRfromE:**

public double getRfromE (double dE, double dEccentricty, double dScalar) { return Math.min(getWidth(), getHeight()) / 2 * dScalar * (1 - (dEccentricty * Math.cos(dE))); }

It looks like it is very hard and requires strong knowledge of physics but in fact it is very easy, you need to know only 2 formulas and basic understanding of vectors:

Attractional force (or gravitational force) between planet1 and planet2 with mass m1 and m2 and distance between them d: Fg = G*m1*m2/d^2; Fg = m*a. G is a constant, find it by substituting random values so that acceleration "a" will not be too small and not too big approximately "0.01" or "0.1".

If you have total vector force which is acting on a current planet at that instant of time, you can find instant acceleration a=(total Force)/(mass of current planet). And if you have current acceleration and current velocity and current position, you can find new velocity and new position

If you want to look it real you can use following supereasy algorythm (pseudocode):

int n; // # of planets Vector2D planetPosition[n]; Vector2D planetVelocity[n]; // initially set by (0, 0) double planetMass[n]; while (true){ for (int i = 0; i < n; i++){ Vector2D totalForce = (0, 0); // acting on planet i for (int j = 0; j < n; j++){ if (j == i) continue; // force between some planet and itself is 0 Fg = G * planetMass[i] * planetMass[j] / distance(i, j) ^ 2; // Fg is a scalar value representing magnitude of force acting // between planet[i] and planet[j] // vectorFg is a vector form of force Fg // (planetPosition[j] - planetPosition[i]) is a vector value // (planetPosition[j]-planetPosition[i])/(planetPosition[j]-plantetPosition[i]).magnitude() is a // unit vector with direction from planet[i] to planet[j] vectorFg = Fg * (planetPosition[j] - planetPosition[i]) / (planetPosition[j] - planetPosition[i]).magnitude(); totalForce += vectorFg; } Vector2D acceleration = totalForce / planetMass[i]; planetVelocity[i] += acceleration; } // it is important to separate two for's, if you want to know why ask in the comments for (int i = 0; i < n; i++) planetPosition[i] += planetVelocity[i]; sleep 17 ms; draw planets; }

If you're simulating physics, I highly recommend Box2D. It's a great physics simulator, and will really cut down the amount of boiler plate you'll need, with physics simulating.

Fundamentals of Astrodynamics by Bate, Muller, and White is still required reading at my alma mater for undergrad Aerospace engineers. This tends to cover the orbital mechanics of bodies in Earth orbit...but that is likely the level of physics and math you will need to start your understanding.

+1 for @Stefano Borini's suggestion for "everything that Jean Meeus has written."

Dear Friend here is the graphics code that simulate solar system Kindly refer through it /*Arpana*/ #include<stdio.h> #include<graphics.h> #include<conio.h> #include<math.h> #include<dos.h> void main() { int i=0,j=260,k=30,l=150,m=90; int n=230,o=10,p=280,q=220; float pi=3.1424,a,b,c,d,e,f,g,h,z; int gd=DETECT,gm; initgraph(&gd,&gm,"c:\tc\bgi"); outtextxy(0,10,"SOLAR SYSTEM-Appu"); outtextxy(500,10,"press any key..."); circle(320,240,20); /* sun */ setfillstyle(1,4); floodfill(320,240,15); outtextxy(310,237,"sun"); circle(260,240,8); setfillstyle(1,2); floodfill(258,240,15); floodfill(262,240,15); outtextxy(240,220,"mercury"); circle(320,300,12); setfillstyle(1,1); floodfill(320,298,15); floodfill(320,302,15); outtextxy(335,300,"venus"); circle(320,160,10); setfillstyle(1,5); floodfill(320,161,15); floodfill(320,159,15); outtextxy(332,150, "earth"); circle(453,300,11); setfillstyle(1,6); floodfill(445,300,15); floodfill(448,309,15); outtextxy(458,280,"mars"); circle(520,240,14); setfillstyle(1,7); floodfill(519,240,15); floodfill(521,240,15); outtextxy(500,257,"jupiter"); circle(169,122,12); setfillstyle(1,12); floodfill(159,125,15); floodfill(175,125,15); outtextxy(130,137,"saturn"); circle(320,420,9); setfillstyle(1,13); floodfill(320,417,15); floodfill(320,423,15); outtextxy(310,400,"urenus"); circle(40,240,9); setfillstyle(1,10); floodfill(38,240,15); floodfill(42,240,15); outtextxy(25,220,"neptune"); circle(150,420,7); setfillstyle(1,14); floodfill(150,419,15); floodfill(149,422,15); outtextxy(120,430,"pluto"); getch(); while(!kbhit()) /*animation*/ { a=(pi/180)*i; b=(pi/180)*j; c=(pi/180)*k; d=(pi/180)*l; e=(pi/180)*m; f=(pi/180)*n; g=(pi/180)*o; h=(pi/180)*p; z=(pi/180)*q; cleardevice(); circle(320,240,20); setfillstyle(1,4); floodfill(320,240,15); outtextxy(310,237,"sun"); circle(320+60*sin(a),240-35*cos(a),8); setfillstyle(1,2); pieslice(320+60*sin(a),240-35*cos(a),0,360,8); circle(320+100*sin(b),240-60*cos(b),12); setfillstyle(1,1); pieslice(320+100*sin(b),240-60*cos(b),0,360,12); circle(320+130*sin(c),240-80*cos(c),10); setfillstyle(1,5); pieslice(320+130*sin(c),240-80*cos(c),0,360,10); circle(320+170*sin(d),240-100*cos(d),11); setfillstyle(1,6); pieslice(320+170*sin(d),240-100*cos(d),0,360,11); circle(320+200*sin(e),240-130*cos(e),14); setfillstyle(1,7); pieslice(320+200*sin(e),240-130*cos(e),0,360,14); circle(320+230*sin(f),240-155*cos(f),12); setfillstyle(1,12); pieslice(320+230*sin(f),240-155*cos(f),0,360,12); circle(320+260*sin(g),240-180*cos(g),9); setfillstyle(1,13); pieslice(320+260*sin(g),240-180*cos(g),0,360,9); circle(320+280*sin(h),240-200*cos(h),9); setfillstyle(1,10); pieslice(320+280*sin(h),240-200*cos(h),0,360,9); circle(320+300*sin(z),240-220*cos(z),7); setfillstyle(1,14); pieslice(320+300*sin(z),240-220*cos(z),0,360,7); delay(20); i++; j++; k++; l++; m++; n++; o++; p++; q+=2; } getch(); }