GausFitCache.h
Go to the documentation of this file.
1 /**
2  * @file GausFitCache.h
3  * @brief Provide caches for TF1 functions to be used with ROOT fitters
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date March 25th, 2015
6  *
7  *
8  * This might be moved to another namespace than hit, and to a more generic
9  * function cacher.
10  */
11 
12 #ifndef GAUSFITCACHE_H
13 #define GAUSFITCACHE_H 1
14 
15 
16 // C/C++ standard libraries
17 #include <string>
18 #include <vector>
19 
20 // ROOT libraries
21 #include "RtypesCore.h" // Double_t
22 #include "TF1.h" // Double_t
23 
24 namespace hit {
25 
26  /** **************************************************************************
27  * @brief A set of TF1 linear sum of base functions (Gaussians)
28  *
29  * This object holds and owns a number of functions that are linear sum of
30  * "base" functions.
31  * The original use is for Gaussian functions, and this class implements
32  * Gaussians as base functions. This class is used as a base class for other
33  * function caches that do not necessarily use Gaussian base functions.
34  *
35  * The idea is that if you need a temporary function to perform a fit and
36  * extract the parameters, you can reuse the same function over and over
37  * rather than creating a new one each time.
38  *
39  * The expected use for an algorithm is to have one of these caches as a data
40  * member and when the algorithm code needs a function it obtains it with:
41  *
42  * TF1* pFunc = fitcache.Get(nGaussians);
43  *
44  * Then `pFunc` is used for fitting but *never* destroyed.
45  */
46  class GausFitCache {
47  public:
48  /// Constructor; optionally set the name of the repository
49  GausFitCache(std::string new_name = "GausFitCache"): name(new_name) {}
50 
51  /// Destructor
52  virtual ~GausFitCache();
53 
54  /// Return the name of this cache
55  std::string GetName() const { return name; }
56 
57  /**
58  * @brief Returns a function sum of nFunc base functions
59  * @param nGaus the number of base functions in the function
60  * @return a pointer to a TF1 with the required characteristics
61  *
62  * The returned function must not be deleted at any time!
63  *
64  * This implementation returns a function sum of nFunc Gaussians.
65  * The parameters are sorted by Gaussian: first normalization (not the area,
66  * but the coefficient), first mean, first sigma, second normalization etc.
67  */
68  virtual TF1* Get(size_t nFunc);
69 
70  /// Returns a new function sum of nFunc base functions
71  /// (caller needs to set limits and parameters)
72  virtual TF1* GetClone(size_t nGaus);
73 
74  /// Returns a name for the function with nFunc base functions
75  virtual std::string FunctionName(size_t nFunc) const;
76 
77  protected:
78 
79  std::string name; ///< name of the cache
80 
81  ///< Gaussian sum functions; n-th element is sum of n base functions
82  std::vector<TF1*> funcs;
83 
84  /// Creates a new sum function
85  virtual TF1* CreateFunction(size_t nFunc) const;
86 
87  }; // class GausFitCache
88 
89 
90 
91  namespace details {
92 
93  template <typename T>
94  inline T sqr(T v) { return v*v; }
95 
96 
97  /// Struct with member type corresponding to the NArg-th type from Args
98  template <unsigned int NArg, typename FirstArg, typename... Args>
100  using type = typename TemplateArgumentHelper<NArg - 1, Args...>::type;
101  }; // struct TemplateArgumentHelper
102 
103 
104  /// Struct with member type corresponding to the NArg-th type from Args
105  template <unsigned int NArg, typename... Args>
107  using type = typename TemplateArgumentHelper<NArg, Args...>::type;
108  }; // struct TemplateArgument
109 
110 
111 
112  /**
113  * @brief A sum of NFunc base functions Func
114  * @tparam NFunc the number of base functions in the sum
115  * @tparam Func the base function in the sum
116  * @tparam NFuncParams the number of parameters required by Func
117  *
118  * This class provides in its `eval` member a compiled function suitable
119  * to be wrapped into a ROOT's TF1 object.
120  * The function is the sum of NFunc base functions.
121  * Each base function is expected to use NFuncParams parameters. The
122  * first function will use the first set of NFuncParams parameters,
123  * the second one the next set of NFuncParams parameters, and so on.
124  * If NFunc is 0, the value 0 is always returned.
125  */
126  template <
127  unsigned int NFunc,
128  Double_t Func(Double_t const*, Double_t const*),
129  unsigned int NFuncParams
130  >
131  struct FuncSum {
132  static Double_t eval(Double_t const*, Double_t const*);
133  static constexpr unsigned int NParams = NFunc * NFuncParams;
134  }; // struct FuncSum
135 
136  // partial specialization (declaration)
137  template <
138  Double_t Func(Double_t const*, Double_t const*),
139  unsigned int NFuncParams
140  >
141  struct FuncSum<0U, Func, NFuncParams>{
142  static Double_t eval(Double_t const*, Double_t const*);
143  static constexpr unsigned int NParams = 0;
144  }; // struct FuncSum<0>
145 
146 
147 
149  /*
150  * Since, as most of C++ metaprogramming code, this one is quite messy,
151  * some explanations follow.
152  *
153  * The idea is to have a function sum of N base functions, and both N and
154  * which base function can be specified as template parameters.
155  *
156  * The implementation of the sum of N base functions requires a
157  * compile-time "for loop" that is implemented by recursion: a function
158  * with a template parameter N=i calls the same with N=i-1. The loop is
159  * interrupted by a template specialization for N=0 that does not call
160  * N=-1. Unfortunately there is another template parameter that is carried
161  * around, that is the base function. This means that the specialization
162  * for N=0 is a partial specialization, since the function still needs
163  * to be a template parameter. Partial specializations are only allowed
164  * for classes (not for functions). Therefore we have here a class
165  * with two template parameters and a static member eval() where the
166  * total function is defined. Partial specializations of the full class
167  * will implement the necessary N=0 exception to the recursion rule.
168  *
169  * Now, we want to put these in a vector of functions.
170  * This is another loop, and since the function types are decided at
171  * compile time, the loop must be done at compile time too.
172  * Here it goes another class, moving around a vector.
173  * Furthermore, now the actual type of function is a different one for
174  * each element in the array: in this compile-time for-loop, the type
175  * depends on the running parameter, and potentially on others.
176  *
177  *
178  *
179  *
180  */
181  public:
183 
184  /// Throws an exception (ROOT does not support cloning compiled functions)
185  virtual TF1* GetClone(size_t nGaus);
186 
187  /// Returns the maximum number of Gaussians in a function that we support
188  virtual unsigned int MaxGaussians() const { return funcs.size() - 1; }
189 
190 
191  /**
192  * @brief Single Gaussian function
193  * @param x vector; [0] variable value
194  * @param params vector: [0] coefficient of the exponent [1] mean [2] sigma
195  * @return the Gaussian evaluated at *x
196  *
197  * This function is equivalent to ROOT's "gaus".
198  */
199  static Double_t gaus(Double_t const* x, Double_t const* params);
200 
201  template <unsigned int CutOff>
202  static Double_t gaus_trunc(Double_t const* x, Double_t const* params);
203 
204 
205  template <unsigned int NGaus>
206  static Double_t ngaus(Double_t const* x, Double_t const* params)
207  { return gaus(x, params) + ngaus<NGaus-1>(x, params + 3); }
208 
209 
210  /// Sum of NGaus Gaussian functions truncated at CutOff sigmas
211  template <unsigned int NGaus, unsigned int CutOff>
212  static Double_t ngaus_trunc(Double_t const* x, Double_t const* params)
213  { return FuncSum<NGaus, gaus_trunc<CutOff>, 3U>::eval(x, params); }
214 
215  /// Class around sum of NGaus Gaussian functions truncated at CutOff sigmas
216  template <unsigned int NGaus, unsigned int CutOff>
218 
219 
220  protected:
221 
222  /**
223  * @brief A helper class initializing the function vector
224  * @tparam NFunc the maximum number of base functions in a function
225  * @tparam Func the function encapsulating object
226  * @tparam Others other template parameters of the function object
227  *
228  * This helper class provides a static function fill() that fills the
229  * function vector of the specified CompiledGausFitCacheBaseStruct
230  * with a sequence on NFunc+1 functions, of types `Func<0, Others...>`,
231  * `Func<1, Others...>`, ... up to `Func<NFunc, Others...>` included.
232  * Each function is actually wrapped by a ROOT's TF1.
233  * Func type is a class, and the actual function must be found in the
234  * member `Func::eval`. Also the Func class is required to have a
235  * `NParams` static constexpr member whose value is the number of
236  * `parameters that the `eval()` function takes.
237  *
238  * The template FuncSum is implementing all these requirements.
239  */
240  template <unsigned int NFunc, template <unsigned int> class Func>
242  static void fill(CompiledGausFitCacheBaseStruct& cache);
243  }; // struct InitializeFuncSumVector
244 
245  // partial specialization: 0 of any function
246  template <template <unsigned int> class Func>
247  struct InitializeFuncSumVector<0U, Func> {
248  static void fill(CompiledGausFitCacheBaseStruct& cache);
249  }; // struct InitializeFuncSumVector<0, Func>
250 
251 
252  /// Returns a vector initialized with multigaussians
253  template <unsigned int NGaus>
254  void InitializeCompiledGausFitVector();
255 
256  /// Adds one function
257  template <unsigned int NGaus>
258  void AppendFunction();
259 
260  /// Throws an error asserting compiled functions can't be cretead run-time
261  void CannotCreateFunction [[noreturn]] (size_t nGaus) const;
262 
263  }; // class CompiledGausFitCacheBaseStruct
264 
265 
266  } // namespace details
267 
268 
269  /** **************************************************************************
270  * @brief A set of TF1 linear sum of Gaussians
271  * @tparam MaxGaus the maximum number of Gaussians in the stored functions
272  *
273  * This class stores a predefined number MaxGaus of TF1
274  * from pre-compiled functions.
275  */
276  template <unsigned int MaxGaus = 10>
278  {
279  public:
280 
281  /// Constructor: initializes all the functions
282  CompiledGausFitCache(std::string new_name = "CompiledGausFitCache"):
283  details::CompiledGausFitCacheBaseStruct(new_name)
284  { InitializeCompiledGausFitVector<MaxGaus>(); }
285 
286  virtual unsigned int MaxGaussians() const { return StoredMaxGaussians(); }
287 
288  /// Returns the maximum number of Gaussians in a function that we support
289  constexpr unsigned int StoredMaxGaussians() const { return MaxGaus; }
290 
291  protected:
292 
293  /// Throws an error, since this class can't create functions run-time
294  virtual TF1* CreateFunction [[noreturn]] (size_t nGaus) const
295  { CannotCreateFunction(nGaus); }
296 
297  }; // class CompiledGausFitCache
298 
299 
300  /** **************************************************************************
301  * @brief A set of TF1 linear sum of truncated Gaussians
302  * @tparam MaxGaus the maximum number of Gaussians in the stored functions
303  * @tparam CutOff number of sigmas beyond which the function evaluates as 0
304  *
305  * This class stores a predefined number MaxGaus of TF1 from pre-compiled
306  * functions. Each function is the linear sum of truncated Gaussians, at most
307  * MaxGaus of them,
308  */
309  template <unsigned int MaxGaus = 10, unsigned int CutOff = 5>
312  {
313  template <unsigned int NGaus>
315 
316  public:
317 
318  /// Constructor: initializes all the functions
320  (std::string new_name = "CompiledTruncatedGausFitCache"):
322  {
324  }
325 
326 
327  virtual unsigned int MaxGaussians() const { return StoredMaxGaussians(); }
328 
329  /// Returns the maximum number of Gaussians in a function that we support
330  constexpr unsigned int StoredMaxGaussians() const { return MaxGaus; }
331 
332  protected:
333 
334  /// Throws an error, since this class can't create functions run-time
335  virtual TF1* CreateFunction [[noreturn]] (size_t nGaus) const
336  { CannotCreateFunction(nGaus); }
337 
338  }; // class CompiledTruncatedGausFitCache
339 
340 
341 
342  //
343  // template implementation
344  //
345 
346  namespace details {
347 
348  // --- FuncSum -------------------------------------------------------------
349  template <
350  unsigned int NFunc,
351  Double_t Func(Double_t const*, Double_t const*),
352  unsigned int NFuncParams
353  >
354  constexpr unsigned int FuncSum<NFunc, Func, NFuncParams>::NParams;
355 
356  template<
357  unsigned int NFunc,
358  Double_t Func(Double_t const*, Double_t const*),
359  unsigned int NFuncParams
360  >
361  Double_t FuncSum<NFunc, Func, NFuncParams>::eval
362  (Double_t const* x, Double_t const* params)
363  {
364  return Func(x, params + NFuncParams*(NFunc-1)) // use the last parameters
366  } // CompiledGausFitCacheBaseStruct::FuncSum<NFunc, Func>::eval()
367 
368 
369  // partial specialization: 0 of any function
370  template <
371  Double_t Func(Double_t const*, Double_t const*),
372  unsigned int NFuncParams
373  >
375  (Double_t const*, Double_t const*)
376  { return 0.; }
377 
378 
379 
380  // --- CompiledGausFitCacheBaseStruct --------------------------------------
381 
382  template <unsigned int NGaus>
383  void CompiledGausFitCacheBaseStruct::InitializeCompiledGausFitVector() {
384  if (NGaus > 0) InitializeCompiledGausFitVector<NGaus-1>();
385  AppendFunction<NGaus>();
386  } // CompiledGausFitCacheBaseStruct::InitializeCompiledGausFitVector()
387 
388 
389  template <>
390  inline void
391  CompiledGausFitCacheBaseStruct::InitializeCompiledGausFitVector<0>()
392  { AppendFunction<0>(); }
393 
394 
395  template <unsigned int NGaus>
396  void CompiledGausFitCacheBaseStruct::AppendFunction() {
397  // create a function in the ficticious range [ 0, 1 ]:
398  funcs.push_back
399  (new TF1(FunctionName(NGaus).c_str(), &ngaus<NGaus>, 0., 1., 3*NGaus));
400  } // CompiledGausFitCacheBaseStruct::AppendFunction()
401 
402 
403  template <unsigned int CutOff>
404  Double_t CompiledGausFitCacheBaseStruct::gaus_trunc
405  (Double_t const* x, Double_t const* params)
406  {
407  const Double_t z = (x[0] - params[1])/params[2];
408  return ((z > -((Double_t) CutOff)) && (z < (Double_t) CutOff))?
409  params[0] * std::exp(-0.5*sqr(z)): 0.;
410  } // CompiledGausFitCacheBaseStruct::gaus_trunc()
411 
412 
413  template <>
414  inline Double_t CompiledGausFitCacheBaseStruct::ngaus<0>
415  (Double_t const* x, Double_t const* params)
416  { return 0.; }
417 
418 
419 
420  // --- CompiledGausFitCacheBaseStruct::InitializeFuncSumVector -------------
421 
422  template <unsigned int NFunc, template <unsigned int> class Func>
423  void
426  {
427  // first fill the lower functions
429  // then add one
430  cache.funcs.push_back(new TF1(
431  cache.FunctionName(NFunc).c_str(), Func<NFunc>::eval,
432  0., 1., Func<NFunc>::NParams
433  ));
434  } // InitializeFuncSumVector<NFunc, Func>::fill()
435 
436 
437  template <template <unsigned int> class Func>
438  void
441  {
442  cache.funcs.push_back
443  (new TF1(cache.FunctionName(0).c_str(), Func<0U>::eval, 0., 1., 0));
444  } // InitializeFuncSumVector<0, Func>::fill()
445 
446  // -------------------------------------------------------------------------
447 
448  } // namespace details
449 
450 
451  // ---------------------------------------------------------------------------
452 
453 } // namespace hit
454 
455 
456 #endif // GAUSFITCACHE_H
virtual unsigned int MaxGaussians() const
Returns the maximum number of Gaussians in a function that we support.
Definition: GausFitCache.h:286
constexpr unsigned int StoredMaxGaussians() const
Returns the maximum number of Gaussians in a function that we support.
Definition: GausFitCache.h:330
std::vector< TF1 * > funcs
Definition: GausFitCache.h:82
virtual TF1 * CreateFunction(size_t nFunc) const
Creates a new sum function.
std::string string
Definition: nybbler.cc:12
static Double_t ngaus_trunc(Double_t const *x, Double_t const *params)
Sum of NGaus Gaussian functions truncated at CutOff sigmas.
Definition: GausFitCache.h:212
CompiledGausFitCache(std::string new_name="CompiledGausFitCache")
Constructor: initializes all the functions.
Definition: GausFitCache.h:282
A sum of NFunc base functions Func.
Definition: GausFitCache.h:131
A set of TF1 linear sum of base functions (Gaussians)
Definition: GausFitCache.h:46
virtual ~GausFitCache()
Destructor.
A set of TF1 linear sum of Gaussians.
Definition: GausFitCache.h:277
A set of TF1 linear sum of truncated Gaussians.
Definition: GausFitCache.h:310
T gaus(T x, T amplitude, T mean, T sigma)
Tests GausssianFit object with a known input.
A helper class initializing the function vector.
Definition: GausFitCache.h:241
virtual unsigned int MaxGaussians() const
Returns the maximum number of Gaussians in a function that we support.
Definition: GausFitCache.h:188
Struct with member type corresponding to the NArg-th type from Args.
Definition: GausFitCache.h:99
virtual TF1 * Get(size_t nFunc)
Returns a function sum of nFunc base functions.
GausFitCache(std::string new_name="GausFitCache")
Constructor; optionally set the name of the repository.
Definition: GausFitCache.h:49
Detector simulation of raw signals on wires.
static Double_t ngaus(Double_t const *x, Double_t const *params)
Definition: GausFitCache.h:206
constexpr unsigned int StoredMaxGaussians() const
Returns the maximum number of Gaussians in a function that we support.
Definition: GausFitCache.h:289
def fill(s)
Definition: translator.py:93
virtual std::string FunctionName(size_t nFunc) const
Returns a name for the function with nFunc base functions.
static QCString type
Definition: declinfo.cpp:672
list x
Definition: train.py:276
virtual unsigned int MaxGaussians() const
Returns the maximum number of Gaussians in a function that we support.
Definition: GausFitCache.h:327
std::string GetName() const
Return the name of this cache.
Definition: GausFitCache.h:55
Struct with member type corresponding to the NArg-th type from Args.
Definition: GausFitCache.h:106
std::string name
name of the cache
Definition: GausFitCache.h:79
virtual TF1 * GetClone(size_t nGaus)