#ifndef BULSTO_H
# define BULSTO_H
# ifndef GPK_STD_H
#  include <gpk_std.h>
# endif

# ifndef RUNGE6_H
	/* Stuff that the Bulrich-Storer and Runge-Kutta methods have in common. */
#  include "runge6.h"
# endif

/* The xdot-function is the ODE itself.  It calculates the derivitives
   as a function of x, and places them in the array deriv.
   Deriv and x are vectors of length nx.
   The xdot-function should return TRUE if the x value is anything like
   reasonable, and FALSE if the derivitives cannot be calculated for
   the given x.  The bulsto() solver will reduce the step size in an
   attempt to make xdot-function() return TRUE, on the assumption that
   things have gone unstable, and a smaller step size will result in the ODE
   staying within reasonable bounds.
	C and nc are arbitrary -- they are passed into the xdot-function as a
	convenience; the solver routines do not use them or modify them in any
	way.  They are useful for passing data or parameters in to the calculation
	of the derivitives. */
typedef BOOL (*xdot_fcn)(double *deriv, C double *x, int nx, void *c, int nc);

/* The output function is optional.  If it is not supplied, bulsto() will
   merely copy out all components of the ODE to the output array.
   The output function is useful if you only wish to copy out a few
   components of the vector (perhaps to save space), or if you wish
   to return e.g. a sum of all the components.

   The function puts whatever it wants into xout.  It *must* put nout
   elements into nout.  There are nx components of the ODE available in x.
   C and nc, are as before, arbitrary things that this output function
   can use or ignore as it sees fit.

   If the output function returns FALSE, it will terminate bulsto() and cause
   an error to be reported. */

typedef BOOL (*out_fcn)(double *xout, C double *x, int nx, void *c, int nc,
							int nout);

/* Bulsto is the differential equation solver itself.  You pass it
initial conditions (in x), a equation (xdot), and times at which you
wish the ODE to be avaluated at, and let it run.  Struct runge_s is defined
in runge6.h.

	x -- a vector of the initial values of the ODE.  There are nx values.
	nx -- number of components of the ODE.
	c -- an arbitrary pointer which is passed into the the derivitive function
		(xdot) and the output function (out).  It isn't used or touched;
		those two function can use it for whatever they like.
	nc -- an arbitrary integer, passed like c, for use bu xdot and out.
	tvals -- time values at which the results equation will be remembered.
			Tvals does not set the stepsize (except as an upper limit);
			stepsize control is automatic.  Tvals should just be those values
			at which you want the data.
	ntv -- how many tvals are there?
	eps -- fractional error allowed for the output values (not fractional
			error per step).
	limit -- A typical magnitude of the solution.  The actual error limit is
			eps*(fabs(x[i])+fabs(limits[i])), so you can have either errors
			proportional to x (by setting limits=0) or errors independent of
			x (by making limits large).
	out -- either zero or a function that will copy out (and perhaps process)
			the components of the differential equation.  If zero, every
			component will be remembered, leading to an output array (in
			the runge_s structure) of size nx*ntv.
	nout -- how many values the output function should remember.  The output
			array will have nout*ntv values in it.
*/

struct runge_s
bulsto(double *x, void *c, int nx, int nc,
		xdot_fcn xdot,
		double eps, C double *tvals, int ntv,
		out_fcn out,
		int nout, C double *limit);

/* The functions below are internal to the bulsto() package. */

double iratio(double step, int ln_n, double *space, int nuse);

int euler(C double *y, C double *dydx0, int nvar, double htot,
					int nstep, double *yout,
					xdot_fcn derivs,
					void *c,int nc);

struct bsresult bsstep(double *y,double *dydx0,int nv,double h,
								double eps,double C *yscal,
								xdot_fcn derivs,
								void *c,int nc);

BOOL rzextr(int iest,double C *x,double C *yest,double *yzero,
						double *yerror,int nv,int nuse,double * *d);


#endif
