BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
IntegratorMCMiser.h
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Base/Utils/IntegratorMCMiser.h
6 //! @brief Defines and implements template class IntegratorMCMiser.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************** //
14 
15 #ifndef BORNAGAIN_BASE_UTILS_INTEGRATORMCMISER_H
16 #define BORNAGAIN_BASE_UTILS_INTEGRATORMCMISER_H
17 
18 #include <gsl/gsl_monte_miser.h>
19 #include <memory>
20 
21 //! Alias template for member function with signature double f(double)
22 template <class T> using miser_integrand = double (T::*)(double*, size_t, void*) const;
23 
24 //! Template class to use Monte Carlo MISER integration of class member functions.
25 //!
26 //! Wraps an integrator from GNU Scientific Library.
27 //! Since this class holds a persistent workspace, we need at least one instance per thread.
28 //! Standard usage for integration inside a class T:
29 //! - Create a handle to an integrator:
30 //! 'auto integrator = make_integrator_miser(this, mem_function, dimension)'
31 //! - Call: 'integrator.integrate(lmin, lmax, data, nbr_points)'
32 //! @ingroup tools_internal
33 
34 template <class T> class IntegratorMCMiser
35 {
36 public:
37  //! structure holding the object and possible extra parameters
38  struct CallBackHolder {
39  const T* m_object_pointer;
41  void* m_data;
42  };
43 
44  //! to integrate p_member_function, which must belong to p_object
45  IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function, size_t dim);
47 
48  //! perform the actual integration over the ranges [min_array, max_array]
49  double integrate(double* min_array, double* max_array, void* params, size_t nbr_points);
50 
51 private:
52  //! static function that can be passed to gsl integrator
53  static double StaticCallBack(double* d_array, size_t dim, void* v)
54  {
55  CallBackHolder* p_cb = static_cast<CallBackHolder*>(v);
56  auto mf = static_cast<miser_integrand<T>>(p_cb->m_member_function);
57  return (p_cb->m_object_pointer->*mf)(d_array, dim, p_cb->m_data);
58  }
59  const T* mp_object;
61  size_t m_dim; //!< dimension of the integration
62  gsl_monte_miser_state* m_gsl_workspace;
63  gsl_rng* m_random_gen;
64 };
65 
66 //! Alias template for handle to a miser integrator
67 template <class T> using P_integrator_miser = std::unique_ptr<IntegratorMCMiser<T>>;
68 
69 //! Template function to create an integrator object
70 //! @ingroup tools_internal
71 
72 template <class T>
74  size_t dim)
75 {
76  P_integrator_miser<T> P_integrator(new IntegratorMCMiser<T>(object, mem_function, dim));
77  return P_integrator;
78 }
79 
80 // ************************************************************************** //
81 // Implementation
82 // ************************************************************************** //
83 
84 template <class T>
85 IntegratorMCMiser<T>::IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function,
86  size_t dim)
87  : mp_object(p_object), m_member_function(p_member_function),
88  m_dim(dim), m_gsl_workspace{nullptr}
89 {
90  m_gsl_workspace = gsl_monte_miser_alloc(m_dim);
91 
92  const gsl_rng_type* random_type;
93  gsl_rng_env_setup();
94  random_type = gsl_rng_default;
95  m_random_gen = gsl_rng_alloc(random_type);
96 }
97 
99 {
100  gsl_monte_miser_free(m_gsl_workspace);
101  gsl_rng_free(m_random_gen);
102 }
103 
104 template <class T>
105 double IntegratorMCMiser<T>::integrate(double* min_array, double* max_array, void* params,
106  size_t nbr_points)
107 {
108  CallBackHolder cb = {mp_object, m_member_function, params};
109 
110  gsl_monte_function f;
111  f.f = StaticCallBack;
112  f.dim = m_dim;
113  f.params = &cb;
114 
115  double result, error;
116  gsl_monte_miser_integrate(&f, min_array, max_array, m_dim, nbr_points, m_random_gen,
117  m_gsl_workspace, &result, &error);
118  return result;
119 }
120 
121 #endif // BORNAGAIN_BASE_UTILS_INTEGRATORMCMISER_H
double(T::*)(double *, size_t, void *) const miser_integrand
Alias template for member function with signature double f(double)
std::unique_ptr< IntegratorMCMiser< T > > P_integrator_miser
Alias template for handle to a miser integrator.
Template class to use Monte Carlo MISER integration of class member functions.
static double StaticCallBack(double *d_array, size_t dim, void *v)
static function that can be passed to gsl integrator
double integrate(double *min_array, double *max_array, void *params, size_t nbr_points)
perform the actual integration over the ranges [min_array, max_array]
miser_integrand< T > m_member_function
IntegratorMCMiser(const T *p_object, miser_integrand< T > p_member_function, size_t dim)
to integrate p_member_function, which must belong to p_object
size_t m_dim
dimension of the integration
gsl_monte_miser_state * m_gsl_workspace
P_integrator_miser< T > make_integrator_miser(const T *object, miser_integrand< T > mem_function, size_t dim)
Template function to create an integrator object.
structure holding the object and possible extra parameters
miser_integrand< T > m_member_function