Flow123d  release_2.2.0-20-gb8056ca
interpolant.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file interpolant.hh
15  * @brief
16  */
17 
18 #ifndef INTERPOLATION_H
19 #define INTERPOLATION_H
20 
21 #include "functors.hh"
22 
23 /** This pair contains both the function and the first derivative values and is used
24  * to as return value for functions of interpolation objects.
25  * The reason is that the FADBAD++ library computes both function value and derivative value
26  * at the same time. So when we use FADBAD++ in interpolant classes to compute
27  * derivates, we also return both values and we stick to it in interpolation evaluation also.
28  * We use the form \verbatim pair<function_value, derivative_value> \endverbatim.
29  */
30 typedef std::pair<double,double> DiffValue;
31 
32 
33 /** Enumerates possible kinds of extrapolation.
34  */
36  {
37  typedef enum {constant, ///< means that the values at the boundary points will be used outside the interval_miss_a
38  linear, ///< means that the linear approximation on the first and last subintervals will be used outside the interval
39  functor ///< means that the original functor will be called outside interpolation interval
40  } Type;
41  };
42 
43 /** Enumerates possible norms in which the interpolation error can be computed.
44  */
45  struct ErrorNorm
46  {
47  typedef enum {l2, ///< L2 norm
48  lp, ///< Lp norm
49  w21, ///< W21 norm
50  wp1, ///< Wp1 norm
51  max ///< Maximum norm
52  } Type;
53  };
54 
55 /** Enumerates types of variable fixation in implicit interpolant.
56  */
57  struct IFixVariable
58  {
59  typedef enum { fix_x, ///< x variable will be fixed with given value
60  fix_y, ///< y variable will be fixed with given value
61  no_fix ///< no variable is fixed (used when InterpolantImplicit is created)
62  } Type;
63  };
64 
65 ///Base class for interpolation.
66 /** This class serves as the common interface for interpolation classes.
67  * It provides functions for setting the common parameters of an interpolation
68  * such as interval, size of the table and extrapolation.
69  *
70  * @see Interpolant
71  * @see InterpolantImplicit
72  */
74 {
75 public:
76  ///Default constructor.
78 
79  ///Destructor.
80  virtual ~InterpolantBase();
81 
82  ///@name Interpolation.
83  //@{
84  ///Returns error of the interpolation.
85  /**It is equal to the chosen norm of the difference divided by the lenght of interval.
86  * Returns -1.0 if the interpolation has not been computed yet.
87  */
88  double error();
89 
90  //Gettters
91  double bound_a() const; ///< Returns left boundary of the interval.
92  double bound_b() const; ///< Returns right boundary of the interval.
93  unsigned int size() const; ///< Returns the size of the interpolation table.
94 
95  ///Sets the interpolation interval boundaries.
96  /** @param bound_a is the left boundary of the interval
97  * @param bound_b is the right boundary of the interval
98  */
99  void set_interval(double bound_a,double bound_b);
100 
101  ///Sets size of the interpolation table. It is also equal to the number of intervals.
102  /** @param size is the new size of the interpolation table
103  */
104  void set_size(unsigned int size);
105 
106  ///Sets the type of norm used for computing estimate of the error of the interpolation.
107  /** @param norm_type is the type of norm in which the error of interpolation is computed
108  * @param p is the exponent used in norms \f$ L_p \f$ and \f$ W_p^1 \f$
109  */
110  void set_norm(ErrorNorm::Type norm_type=ErrorNorm::max, double p=2);
111 
112  /// Sets automatic choice of the size of the table.
113  /** When @p interpolate is called than the size is increased (by smaller interval dividing)
114  * until the given tolerance or the maximum size of the interpolation table is reached.
115  * @param user_tol is the tolerance which should the interpolation meet
116  * @param init_size is the initial choice of table size
117  * @param max_size is maximal size of the table that user allows
118  */
119  void set_size_automatic(double user_tol, unsigned int init_size, unsigned int max_size=default_max_size);
120 
121  ///Sets the type of extrapolation. Functor type is default.
122  /** @param extrapolation is the type of extrapolation (defined by enumeration @p ExtrapolationType)
123  */
124  void set_extrapolation(Extrapolation::Type extrapolation);
125 
126  ///Creates piecewise polynomial interpolation.
127  /** @return
128  * - 0 if interpolation has been created
129  * - 1 if the tolerance has not been satisfied (in case of automatic choice of size)
130  */
131  virtual int interpolate() = 0;
132  //@}
133 
134  /** @name Evaluation statistics.
135  * These members are used recording the statistics of the evaluation.
136  */
137  //@{
138  ///Structure that keeps statistics of evaluation.
139  typedef struct {
140  unsigned int interval_miss_a, ///< counts left misses of the interval
141  interval_miss_b, ///< counts right misses of the interval
142  total_calls; ///< counts total calls of evaluation
143 
144  double min, ///< minimal x for which the evaluation was called outside the interval (initially is equal the left boundary)
145  max; ///< maximal x for which the evaluation was called outside the interval ((initially is equal the right boundary)
146  } EvalStatistics;
147 
148  EvalStatistics statistics() const; ///< Returns structure with evaluation statistics.
149 
150  ///Resets all measured statistics.
151  void reset_stat();
152 
153  ///Can be called to check automatically the evaluation statistics and possibly reinterpolate.
154  /** The function computes ratio of evaluations outside the interpolation interval - on each side of the interval.
155  * Then it compares the results with given percentage and accordingly changes (only streches) the interval and reinterpolate.
156  * @param percentage is the percentage of evaluations outside the interval (on one side)
157  */
158  void check_stats_and_reinterpolate(double percentage=0.3);
159  //@}
160 
161 protected:
162  double bound_a_, ///< Left interval boundary.
163  bound_b_, ///< Right interval boundary.
164  step, ///< Chosen interpolation step.
165  a_div_step; ///< bound_ divided by step - precomputed value for evaluation
166 
167  unsigned int size_, ///< Number of dividing intervals.
168  n_nodes; ///< Number of nodes in the interval \f$(a,b)\f$.
169 
170  double user_tol; ///< User set tolerance which is used during automatic step choice.
171  unsigned int max_size;///< Maximal size of the interpolation table.
172  bool automatic_size; ///< Is true if step/size should be chosen automatically.
173  ErrorNorm::Type norm_type; ///< Type of norm used to compute error of the interpolation.
174  double p; ///< Exponent used in norms \f$ L_p \f$ and \f$ W_p^1 \f$ when computing error.
175 
176  double error_; ///< Error of the interpolation.
177 
178  /** Extrapolation type - 'what' is evaluated outside the interpolation interval.
179  * Default value after interpolant construction is InterpolantBase::functor.
180  */
182 
183 
184  const static unsigned int n_derivatives; ///< Defines how many derivatives we allow to be returned from Taylor's coeficients.
185  const static unsigned int default_max_size; ///< Default maximal size of the interpolation table.
186  const static double simpson_tolerance; ///< Tolerance in Adaptive Simpson intergration. @see AdaptiveSimpson
187 
188  ///Recursive factorial function (used in Taylor row expansion in n-th derivative computation).
189  long fact (long x);
190 
191 
192  ///@name Internal check system.
193  /// This is internal check system which checks the values of parameters before making interpolation.
194  //@{
195  struct Check{
196  ///Enumerates parameters that must be set before creation of the interpolant.
197  enum {functor, bound_a, bound_b, size
198  } Type;
199  };
200  ///Vector of boolean values telling us which parameters are set or not.
202  ///Checks that the parameters are set before interpolation.
203  void check_all();
204  //@}
205 
206 
207  //currently not used
208  //bool use_statistics; ///< Is true if statistics is checked (it must be switched of during error computation)
209  EvalStatistics stats; ///< Structure which keeps evaluation statistics. See \ref InterpolantBase::eval_statistics.
210 
211 };
212 
213 
214 /// The main class for interpolation of functors.
215 /** This class is a wrapper of a functor (defined by class \ref FunctorBase) which provides
216  * computation of derivates and interpolation of the functor. We will describe the functionality
217  * in the following paragrahphs.
218  *
219  * ## Evaluation of a functor and its derivatives
220  *
221  * Beside the interpolation, the class provides calling of the functor itself.
222  * All functions evaluating directly the functor starts with '`f_`', e.g. function \ref f_val computes the functor value.
223  *
224  * We use the FADBAD++ library ([website](http://www.fadbad.com)) to compute derivatives of the functor. First derivatives
225  * can be obtained by function \ref f_diff which uses backward automatic differentiation. Higher order derivatives can be
226  * obtained via \ref f_diffn which uses Taylor expansion method.
227  *
228  * ## Interpolation
229  *
230  * Sofar we provide only a piecewise linear interpolation. Both the function and its derivative can be
231  * interpolated. User has to provide the functor object to the constructor or later to the function \ref set_functor.
232  * Then one must set at least the interval \f$ [a,b]\f$ by \ref set_interval and the size of the interpolation table
233  * by \ref set_size before calling \ref interpolate. Otherwise assert will crash the program in debug build.
234  *
235  * When user wants the size to be chosen automatically then \ref set_size_automatic must be called at first.
236  * An initial guess of size of the interpolation table and a tolerance which is assumed to be the maximum relative difference
237  * between the function and the interpolant (sum of value and derivative difference) must be provided.
238  * Futher user can set the maximum size of the interpolation (default 1000) table which will not be exceeded and the type of norm
239  * in which the estimate of the error of interpolation will be computed (enumerated in \ref ErrorNorm, default maximal norm).
240  * See one of the following paragraphs to learn how we deal with the error of the interpolation.
241  *
242  * Outside the given interval the interpolation is extrapolated. User can choose among several types of extrapolation
243  * which are enumerated in \ref Extrapolation. Constant and linear extrapolation use the first and last interpolating polynomials
244  * to compute the value. Functor type means that the functor itself will be evaluated outside the interval. Type of extrapolation
245  * can be changed by \ref set_extrapolation function. Calling functor is the default type of extrapolation.
246  *
247  *
248  * ### Error of the interpolation
249  *
250  * We are interested in the maximum difference between the function value and its interpolation.
251  * When interpolating also the derivative, we need to compute the difference between derivative and
252  * its interpolation too.
253  * Therefore we would like to compute something like the L-infinity norm, relative to function value and its derivative.
254  * Let \f$ f(x), f'(x) \f$ be the function and its derivative and \f$ g(x), g'(x)\f$ interpolation of the function and interpolation
255  * of the derivative on the interval \f$ I \f$. We suggest an approximation of the infinity norm:
256  * \f[
257  * \|f-g\|_\infty = \sup_{x\in I} F(x) = \sup_{x\in I} \left( \frac{|f(x)-g(x)|}{|f(x)| + tol} + \frac{|f'(x)-g'(x)|}{|f'(x)| + tol} \right)
258  * \approx \max_{x\in J} \left( \frac{|f(x)-g(x)|}{|f(x)| + tol} + \frac{|f'(x)-g'(x)|}{|f'(x)| + tol} \right)
259  * \f]
260  * where \f$ J \f$ is set of points that lies in the middle of two neighboring nodes. \f$ tol \f$ is a given tolerance for zero (avoids zero division).
261  * When computing the size of the interpolation table automatically, we compare the user tolerance \f$ TOL \f$ given by \ref set_size_automatic funtion
262  * directly with the estimated value of the supremum norm.
263  *
264  * This approach is fast and when computing the size automatically, we use the computed values (middle points, function and derivative values) in next
265  * interpolation. On the other hand this does not work good around zero points of the function where the value is small and the fraction becomes large or does
266  * not converge when dividing the intervals (\f$ x^2 \f$ is a good example).
267  *
268  * Therefore we provide also error estimation with \f$ L_p \f$ and \f$ W_p^1 \f$ norm. Then the user given tolerance is compared
269  * as it is stated in the following inequation:
270  * \f[
271  * \left( \frac{\int \limits_I F^p(x) \,\rm{d} x}{|I|} \right)^{\frac{1}{p}} \leq TOL.
272  * \f]
273  * This approach is much more expensive but can give better results.
274  *
275  * TODO: Improve error computation. Suggest more robust method.
276  *
277  * ### Evaluation statistics
278  *
279  * We collect some statistics during the evaluation of the interpolant in the struct \ref InterpolantBase::EvalStatistics -- total number of calls, number of evaluations
280  * inside the interpolation interval and number of evaluation outside the interval. One can use these statistics to decide whether it is necessary
281  * to widen the interval and recompute the interpolation. Function \ref check_stats_and_reinterpolate is provided to do this automatically
282  * according to the given percentage of evaluation outside the interval.
283  *
284  */
285 
287 {
288 public:
289  ///Default constructor.
290  Interpolant();
291 
292  ///Constructor with functor setting.
293  /**
294  * @param func is the pointer to functor
295  * @param interpolate_derivative is true when derivate is also interpolated
296  * @tparam Func is the functor type
297  * @tparam Type is the template type of the functor (e.g. double)
298  */
299  template<template<class> class Func, class Type >
300  Interpolant(Func<Type>* func, bool interpolate_derivative=false);
301 
302  ///Destructor.
303  virtual ~Interpolant(void);
304 
305  ///@name Evaluation.
306  //@{
307  ///Returns interpolated value.
308  /** @param x is the point at which we evaluate the interpolation
309  */
310  double val(double x);
311 
312  ///Do NOT use, only for testing purpose.
313  /** TODO: After testing it can be removed and
314  * \ref val_p1 can be made private again.
315  */
316  double val_test(double x);
317 
318  ///Do NOT use, unless you are 100% sure.
319  /** This function evaluates the P1 interpolant at x.
320  * It does not check the interval, does not provide extrapolation
321  * and does not collect statistics.
322  *
323  * Can be used to POSSIBLY speed the evaluation just a little bit,
324  * if you are absolutely sure that you evaluate the interpolant
325  * only on the given interval and do not want to collect statistics.
326  *
327  * Same can be done with \ref diff_p1 if it is made public.
328  *
329  * Used in unit_test benchmark to compare with val function.
330  */
331  double val_p1(double x);
332 
333  ///Returns interpolated value of the derivation.
334  /** @param x is the point at which we evaluate the interpolation
335  */
336  DiffValue diff(double x);
337 
338  ///Returns value of the original functor.
339  /** @param x is the point at which we evaluate the original functor
340  */
341  double f_val(double x);
342 
343  ///Returns 1st derivative of original functor using FADBAD.
344  /** @param x is the point at which we evaluate the original functor
345  */
346  DiffValue f_diff (double x);
347 
348  /** Returns n-th derivative of original functor using FADBAD.
349  * Uses coeficients in Taylor's row.
350  * @param x is the point at which we evaluate the original functor
351  * @param n is the order of the derivative we want
352  */
353  double f_diffn(double x, unsigned int n);
354  //@}
355 
356 
357  ///@name Interpolation.
358  //@{
359  ///Creates piecewise interpolation with polynomials of selected degree.
360  virtual int interpolate();
361 
362  ///Sets the functor.
363  /** Can be used when the functor is not set in the constructor.
364  * @param func is the pointer to functor
365  * @param interpolate_derivative is true when derivate is also interpolated
366  * @tparam Func is the functor type
367  * @tparam Type is the template type of the functor (e.g. double)
368  */
369  template<template<class> class Func, class Type >
370  void set_functor(Func<Type>* func, bool interpolate_derivative=false);
371  //@}
372 
373 protected:
374  class FuncError_lp;
376 
377  FunctorBase<double>* func; ///< Pointer to original functor with double type.
378  FunctorBase<B<double> >* func_diff; ///< Pointer to original functor with FADBAD B type.
379  FunctorBase<T<double> >* func_diffn; ///< Pointer to original functor with FADBAD T type.
380 
381  bool interpolate_derivative; ///< Is true if we want to interpolate the derivative too.
382 
383  //std::vector<double> x_vec; ///< Vector of nodes.
384  std::vector<double> f_vec; ///< Vector of function values at nodes.
385  std::vector<double> df_vec; ///< Vector of function derivatives values at nodes.
386  //std::vector<double> p1_vec; ///< Vector of linear coeficients of P1 interpolation.
387  //std::vector<double> p1d_vec; ///< Vector of linear coeficients of P1 interpolation.
388 
389  //Creates piecewise constant interpolation.
390  //void interpolate_p0();
391 
392  ///Creates piecewise linear interpolation.
393  //void interpolate_p1();
394 
395  ///Computes estimate of interpolation error in maximum norm.
396  void compute_error(double tol, std::vector<double>& f, std::vector<double>& df);
397 
398  ///Computes estimate of interpolation error with given norm.
399  void compute_error(double tol, double p, ErrorNorm::Type norm_type);
400 
401  void swap_middle_values(std::vector<double>& f, std::vector<double>& df);
402 
403  ///Creates table of nodes and function values.
404  /** Creates vector of nodes according to the table size
405  * and computes function and derivative values at the nodes.
406  */
407  void compute_values();
408 
409  ///Finds interval on which @p x lies.
410  //unsigned int find_interval(double x);
411 
412 
413  ///Function that evaluates the derivative of P1 interpolant at @p x.
414  DiffValue diff_p1(double x);
415 };
416 
417 
418 
419 
420 
422 {
423 public:
424 
425  ///@name Construction.
426  //@{
427  ///constructor
429 
430  ///Constructor with functor setting.
431  /**
432  * @param func is the pointer to functor
433  * @param interpolate_derivative is true when derivate is also interpolated
434  * @tparam Func is the functor type
435  * @tparam Type is the template type of the functor (e.g. double)
436  */
437  template<template<class> class Func, class Type >
438  InterpolantImplicit(Func<Type>* func, bool interpolate_derivative=false);
439 
440  ///destructor
441  virtual ~InterpolantImplicit(void);
442 
443  ///Sets the implicit functor.
444  /**
445  * @param func is the pointer to implicit functor.
446  * @tparam Func is the functor class.
447  * @tparam Type is the template type of the functor (e.g. double)
448  */
449  template<template<class> class Func, class Type >
450  void set_functor(Func<Type>* func, bool interpolate_derivative=false);
451 
452  //@}
453 
454  ///@name Evaluation.
455  //@{
456 
457  /** Fixes the chosen variable and sets its fixed value.
458  * @param fix is the chosen variable (no_fix, fix_x or fix_y)
459  * @param value is the fixed value
460  */
461  void fix_variable(IFixVariable::Type fix, double value);
462 
463  ///Returns interpolated value.
464  /** @param u is the point at which we evaluate the interpolation
465  */
466  double val(double u);
467 
468  ///Returns interpolated value of the derivation.
469  /** @param u is the point at which we evaluate the interpolation
470  */
471  DiffValue diff(double u);
472 
473  ///Returns interpolated value of the derivation.
474  /** @param x is the point at which we evaluate the interpolation
475  */
476  //double diffn(const double& x, const unsigned int& n);
477 
478  ///Returns value of the original functor.
479  /** @param x is function variable.
480  * @param y is function variable.
481  */
482  double f_val(double x, double y);
483 
484  ///Returns value of the original functor when one of the variables is fixed.
485  /** @param u is function variable (the one not fixed).
486  */
487  double f_val(double u);
488 
489  ///Returns 1st derivative of original functor using FADBAD.
490  /** @param x is function variable.
491  * @param y is function variable.
492  */
493  DiffValue f_diff (double x, double y);
494 
495  /** Returns n-th derivative of original functor using FADBAD.
496  * Uses coeficients in Taylor's row.
497  * @param u is the point at which we evaluate the original functor
498  * @param n is the order of the derivative we want
499  */
500  double f_diffn(double u, unsigned int n);
501  //@}
502 
503 
504  ///@name Interpolation.
505  //@{
506 
507  ///Creates piecewise interpolation with polynomials of selected degree.
508  virtual int interpolate();
509 
510 
511  //@}
512 
513 
514 protected:
515 
516  template<class Type=double>
518 
523 
524  bool interpolate_derivative; ///< Is true if we want to interpolate the derivative too.
525 
527 
529  double fix_val;
530 
531  ///@name Interpolation.
532  //@{
533 
534  ///Creates piecewise linear interpolation.
535  void interpolate_p1();
536 
537  //@}
538 
539 };
540 
541 #endif
FunctorBase< B< double > > * func_diff
Pointer to original functor with FADBAD B type.
Definition: interpolant.hh:378
bool automatic_size
Is true if step/size should be chosen automatically.
Definition: interpolant.hh:172
ErrorNorm::Type norm_type
Type of norm used to compute error of the interpolation.
Definition: interpolant.hh:173
Lp norm.
Definition: interpolant.hh:48
static const double simpson_tolerance
Tolerance in Adaptive Simpson intergration.
Definition: interpolant.hh:186
IntersectionPoint * interpolate(const IntersectionPoint &A1, const IntersectionPoint &A2, double t)
bool interpolate_derivative
Is true if we want to interpolate the derivative too.
Definition: interpolant.hh:524
static const unsigned int default_max_size
Default maximal size of the interpolation table.
Definition: interpolant.hh:185
unsigned int total_calls
counts total calls of evaluation
Definition: interpolant.hh:140
double user_tol
User set tolerance which is used during automatic step choice.
Definition: interpolant.hh:170
std::vector< double > df_vec
Vector of function derivatives values at nodes.
Definition: interpolant.hh:385
FunctorBase< T< double > > * func_diffn
Pointer to original functor with FADBAD T type.
Definition: interpolant.hh:379
std::pair< double, double > DiffValue
Definition: interpolant.hh:30
Base class for interpolation.
Definition: interpolant.hh:73
std::vector< double > f_vec
Vector of function values at nodes.
Definition: interpolant.hh:384
double error_
Error of the interpolation.
Definition: interpolant.hh:176
static constexpr bool value
Definition: json.hpp:87
IFunctorBase< B< double > > * func_diff
Definition: interpolant.hh:521
Interpolant * explicit_interpolant
Definition: interpolant.hh:526
Wp1 norm.
Definition: interpolant.hh:50
means that the linear approximation on the first and last subintervals will be used outside the inter...
Definition: interpolant.hh:38
Structure that keeps statistics of evaluation.
Definition: interpolant.hh:139
unsigned int max_size
Maximal size of the interpolation table.
Definition: interpolant.hh:171
FunctorBase< double > * func
Pointer to original functor with double type.
Definition: interpolant.hh:375
means that the values at the boundary points will be used outside the interval_miss_a ...
Definition: interpolant.hh:37
W21 norm.
Definition: interpolant.hh:49
double step
Chosen interpolation step.
Definition: interpolant.hh:162
means that the original functor will be called outside interpolation interval
Definition: interpolant.hh:39
IFixVariable::Type fix_
Definition: interpolant.hh:528
std::vector< bool > checks
Vector of boolean values telling us which parameters are set or not.
Definition: interpolant.hh:201
EvalStatistics stats
Structure which keeps evaluation statistics. See InterpolantBase::eval_statistics.
Definition: interpolant.hh:209
Extrapolation::Type extrapolation
Definition: interpolant.hh:181
The main class for interpolation of functors.
Definition: interpolant.hh:286
IFunctorBase< T< double > > * func_diffn
Definition: interpolant.hh:522
IFunctorBase< double > * func
Definition: interpolant.hh:520
FuncExplicit< double > * func_u
Definition: interpolant.hh:517
bool interpolate_derivative
Is true if we want to interpolate the derivative too.
Definition: interpolant.hh:381
static const unsigned int n_derivatives
Defines how many derivatives we allow to be returned from Taylor&#39;s coeficients.
Definition: interpolant.hh:184
y variable will be fixed with given value
Definition: interpolant.hh:60
double p
Exponent used in norms and when computing error.
Definition: interpolant.hh:174
double min
minimal x for which the evaluation was called outside the interval (initially is equal the left bound...
Definition: interpolant.hh:144
Maximum norm.
Definition: interpolant.hh:51
unsigned int size_
Number of dividing intervals.
Definition: interpolant.hh:167