/*
Programmazione II - Esempio di codice
Example code: Runge-Kutta integration of a 1-dim dynamic system
with adaptive stepsize calculation.
(20000816 prelz@mi.infn.it)
*/
#include
#include
#include
#include "graph_helper.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
struct vel_pass
{
double t0;
double v0;
} ;
double fourth_order_rk_step(double t0, double dt, double q0, double dq0,
void *user_data,
double (*deriv)(double t, double q, void *user_data) );
double velocity_deriv(double t, double q, void *us_pointer);
double oscillator_force (double t, double v, void *us_pointer);
double duffing_force (double t, double v, void *us_pointer);
#define MAX_REPEATS 5
double (*force)(double t, double q, void *user_data);
int
main (int argc, char *argv[])
{
graph *mygr;
double xcur, vcur, vnew, xnew, v1, v2, tcur, tstep;
double req_trunc_error=5E-7;
double est_trunc_error;
char dumb[8];
int i;
struct vel_pass velocity;
mygr = graph_create_new(NULL,"Phase diagram",500,500,"x","v");
if (mygr == NULL)
{
fprintf(stderr,"Cannot create graph.\n");
exit(1);
}
graph_set_scale(mygr,-2.5,2.5,-1.5,1.5);
graph_clear(mygr);
force = oscillator_force;
for (i=0; i req_trunc_error)
{
/* Reduce step and waste this cycle */
tstep *= pow(req_trunc_error/est_trunc_error,0.2);
continue;
}
/* Adapt step and continue */
tcur += tstep;
xcur = xnew;
vcur = vnew;
tstep *= pow(req_trunc_error/est_trunc_error,0.2);
graph_add_and_plot(mygr, xcur, vcur, "green4");
}
printf("Final step: %g\n",tstep);
printf("Final trunc error: %g\n",est_trunc_error);
graph_plot(mygr, "red");
}
printf("Press to finish\n");
fgets(dumb, sizeof(dumb), stdin);
graph_free(mygr);
XHLP_close_display();
exit(0);
}
double
fourth_order_rk_step(double t0, double dt, double q0, double dq0,
void *user_data,
double (*deriv)(double t, double q, void *user_data) )
{
double retval;
double k1,k2,k3,k4;
retval = q0;
k1 = dq0 * dt;
retval += k1/6;
k2 = deriv(t0 + dt/2, q0 + k1/2, user_data) * dt;
retval += k2/3;
k3 = deriv(t0 + dt/2, q0 + k2/2, user_data) * dt;
retval += k3/3;
k4 = deriv(t0 + dt, q0 + k3, user_data) * dt;
retval += k4/6;
if (retval == q0)
{
fprintf(stderr,"Error in fourth_order_rk_step: step is too small!\n");
}
return(retval);
}
double
velocity_deriv(double t, double q, void *user_pointer)
{
double retval;
static double last_t = 0;
static double last_v = 0;
static last_t_valid = FALSE;
struct vel_pass *vel0;
vel0 = (struct vel_pass *)user_pointer;
if (vel0->t0 == t)
{
retval = vel0->v0;
}
else if (last_t_valid && t == last_t)
{
retval = last_v;
}
else
{
retval = fourth_order_rk_step(vel0->t0, (t - vel0->t0), vel0->v0,
(*force)(vel0->t0, vel0->v0, &q),
&q,
(*force));
}
last_t = t;
last_v = retval;
last_t_valid = TRUE;
return(retval);
}
double
oscillator_force (double t, double v, void *us_pointer)
{
double x;
x = *(double *)us_pointer;
return (-0.5*x);
}
double
duffing_force (double t, double v, void *us_pointer)
{
double x;
x = *(double *)us_pointer;
return (x*(1-x*x) + 0.4*cos(t) - 0.25*v);
}