4

I am trying to implement the multidimensional integration routine from Numerical Recipes (code taken from here, pg. 164). The use of wrappers to pass the integrand to void* params is from here (further references there). My class declarations are in NRquad3d_Const_qags_2.C as follows

#include <gsl/gsl_integration.h>

gsl_integration_workspace * w1 = gsl_integration_workspace_alloc (100000);
gsl_integration_workspace * w2 = gsl_integration_workspace_alloc (100000);

double func3d(double x, double y, double z);

class NRf3 {
public:
  double xsav, ysav;

  double ret_int(double z)
  {  
    return func3d(xsav, ysav, z);
  }

  static double ret_int_wrapper(double z, void *params)
  {
   return static_cast<NRf3*>(params)->ret_int(z); 
  }

};

//integrates over the z-variable
class NRf2 {
private:
  double z1, z2;
  gsl_function F2; 

public:
  NRf3 f3;
  double resultf2, errorf2;

  NRf2 (double zz1, double zz2): z1(zz1), z2(zz2) {}

  double ret_int_2(double y) 
  {
    f3.ysav = y;        

    F2.function = &(f3.ret_int_wrapper);
    F2.params = &f3;

    gsl_integration_qags(&F2, z1, z2, 0, 1e-7, 10, w1, &resultf2, &errorf2);
    gsl_integration_workspace_free (w1);

    return resultf2; 
    }

  static double ret_int_2_wrapper(double y, void *params)
  {
   return static_cast<NRf2*>(params)->ret_int_2(y); 
  }

};
//integrates over the y-variable ==> gives function of x

class output {
private:  
  gsl_function F;
public:
  double result, error;

  double integrate(double x, double y1, double y2, double z1, double z2){

    NRf2 f2(z1, z2);
    f2.f3.xsav = x;

    F.function = &(f2.ret_int_2_wrapper);
    F.params = &f2;

    gsl_integration_qags(&F, y1, y2, 0, 1e-7, 10, w2, &result, &error);
    gsl_integration_workspace_free (w2);

    return result;
  }

};

And i call the integrator as follows:

#include <stdio.h>
#include </users/.../NRquad3d_Const_qags_2.C>

double func3d(double x, double y, double z)
  {
    double f = x*y*z;
    return f;
  }


int main (void)
{
  double result; 
  double error;
  double expected = -4.0;

  output out ; 
  result = out.integrate(1.0, -1.0, 1.0, -1.0, 1.0);

  printf ("result          = % .18f\n", result);
  printf ("exact result    = % .18f\n", expected); 
  printf ("actual error    = % .18f\n", result - expected);

  return 0;
}

Code compiles ok, but running a.out gives me a segfault. Backtrace from gdb gives

#0  0x00007ffff7a4b430 in ?? () from /usr/lib64/libgsl.so.0
#1  0x0000000000400bed in NRf2::ret_int_2 (this=0x7fffffffdbd0, y=-0.97390652851717174) at /users/.../NRquad3d_Const_qags_2.C:45
#2  0x0000000000400c39 in NRf2::ret_int_2_wrapper (y=-0.97390652851717174, params=0x7fffffffdbd0) at /users/.../NRquad3d_Const_qags_2.C:53
#3  0x00007ffff7a49c6e in gsl_integration_qk () from /usr/lib64/libgsl.so.0
#4  0x00007ffff7a4997b in gsl_integration_qk21 () from /usr/lib64/libgsl.so.0
#5  0x00007ffff7a4b4c7 in ?? () from /usr/lib64/libgsl.so.0
#6  0x0000000000400d14 in output::integrate (this=0x7fffffffdc30, x=1, y1=-1, y2=1, z1=-1, z2=1) at /users/.../NRquad3d_Const_qags_2.C:73
#7  0x00000000004009ac in main () at crap_test.cpp:22
(gdb) frame 6
#6  0x0000000000400d14 in output::integrate (this=0x7fffffffdc30, x=1, y1=-1, y2=1, z1=-1, z2=1) at /users/.../NRquad3d_Const_qags_2.C:73
73          gsl_integration_qags(&F, y1, y2, 0, 1e-7, 10, w2, &result, &error);
(gdb) frame 1
#1  0x0000000000400bed in NRf2::ret_int_2 (this=0x7fffffffdbd0, y=-0.97390652851717174) at /users/.../NRquad3d_Const_qags_2.C:45
45          gsl_integration_qags(&F2, z1, z2, 0, 1e-7, 10, w1, &resultf2, &errorf2);

Running gdb already helped me eliminate a clash in the addresses of w1 and w2, but the segfault still remains. Since the error seems to occur in the call in the second call to qags in NRf2 i think there must be a deallocated pointer i am trying to refer to, but i can't seem to find it. Can anyone help?

Community
  • 1
  • 1
Zhong Yuan Lai
  • 123
  • 1
  • 6

1 Answers1

1

Running valgrind gives errors of the form:

==26286== Invalid read of size 8
==26286==    at 0x4ED0239: gsl_integration_workspace_free (in /usr/lib64/libgsl.so.0.16.0)
==26286==    by 0x400A54: main (crap_test.cpp:32)
==26286==  Address 0x6053090 is 80 bytes inside a block of size 88 free'd
==26286==    at 0x4C29D4E: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==26286==    by 0x400C39: NRf2::ret_int_2(double) (NRquad3d_Const_qags_2.C:46)
==26286==    by 0x400C76: NRf2::ret_int_2_wrapper(double, void*) (NRquad3d_Const_qags_2.C:53)
==26286==    by 0x4ECBBA3: gsl_integration_qk (in /usr/lib64/libgsl.so.0.16.0)
==26286==    by 0x4ECB97A: gsl_integration_qk21 (in /usr/lib64/libgsl.so.0.16.0)
==26286==    by 0x4ECD4C6: ??? (in /usr/lib64/libgsl.so.0.16.0)
==26286==    by 0x400D51: output::integrate(double, double, double, double, double) (NRquad3d_Const_qags_2.C:73)
==26286==    by 0x4009CB: main (crap_test.cpp:25)

which hints at me trying to access freed memory. The only places in my script where i try to do this are at the lines

gsl_integration_workspace_free (w1);
.
.
.
.
gsl_integration_workspace_free (w2);

in the .C file. I then (re)move these lines to the end of my .cpp file and it works.

Silly error, but i'm going to answer this anyway in case someone has this exact (or similar!) error and needs a solution.

Community
  • 1
  • 1
Zhong Yuan Lai
  • 123
  • 1
  • 6