TabulatedFunction.cc
Go to the documentation of this file.
1 #include <iomanip>
2 #include <sstream>
3 #include <cmath>
4 #if !defined(__clang_major__) || __clang_major__ < 5
5 # include <ext/algorithm>
6 #endif
7 #include <utl/TabulatedFunction.h>
8 #include <utl/AugerException.h>
9 #include <utl/ErrorLogger.h>
10 
11 using namespace std;
12 using namespace utl;
13 
15 
16 
17 void
18 TabulatedFunction::FillTable(const Array& xValues,
19  const Array& yValues)
20 {
21  const unsigned int xSize = xValues.size();
22 
23  if (xSize != yValues.size()) {
24  ostringstream err;
25  err << "Size of x and y arrays are different.";
26  ERROR(err);
27  throw OutOfBoundException(err.str());
28  }
29 
30  fX = xValues;
31  fY = yValues;
32 
33  if (is_sorted(fX.begin(), fX.end()))
34  return;
35 
36  // insertion sort
37  for (unsigned int i = 0; i < xSize; ++i) {
38  unsigned int mini = i;
39  double minx = fX[i];
40  for (unsigned int j = i+1; j < xSize; ++j) {
41  const double x = fX[j];
42  if (x < minx) {
43  minx = x;
44  mini = j;
45  }
46  }
47  if (mini != i) {
48  using std::swap;
49  swap(fX[i], fX[mini]);
50  swap(fY[i], fY[mini]);
51  }
52  }
53 }
54 
55 
56 void
57 TabulatedFunction::PushBack(const double x, const double y)
58 {
59  // Check that same X value is not accidentally pushed twice in a row
60  // (a common error)
61  if (fX.size() && fabs(fX.back() - x) < 1./numeric_limits<float>::max()) {
62  ostringstream warn;
63  warn << "Refusing to push the same x value " << x << " twice (y = " << y << ')';
64  WARNING(warn);
65  return;
66  }
67 
68  fX.push_back(x);
69  fY.push_back(y);
70 }
71 
72 
75 double
76 TabulatedFunction::LinearInterpolateY(double x)
77  const
78 {
79  const unsigned int size = fX.size();
80 
81  if (!size) {
82  ostringstream msg;
83  msg << "No points in table.";
84  ERROR(msg);
85  throw OutOfBoundException(msg.str());
86  }
87 
88  if (size == 1)
89  return fY[0];
90 
91  if (x < fX[0] || x > fX[size-1]) {
92 
93  if (x < fX[0] && (fX[0] - x) / (fX[1] - fX[2]) < fBoundaryTolerance)
94  x = fX[0];
95  else if (x > fX[size-1] &&
96  (x - fX[size-1]) / (fX[size-1] - fX[size-2]) < fBoundaryTolerance)
97  x = fX[size-1];
98  else {
99  boost::format err("Value x=%.10f is out of table bounds [%.10f, %.12f].");
100  err % x % fX[0] % fX[size-1];
101  ERROR(err);
102  throw OutOfBoundException(err.str());
103  }
104 
105  }
106 
107  const Array::const_iterator xBegin = fX.begin();
108  const Array::const_iterator xIt = upper_bound(xBegin, fX.end(), x);
109  int index = xIt - xBegin - 1;
110  const double x1 = fX[index];
111  const double y1 = fY[index];
112  if (x1 == x)
113  return y1;
114  ++index;
115  const double x2 = fX[index];
116  const double y2 = fY[index];
117 
118  return y1 + (y2 - y1)*(x - x1)/(x2 - x1);
119 }
120 
121 
122 double
123 TabulatedFunction::InterpolateY(const double x, const unsigned int polyDegree)
124  const
125 {
126  const int nn = fX.size();
127 
128  if (nn == 1 && x == fX.front())
129  return fY.front();
130 
131  if (nn < 2 || polyDegree < 1) {
132  ostringstream msg;
133  msg << "Not enough points in table or wrong polynomial degree.";
134  ERROR(msg);
135  throw OutOfBoundException(msg.str());
136  }
137 
138  const unsigned int mmax = 10;
139  const int m = min(min(polyDegree, mmax), (unsigned int)(nn-1));
140 
141  if (m == 1)
142  return LinearInterpolateY(x);
143 
144  double d[20];
145  double t[20];
146 
147  const Array::const_iterator xBegin = fX.begin();
148  const int ix = upper_bound(xBegin, fX.end(), x) - xBegin - 1;
149 
150  const int mplus = m + 1;
151 
152  // Copy reordered interpolation points into (t[i],d[i]),
153  // setting 'extra' to true if m+2 points to be used.
154  int npts = m + 2 - m % 2;
155  t[0] = fX[ix];
156  d[0] = fY[ix];
157  for (int ip = 1, i = 1; ip < npts; ++i)
158  for (int sign = 1; sign >= -1 && ip < npts; sign -= 2) {
159  const int isub = ix + i*sign;
160  if (0 <= isub && isub < nn) {
161  t[ip] = fX[isub];
162  d[ip] = fY[isub];
163  ++ip;
164  } else
165  npts = mplus;
166  }
167 
168  const bool extra = (npts != mplus);
169  // Replace d by the leading diagonal of a divided-difference table,
170  // Supplemented by an extra line if 'extra' is true.
171  for (int i = 1; i <= m; ++i) {
172  if (extra) {
173  const int isub = mplus - i;
174  d[mplus] = (d[mplus] - d[m - 1]) / (t[mplus] - t[isub - 1]);
175  }
176  for (int k = mplus; k > i; --k) {
177  const int k1 = k - 1;
178  const int isub = k - i;
179  d[k1] = (d[k1] - d[k - 2]) / (t[k1] - t[isub - 1]);
180  }
181  }
182 
183  // Evaluate the Newton interpolation formula at x, averaging two
184  // values of last difference if 'extra' is true.
185  double sum = d[m];
186  if (extra)
187  sum = (sum + d[mplus])/2;
188  for (int j = m; j; --j)
189  sum = d[j - 1] + (x - t[j - 1])*sum;
190 
191  return sum;
192 }
193 
194 
196 TabulatedFunction::FindX(const double x)
197  const
198 {
199  const Array::const_iterator xBegin = fX.begin();
200  const Array::const_iterator xEnd = fX.end();
201  const Array::const_iterator xIt = lower_bound(xBegin, xEnd, x);
202  if (xIt != xEnd && x == *xIt) {
203  const Array::const_iterator yIt = fY.begin() + (xIt - xBegin);
204  return ConstTabulatedFunctionIterator(xIt, yIt);
205  } else
206  return ConstTabulatedFunctionIterator(xEnd, fY.end());
207 }
208 
209 
211 TabulatedFunction::FindY(const double y)
212  const
213 {
214  const Array::const_iterator yIt = find(fY.begin(), fY.end(), y);
215  const Array::const_iterator xIt = yIt != fY.end() ?
216  fX.begin() + (yIt - fY.begin()) : fX.end();
217  return ConstTabulatedFunctionIterator(xIt, yIt);
218 }
219 
220 
222 TabulatedFunction::Insert(const double x, const double y)
223 {
224  const Array::iterator xIt = lower_bound(fX.begin(), fX.end(), x);
225  const Array::iterator yIt = fY.begin() + (xIt - fX.begin());
226  const Array::iterator ixIt = fX.insert(xIt, x);
227  const Array::iterator iyIt = fY.insert(yIt, y);
228  return TabulatedFunctionIterator(ixIt, iyIt);
229 }
void swap(utl::Trace< T > &t1, utl::Trace< T > &t2)
Definition: Trace.h:363
Exception for reporting variable out of valid range.
#define max(a, b)
std::vector< double > Array
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
TabulatedPDF::Array Array
Definition: TabulatedPDF.cc:15

, generated on Tue Sep 26 2023.