Difference between revisions of "RDYNLAB Code"

From New IAC Wiki
Jump to navigation Jump to search
(New page: The following files constitute the source code for RDYNLAB. They can be compiled with any source code intended to use the library functions or (preferably) compiled as a shared object ...)
 
 
Line 301: Line 301:
 
<pre><nowiki>
 
<pre><nowiki>
  
 +
/* RDLparticle.cpp: defines class for a particle */
 +
 +
#include <rdynlab.h>
 +
#include <math.h>
 +
 +
RDL_Particle::RDL_Particle(double qin, double min, const RDL_Vector &xin, const RDL_Vector &vin)
 +
{
 +
  q=qin;
 +
  m=min;
 +
  x=xin;
 +
  v=vin;
 +
}
 +
 +
RDL_Particle RDL_Particle::operator=(const RDL_Particle &param)
 +
{
 +
  q=param.q;
 +
  m=param.m;
 +
  x=param.x;
 +
  v=param.v;
 +
  return *this;
 +
}
 +
 +
double RDL_Particle::gamma(void)
 +
{
 +
  double s=length(v);
 +
  return 1./sqrt(1.-s*s/(RDL_CLIGHT*RDL_CLIGHT));
 +
}
 +
 +
double RDL_Particle::energy(void)
 +
{
 +
  return gamma()*m*RDL_CLIGHT*RDL_CLIGHT;
 +
}
 +
 +
double RDL_Particle::kinetic_energy(void)
 +
{
 +
  return (gamma()-1.0)*m*RDL_CLIGHT*RDL_CLIGHT;
 +
}
 +
 +
double RDL_Particle::rest_energy(void)
 +
{
 +
  return m*RDL_CLIGHT*RDL_CLIGHT;
 +
}
 +
 +
RDL_Vector RDL_Particle::momentum(void)
 +
{
 +
  return v*gamma()*m;
 +
}
 +
 +
ostream &operator<<(ostream &out, const RDL_Particle &p)
 +
{
 +
  out << "Current state of particle:\n";
 +
  out << "  mass:    " << p.m << "\n";
 +
  out << "  charge:  " << p.q << "\n";
 +
  out << "  position: " << p.x << "\n";
 +
  out << "  velocity: " << p.v << "\n";
 +
  return out;
 +
}
  
 
</nowiki></pre>
 
</nowiki></pre>
Line 310: Line 367:
  
 
<pre><nowiki>
 
<pre><nowiki>
 +
 +
/* RDLsolver.cpp: The main solver routine for the RDYNLAB package */
 +
 +
#include <rdynlab.h>
 +
#include <gsl/gsl_odeiv.h>
 +
#include <gsl/gsl_errno.h>
 +
#include <gsl/gsl_math.h>
 +
#include <gsl/gsl_diff.h>
 +
#include <math.h>
 +
#include <iostream>
 +
#include <iomanip>
 +
 +
int RDL_solver(RDL_Particle &p,
 +
              RDL_Vector (*force) (const RDL_Particle&, double),
 +
      double ti,
 +
      double dt,
 +
      int (*stopping_conditions) (const RDL_Particle&, double, int),
 +
      ostream &out)
 +
{
 +
  double y[6];
 +
  double t;
 +
  int status,iter,retval;
 +
  struct RDL_solver_parameters pars;
 +
 +
  /* Initialize the parameters struct */
 +
 +
  pars.p=p;
 +
  pars.t=ti;
 +
  pars.f=force;
 +
 +
  /* Write information to ostream... */
 +
 
 +
  out << scientific;
 +
  out << setprecision(3);
 +
  out << setfill(' ');
 +
  out << "# Beginning solver iterations. Output columns are as follows\n";
 +
  out << "#  (1) Time, in seconds\n";
 +
  out << "#  (2) X position of particle, in meters\n";
 +
  out << "#  (3) Y position of particle, in meters\n";
 +
  out << "#  (4) Z position of particle, in meters\n";
 +
  out << "#  (5) X component of velocity, in m/s\n";
 +
  out << "#  (6) Y component of velocity, in m/s\n";
 +
  out << "#  (7) Z component of velocity, in m/s\n";
 +
 +
  /* Set up GSL ODE solver system */
 +
 +
  const gsl_odeiv_step_type *T=gsl_odeiv_step_rk8pd;
 +
 +
  gsl_odeiv_step *s=gsl_odeiv_step_alloc(T,6);
 +
  gsl_odeiv_control *c=gsl_odeiv_control_y_new(RDL_TINY,0.0);
 +
  gsl_odeiv_evolve *e=gsl_odeiv_evolve_alloc(6);
 +
  gsl_odeiv_system sys={RDL_solver_func,NULL,6,&pars};
 +
 +
  /* Initialize variable array */
 +
 +
  y[0]=p.x.x;
 +
  y[1]=p.x.y;
 +
  y[2]=p.x.z;
 +
  y[3]=p.v.x;
 +
  y[4]=p.v.y;
 +
  y[5]=p.v.z;
 +
 +
  /* Print out initial position */
 +
 +
  out << setw(10) << ti << " ";
 +
  out << setw(10) << y[0] << " ";
 +
  out << setw(10) << y[1] << " ";
 +
  out << setw(10) << y[2] << " ";
 +
  out << setw(10) << y[3] << " ";
 +
  out << setw(10) << y[4] << " ";
 +
  out << setw(10) << y[5] << "\n";
 +
 +
  /* Solver loop */
 +
 +
  t=ti;
 +
  status=GSL_SUCCESS;
 +
  iter=1;
 +
 +
  while (t<(RDL_TMAX+ti))
 +
  {
 +
    pars.p=p;
 +
    pars.t=t;
 +
    status=gsl_odeiv_evolve_apply(e,c,s,&sys,&t,(RDL_TMAX+ti),&dt,y);
 +
    out << setw(10) << t << " ";
 +
    out << setw(10) << y[0] << " ";
 +
    out << setw(10) << y[1] << " ";
 +
    out << setw(10) << y[2] << " ";
 +
    out << setw(10) << y[3] << " ";
 +
    out << setw(10) << y[4] << " ";
 +
    out << setw(10) << y[5] << "\n";
 +
    /* Update the particle and the struct that carries the info */
 +
    p.x.x=y[0];
 +
    p.x.y=y[1];
 +
    p.x.z=y[2];
 +
    p.v.x=y[3];
 +
    p.v.y=y[4];
 +
    p.v.z=y[5];
 +
    /* Check break conditions */
 +
    if(status!=GSL_SUCCESS) break;
 +
    retval=stopping_conditions(p,t,iter);
 +
    if(retval) break;
 +
    iter++;
 +
  }
 +
 +
  /* Free memory allocated by GSL */
 +
 +
  gsl_odeiv_evolve_free(e);
 +
  gsl_odeiv_control_free(c);
 +
  gsl_odeiv_step_free(s);
 +
 +
  /* Return */
 +
 +
  if(status!=GSL_SUCCESS) return 0;
 +
  else return retval;
 +
 +
}
  
 
</nowiki></pre>
 
</nowiki></pre>
Line 319: Line 492:
  
 
<pre><nowiki>
 
<pre><nowiki>
 +
 +
/* RDLsolver_func.cpp: This function is needed by the RDYNLAB main routine, and
 +
* should net be called from user space */
 +
 +
#include <rdynlab.h>
 +
#include <gsl/gsl_odeiv.h>
 +
#include <gsl/gsl_errno.h>
 +
#include <gsl/gsl_math.h>
 +
#include <gsl/gsl_diff.h>
 +
#include <math.h>
 +
#include <iostream>
 +
#include <iomanip>
 +
 +
int RDL_solver_func(double t,const double y[],double f[], void *params)
 +
{
 +
  /* Note: variables coming in array y are as follows:
 +
  * y[0]: x
 +
  * y[1]: y
 +
  * y[2]: z
 +
  * y[3]: vx
 +
  * y[4]: vy
 +
  * y[5]: vz */
 +
 +
  /* Extract the particle and force from the input parameters */
 +
 +
  RDL_solver_parameters *pars=(RDL_solver_parameters*)params;
 +
  RDL_Particle p=(pars->p);
 +
  RDL_Vector (*F)(const RDL_Particle&,const double)=pars->f;
 +
 +
  /* Other variables we will need */
 +
 +
  RDL_Vector Fpar,Fperp;
 +
  RDL_Vector a;
 +
  double gm,g3m;
 +
  double dgdt,g;
 +
 +
  /* Update position and velocity of the particle from the y array. If I
 +
  * don't do this, the solver has no way of testing the accuracy of a step! */
 +
 +
  p.x.x=y[0];
 +
  p.x.y=y[1];
 +
  p.x.z=y[2];
 +
  p.v.x=y[3];
 +
  p.v.y=y[4];
 +
  p.v.z=y[5];
 +
 +
  /* Calculate gamma*m and gamma^3*m */
 +
 +
  g=p.gamma();
 +
  gm=g*p.m;
 +
  g3m=g*g*gm;
 +
 +
 +
  /* Calculate the components of the force that are parallel and
 +
  * perpendicular to the velocity of the particle */
 +
 +
  if(length(p.v)>0.)
 +
  {
 +
    Fpar=unit(p.v)*(F(p,t)*p.v)/length(p.v);
 +
    Fperp=F(p,t)-Fpar;
 +
  }
 +
  else /* Velocity is zero, no component of force is parallel to velocity! */
 +
  {
 +
    Fpar=p.v;
 +
    Fperp=F(p,t);
 +
  }
 +
 +
  /* Calculate the acceleration w/o radiative losses (dv/dt) */
 +
 +
  a=Fperp/gm+Fpar/g3m;
 +
 +
  /* Use this acceleration to calculate dgamma/dt, derived from the
 +
  * Lienard formula: dgdt = 1/(mc^2) dE/dt */
 +
 +
  dgdt=-RDL_MU0*p.q*p.q*g*g*g*g*g*g;
 +
  dgdt=dgdt/(6.*M_PI*p.m*RDL_CLIGHT*RDL_CLIGHT*RDL_CLIGHT);
 +
  dgdt=dgdt*(a*a-(p.v^a)*(p.v^a)/(RDL_CLIGHT*RDL_CLIGHT));
 +
 +
  /* Update acceleration with radiative losses */
 +
 +
  a=a+p.v*dgdt/g;
 +
 +
  /* Put the time derivatives in the appropriate array */
 +
 +
  f[0]=y[3];
 +
  f[1]=y[4];
 +
  f[2]=y[5];
 +
  f[3]=a.x;
 +
  f[4]=a.y;
 +
  f[5]=a.z;
 +
 +
  /* return */
 +
 
 +
  return GSL_SUCCESS;
 +
}
  
 
</nowiki></pre>
 
</nowiki></pre>

Latest revision as of 18:06, 18 June 2009

The following files constitute the source code for RDYNLAB. They can be compiled with any source code intended to use the library functions or (preferably) compiled as a shared object library using GNU autoconf, automake, and libtool. Compiling a shared object library is beyond the scope of this document. The package, with the appropriate configure scripts and makefiles, can be obtained by contacting the author (kelleyk@byui.edu).

It should be noted that the library is written in C++, and will probably only compile or work properly with other C++ codes.


***rdynlab.h***


/* RDYNLAB: Relativistic particle DYNamics in the LAB frame. */

#ifndef _RDYNLAB_H_
#define _RDYNLAB_H_

#include <iostream>

using namespace std;

/* Some global control parameters */

#define RDL_TINY 1.e+00 /* Required numerical accuracy */
#define RDL_TMAX 1.e+18 /* Maximum time we will ever be allowed to run to.
                         * This number can be rediculously large, since the
		         * stopping time will normally be provided by the
			 * user. */

/* A few constants that we will need */

#define RDL_CLIGHT 2.99792458E8 /* Speed of light in vacuum */

#define RDL_MU0 1.25663706144E-6 /* Permeability of free space, needed for power
                                  * loss of charged particles */

/*****************************  Vector Class **********************************/

class RDL_Vector
{
  public:
    double x,y,z; /* The three components of a vector */

    /* Construction and destruction operators */

    RDL_Vector() {};
   ~RDL_Vector() {};
    RDL_Vector(double,double,double);

    /* Operators */

    RDL_Vector operator+(const RDL_Vector&); /* Add vectors */
    RDL_Vector operator+(void);              /* "Positive" of a vector */
    RDL_Vector operator-(const RDL_Vector&); /* Subtract vectors */
    RDL_Vector operator-(void);              /* "Negative" of a vector */
    RDL_Vector operator*(double);            /* Multiply vector by scalar */
    double operator*(const RDL_Vector&);     /* Vector dot product */
    RDL_Vector operator/(double);            /* Divide vector by scalar */
    RDL_Vector operator^(const RDL_Vector&); /* Vector cross product */
    bool operator==(const RDL_Vector&);      /* Are vectors the same? */
    
    /* Friends to this class */

    friend ostream &operator<<(ostream &out,const RDL_Vector &V);
    friend RDL_Vector operator*(double a, const RDL_Vector &V);
};

/* Define << operator for vectors */

ostream &operator<<(ostream &out, const RDL_Vector &V);

/* Allows us to do scalar times vector */

RDL_Vector operator*(double a, const RDL_Vector &V);

/* These return the length of a vector and a unit vector */

double length(const RDL_Vector &V);
RDL_Vector unit(const RDL_Vector &V);


/*****************************  Particle Class ********************************/

class RDL_Particle
{
  public:
    double q;     /* Charge, in Coulombs */
    double m;     /* Mass, in kg */
    RDL_Vector x;     /* Position, in meters */
    RDL_Vector v;     /* Velocity, in m/s */

    /* Construction and Destruction operators */

    RDL_Particle() {};
   ~RDL_Particle() {};
    RDL_Particle(double, double, const RDL_Vector&, const RDL_Vector&); 
      /* Init with q,m,x,v */

    /* We need to define the = operator */

    RDL_Particle operator=(const RDL_Particle&);

    /* Allow the << operator access... */

    friend ostream &operator<<(ostream &out, const RDL_Particle &p);

    /* Return particle properties */

    double gamma(void);          /* Returns relativistic factor gamma */
    double energy(void);         /* Returns total energy */
    double kinetic_energy(void); /* Returns kinetic energy */
    double rest_energy(void);    /* Returns rest energy */
    RDL_Vector momentum(void);       /* Returns momentum vector */
};

/* Overload << operator for particles */

ostream &operator<<(ostream &out, const RDL_Particle &p);

/******************* Struct for passing information to GSL ********************/

struct RDL_solver_parameters
{
  RDL_Particle p;                                 /* The particle */
  double t;                                   /* The time */
  RDL_Vector (*f)(const RDL_Particle&,double);  /* Function returning force */
};

/******************** Declaration of main solver routine **********************/

/* This is the main solver routine. Input parameters are the particle,
 * a function that returns the force, the initial time, the initial time step, 
 * a function that determines if the simulation should stop, and an ostream for
 * writing output.
 *
 * The force function takes arguments of a particle (which will include position
 * and velocity) and time. The stopping condition function takes arguments of a
 * particle (which has the particle's position and velocity), the time, and the
 * number of iterations the solver has completed. */

int RDL_solver(RDL_Particle&, 
               RDL_Vector (*)(const RDL_Particle&,double), 
	       double, double, 
	       int (*)(const RDL_Particle&,double,int),
	       ostream&);

/* This function is required by the solver routine, and will probably never
 * need to be called from user space. */

int RDL_solver_func(double t,
                    const double y[],
	  	    double f[], 
	            void *params);

#endif



***RDLvector.cpp***


/* RDLvector.c: 3-D vectors and functions */

#include <rdynlab.h>
#include <math.h>

using namespace std;

/* Constructor */

RDL_Vector::RDL_Vector (double xin, double yin, double zin) 
{
  x = xin;
  y = yin;
  z = zin;
}

/* Operators */

RDL_Vector RDL_Vector::operator+(const RDL_Vector &param) 
{
  RDL_Vector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  temp.z = z + param.z;
  return temp;
}

RDL_Vector RDL_Vector::operator+(void)
{
  RDL_Vector temp;
  temp.x = x;
  temp.y = y;
  temp.z = z;
  return temp;
}

RDL_Vector RDL_Vector::operator-(const RDL_Vector &param)
{
  RDL_Vector temp;
  temp.x = x - param.x;
  temp.y = y - param.y;
  temp.z = z - param.z;
  return temp;
}

RDL_Vector RDL_Vector::operator-(void)
{
  RDL_Vector temp;
  temp.x = -x;
  temp.y = -y;
  temp.z = -z;
  return temp;
}

RDL_Vector RDL_Vector::operator*(double a)
{
  RDL_Vector temp;
  temp.x = x*a;
  temp.y = y*a;
  temp.z = z*a;
  return temp;
}

double RDL_Vector::operator*(const RDL_Vector &param)
{
  double temp;
  temp = (x * param.x) + (y * param.y) + (z * param.z);
  return temp;
}

RDL_Vector RDL_Vector::operator/(double a)
{
  RDL_Vector temp;
  temp.x = x/a;
  temp.y = y/a;
  temp.z = z/a;
  return temp;
}

RDL_Vector RDL_Vector::operator^(const RDL_Vector &param)
{
  RDL_Vector temp;
  temp.x = (y * param.z) - (z * param.y);
  temp.y = (z * param.x) - (x * param.z);
  temp.z = (x * param.y) - (y * param.x);
  return temp;
}

bool RDL_Vector::operator==(const RDL_Vector &param)
{
  if(param.x==x && param.y==y && param.z==z) return true;
  else return false;
}

/* << operator */

ostream &operator<<(ostream &out, const RDL_Vector &V)
{
  out << "<" << V.x << ", " << V.y << ", " << V.z << ">";
  return out;
}

/* This one allows double*RDL_Vector */

RDL_Vector operator*(double a, const RDL_Vector &V)
{
  RDL_Vector temp;
  temp.x = V.x*a;
  temp.y = V.y*a;
  temp.z = V.z*a;
  return (temp);
}

/* Return the length of a vector, unit vector */

double length(const RDL_Vector &V)
{
  RDL_Vector temp=V;
  return sqrt(temp*temp);
}

RDL_Vector unit(const RDL_Vector &V)
{
  RDL_Vector temp=V;
  double s=length(temp);
  /* Return zero if the length is zero */
  if(s>0) return temp/s;
  else return temp;
}



***RDLparticle.cpp***


/* RDLparticle.cpp: defines class for a particle */

#include <rdynlab.h>
#include <math.h>

RDL_Particle::RDL_Particle(double qin, double min, const RDL_Vector &xin, const RDL_Vector &vin)
{
  q=qin;
  m=min;
  x=xin;
  v=vin;
}

RDL_Particle RDL_Particle::operator=(const RDL_Particle &param)
{
  q=param.q;
  m=param.m;
  x=param.x;
  v=param.v;
  return *this;
}

double RDL_Particle::gamma(void)
{
  double s=length(v);
  return 1./sqrt(1.-s*s/(RDL_CLIGHT*RDL_CLIGHT));
}

double RDL_Particle::energy(void)
{
  return gamma()*m*RDL_CLIGHT*RDL_CLIGHT;
}

double RDL_Particle::kinetic_energy(void)
{
  return (gamma()-1.0)*m*RDL_CLIGHT*RDL_CLIGHT;
}

double RDL_Particle::rest_energy(void)
{
  return m*RDL_CLIGHT*RDL_CLIGHT;
}

RDL_Vector RDL_Particle::momentum(void)
{
  return v*gamma()*m;
}

ostream &operator<<(ostream &out, const RDL_Particle &p)
{
  out << "Current state of particle:\n";
  out << "  mass:     " << p.m << "\n";
  out << "  charge:   " << p.q << "\n";
  out << "  position: " << p.x << "\n";
  out << "  velocity: " << p.v << "\n";
  return out;
}



***RDLsolver.cpp***


/* RDLsolver.cpp: The main solver routine for the RDYNLAB package */

#include <rdynlab.h>
#include <gsl/gsl_odeiv.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_diff.h>
#include <math.h>
#include <iostream>
#include <iomanip>

int RDL_solver(RDL_Particle &p, 
               RDL_Vector (*force) (const RDL_Particle&, double), 
	       double ti, 
	       double dt, 
	       int (*stopping_conditions) (const RDL_Particle&, double, int), 
	       ostream &out)
{
  double y[6];
  double t;
  int status,iter,retval;
  struct RDL_solver_parameters pars;

  /* Initialize the parameters struct */

  pars.p=p;
  pars.t=ti;
  pars.f=force;

  /* Write information to ostream... */
  
  out << scientific;
  out << setprecision(3);
  out << setfill(' ');
  out << "# Beginning solver iterations. Output columns are as follows\n";
  out << "#   (1) Time, in seconds\n";
  out << "#   (2) X position of particle, in meters\n";
  out << "#   (3) Y position of particle, in meters\n";
  out << "#   (4) Z position of particle, in meters\n";
  out << "#   (5) X component of velocity, in m/s\n";
  out << "#   (6) Y component of velocity, in m/s\n";
  out << "#   (7) Z component of velocity, in m/s\n";

  /* Set up GSL ODE solver system */

  const gsl_odeiv_step_type *T=gsl_odeiv_step_rk8pd;

  gsl_odeiv_step *s=gsl_odeiv_step_alloc(T,6);
  gsl_odeiv_control *c=gsl_odeiv_control_y_new(RDL_TINY,0.0);
  gsl_odeiv_evolve *e=gsl_odeiv_evolve_alloc(6);
  gsl_odeiv_system sys={RDL_solver_func,NULL,6,&pars};

  /* Initialize variable array */

  y[0]=p.x.x;
  y[1]=p.x.y;
  y[2]=p.x.z;
  y[3]=p.v.x;
  y[4]=p.v.y;
  y[5]=p.v.z;

  /* Print out initial position */

  out << setw(10) << ti << " ";
  out << setw(10) << y[0] << " ";
  out << setw(10) << y[1] << " ";
  out << setw(10) << y[2] << " ";
  out << setw(10) << y[3] << " ";
  out << setw(10) << y[4] << " ";
  out << setw(10) << y[5] << "\n";

  /* Solver loop */
 
  t=ti;
  status=GSL_SUCCESS;
  iter=1;

  while (t<(RDL_TMAX+ti))
  {
    pars.p=p;
    pars.t=t;
    status=gsl_odeiv_evolve_apply(e,c,s,&sys,&t,(RDL_TMAX+ti),&dt,y);
    out << setw(10) << t << " ";
    out << setw(10) << y[0] << " ";
    out << setw(10) << y[1] << " ";
    out << setw(10) << y[2] << " ";
    out << setw(10) << y[3] << " ";
    out << setw(10) << y[4] << " ";
    out << setw(10) << y[5] << "\n";
    /* Update the particle and the struct that carries the info */
    p.x.x=y[0];
    p.x.y=y[1];
    p.x.z=y[2];
    p.v.x=y[3];
    p.v.y=y[4];
    p.v.z=y[5];
    /* Check break conditions */
    if(status!=GSL_SUCCESS) break;
    retval=stopping_conditions(p,t,iter);
    if(retval) break;
    iter++;
  }

  /* Free memory allocated by GSL */

  gsl_odeiv_evolve_free(e);
  gsl_odeiv_control_free(c);
  gsl_odeiv_step_free(s);

  /* Return */

  if(status!=GSL_SUCCESS) return 0;
  else return retval;

}



***RDLsolver_func.cpp***


/* RDLsolver_func.cpp: This function is needed by the RDYNLAB main routine, and
 * should net be called from user space */

#include <rdynlab.h>
#include <gsl/gsl_odeiv.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_diff.h>
#include <math.h>
#include <iostream>
#include <iomanip>

int RDL_solver_func(double t,const double y[],double f[], void *params)
{
  /* Note: variables coming in array y are as follows:
   * y[0]: x
   * y[1]: y
   * y[2]: z
   * y[3]: vx
   * y[4]: vy
   * y[5]: vz */

  /* Extract the particle and force from the input parameters */

  RDL_solver_parameters *pars=(RDL_solver_parameters*)params;
  RDL_Particle p=(pars->p);
  RDL_Vector (*F)(const RDL_Particle&,const double)=pars->f;

  /* Other variables we will need */

  RDL_Vector Fpar,Fperp;
  RDL_Vector a;
  double gm,g3m;
  double dgdt,g;

  /* Update position and velocity of the particle from the y array. If I
   * don't do this, the solver has no way of testing the accuracy of a step! */

  p.x.x=y[0];
  p.x.y=y[1];
  p.x.z=y[2];
  p.v.x=y[3];
  p.v.y=y[4];
  p.v.z=y[5];

  /* Calculate gamma*m and gamma^3*m */

  g=p.gamma();
  gm=g*p.m;
  g3m=g*g*gm;


  /* Calculate the components of the force that are parallel and 
   * perpendicular to the velocity of the particle */

  if(length(p.v)>0.)
  {
    Fpar=unit(p.v)*(F(p,t)*p.v)/length(p.v);
    Fperp=F(p,t)-Fpar;
  }
  else /* Velocity is zero, no component of force is parallel to velocity! */
  {
    Fpar=p.v;
    Fperp=F(p,t);
  }

  /* Calculate the acceleration w/o radiative losses (dv/dt) */

  a=Fperp/gm+Fpar/g3m;

  /* Use this acceleration to calculate dgamma/dt, derived from the 
   * Lienard formula: dgdt = 1/(mc^2) dE/dt */

  dgdt=-RDL_MU0*p.q*p.q*g*g*g*g*g*g;
  dgdt=dgdt/(6.*M_PI*p.m*RDL_CLIGHT*RDL_CLIGHT*RDL_CLIGHT);
  dgdt=dgdt*(a*a-(p.v^a)*(p.v^a)/(RDL_CLIGHT*RDL_CLIGHT));

  /* Update acceleration with radiative losses */

  a=a+p.v*dgdt/g;

  /* Put the time derivatives in the appropriate array */

  f[0]=y[3];
  f[1]=y[4];
  f[2]=y[5];
  f[3]=a.x;
  f[4]=a.y;
  f[5]=a.z;

  /* return */
  
  return GSL_SUCCESS;
}