ReFRACtor
linear_interpolate_ad.h
Go to the documentation of this file.
1 #ifndef LINEAR_INTERPOLATE_AD_H
2 #define LINEAR_INTERPOLATE_AD_H
3 #include "linear_interpolate.h"
4 #include "auto_derivative.h"
5 #include <iostream>
6 
7 namespace FullPhysics {
8 
9 template<> class InterpolatePoint<AutoDerivative<double>,
10  AutoDerivative<double> > {
11 public:
12  virtual const AutoDerivative<double>& x_min() const = 0;
13  virtual const AutoDerivative<double>& x_max() const = 0;
14  virtual void interpolate(const AutoDerivative<double>& x,
15  const AutoDerivativeRef<double>& res) const = 0;
16 };
17 
18 template<> class Return1Point<AutoDerivative<double>,
19  AutoDerivative<double> > :
20  public InterpolatePoint<AutoDerivative<double>,
21  AutoDerivative<double> >,
22  public Printable<Return1Point<AutoDerivative<double>,
23  AutoDerivative<double> > > {
24 public:
26  : x0_(x0), y0_(y0)
27  {}
28  const AutoDerivative<double>& x_min() const {return x0_; }
29  const AutoDerivative<double>& x_max() const {return x0_; }
31  const AutoDerivativeRef<double>& res) const { res = y0_; }
32  void print(std::ostream& Os) const { Os << "Return1Point"; }
33 private:
36 };
37 
38 /****************************************************************/
43 template<>
45  public InterpolatePoint<AutoDerivative<double>, AutoDerivative<double> >,
46  public Printable<LinearInterpolate2Point<AutoDerivative<double>,
47  AutoDerivative<double> > > {
48 public:
50  const AutoDerivative<double> & y0,
51  const AutoDerivative<double>& x1,
52  const AutoDerivative<double> & y1)
53  : x0_(x0), x1_(x1), y0_(y0), delta_y0_((y1 - y0) / (x1 - x0))
54  {
55  range_max_check(x0, x1);
56  }
57  const AutoDerivative<double>& x_min() const {return x0_; }
58  const AutoDerivative<double>& x_max() const {return x1_; }
59  virtual void interpolate(const AutoDerivative<double>& x,
60  const AutoDerivativeRef<double>& res) const
61  {
62  res.value_ref() = y0_.value() +
63  delta_y0_.value() * (x.value() - x0_.value());
64  if(x.is_constant() && y0_.is_constant())
65  res.gradient_ref() = 0;
66  else if(x.is_constant())
67  res.gradient_ref() = y0_.gradient() + delta_y0_.gradient() *
68  (x.value() - x0_.value()) - delta_y0_.value() * x0_.gradient();
69  else if(y0_.is_constant())
70  res.gradient_ref() = delta_y0_.value() * x.gradient();
71  else
72  res.gradient_ref() = y0_.gradient() + delta_y0_.gradient() *
73  (x.value() - x0_.value()) +
74  delta_y0_.value() * (x.gradient() - x0_.gradient());
75  }
76  void print(std::ostream& Os) const { Os << "LinearInterpolate2Point"; }
77 private:
81  AutoDerivative<double> delta_y0_;
82 };
83 
84 /****************************************************************/
89 template<> class LinearInterpolate<AutoDerivative<double>,
90  AutoDerivative<double> > :
91  public Printable<LinearInterpolate<AutoDerivative<double>,
92  AutoDerivative<double> > > {
93 public:
95  {OUT_OF_RANGE_EXTRAPOLATE = 0, OUT_OF_RANGE_CLIP, OUT_OF_RANGE_ERROR};
97 
98 //-----------------------------------------------------------------------
101 //-----------------------------------------------------------------------
102 
103  template<class I1, class I2> LinearInterpolate(I1 xstart, I1 xend,
104  I2 ystart, BehaviorOutOfRange Out_of_range = OUT_OF_RANGE_EXTRAPOLATE)
105  : out_of_range(Out_of_range), nvar(0)
106 
107  {
108  if(std::distance(xstart, xend) == 0) {
109  // If no values then we can not do any interpolation,
110  // error in operator if attempted
111  return;
112  } else {
113  nvar = std::max(xstart->number_variable(), ystart->number_variable());
114  if(std::distance(xstart, xend) == 1) {
115  // If only one value available then just return that one point
116  // no need for interpolation
117  AutoDerivative<double> x0 = *xstart;
118  AutoDerivative<double> y0 = *ystart;
119  if(nvar > 0 && x0.is_constant()) {
120  x0.gradient().resize(nvar);
121  x0.gradient() = 0;
122  }
123  if(nvar > 0 && y0.is_constant()) {
124  y0.gradient().resize(nvar);
125  y0.gradient() = 0;
126  }
127  if(x0.number_variable() != y0.number_variable())
128  throw Exception("x0 and y0 need to have the same number of variables");
132  AutoDerivative<double> >(x0, y0));
133 
134  } else while(xstart != xend) {
135  // For two more points we can use linear interpolation
136  AutoDerivative<double> x0 = *xstart++;
137  AutoDerivative<double> y0 = *ystart++;
138  if(nvar > 0 && x0.is_constant()) {
139  x0.gradient().resize(nvar);
140  x0.gradient() = 0;
141  }
142  if(nvar > 0 && y0.is_constant()) {
143  y0.gradient().resize(nvar);
144  y0.gradient() = 0;
145  }
146  if(x0.number_variable() != nvar)
147  throw Exception("All X and Y need to have the same number of variables");
148  if(y0.number_variable() != nvar)
149  throw Exception("All X and Y need to have the same number of variables");
150 
151  if(xstart == xend)
152  break;
153  AutoDerivative<double> x1 = *xstart;
154  AutoDerivative<double> y1 = *ystart;
155  if(nvar > 0 && x1.is_constant()) {
156  x1.gradient().resize(nvar);
157  x1.gradient() = 0;
158  }
159  if(nvar > 0 && y1.is_constant()) {
160  y1.gradient().resize(nvar);
161  y1.gradient() = 0;
162  }
163  if(x1.number_variable() != nvar)
164  throw Exception("All X and Y need to have the same number of variables");
165  if(y1.number_variable() != nvar)
166  throw Exception("All X and Y need to have the same number of variables");
167  if(x1 <= x0)
168  throw Exception("X needs to be sorted");
169 
173  AutoDerivative<double> >(x0, y0, x1, y1));
174  }
175  }
176  }
179  res.gradient().resize(std::max(nvar, x.number_variable()));
180  AutoDerivativeRef<double> res2(res.value(), res.gradient());
181  interpolate(x, res2);
182  return res;
183  }
184  // Version of operator() that avoids creating a new temporary for
185  // returning. Instead we use an existing ArrayRef. Note that this
186  // should already be the right size, if it isn't an error will
187  // occur.
189  const AutoDerivativeRef<double>& res) const
190  {
191  if(inter.empty()) {
192  throw Exception("Can not interpolate since interpolation map is empty.");
193  }
194 
195  typedef
197  const_iterator Itype;
198  Itype i = inter.lower_bound(x);
199  if(i == inter.end()) { // Are we past the end?
200  switch(out_of_range) {
201  case OUT_OF_RANGE_ERROR:
202  {
203  std::stringstream err_msg;
204  err_msg << "Linear interpolation AD point "
205  << x.value() << " is past the end of interpolation range: "
206  << "[" << inter.begin()->first.value()
207  << ", " << inter.rbegin()->first.value() << "]";
208  throw Exception(err_msg.str());
209  }
210  case OUT_OF_RANGE_EXTRAPOLATE:
211  inter.rbegin()->second->interpolate(x, res);
212  break;
213  case OUT_OF_RANGE_CLIP:
214  inter.rbegin()->second->interpolate(inter.rbegin()->second->x_max(),
215  res);
216  break;
217  default:
218  throw Exception("Unknown out_of_range value");
219  }
220  } else {
221  if(x >= i->second->x_min())
222  i->second->interpolate(x, res);
223  else
224  switch(out_of_range) {
225  case OUT_OF_RANGE_ERROR:
226  {
227  std::stringstream err_msg;
228  err_msg << "Linear interpolation AD point "
229  << x.value() << " is outside of interpolation range: "
230  << "[" << inter.begin()->first.value()
231  << ", " << inter.rbegin()->first.value() << "]";
232  throw Exception(err_msg.str());
233  }
234  case OUT_OF_RANGE_EXTRAPOLATE:
235  i->second->interpolate(x, res);
236  break;
237  case OUT_OF_RANGE_CLIP:
238  i->second->interpolate(i->second->x_min(), res);
239  break;
240  default:
241  throw Exception("Unknown out_of_range value");
242  }
243  }
244  }
245  void print(std::ostream& Os) const { Os << "LinearInterpolate"; }
246 private:
247  std::map<AutoDerivative<double>, boost::shared_ptr<InterpolatePoint<AutoDerivative<double>, AutoDerivative<double> > > > inter;
248  BehaviorOutOfRange out_of_range;
249  int nvar;
250 };
251 }
252 #endif
#define range_max_check(V, Max)
Range check.
Definition: fp_exception.h:194
bool is_constant() const
Is this object a constant (with a gradient() all zeros)?
This just returns the same y value, always.
LinearInterpolate2Point(const AutoDerivative< double > &x0, const AutoDerivative< double > &y0, const AutoDerivative< double > &x1, const AutoDerivative< double > &y1)
This class takes a set of points and values, and linearly interpolates between those values...
This is the base of the exception hierarchy for Full Physics code.
Definition: fp_exception.h:16
blitz::Array< T, 1 > & gradient_ref() const
Helper class that gives us a reference that we can assign a AutoDerivative to and write into the corr...
AutoDerivative< double > operator()(const AutoDerivative< double > &x) const
This is a Mixin for classes that can be printed.
Definition: printable.h:24
Interface for interpolating values.
void interpolate(const AutoDerivative< double > &x, const AutoDerivativeRef< double > &res) const
void interpolate(const AutoDerivative< double > &x, const AutoDerivativeRef< double > &res) const
This does linear interpolate between two points.
There are a number of tools that can be used to do "Automatic Differentiation" (see for example http:...
LinearInterpolate(I1 xstart, I1 xend, I2 ystart, BehaviorOutOfRange Out_of_range=OUT_OF_RANGE_EXTRAPOLATE)
Constructor.
int number_variable() const
Number of variables in gradient.
const blitz::Array< T, 1 > & gradient() const
Gradient.
virtual void interpolate(const AutoDerivative< double > &x, const AutoDerivativeRef< double > &res) const
virtual const TX & x_min() const =0
Contains classes to abstract away details in various Spurr Radiative Transfer software.
Definition: doxygen_python.h:1
const T & value() const
Convert to type T.
Return1Point(const AutoDerivative< double > &x0, const AutoDerivative< double > &y0)
virtual const TX & x_max() const =0

Copyright © 2017, California Institute of Technology.
ALL RIGHTS RESERVED.
U.S. Government Sponsorship acknowledged.
Generated Fri Aug 24 2018 15:44:11