// orbit - Program to compute the orbit of a comet. #include "NumMeth.h" void gravrk( double x[], double t, double param[], double deriv[] ); void rk4( double x[], int nX, double t, double tau, void (*derivsRK)(double x[], double t, double param[], double deriv[]), double param[]); void rka( double x[], int nX, double& t, double& tau, double err, void (*derivsRK)(double x[], double t, double param[], double deriv[]), double param[]); void main() { //* Set initial position and velocity of the comet. double r0, v0; cout << "Enter initial radial distance (AU): "; cin >> r0; cout << "Enter initial tangential velocity (AU/yr): "; cin >> v0; double r[2+1], v[2+1], state[4+1], accel[2+1]; r[1] = r0; r[2] = 0; v[1] = 0; v[2] = v0; state[1] = r[1]; state[2] = r[2]; // Used by R-K routines state[3] = v[1]; state[4] = v[2]; int nState = 4; // Number of elements in state vector //* Set physical parameters (mass, G*M) const double pi = 3.141592654; double GM = 4*pi*pi; // Grav. const. * Mass of Sun (au^3/yr^2) double param[1+1]; param[1] = GM; double mass = 1.; // Mass of comet double adaptErr = 1.e-3; // Error parameter used by adaptive Runge-Kutta double time = 0; //* Loop over desired number of steps using specified // numerical method. cout << "Enter number of steps: "; int nStep; cin >> nStep; cout << "Enter time step (yr): "; double tau; cin >> tau; cout << "Choose a numerical method:" << endl; cout << "1) Euler, 2) Euler-Cromer, " << endl << "3) Runge-Kutta, 4) Adaptive R-K: "; int method; cin >> method; double *rplot, *thplot, *tplot, *kinetic, *potential; // Plotting variables rplot = new double [nStep+1]; thplot = new double [nStep+1]; tplot = new double [nStep+1]; kinetic = new double [nStep+1]; potential = new double [nStep+1]; int iStep; for( iStep=1; iStep<=nStep; iStep++ ) { //* Record position and energy for plotting. double normR = sqrt( r[1]*r[1] + r[2]*r[2] ); double normV = sqrt( v[1]*v[1] + v[2]*v[2] ); rplot[iStep] = normR; // Record position for plotting thplot[iStep] = atan2(r[2],r[1]); tplot[iStep] = time; kinetic[iStep] = 0.5*mass*normV*normV; // Record energies potential[iStep] = - GM*mass/normR; //* Calculate new position and velocity using desired method. if( method == 1 ) { accel[1] = -GM*r[1]/(normR*normR*normR); accel[2] = -GM*r[2]/(normR*normR*normR); r[1] += tau*v[1]; // Euler step r[2] += tau*v[2]; v[1] += tau*accel[1]; v[2] += tau*accel[2]; time += tau; } else if( method == 2 ) { accel[1] = -GM*r[1]/(normR*normR*normR); accel[2] = -GM*r[2]/(normR*normR*normR); v[1] += tau*accel[1]; v[2] += tau*accel[2]; r[1] += tau*v[1]; // Euler-Cromer step r[2] += tau*v[2]; time += tau; } else if( method == 3 ) { rk4( state, nState, time, tau, gravrk, param ); r[1] = state[1]; r[2] = state[2]; // 4th order Runge-Kutta v[1] = state[3]; v[2] = state[4]; time += tau; } else { rka( state, nState, time, tau, adaptErr, gravrk, param ); r[1] = state[1]; r[2] = state[2]; // Adaptive Runge-Kutta v[1] = state[3]; v[2] = state[4]; } } //* Print out the plotting variables: // thplot, rplot, potential, kinetic ofstream thplotOut("thplot.txt"), rplotOut("rplot.txt"), tplotOut("tplot.txt"), potentialOut("potential.txt"), kineticOut("kinetic.txt"); int i; for( i=1; i<=nStep; i++ ) { thplotOut << thplot[i] << endl; rplotOut << rplot[i] << endl; tplotOut << tplot[i] << endl; potentialOut << potential[i] << endl; kineticOut << kinetic[i] << endl; } delete [] rplot, thplot, tplot, kinetic, potential; } /***** To plot in MATLAB; use the script below ******************** load thplot.txt; load rplot.txt; load tplot.txt; load potential.txt; load kinetic.txt; %* Graph the trajectory of the comet. figure(1); clf; % Clear figure 1 window and bring forward polar(thplot,rplot,'+'); % Use polar plot for graphing orbit xlabel('Distance (AU)'); grid; pause(1) % Pause for 1 second before drawing next plot %* Graph the energy of the comet versus time. figure(2); clf; % Clear figure 2 window and bring forward totalE = kinetic + potential; % Total energy plot(tplot,kinetic,'-.',tplot,potential,'--',tplot,totalE,'-') legend('Kinetic','Potential','Total'); xlabel('Time (yr)'); ylabel('Energy (M AU^2/yr^2)'); ******************************************************************/