Four dimensional integration in cpp using gsl

  • Context:
  • Thread starter Thread starter CAF123
  • Start date Start date
  • Tags Tags
    Integration
Click For Summary
SUMMARY

This discussion centers on performing four-dimensional integration in C++ using the GNU Scientific Library (GSL). The user successfully implements nested one-dimensional integration routines but encounters issues with specific integrands, particularly due to the behavior of the square root function in the integrand. The error message "gsl: qags.c:553: ERROR: bad integrand behavior found in the integration interval" indicates that the integrand can yield complex values, which GSL does not handle. The user notes that Mathematica can compute the integral correctly, suggesting that GSL's limitations in handling complex numbers are the root of the problem.

PREREQUISITES
  • Familiarity with C++ programming
  • Understanding of numerical integration techniques
  • Knowledge of the GNU Scientific Library (GSL) version 2.6 or later
  • Basic concepts of complex numbers and their implications in integration
NEXT STEPS
  • Explore GSL's documentation on numerical integration methods.
  • Investigate alternative libraries for multidimensional integration, such as ROOT's TMinuit.
  • Learn about handling complex numbers in C++ to manage integrands that may yield complex results.
  • Examine the differences in error handling between GSL and Mathematica for numerical computations.
USEFUL FOR

Researchers, physicists, and software developers involved in numerical analysis and simulations requiring multidimensional integration, particularly those using C++ and the GSL library.

CAF123
Gold Member
Messages
2,918
Reaction score
87
I am trying to perform a four dimensional integration in cpp using gsl. I do this by nesting together the one-dimensional integration routines from gsl library. What I wrote seems to work for a few test integrands but I am having trouble with the integrand that I actually want a value for. See below for the full code I am using.
C++:
#include <iostream>
#include <gsl/gsl_integration.h>
#include <math.h>
#include <complex>

double b = 7.2;
double c = 0.130477;
double d = 0.549;

struct Params_t {
    double z1, z2, bx1, by1, bx, by;
};

double f (double z1, void * params) {
    
    Params_t& Params = *(Params_t *)(params);
    double z2 = Params.z2;
    double bx1 = Params.bx1;
    double by1 = Params.by1;
    double bx = Params.bx;
    double by = Params.by;
    
    double r1 = sqrt( z1*z1 + bx1*bx1 + by1*by1 );
    double r2 = sqrt( z2*z2 + bx*bx-bx1*bx1 + by*by-by1*by1 );
    double exp1 = c/(1. + exp( (r1-b)/d) );
    double exp2 = c/(1. + exp( (r2-b)/d) );
    
    return exp1*exp2;
    
}

double firstIntegrand(double z2, void * params) {   //does the integration over z1 and sets up function ready for integration over z2 (with bx1,by1 kept fixed)
    
    Params_t& Params = *(Params_t *)(params);
    
    double epsabs = 1e-5;
    double epsrel = 1e-5;
    double lower = 0.;
    double upper = 10;
    
    double result, error;
    
    Params_t custom_Params;
    custom_Params.z2=z2;
    
    double bx1 = Params.bx1;
    double by1 = Params.by1;
    double bx = Params.bx;
    double by = Params.by;
    
    custom_Params.bx1=bx1;
    custom_Params.by1=by1;
    custom_Params.bx=bx;
    custom_Params.by=by;
    
    
    gsl_integration_workspace * ws = gsl_integration_workspace_alloc (3e8);

      gsl_function F;
      F.function = &f;
      F.params = &custom_Params;

      gsl_integration_qags (&F, lower, upper, epsabs, epsrel, 3e8,
                            ws, &result, &error);

      gsl_integration_workspace_free (ws);
    
    return result;
}

double secondIntegrand(double bx1, void * params) { //does the integration over z2 and sets up function ready for integration over bx1 (with by1 kept fixed)
    
    Params_t& Params = *(Params_t *)(params);
    
    double epsabs = 0;
    double epsrel = 1e-7;
    double lower = 0;
    double upper = 10;
    
    double result, error;
    
    Params_t custom_Params;
    custom_Params.bx1=bx1;
    
    
    double by1 = Params.by1;
    double bx = Params.bx;
    double by = Params.by;
    
    custom_Params.by1=by1;
    custom_Params.bx=bx;
    custom_Params.by=by;
    
    
    gsl_integration_workspace * ws = gsl_integration_workspace_alloc (3e8);

      gsl_function F;
      F.function = &firstIntegrand;
      F.params = &custom_Params;

      gsl_integration_qags (&F, lower, upper, epsabs, epsrel, 3e8,
                            ws, &result, &error);

      gsl_integration_workspace_free (ws);
    
    return result;
}

double thirdIntegrand(double by1, void * params) { //does the integration over bx1 and sets up function ready for integration over by1
    
    Params_t& Params = *(Params_t *)(params);
    
    double epsabs = 0;
    double epsrel = 1e-7;
    double lower = 0.;
    double upper = 10;
    
    double result, error;
    
    Params_t custom_Params;
    custom_Params.by1 = by1;
    
    double bx = Params.bx;
    double by = Params.by;
    
    custom_Params.bx=bx;
    custom_Params.by=by;
    
    gsl_integration_workspace * ws = gsl_integration_workspace_alloc (3e8);

      gsl_function F;
      F.function = &secondIntegrand;
      F.params = &custom_Params;

      gsl_integration_qags (&F, lower, upper, epsabs, epsrel, 3e8,
                            ws, &result, &error);

      gsl_integration_workspace_free (ws);
    
    return result;
}

double fourthIntegrand(double bx, double by) { //does the integration over by1 finally
    
    double epsabs = 0.;
    double epsrel = 1e-7;
    double lower = 0.;
    double upper = 10;
    
    double result, error;
    
    Params_t custom_Params;
    
    custom_Params.bx=bx;
    custom_Params.by=by;
    
    
    gsl_integration_workspace * ws = gsl_integration_workspace_alloc (3e8);

    gsl_function F;
    F.function = &thirdIntegrand;
    F.params = &custom_Params;

      gsl_integration_qags (&F, lower, upper, epsabs, epsrel, 3e8,
                            ws, &result, &error);

      gsl_integration_workspace_free (ws);
    
    return result;
}

int main(int argc, const char * argv[]) {
     
     std::count << fourthIntegrand(0.2,0.3) << std::endl; //prints out val of four dim integration for a particular value of bx and by
   
 }
The code works okay for simpler integrands than the exp1*exp2 declared in the opening function declaration. E.g. for bx*by*bx1*by1 or sqrt[z1*z2+bx1*by1]. The problem is in r2, and in particular due to the combination in the sqrt: bx*bx-bx1*bx1 and the fact there is a relative minus (change this to a + and code is OK). I have however been able to my integral in mathematica so I am trying to understand why there is a problem here in gsl. I have played with the relative and absolute error accuracy parameters. Thanks in advance for any comments about this and/or if there is a way to do a multi dimensional integration in gsl more efficiently.
 
Technology news on Phys.org
Is there any overflow or under flow issues that you can check for?
 
  • Like
Likes   Reactions: CAF123
Was the result not what you expected? Was it close but not accurate enough? Did it fail to (a) compile, (b) execute, or (c) terminate? Does it run too slowly? Did your computer burst into flames?
 
  • Like
Likes   Reactions: CAF123
jedishrfu said:
Is there any overflow or under flow issues that you can check for?

pbuk said:
Was the result not what you expected? Was it close but not accurate enough? Did it fail to (a) compile, (b) execute, or (c) terminate? Does it run too slowly? Did your computer burst into flames?
:P yes sorry I should have made that clear. I get the error

gsl: qags.c:553: ERROR: bad integrand behavior found in the integration interval
Default GSL error handler invoked.

originating in firstIntegrand function. So compilation is fine, but execution is not. Thanks.
 
CAF123 said:
The code works okay for simpler integrands than the exp1*exp2 declared in the opening function declaration. E.g. for bx*by*bx1*by1 or sqrt[z1*z2+bx1*by1]. The problem is in r2, and in particular due to the combination in the sqrt: bx*bx-bx1*bx1 and the fact there is a relative minus (change this to a + and code is OK).
From post #1:
Code:
double r2 = sqrt( z2*z2 + bx*bx-bx1*bx1 + by*by-by1*by1 );
If there is a subinterval for which the expression in the call to sqrt() is negative, that seems to me possibly to be the source of the problem noted in the error message.
CAF123 said:
gsl: qags.c:553: ERROR: bad integrand behavior found in the integration interval
 
  • Like
Likes   Reactions: CAF123
Mark44 said:
From post #1:
Code:
double r2 = sqrt( z2*z2 + bx*bx-bx1*bx1 + by*by-by1*by1 );
If there is a subinterval for which the expression in the call to sqrt() is negative, that seems to me possibly to be the source of the problem noted in the error message.
Yes I agree, I had thought about this too but then I was thinking
a) why would the error show up in firstIntegrand when the integration there is over z1?
b) mathematica is able to do it and returns real number
 
CAF123 said:
Yes I agree, I had thought about this too but then I was thinking
a) why would the error show up in firstIntegrand when the integration there is over z1?
b) mathematica is able to do it and returns real number
You are computing
<br /> \int_0^{10} \int_0^{10} \int_0^{10} \int_0^{10} f(x,y,x_1,y_1,z_1,z_2)\,dz_1\,dz_2\,dx_1\,dy_1. The integrand f is only evaluated when integrating over the innermost variable, which is done for all values of the outer variables. Thus if f becomes complex for some value of an outer variable, the program will notice this when trying to integrate over the innermost variable at that value of the outer variable.

The GSL routines define their integrand as a gsl_function, which expects a double argument and returns a double value. They are not therefore designed to deal with complex intermediate results, even if the final result is real. Mathematica is designed to deal with complex values.
 
  • Like
Likes   Reactions: CAF123, pbuk and jim mcnamara
OK I see, thanks. So the calculation must generate an even number of i factors in the evaluation of the integrals such that the end result is overall real, as given by mathematica. I actually prefer what gsl does because, without specifying what side of the branch cut you are on, likely mathematica can give you the wrong sign of the imaginary part in what it does.
 

Similar threads

Replies
6
Views
2K
  • · Replies 11 ·
Replies
11
Views
2K