Sindbad~EG File Manager

Current Path : /usr/home/beeson/ThreeBody/ThreeBodyProblem/
Upload File :
Current File : /usr/home/beeson/ThreeBody/ThreeBodyProblem/ode3.c

/* Numerical integration of a function of one variable using
Runge-Kutta solver rk4 similar to the one in Numerical Recipes */
/* M. Beeson, for MathXpert */
/* code last modified 12.20.95
   1.29.98, TRIGCALC_DLL etc.
   3.25.01  changed hmin in numint to be nonzero
            and changed TINY  to 1.0e-10 instead of 1.0e-30
   5.6.13 made odeint2 static
*/


#include <string.h>
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include "ode3.h"
#include "svgGraph3.h"
#include "uthash.h"
#include "ThreeBodyDoc.h"
#include "leapfrog.h"

#define EPS 1.0e-6      // was 6
#define ODETINY 1.0e-10   // was 10

static double tvalues[MAXSTEPS];
static double xvalues[MAXBODIES][MAXSTEPS];
static double yvalues[MAXBODIES][MAXSTEPS];
static double pvalues[MAXBODIES][MAXSTEPS];
static double qvalues[MAXBODIES][MAXSTEPS];

// Reset all arrays to zero.
void reset_arrays(void) {
    memset(tvalues, 0, sizeof(tvalues));
    memset(xvalues, 0, sizeof(xvalues));
    memset(yvalues, 0, sizeof(yvalues));
    memset(pvalues, 0, sizeof(pvalues));
    memset(qvalues, 0, sizeof(qvalues));
}

/* The original source of the numerical code is Numerical Recipes,
which uses 'vectors' so indices start at 1.  Since that code is complicated,
and works fine, I continued to pass vectors to it, but the price of not tinkering
with the Numerical Recipes code is vigilance about vectors versus 0-based arrays.
*/

/*_______________________________________________________________________*/
/* This function solves the differential equations but does not draw the solution.
Instead, it writes the computed values into static arrays of doubles defined above.
*/
static int odeint22( double *ystart, /* ystart[1..nvar] are the initial values     */
            int nvar,       /* number of dependent variables  = 4*nbodies  */
            double x1,      /* starting value of independent variable      */
            double x2,      /* ending value of independent variable        */
            double eps,     /* accuracy desired                            */
            double h1,      /* guessed first stepsize                      */
            double hmin,    /* minimum allowed stepsize (can be zero)      */
            int *nok,       /* number of good steps taken                  */
            int *nbad,      /* number of bad, but retried and fixed, steps */
            double *xptr,   /* pointer to value of independent variable    */
            double xtol,    /* don't make lines more than this long        */
            double ytol,
            double *mass,   /* array of nbodies masses                     */
            char *integrationMethod   /* rk4 or leapfrog                   */
          )
{ int nstp,i,err;
  double x,hnext,hdid,h;
  int nbodies = nvar/4;
  assert(nvar %4 == 0);
  if(nbodies==3)
    printf("masses are %lf, %lf, and %lf\n", mass[1], mass[2], mass[3]);
  double *yscal,*y,*dydx;
  h=(x2 > x1) ? fabs(h1) : -fabs(h1);
  if(h == 0.0)
    return 0;  /* wrong input, nothing to draw; but not an error. */
  yscal=vector(1,nvar);
  y=vector(1,nvar);
  dydx=vector(1,nvar);
  x=x1;
  int leapfrogflag = !strcmp(integrationMethod, "leapfrog");
   // making the default "rk4"
  *nok = (*nbad) = 0;
  for (i=1;i<=nvar;i++)
     y[i]=ystart[i];
  for(int k = 0; k<nbodies;k++)
     {  // starting position and velocity of the kth body
        // presently all in the 1-based array y
        // Let's put them in clearly-labeled 0-based arrays.
        // xvalues etc. are 0-based arrays, y is a 1-based vector
       xvalues[k][0] = y[1+2*k];            // x-coordinate of k-th body, k starting at 0
       yvalues[k][0] = y[2+2*k];            // x-velocity of k-th body, k starting at 0
       pvalues[k][0] = y[1+2*nbodies+2*k];  // x-velocity of k-th body, k starting at 0
       qvalues[k][0] = y[2+2*nbodies+2*k];  // y-velocity of k-th body, k starting at 0
       printf("body %d: %.10lf, %.10lf, %.10lf, %.10lf\n", k,xvalues[k][0], yvalues[k][0], pvalues[k][0],qvalues[k][0]);
     }
  for (nstp=0;nstp<MAXSTEPS;nstp++)
     { tvalues[nstp] = x;
       derivs(nbodies,x,y,dydx,xptr,mass);
       for (i=1;i<=nvar;i++)
          yscal[i]=fabs(y[i])+fabs(dydx[i]*h)+ODETINY;
       if(leapfrogflag)
          h = 0.001; // added 3.28.25 for use with leapfrog integration
                  // not needed with rkqc because rkqc adjusts it internally
                  // but leapfrog_step does not, so without this, nothing
                  // ever increases it and we draw only a millimeter of solution.
       if ((x+h-x2)*(x+h-x1) > 0.0)
          h=x2-x;
             //  rkqc is numerically inadequate for the figure eight problem!
             //  So we use Leapfrog integration.   See secion 16.6 of Third Edition
             //  of Numerical Recipes in C,  or the Wikipedia article on Leapfrog Integration.
             //  But rkqc is more accurate in many simple examples.  So we provide both.
       if(leapfrogflag)
          err = leapfrog_step(y,dydx,nvar,&x,h,eps,yscal,&hdid,&hnext,xptr,xtol,ytol,mass);
       else
          err = rkqc(y,dydx,nvar,&x,h,eps,yscal,&hdid,&hnext,xptr,xtol,ytol,mass);
       if (err != 0)
          printf("integration failed\n");
       // printf("step %d, t = %.6f, hdid = %.10f, hnext = %.10f \n", nstp, x, hdid, hnext);
       if(err)
          { free_vector(dydx,1);
            free_vector(y,1);
            free_vector(yscal,1);
            if(err == 5)
               return 0;  /* failure of deval in rkqc is not an error in odeint */
            return err;
          }
       if (hdid == h)
          ++(*nok);
       else
          ++(*nbad);
       for(int k = 0; k<nbodies;k++)
         {  xvalues[k][nstp] = y[1+2*k];
            yvalues[k][nstp] = y[2+2*k];
            pvalues[k][nstp] = y[1+2*nbodies+2*k];
            qvalues[k][nstp] = y[2+2*nbodies+2*k];
            // starting position and velocity of the kth body
         }
      // #define ENERGY
       #ifdef ENERGY
          double E = 0.0;
         
         // Kinetic energy
         for (int ell = 0; ell < nbodies; ell++) {
             E += 0.5 * mass[ell] * (pvalues[ell][nstp] * pvalues[ell][nstp] + qvalues[ell][nstp] * qvalues[ell][nstp]);
         }

         // Potential energy (each pair once)
         for (int i = 0; i < nbodies; i++) {
             for (int j = i + 1; j < nbodies; j++) {
                 double dx = xvalues[i][nstp] - xvalues[j][nstp];
                 double dy = yvalues[i][nstp] - yvalues[j][nstp];
                 double r = hypot(dx, dy);
                 E -= mass[i] * mass[j] / r;
             }
         }
         if(nstp % 10000 == 0)
         printf("E = %.10lf\n", E);
       #endif

       if (x >= x2)  /* are we done?  In this program x2 > x1 always */
          {   // We're done, no need to write xvalues[k][nstp+1]
            free_vector(dydx,1);
            free_vector(y,1);
            free_vector(yscal,1);
             printf("Used %d steps\n",nstp);
            return 0;
          }
       if (fabs(hnext) <= hmin)
          { free_vector(yscal,1);
            free_vector(dydx,1);
            free_vector(y,1);
            return 2; /* step size too small */
            /* 11.28.91, set hmin to 0.0 so we should never hit this error */
            /*  9.9.93,  set hmin nonzero:  example, y'=1/y.  The solution
                is really y= \sqrt (2x-1), but the step size goes to zero as
                we approach the point (0.5, 0), and the program hangs up. */
          }
       h=hnext;
     }
  free_vector(yscal,1);
  free_vector(dydx,1);
  free_vector(y,1);
  printf("Completed all allowed %d steps\n",nstp);
  return 3; /* too many steps */
}


// we need space to store the solution.  There will
// 4*DIM*nbodies  variables.  space required will be
// 4*DIM*nbodies*MAXSTEPS.  if DIM is 2 and nbodies is 12 and MAXSTEPS is 10000
// that comes to one million,  which is not too much.  So let's just
// allocate it statically so we can see it in the debugger.

double values[4*MAXBODIES+1][2];
double times[MAXSTEPS];


void computeSolution(PDOCDATA3 pDocData)
// pDocData must already be initialized.
// use odeint22 to compute the solution.
{
   double ystart[MAXBODIES*4+1];/*  the initial values*/
   int i;
   int nbodies = pDocData->nbodies;
   int nvar = 4*nbodies;
   for(i=0;i< nbodies;i++)
     {  // set position variables
        // there are 2*nbodies position and 2*nbodies velocity variables
        // we list all the position variable first, then the velocities
        // remember ystart is 1-based
        ystart[2*i+1] = pDocData->bodies[i].x0;
        ystart[2*i+2] = pDocData->bodies[i].y0;
        // set velocity variables
        ystart[2*nbodies+ 2*i+1] = pDocData->bodies[i].p0;
        ystart[2*nbodies+ 2*i+2] = pDocData->bodies[i].q0;
     }
   double starttime  = 0.0;
   double endtime = pDocData->tmax;    /* ending value of independent variable */
   double eps = 1e-7;   /* accuracy desired */
   // double eps = 1.0e-10;  in MathXpert; but doesn't work on comet and slingshot in ThreeBody
   //  1e-8  doesn't draw the whole slingshot and 1e-9 only draws a few millimeters
   double h1 = 0.0001;   /* guessed first stepsize */
   double hmin = 0;  /* minimum allowed stepsize (can be zero) */
   int nok;    /* number of good steps taken */
   int nbad;   /* number of bad, but retried and fixed, steps */
   double xtol = 0.001;
   double ytol = 0.001;
   double mass[MAXBODIES];
   for(i=0;i<pDocData->nbodies;i++)
      mass[i] = pDocData->bodies[i].mass;  // 0-based indexing
   //int err =
   odeint22(ystart, nvar, starttime,endtime, eps, h1,hmin,
                     &nok, &nbad, times,
                     xtol, ytol, mass,
                     pDocData->integrationMethod);
   return;  // ignoring err for now
}
/*__________________________________________________________*/
#define RGB(r,g,b)  ((unsigned int)(r) | ((unsigned int)(g) << 8) | ((unsigned int)(b) << 16))

void drawAxes(PDOCDATA3 pDocData)
// draw the axes on the graph
{ set_graphpencolor(RGB(128,128,128));
  set_world(pDocData->xmin,pDocData->xmax, pDocData->ymin,pDocData->ymax);
  begin_path();
  move_to(pDocData->xmin,0);
  line_to(pDocData->xmax,0);  /* draw the x-axis (if visible) */
  move_to(0,pDocData->ymin);
  move_to(0,pDocData->ymin);
  line_to(0,pDocData->ymax);  /* draw the y-axis (if visible) */
  end_path();
}
/*__________________________________________________________*/
int drawSolution(PDOCDATA3 pDocData)
// send the solution in SVG form to the browser
// return 0 for success, 1 for error.
// numerical error solving is considered "collision" and
// is not an error here.
// Assumes the data for the solution are in the static arrays
// defined near the top of this file.  Also assumes
// theDevice has been initialized to the correct viewport
{
   // set up world coordinates
   int i,k;
   int nbodies = pDocData->nbodies;
   set_world(pDocData->xmin,pDocData->xmax, pDocData->ymin,pDocData->ymax);
   for(i=0;i<nbodies;i++)
      {  body theBody = pDocData->bodies[i];
         int color = theBody.color;
         // double mass = theBody.mass;
         set_graphpencolor(color);
         double tmax = pDocData->tmax;
         char attr[64];
         sprintf(attr,"body=\"%d\"",i+1);  // so the labels with start with 1 
         // draw the path of the i-th body now
         begin_path2(attr);  // leaves it ready for 'M' command
         move_to(xvalues[i][0],yvalues[i][0]);
         for (k = 1; k < MAXSTEPS && tvalues[k] > 0.0 && tvalues[k] <= tmax; k++)
            line_to(xvalues[i][k], yvalues[i][k]);
         end_path();
      }
   return 0;
}

#undef MAXSTEPS
#undef ODETINY

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists