Re: fixed classic rk4 step actually returns result for two half steps

2020-10-08 Thread Tuomo Keskitalo
Hi,

if I remember correctly, all steppers that use step doubling for error
estimates return the more accurate value from two half steps. At this point
I think it is best to just document this behavior, I can update docs this
week. Thanks for mentioning this issue!

BR,
Tuomo


On Tue, Oct 6, 2020 at 11:27 PM Krishna Myneni 
wrote:

> The function gsl_odeiv2_driver_apply_fixed_step() function in GSL 2.5,
> using the rk4 step method actually returns the result for two half-
> steps instead of the result for a single step. The attached code shows
> the result for integrating the Lorenz system of ODEs with given
> parameters and initial conditions, after 1 step at dt = 1e-4:
>
> $ ./bench_gsl_rk4
> 1.59864268529822870e-03  9.99903676398808394e-01  7.99388902928489989e-
> 08
>
> The above result for y[0] only has 12 significant digits in comparison
> to the double precision result for a single step of the classical RK4
> estimate for the step size used. Of course it is more accurate, but the
> point is that it is not giving the expected result for 1 classical RK4
> step. The problem appears to be with rk4_apply() which is using both
> single step and two half steps for estimating the error. It leaves the
> output state to be the result of the two half steps.
>
> Perhaps this is by design, but it will cause confusion when comparing
> with other rk4 fixed step solutions.
>
> Krishna Myneni
>
>

-- 
tuomo.keskit...@iki.fi
http://iki.fi/tuomo.keskitalo


fixed classic rk4 step actually returns result for two half steps

2020-10-06 Thread Krishna Myneni
The function gsl_odeiv2_driver_apply_fixed_step() function in GSL 2.5,
using the rk4 step method actually returns the result for two half-
steps instead of the result for a single step. The attached code shows
the result for integrating the Lorenz system of ODEs with given
parameters and initial conditions, after 1 step at dt = 1e-4:

$ ./bench_gsl_rk4
1.59864268529822870e-03  9.99903676398808394e-01  7.99388902928489989e-
08

The above result for y[0] only has 12 significant digits in comparison
to the double precision result for a single step of the classical RK4
estimate for the step size used. Of course it is more accurate, but the
point is that it is not giving the expected result for 1 classical RK4
step. The problem appears to be with rk4_apply() which is using both
single step and two half steps for estimating the error. It leaves the
output state to be the result of the two half steps. 

Perhaps this is by design, but it will cause confusion when comparing
with other rk4 fixed step solutions.

Krishna Myneni

/*
 * Sample ODE solver using the GSL (GNU Scientific Library)
 * (Packages gsl and gsl-devel must be installed)
 *
 * This example is modified to solve the Lorenz equations with
 * a fixed step solver, from the example at following web page:
 * 
 * https://www.gnu.org/software/gsl/doc/html/ode-initval.html
 *
 * Lorenz Equations:
 *
 *   dx/dt = sig*(y - x)
 *   dy/dt = (r - z)*x - y
 *   dz/dt = x*y - bp*z
 *
 * Build:
 *
 * gcc -o bench_gsl_rk4 -lgsl -lgslcblas -lm bench_gsl_rk4.c
 *
*/

#include 
#include 
#include 
#include 

int func (double t, const double y[], double f[],
  void *params)
{
  double* p = (double *) params;
  (void)(t); /* avoid unused parameter warning */
  double sig = p[0];
  double r =   p[1];
  double bp =  p[2];

  f[0] = sig*(y[1] - y[0]);
  f[1] = (r - y[2])*y[0] - y[1];
  f[2] = y[0]*y[1] - bp*y[2];
  return GSL_SUCCESS;
}

int jac (double t, const double y[], double *dfdy,
 double dfdt[], void *params)
{
  (void)(t); /* avoid unused parameter warning */
  double* p = (double*) params;
  double sig = p[0];
  double r   = p[1];
  double bp  = p[2];
  gsl_matrix_view dfdy_mat
= gsl_matrix_view_array (dfdy, 3, 3);
  gsl_matrix * m = _mat.matrix;
  gsl_matrix_set (m, 0, 0, -sig);
  gsl_matrix_set (m, 0, 1, sig);
  gsl_matrix_set (m, 0, 2, 0.0);
  gsl_matrix_set (m, 1, 0, r - y[2]);
  gsl_matrix_set (m, 1, 1, -1.0);
  gsl_matrix_set (m, 1, 2, -y[0]);
  gsl_matrix_set (m, 2, 0, y[1]);
  gsl_matrix_set (m, 2, 1, y[0]);
  gsl_matrix_set (m, 2, 2, -bp);
  dfdt[0] = sig;
  dfdt[1] = -1.0;
  dfdt[2] = 0.0;
  return GSL_SUCCESS;
}

int main (void)
{
  int nsteps = 1;
  double dt = 1e-4;
  double p[3];
  p[0] = 16.0 ; // sig
  p[1] = 45.92; // r
  p[2] = 4.0;   // bp

  gsl_odeiv2_system sys = { func, jac, 3, p };

  gsl_odeiv2_driver *d =
gsl_odeiv2_driver_alloc_y_new (, gsl_odeiv2_step_rk4,
   dt, 1e-11, 1e-11);

  double t = 0.0;
  double y[3] = { 0.0, 1.0, 0.0 };
  int i, j, s;

for (i = 0; i < nsteps; i++)
{
  s = gsl_odeiv2_driver_apply_fixed_step (d, , dt, 1, y);

  if (s != GSL_SUCCESS)
{
  printf ("error: driver returned %d\n", s);
  break;
}
}

/* print final values of solution */
printf ("%.17e %.17e %.17e\n", y[0], y[1], y[2]);

  gsl_odeiv2_driver_free (d);
  return s;
}



signature.asc
Description: This is a digitally signed message part