BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
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>
28 using miser_integrand = double (T::*)(const double*, size_t, const void*) const;
29 
30 //! Template class to use Monte Carlo MISER integration of class member functions.
31 //!
32 //! Wraps an integrator from GNU Scientific Library.
33 //! Since this class holds a persistent workspace, we need at least one instance per thread.
34 //! Standard usage for integration inside a class T:
35 //! - Create a handle to an integrator:
36 //! 'auto integrator = make_integrator_miser(this, mem_function, dimension)'
37 //! - Call: 'integrator.integrate(lmin, lmax, data, nbr_points)'
38 
39 template <class T>
41 public:
42  //! structure holding the object and possible extra parameters
43  struct CallBackHolder {
44  const T* m_object_pointer;
46  const void* m_data;
47  };
48 
49  //! to integrate p_member_function, which must belong to p_object
50  IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function, size_t dim);
52 
53  //! perform the actual integration over the ranges [min_array, max_array]
54  double integrate(double* min_array, double* max_array, const void* params,
55  size_t nbr_points) const;
56 
57 private:
58  //! static function that can be passed to gsl integrator
59  static double StaticCallBack(double* d_array, size_t dim, void* v)
60  {
61  auto* p_cb = static_cast<CallBackHolder*>(v);
62  auto mf = static_cast<miser_integrand<T>>(p_cb->m_member_function);
63  return (p_cb->m_object_pointer->*mf)(d_array, dim, p_cb->m_data);
64  }
65  const T* m_object;
67  const size_t m_dim; //!< dimension of the integration
68  gsl_monte_miser_state* m_gsl_workspace;
69  gsl_rng* m_random_gen;
70 };
71 
72 //! Alias template for handle to a miser integrator
73 template <class T>
74 using P_integrator_miser = std::unique_ptr<IntegratorMCMiser<T>>;
75 
76 //! Template function to create an integrator object
77 
78 template <class T>
80  size_t dim)
81 {
82  P_integrator_miser<T> P_integrator(new IntegratorMCMiser<T>(object, mem_function, dim));
83  return P_integrator;
84 }
85 
86 // ************************************************************************************************
87 // Implementation
88 // ************************************************************************************************
89 
90 template <class T>
91 IntegratorMCMiser<T>::IntegratorMCMiser(const T* p_object, miser_integrand<T> p_member_function,
92  size_t dim)
93  : m_object(p_object)
94  , m_member_function(p_member_function)
95  , m_dim(dim)
96  , m_gsl_workspace{nullptr}
97 {
98  m_gsl_workspace = gsl_monte_miser_alloc(m_dim);
99 
100  const gsl_rng_type* random_type;
101  gsl_rng_env_setup();
102  random_type = gsl_rng_default;
103  m_random_gen = gsl_rng_alloc(random_type);
104 }
105 
106 template <class T>
108 {
109  gsl_monte_miser_free(m_gsl_workspace);
110  gsl_rng_free(m_random_gen);
111 }
112 
113 template <class T>
114 double IntegratorMCMiser<T>::integrate(double* min_array, double* max_array, const void* params,
115  size_t nbr_points) const
116 {
117  CallBackHolder cb = {m_object, m_member_function, params};
118 
119  gsl_monte_function f;
120  f.f = StaticCallBack;
121  f.dim = m_dim;
122  f.params = &cb;
123 
124  double result, error;
125  gsl_monte_miser_integrate(&f, min_array, max_array, m_dim, nbr_points, m_random_gen,
126  m_gsl_workspace, &result, &error);
127  return result;
128 }
129 
130 #endif // BORNAGAIN_BASE_MATH_INTEGRATORMCMISER_H
131 #endif // USER_API
std::unique_ptr< IntegratorMCMiser< T > > P_integrator_miser
Alias template for handle to a miser integrator.
double(T::*)(const double *, size_t, const void *) const miser_integrand
Alias template for member function with signature double f(double)
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.
Template class to use Monte Carlo MISER integration of class member functions.
double integrate(double *min_array, double *max_array, const void *params, size_t nbr_points) const
perform the actual integration over the ranges [min_array, max_array]
static double StaticCallBack(double *d_array, size_t dim, void *v)
static function that can be passed to gsl integrator
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
const miser_integrand< T > m_member_function
gsl_monte_miser_state * m_gsl_workspace
const size_t m_dim
dimension of the integration
structure holding the object and possible extra parameters
const miser_integrand< T > m_member_function