Sindbad~EG File Manager

Current Path : /home/beeson/cgraph/
Upload File :
Current File : //home/beeson/cgraph/ode.c

/* M. Beeson */
/* ode solver for Mathpert */
/* adapted from Numerical Recipes in C,
   files odeint.c, rk4.c, rkqc.c, nrutil.c
8.27.89 original date
11.7.95 last modified before release of Mathpert 1.06
6.14.98 modified
3.25.01 changed ODETINE to 1.0e-10 instead of 1.0e-30
2.24.24 changed include cgraph. to svgGraph.h and svgDevice to svgDevice
2.26.24 added include graphstr.h
3.23.24  added begin_path() and end_path() calls in ode.
*/

#include <math.h>
#include <stdlib.h>
#include "globals.h"
#include "graphstr.h"
#include "svgGraph.h"
#include "userint.h"
#include "ode.h"
#include "heap.h"
#include "deval.h"
#include "rk.h"

/*_________________________________________________________________*/
#define MAXSTP 10000
#define ODETINY 1.0e-10

/* This function began with the 'odeint' from p. 579 of Numerical Recipes,
which is a "Runge-Kutta driver with adaptive stepsize control".  I haven't
modified the numerical analysis, but removed the provision for saving the
results (you could put it back: it was all the parts beginning "if (kmax > 0)"),
changed the error handling, and introduced graphics.  I also changed all
'float' to 'double'.  The function should be called only after set_device
has been done, so that world coordinates have been set up appropriately.

The code in Numerical Recipes copies the final values into 'ystart' before
exiting.  This is no good for MATHPERT, because if the user zooms or changes
a parameter, you want to start again with the same initial conditions; so
I took this line out.

You can integrate a system with any number of variables, but you can
only graph the first two.  This is needed to use this to graph higher-order
linear ode's.  It may be interesting in other situations too.
*/

/* return value 0 is success;
   1,2 are step size too small;
   3 is too many steps;
   0 if interrupted by user's keypress or mouse (this is considered success)
*/

int odeint( double *ystart, /* ystart[1..n] are the initial values         */
            int nvar,       /* number of dependent variables               */
            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 */
            term *f,
            double *xptr,   /* pointer to value of independent variable    */
            double **yptr,  /* array of pointers, dimension nvar,
                               legal indices starting from 1               */
            double xtol,    /* don't make lines more than this long        */
            double ytol
          )
{ int nstp,i,err;
  double x,hnext,hdid,h;
  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;

  *nok = (*nbad) = 0;
  for (i=1;i<=nvar;i++)
     y[i]=ystart[i];
  move_to( y[1], y[2]);
  for (nstp=1;nstp<=MAXSTP;nstp++)
     { derivs(f,nvar,x,y,dydx,xptr,yptr);
       for (i=1;i<=nvar;i++)
          yscal[i]=fabs(y[i])+fabs(dydx[i]*h)+ODETINY;
       line_to( y[1], y[2] );
       if ((x+h-x2)*(x+h-x1) > 0.0)
          h=x2-x;
       err = rkqc(y,dydx,nvar,&x,h,eps,yscal,&hdid,&hnext,f,xptr,yptr,xtol,ytol);
       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);
       if ((x-x2)*(x2-x1) >= 0.0)  /* are we done? */
          { line_to( y[1], y[2]);   /* last line segment */
            free_vector(dydx,1);
            free_vector(y,1);
            free_vector(yscal,1);
            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= �(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);
  return 3; /* too many steps */
}

#undef MAXSTP
#undef ODETINY
/*______________________________________________________________________*/
int ode(double *ystart, /* ystart[1..n] are the initial values */
        int nvar,    /* number of dependent variables */
        double x1,    /* starting value of independent variable */
        double x2,    /* ending value of independent variable */
        term x,      /* the independent variable */
        term *y,     /* array of dependent variables */
        term *f,    /*  array of symbolic right-hand sides in y' = f(x,y) */
        double eps,   /* accuracy desired */
        double h1,    /* guessed first step size */
        double xtol, /* world coordinates of four pixels in x direction */
        double ytol  /* don't make lines more than four pixels wide or high */
       )
/* graphically solves the system y' = f(x,y)  by calling 'odeint' above */
/* Returns 0 for success.  Return value 2 means the step size became
way too small; probably that means hitting a natural 'endpoint' of the
solution, as in the example y' = 1/y  starting at (1,1), which has
solution y = sqrt(2x-1) and a natural endpoint at (0.5,1).
Return value 3 means too many steps.
Return value 5 means deval failed, as in y' = sqrt(x^2-1)
*/
{ int ans;
  double hmin =  fabs(x2-x1) * 1.0e-12;  /* minimum allowed stepsize */
  int nok;    /* number of good steps taken */
  int nbad;   /* number of bad, but retried and fixed, steps */
  double *xptr = (double *) x.args;
  double **yptr;
  int i;
  yptr = (double **) callocate(nvar+1, sizeof(double *));  // changed nvar to nvar + 1 on 9.29.13
  if(!yptr)
     nospace();
  --yptr;  /* so valid references are 1 to nvar */
  for(i=1;i<=nvar;i++)
      yptr[i] = (double *) (y[i].args);
      /* pointer to value of y[i] on value list */
  begin_path();
  ans = odeint( ystart,nvar,x1,x2, eps,h1,hmin,&nok,&nbad,f,xptr,yptr,xtol,ytol);
  end_path();
  free2(yptr+1);
  return ans;
}
/*_____________________________________________________________________*/

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