GSL sample: Initial Value Problem for Ordinary Differential Equation

Last Update: Oct. 4, 2007


Sample code

linear_ode.c

/***********************************************/
/* T.Kouya's GSL sample program collection     */
/* Stiff and Non-stiff Linear Ordinary         */
/*                      Differential Equations */
/*                   Written by Tomonori Kouya */
/*                                             */
/* Version 0.01: 2007-08-13                    */
/***********************************************/
#include <stdio.h>
#include <gsl/gsl_errno.h>// GSL_SUCCESS ...
#include <gsl/gsl_math.h> // cos(x), sin(x) ...
#include <gsl/gsl_odeiv.h>// ODE solver

/* Return relative and absolute errors */
void vec_rel_error(double relerr[], double approx_val[], double true_val[], int dimension)
{
	static int i;
	static double abs_error, rel_error;

	for(i = 0; i < dimension; i++)
	{
		abs_error = fabs(approx_val[i] - true_val[i]);
		rel_error = abs_error;
		if(true_val[i] >= 1.0e-15)
			rel_error /= fabs(true_val[i]);
		relerr[i] = rel_error;
	}

	return;
}

/* Dimension of ODEs */
#define DIM 2

/* Common True Solution */
void true_solution(double ret_y[], double x)
{
	ret_y[0] = exp(-x);
	ret_y[1] = exp(-x) + cos(x);
}

/* Definition of ODE system */
/* Non-stiff Linear ODE (cf. http://na-inet.jp/nasoft/chap16.pdf) */
/* dydx[] := func(x, y[]) */
int nonstiff_lode_func(double x, const double y[], double dydx[], void *params)
{
	dydx[0] = -2.0 * y[0] +       y[1] - cos(x);
	dydx[1] =  2.0 * y[0] - 3.0 * y[1] + 3.0 * cos(x) - sin(x);

	return GSL_SUCCESS;
}

/* Jacobian matrix of nonstiff_lode_func */
int jac_nonstiff_lode_func(double x, const double y[], double *dfdy, double dfdx[], void *params)
{
	/* Jacobian matrix -> dfdy */
	*(dfdy + 0 * DIM + 0) = -2.0;
	*(dfdy + 0 * DIM + 1) =  1.0;
	*(dfdy + 1 * DIM + 0) =  2.0;
	*(dfdy + 1 * DIM + 1) = -3.0;

	/* df/dt */
	dfdx[0] = sin(x);
	dfdx[1] = -3.0 * sin(x) - cos(x);

	return GSL_SUCCESS;
}

/* Definition of ODE system */
/* Stiff Linear ODE (cf. http://na-inet.jp/nasoft/chap16.pdf) */
/* dydx[] := func(x, y[]) */
int stiff_lode_func(double x, const double y[], double dydx[], void *params)
{
	dydx[0] =    -2.0 * y[0] +          y[1] - cos(x);
	dydx[1] =  1998.0 * y[0] - 1999.0 * y[1] + 1999.0 * cos(x) - sin(x);

	return GSL_SUCCESS;
}

/* Jacobian matrix of stiff_lode_func */
int jac_stiff_lode_func(double x, const double y[], double *dfdy, double dfdx[], void *params)
{
	/* Jacobian matrix -> dfdy */
	*(dfdy + 0 * DIM + 0) = -2.0;
	*(dfdy + 0 * DIM + 1) =  1.0;
	*(dfdy + 1 * DIM + 0) =  1998.0;
	*(dfdy + 1 * DIM + 1) = -1999.0;

	/* df/dt */
	dfdx[0] = sin(x);
	dfdx[1] = -1999.0 * sin(x) - cos(x);

	return GSL_SUCCESS;
}

int main(void)
{
	int i;

	/* Integration Interval: [0, 10] */
	/* Initial min stepsize: 1.0e-5  */
	/* Initial value       : y(0) = [1, 2]^T */
	double x_start = 0.0, x_end = 10.0;
	double h_init = 1.0e-5;
	double y_init[DIM] = {1.0, 2.0};
	double relerr_y[DIM], true_y[DIM];

	/* Variables used for evolving */
	int status_nonstiff, status_stiff;
	double h_nonstiff, x_nonstiff, y_nonstiff[DIM];
	double h_stiff, x_stiff, y_stiff[DIM];

	/* Definitions to determine ODE solvers */
	const gsl_odeiv_step_type *solver_nonstiff = gsl_odeiv_step_rkf45; // Runge-Kutta Felberg (4, 5)
	const gsl_odeiv_step_type *solver_stiff = gsl_odeiv_step_rk4imp; // Fully implicit RK Gauss 4th order

	/* Memories of stepsizes */
	gsl_odeiv_step *step_nonstiff, *step_stiff;

	/* Constants to control errors */
	gsl_odeiv_control *tol_nonstiff, *tol_stiff;

	/* Memories needed to evolve ODE solvers */
	gsl_odeiv_evolve *evol_nonstiff, *evol_stiff;

	/* Definitions of ODE systems */
	gsl_odeiv_system sys_nonstiff, sys_stiff;

/* Non-stiff Problem */

	/* ODE system */
	sys_nonstiff.function = nonstiff_lode_func;
	sys_nonstiff.jacobian = jac_nonstiff_lode_func;
	sys_nonstiff.dimension = (size_t)(DIM);
	sys_nonstiff.params = NULL;

	/* ODE solver */
	/* Determine constans for error controling */
	/* Preparing evolution */
	step_nonstiff = gsl_odeiv_step_alloc(solver_nonstiff, DIM);
	tol_nonstiff = gsl_odeiv_control_standard_new(1.0e-10, 1.0e-5, 1.0, 0.0);
	evol_nonstiff = gsl_odeiv_evolve_alloc(DIM);

	/* Initialize for integration */
	h_nonstiff = h_init;
	x_nonstiff = x_start;
	for(i = 0; i < DIM; i++)
		y_nonstiff[i] = y_init[i];

	/* Integration with stepsize control */
	printf("Non-stiff Problem:\n");
	printf("  Solver: %s, Controling: %s\n", gsl_odeiv_step_name(step_nonstiff), gsl_odeiv_control_name(tol_nonstiff));
	printf("     x                    y[0]                     y[1]           Relerr y[0] Relerr y[1]\n");
	while(x_nonstiff < x_end)
	{
		status_nonstiff = gsl_odeiv_evolve_apply(evol_nonstiff, tol_nonstiff, step_nonstiff, &sys_nonstiff, &x_nonstiff, x_end, &h_nonstiff, y_nonstiff);
		if(status_nonstiff != GSL_SUCCESS)
		{
			fprintf(stderr, "ERROR: Non-stiff Problem at x = %25.17e\n", x_nonstiff);
			break;
		}
	
		true_solution(true_y, x_nonstiff);
		vec_rel_error(relerr_y, y_nonstiff, true_y, DIM);
		printf("%15.7e %25.17e %25.17e %10.3e %10.3e\n", x_nonstiff, y_nonstiff[0], y_nonstiff[1], relerr_y[0], relerr_y[1]);
	}

	/* Free */
	gsl_odeiv_evolve_free(evol_nonstiff);
	gsl_odeiv_control_free(tol_nonstiff);
	gsl_odeiv_step_free(step_nonstiff);

/* Stiff Problem */

	/* ODE system */
	sys_stiff.function = stiff_lode_func;
	sys_stiff.jacobian = jac_stiff_lode_func;
	sys_stiff.dimension = (size_t)(DIM);
	sys_stiff.params = NULL;

	/* ODE solver */
	/* Determine constans for error controling */
	/* Preparing evolution */
	step_stiff = gsl_odeiv_step_alloc(solver_stiff, DIM);
	tol_stiff = gsl_odeiv_control_standard_new(1.0e-10, 1.0e-5, 1.0, 0.0);
	evol_stiff = gsl_odeiv_evolve_alloc(DIM);

	/* Initialize for integration */
	h_stiff = h_init;
	x_stiff = x_start;
	for(i = 0; i < DIM; i++)
		y_stiff[i] = y_init[i];

	/* Integration with stepsize control */
	printf("Stiff Problem:\n");
	printf("  Solver: %s, Controling: %s\n", gsl_odeiv_step_name(step_stiff), gsl_odeiv_control_name(tol_stiff));
	printf("     x                    y[0]                     y[1]           Relerr y[0] Relerr y[1]\n");
	while(x_stiff < x_end)
	{
		status_stiff = gsl_odeiv_evolve_apply(evol_stiff, tol_stiff, step_stiff, &sys_stiff, &x_stiff, x_end, &h_stiff, y_stiff);
		if(status_stiff != GSL_SUCCESS)
		{
			fprintf(stderr, "ERROR: Stiff Problem at x = %25.17e\n", x_stiff);
			break;
		}
	
		true_solution(true_y, x_stiff);
		vec_rel_error(relerr_y, y_stiff, true_y, DIM);
		printf("%15.7e %25.17e %25.17e %10.3e %10.3e\n", x_stiff, y_stiff[0], y_stiff[1], relerr_y[0], relerr_y[1]);
	}

	/* Free */
	gsl_odeiv_evolve_free(evol_stiff);
	gsl_odeiv_control_free(tol_stiff);
	gsl_odeiv_step_free(step_stiff);

	return 0;
}

Example execution

$ ./linear_ode
Non-stiff Problem:
  Solver: rkf45, Controling: standard
     x                    y[0]                     y[1]           Relerr y[0] Relerr y[1]
  1.0000000e-05   9.99990000049999828e-01   1.99998999999999993e+00  0.000e+00  0.000e+00
  6.0000000e-05   9.99940001799964007e-01   1.99993999999996408e+00  0.000e+00  0.000e+00
  3.1000000e-04   9.99690048045035251e-01   1.99968999999503572e+00  0.000e+00  0.000e+00
  1.5600000e-03   9.98441216167510692e-01   1.99843999936775751e+00  0.000e+00  0.000e+00
  7.8100000e-03   9.92220418808186233e-01   1.99218992091321856e+00  3.692e-15  3.567e-15
  3.9060000e-02   9.61693005778894716e-01   1.96093026112794799e+00  5.827e-11  5.610e-11
(OMIT)
  9.7572849e+00   5.78719406467666030e-05  -9.45169137882558519e-01  7.013e-06  8.551e-10
  9.7874581e+00   5.61518489106037504e-05  -9.34893173693603030e-01  7.137e-06  8.440e-10
  9.8176313e+00   5.44828825914175032e-05  -9.23766026470360435e-01  7.265e-06  8.332e-10
  9.8478044e+00   5.28635220633079945e-05  -9.11797828859521320e-01  7.396e-06  8.227e-10
  9.8779776e+00   5.12922928725537602e-05  -8.98999479068398610e-01  7.529e-06  8.122e-10
  9.9081507e+00   4.97677643944452827e-05  -8.85382630946418447e-01  7.664e-06  8.018e-10
  9.9383239e+00   4.82885485301170624e-05  -8.70959683378632055e-01  7.798e-06  7.913e-10
  9.9684971e+00   4.68532984421406228e-05  -8.55743769000906318e-01  7.932e-06  7.807e-10
  9.9986702e+00   4.54607073277795066e-05  -8.39748742247069080e-01  8.065e-06  7.699e-10
  1.0000000e+01   4.54002943932760116e-05  -8.39026129912536334e-01  8.032e-06  7.658e-10
Stiff Problem:
  Solver: rk4imp, Controling: standard
     x                    y[0]                     y[1]           Relerr y[0] Relerr y[1]
  1.0000000e-05   9.99990000049999828e-01   1.99998999999999971e+00  0.000e+00  1.110e-16
  6.0000000e-05   9.99940001799964007e-01   1.99993999999996386e+00  0.000e+00  1.110e-16
  3.1000000e-04   9.99690048045035362e-01   1.99968999999464692e+00  1.111e-16  1.944e-13
  1.5600000e-03   9.98441216170407153e-01   1.99843999358035185e+00  2.901e-12  2.896e-09
  4.3639627e-03   9.95645547812364029e-01   1.99563145641214712e+00  2.296e-09  2.289e-06
  5.8180308e-03   9.94198861343948082e-01   1.99418160531753896e+00  1.667e-10  1.661e-07
  8.0221772e-03   9.92009914828045125e-01   1.99197728977807276e+00  2.257e-10  2.246e-07
(OMIT)
  9.9804552e+00   4.62958761739525062e-05  -8.49496859624095046e-01  2.480e-06  2.294e-07
  9.9825539e+00   4.61988174664507395e-05  -8.48387990757782595e-01  2.482e-06  2.291e-07
  9.9846526e+00   4.61019622419043659e-05  -8.47275384776054685e-01  2.484e-06  2.288e-07
  9.9867512e+00   4.60053100737143624e-05  -8.46159046580215457e-01  2.486e-06  2.285e-07
  9.9888499e+00   4.59088605361768437e-05  -8.45038981088006569e-01  2.488e-06  2.282e-07
  9.9909486e+00   4.58126132044794909e-05  -8.43915193233583549e-01  2.490e-06  2.279e-07
  9.9930473e+00   4.57165676547016873e-05  -8.42787687967497146e-01  2.492e-06  2.276e-07
  9.9951460e+00   4.56207234638109064e-05  -8.41656470256668010e-01  2.494e-06  2.273e-07
  9.9972447e+00   4.55250802096614788e-05  -8.40521545084366828e-01  2.496e-06  2.270e-07
  9.9993434e+00   4.54296374709929523e-05  -8.39382917450192223e-01  2.498e-06  2.267e-07
  1.0000000e+01   4.53998991727971499e-05  -8.39026068028467908e-01  6.738e-07  6.112e-08

<- Go back