BornAgain  1.19.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 reflection and scattering
4 //
5 //! @file Base/Math/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 #ifdef SWIG
16 #error no need to expose this header to Swig
17 #endif
18 
19 #ifndef USER_API
20 #ifndef BORNAGAIN_BASE_MATH_INTEGRATORMCMISER_H
21 #define BORNAGAIN_BASE_MATH_INTEGRATORMCMISER_H
22 
23 #include <gsl/gsl_monte_miser.h>
24 #include <memory>
25 
26 //! Alias template for member function with signature double f(double)
27 template <class T> using miser_integrand = double (T::*)(double*, size_t, void*) const;
28 
29 //! Template class to use Monte Carlo MISER integration of class member functions.
30 //!
31 //! Wraps an integrator from GNU Scientific Library.
32 //! Since this class holds a persistent workspace, we need at least one instance per thread.
33 //! Standard usage for integration inside a class T:
34 //! - Create a handle to an integrator:
35 //! 'auto integrator = make_integrator_miser(this, mem_function, dimension)'
36 //! - Call: 'integrator.integrate(lmin, lmax, data, nbr_points)'
37 //! @ingroup tools_internal
38 
39 template <class T> class IntegratorMCMiser {
40 public:
41  //! structure holding the object and possible extra parameters
42  struct CallBackHolder {
43  const T* m_object_pointer;
45  void* m_data;
46  };
47 
48  //! to integrate p_member_function, which must belong to p_object
49  IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function, size_t dim);
51 
52  //! perform the actual integration over the ranges [min_array, max_array]
53  double integrate(double* min_array, double* max_array, void* params, size_t nbr_points);
54 
55 private:
56  //! static function that can be passed to gsl integrator
57  static double StaticCallBack(double* d_array, size_t dim, void* v)
58  {
59  CallBackHolder* p_cb = static_cast<CallBackHolder*>(v);
60  auto mf = static_cast<miser_integrand<T>>(p_cb->m_member_function);
61  return (p_cb->m_object_pointer->*mf)(d_array, dim, p_cb->m_data);
62  }
63  const T* m_object;
65  size_t m_dim; //!< dimension of the integration
66  gsl_monte_miser_state* m_gsl_workspace;
67  gsl_rng* m_random_gen;
68 };
69 
70 //! Alias template for handle to a miser integrator
71 template <class T> using P_integrator_miser = std::unique_ptr<IntegratorMCMiser<T>>;
72 
73 //! Template function to create an integrator object
74 //! @ingroup tools_internal
75 
76 template <class T>
78  size_t dim)
79 {
80  P_integrator_miser<T> P_integrator(new IntegratorMCMiser<T>(object, mem_function, dim));
81  return P_integrator;
82 }
83 
84 // ************************************************************************************************
85 // Implementation
86 // ************************************************************************************************
87 
88 template <class T>
89 IntegratorMCMiser<T>::IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function,
90  size_t dim)
91  : m_object(p_object), m_member_function(p_member_function), m_dim(dim), m_gsl_workspace{nullptr}
92 {
93  m_gsl_workspace = gsl_monte_miser_alloc(m_dim);
94 
95  const gsl_rng_type* random_type;
96  gsl_rng_env_setup();
97  random_type = gsl_rng_default;
98  m_random_gen = gsl_rng_alloc(random_type);
99 }
100 
102 {
103  gsl_monte_miser_free(m_gsl_workspace);
104  gsl_rng_free(m_random_gen);
105 }
106 
107 template <class T>
108 double IntegratorMCMiser<T>::integrate(double* min_array, double* max_array, void* params,
109  size_t nbr_points)
110 {
111  CallBackHolder cb = {m_object, m_member_function, params};
112 
113  gsl_monte_function f;
114  f.f = StaticCallBack;
115  f.dim = m_dim;
116  f.params = &cb;
117 
118  double result, error;
119  gsl_monte_miser_integrate(&f, min_array, max_array, m_dim, nbr_points, m_random_gen,
120  m_gsl_workspace, &result, &error);
121  return result;
122 }
123 
124 #endif // BORNAGAIN_BASE_MATH_INTEGRATORMCMISER_H
125 #endif // USER_API
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