Project
Loading...
Searching...
No Matches
Spline1DHelperOld.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
17#include "Spline1DHelperOld.h"
18#include "GPUCommonLogger.h"
19#include "TMath.h"
20#include "TMatrixD.h"
21#include "TVectorD.h"
22#include "TDecompBK.h"
23#include <vector>
24
25#include "TRandom.h"
26#include "TMath.h"
27#include "TCanvas.h"
28#include "TNtuple.h"
29#include "TFile.h"
30#include "GPUCommonMath.h"
31#include <iostream>
32
34
35using namespace o2::gpu;
36
37template <typename DataT>
38Spline1DHelperOld<DataT>::Spline1DHelperOld() : mError(), mSpline(), mFdimensions(0)
39{
40}
41
42template <typename DataT>
43int32_t Spline1DHelperOld<DataT>::storeError(int32_t code, const char* msg)
44{
45 mError = msg;
46 return code;
47}
48
49template <typename DataT>
51 double& cSl, double& cDl, double& cSr, double& cDr)
52{
55
56 // F(u) = cSl * Sl + cSr * Sr + cDl * Dl + cDr * Dr;
57
58 u = u - knotL.u;
59 double v = u * double(knotL.Li); // scaled u
60 double vm1 = v - 1.;
61 double a = u * vm1;
62 double v2 = v * v;
63 cSl = v2 * (2 * v - 3.) + 1; // == 2*v3 - 3*v2 + 1
64 cDl = vm1 * a; // == (v2 - 2v + 1)*u
65 cSr = 1. - cSl;
66 cDr = v * a; // == (v2 - v)*u
67}
68
69template <typename DataT>
71 double& cSl, double& cDl, double& cSr, double& cDr)
72{
73 u = u - knotL.u;
74 double dv = double(knotL.Li);
75 double v = u * dv; // scaled u
76 double v2 = v * v;
77 cSl = 6 * (v2 - v) * dv;
78 cDl = 3 * v2 - 4 * v + 1.;
79 cSr = -cSl;
80 cDr = 3 * v2 - 2 * v;
81 // at v==0 : 0, 1, 0, 0
82 // at v==1 : 0, 0, 0, 1
83}
84
85template <typename DataT>
87 double& cSl, double& cDl, double& cSr, double& cDr)
88{
89 u = u - knotL.u;
90 double dv = double(knotL.Li);
91 double v = u * dv; // scaled u
92 cSl = (12 * v - 6) * dv * dv;
93 cDl = (6 * v - 4) * dv;
94 cSr = -cSl;
95 cDr = (6 * v - 2) * dv;
96}
97
98template <typename DataT>
100 double& cSl, double& cDl, double& cSr, double& cDr)
101{
102 double dv = double(knotL.Li);
103 cSl = -6 * dv * dv;
104 cDl = -4 * dv;
105 cSr = -cSl;
106 cDr = -2 * dv;
107}
108
109template <typename DataT>
111 double& cSl, double& cDl, double& cSr, double& cDr)
112{
113 double dv = double(knotL.Li);
114 cSl = 6 * dv * dv;
115 cDl = 2 * dv;
116 cSr = -cSl;
117 cDr = 4 * dv;
118}
119
120template <typename DataT>
122 double& cSl, double& cDl, double& cSr, double& cDr)
123{
124 double dv = double(knotL.Li);
125 cSl = 12 * dv * dv * dv;
126 cDl = 6 * dv * dv;
127 cSr = -cSl;
128 cDr = cDl;
129}
130
131template <typename DataT>
133 double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F)
134{
137
138 int32_t Ndim = spline.getYdimensions();
139 const int32_t nKnots = spline.getNumberOfKnots();
140
141 TMatrixD A(nKnots, nKnots);
142
143 A.Zero();
144
145 /*
146 const Spline1D::Knot& knot0 = spline.getKnot(i);
147 double x = (u - knot0.u) * knot0.Li; // scaled u
148 double cS1 = (6 - 12*x)*knot0.Li*knot0.Li;
149 double cZ0 = (6*x-4)*knot0.Li;
150 double cZ1 = (6*x-2)*knot0.Li;
151 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
152 */
153
154 // second derivative at knot0 is 0
155 {
156 const Knot<DataT>& knot0 = spline.getKnot(0);
157 double cZ0 = (-4) * knot0.Li;
158 double cZ1 = (-2) * knot0.Li;
159 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
160 A(0, 0) = cZ0;
161 A(0, 1) = cZ1;
162 }
163
164 // second derivative at knot nKnots-1 is 0
165 {
166 const Knot<DataT>& knot0 = spline.getKnot(nKnots - 2);
167 double cZ0 = (6 - 4) * knot0.Li;
168 double cZ1 = (6 - 2) * knot0.Li;
169 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
170 A(nKnots - 1, nKnots - 2) = cZ0;
171 A(nKnots - 1, nKnots - 1) = cZ1;
172 }
173
174 // second derivative at other knots is same from the left and from the right
175 for (int32_t i = 1; i < nKnots - 1; i++) {
176 const Knot<DataT>& knot0 = spline.getKnot(i - 1);
177 double cZ0 = (6 - 4) * knot0.Li;
178 double cZ1_0 = (6 - 2) * knot0.Li;
179 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
180
181 const Knot<DataT>& knot1 = spline.getKnot(i);
182 double cZ1_1 = (-4) * knot1.Li;
183 double cZ2 = (-2) * knot1.Li;
184 // f''(u) = cS2*(f2-f1) + cZ1_1*z1 + cZ2*z2;
185 A(i, i - 1) = cZ0;
186 A(i, i) = cZ1_0 - cZ1_1;
187 A(i, i + 1) = -cZ2;
188 }
189
190 A.Invert();
191
192 spline.setXrange(xMin, xMax);
193 DataT* parameters = spline.getParameters();
194
195 TVectorD b(nKnots);
196 b.Zero();
197
198 double uToXscale = (((double)xMax) - xMin) / spline.getUmax();
199
200 for (int32_t i = 0; i < nKnots; ++i) {
201 const Knot<DataT>& knot = spline.getKnot(i);
202 double u = knot.u;
203 double f[Ndim];
204 F(xMin + u * uToXscale, f);
205 for (int32_t dim = 0; dim < Ndim; dim++) {
206 parameters[(2 * i) * Ndim + dim] = f[dim];
207 }
208 }
209
210 for (int32_t dim = 0; dim < Ndim; dim++) {
211
212 // second derivative at knot0 is 0
213 {
214 double f0 = parameters[(2 * 0) * Ndim + dim];
215 double f1 = parameters[(2 * 1) * Ndim + dim];
216 const Knot<DataT>& knot0 = spline.getKnot(0);
217 double cS1 = (6) * knot0.Li * knot0.Li;
218 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
219 b(0) = -cS1 * (f1 - f0);
220 }
221
222 // second derivative at knot nKnots-1 is 0
223 {
224 double f0 = parameters[2 * (nKnots - 2) * Ndim + dim];
225 double f1 = parameters[2 * (nKnots - 1) * Ndim + dim];
226 const Knot<DataT>& knot0 = spline.getKnot(nKnots - 2);
227 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
228 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
229 b(nKnots - 1) = -cS1 * (f1 - f0);
230 }
231
232 // second derivative at other knots is same from the left and from the right
233 for (int32_t i = 1; i < nKnots - 1; i++) {
234 double f0 = parameters[2 * (i - 1) * Ndim + dim];
235 double f1 = parameters[2 * (i)*Ndim + dim];
236 double f2 = parameters[2 * (i + 1) * Ndim + dim];
237 const Knot<DataT>& knot0 = spline.getKnot(i - 1);
238 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
239 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
240
241 const Knot<DataT>& knot1 = spline.getKnot(i);
242 double cS2 = (6) * knot1.Li * knot1.Li;
243 // f''(u) = cS2*(f2-f1) + cZ1_1*z1 + cZ2*z2;
244 b(i) = -cS1 * (f1 - f0) + cS2 * (f2 - f1);
245 }
246
247 TVectorD c = A * b;
248 for (int32_t i = 0; i < nKnots; i++) {
249 parameters[(2 * i + 1) * Ndim + dim] = c[i];
250 }
251 }
252}
253
254template <typename DataT>
257 double xMin, double xMax,
258 double vx[], double vf[], int32_t nDataPoints)
259{
261
262 spline.setXrange(xMin, xMax);
263 setSpline(spline, spline.getYdimensions(), xMin, xMax, vx, nDataPoints);
264 approximateFunction(spline.getParameters(), vf);
265}
266
267template <typename DataT>
269 Spline1DContainer<DataT, FlatObject>& spline, double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F,
270 int32_t nAuxiliaryDataPoints)
271{
273 setSpline(spline, spline.getYdimensions(), nAuxiliaryDataPoints);
274 approximateFunction(spline.getParameters(), xMin, xMax, F);
275 spline.setXrange(xMin, xMax);
276}
277
278template <typename DataT>
280 Spline1DContainer<DataT, FlatObject>& spline, double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F,
281 int32_t nAuxiliaryDataPoints)
282{
284 setSpline(spline, spline.getYdimensions(), nAuxiliaryDataPoints);
285 approximateFunctionGradually(spline.getParameters(), xMin, xMax, F);
286 spline.setXrange(xMin, xMax);
287}
288
289template <typename DataT>
291 DataT* Sparameters, double xMin, double xMax, std::function<void(double x, double f[])> F) const
292{
295 std::vector<double> vF(getNumberOfDataPoints() * mFdimensions);
296 double mUtoXscale = (((double)xMax) - xMin) / mSpline.getUmax();
297 for (int32_t i = 0; i < getNumberOfDataPoints(); i++) {
298 F(xMin + mUtoXscale * mDataPoints[i].u, &vF[i * mFdimensions]);
299 }
300 approximateFunction(Sparameters, vF.data());
301}
302
303template <typename DataT>
305 DataT* Sparameters, double xMin, double xMax, std::function<void(double x, double f[])> F) const
306{
309 std::vector<double> vF(getNumberOfDataPoints() * mFdimensions);
310 double mUtoXscale = (((double)xMax) - xMin) / mSpline.getUmax();
311 for (int32_t i = 0; i < getNumberOfDataPoints(); i++) {
312 F(xMin + mUtoXscale * mDataPoints[i].u, &vF[i * mFdimensions]);
313 }
314 approximateFunctionGradually(Sparameters, vF.data());
315}
316
317template <typename DataT>
319 const Spline1DContainer<DataT, FlatObject>& spline, int32_t nFdimensions, int32_t nAuxiliaryDataPoints)
320{
321 // Prepare creation of a best-fit spline
322 //
323 // Data points will be set at all integer U (that includes all knots),
324 // plus at nAuxiliaryDataPoints points between the integers.
325 //
326 // nAuxiliaryDataPoints must be >= 2
327 //
328 // nAuxiliaryDataPoints==1 is also possible, but there must be at least
329 // one integer U without a knot, in order to get 2*nKnots data points in total.
330 //
331 // The return value is an error index, 0 means no error
332
333 int32_t ret = 0;
334
335 mFdimensions = nFdimensions;
336 int32_t nPoints = 0;
337 if (!spline.isConstructed()) {
338 ret = storeError(-1, "Spline1DHelperOld<DataT>::setSpline: input spline is not constructed");
339 mSpline.recreate(0, 2);
340 nAuxiliaryDataPoints = 2;
341 nPoints = 4;
342 } else {
343 std::vector<int32_t> knots;
344 for (int32_t i = 0; i < spline.getNumberOfKnots(); i++) {
345 knots.push_back(spline.getKnot(i).getU());
346 }
347 mSpline.recreate(0, spline.getNumberOfKnots(), knots.data());
348
349 nPoints = 1 + mSpline.getUmax() + mSpline.getUmax() * nAuxiliaryDataPoints;
350 if (nPoints < 2 * mSpline.getNumberOfKnots()) {
351 nAuxiliaryDataPoints = 2;
352 nPoints = 1 + mSpline.getUmax() + mSpline.getUmax() * nAuxiliaryDataPoints;
353 ret = storeError(-3, "Spline1DHelperOld::setSpline: too few nAuxiliaryDataPoints, increase to 2");
354 }
355 }
356
357 const int32_t nPar = 2 * mSpline.getNumberOfKnots(); // n parameters for 1D
358
359 mDataPoints.resize(nPoints);
360 double scalePoints2Knots = ((double)mSpline.getUmax()) / (nPoints - 1.);
361
362 for (int32_t i = 0; i < nPoints; ++i) {
363 DataPoint& p = mDataPoints[i];
364 double u = i * scalePoints2Knots;
365 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
366 const typename Spline1D<double>::KnotType& knot0 = mSpline.getKnot(iKnot);
367 const typename Spline1D<double>::KnotType& knot1 = mSpline.getKnot(iKnot + 1);
368 double l = knot1.u - knot0.u;
369 double s = (u - knot0.u) * knot0.Li; // scaled u
370 double s2 = s * s;
371 double sm1 = s - 1.;
372
373 p.iKnot = iKnot;
374 p.isKnot = 0;
375 p.u = u;
376 p.cS1 = s2 * (3. - 2. * s);
377 p.cS0 = 1. - p.cS1;
378 p.cZ0 = s * sm1 * sm1 * l;
379 p.cZ1 = s2 * sm1 * l;
380 }
381
382 const int32_t nKnots = mSpline.getNumberOfKnots();
383
384 mKnotDataPoints.resize(nKnots);
385
386 for (int32_t i = 0; i < nKnots; ++i) {
387 const typename Spline1D<double>::KnotType& knot = mSpline.getKnot(i);
388 int32_t iu = (int32_t)(knot.u + 0.1f);
389 mKnotDataPoints[i] = iu * (1 + nAuxiliaryDataPoints);
390 mDataPoints[mKnotDataPoints[i]].isKnot = 1;
391 }
392
393 TMatrixDSym A(nPar);
394 A.Zero();
395
396 for (int32_t i = 0; i < nPoints; ++i) {
397 DataPoint& p = mDataPoints[i];
398 int32_t j = p.iKnot * 2;
399 A(j + 0, j + 0) += p.cS0 * p.cS0;
400 A(j + 1, j + 0) += p.cS0 * p.cZ0;
401 A(j + 2, j + 0) += p.cS0 * p.cS1;
402 A(j + 3, j + 0) += p.cS0 * p.cZ1;
403
404 A(j + 1, j + 1) += p.cZ0 * p.cZ0;
405 A(j + 2, j + 1) += p.cZ0 * p.cS1;
406 A(j + 3, j + 1) += p.cZ0 * p.cZ1;
407
408 A(j + 2, j + 2) += p.cS1 * p.cS1;
409 A(j + 3, j + 2) += p.cS1 * p.cZ1;
410
411 A(j + 3, j + 3) += p.cZ1 * p.cZ1;
412 }
413
414 // copy symmetric matrix elements
415
416 for (int32_t i = 0; i < nPar; i++) {
417 for (int32_t j = i + 1; j < nPar; j++) {
418 A(i, j) = A(j, i);
419 }
420 }
421
422 TMatrixDSym Z(nKnots);
423 mLSMmatrixSvalues.resize(nKnots * nKnots);
424 for (int32_t i = 0, k = 0; i < nKnots; i++) {
425 for (int32_t j = 0; j < nKnots; j++, k++) {
426 mLSMmatrixSvalues[k] = A(i * 2 + 1, j * 2);
427 Z(i, j) = A(i * 2 + 1, j * 2 + 1);
428 }
429 }
430
431 {
432 TDecompBK bk(A, 0);
433 bool ok = bk.Invert(A);
434
435 if (!ok) {
436 ret = storeError(-4, "Spline1DHelperOld::setSpline: internal error - can not invert the matrix");
437 A.Zero();
438 }
439 mLSMmatrixFull.resize(nPar * nPar);
440 for (int32_t i = 0, k = 0; i < nPar; i++) {
441 for (int32_t j = 0; j < nPar; j++, k++) {
442 mLSMmatrixFull[k] = A(i, j);
443 }
444 }
445 }
446
447 {
448 TDecompBK bk(Z, 0);
449 if (!bk.Invert(Z)) {
450 ret = storeError(-5, "Spline1DHelperOld::setSpline: internal error - can not invert the matrix");
451 Z.Zero();
452 }
453 mLSMmatrixSderivatives.resize(nKnots * nKnots);
454 for (int32_t i = 0, k = 0; i < nKnots; i++) {
455 for (int32_t j = 0; j < nKnots; j++, k++) {
456 mLSMmatrixSderivatives[k] = Z(i, j);
457 }
458 }
459 }
460
461 return ret;
462}
463
464template <typename DataT>
466 const Spline1DContainer<DataT, FlatObject>& spline, int32_t nFdimensions, double xMin, double xMax, double vx[], int32_t nDataPoints)
467{
468 // Prepare creation of a best-fit spline
469 //
470 // Data points will be set at all integer U (that includes all knots),
471 // plus at nAuxiliaryDataPoints points between the integers.
472 //
473 // nAuxiliaryDataPoints must be >= 2
474 //
475 // nAuxiliaryDataPoints==1 is also possible, but there must be at least
476 // one integer U without a knot, in order to get 2*nKnots data points in total.
477 //
478 // The return value is an error index, 0 means no error
479
480 int32_t ret = 0;
481
482 mFdimensions = nFdimensions;
483 int32_t nPoints = nDataPoints;
484 if (!spline.isConstructed()) {
485 ret = storeError(-1, "Spline1DHelperOld<DataT>::setSpline: input spline is not constructed");
486 mSpline.recreate(0, 2);
487 } else {
488 std::vector<int32_t> knots;
489 for (int32_t i = 0; i < spline.getNumberOfKnots(); i++) {
490 knots.push_back(spline.getKnot(i).getU());
491 }
492 mSpline.recreate(0, spline.getNumberOfKnots(), knots.data());
493 }
494
495 mSpline.setXrange(xMin, xMax);
496
497 const int32_t nPar = 2 * mSpline.getNumberOfKnots(); // n parameters for 1D
498
499 mDataPoints.resize(nPoints);
500
501 for (int32_t i = 0; i < nPoints; ++i) {
502 DataPoint& p = mDataPoints[i];
503 double u = mSpline.convXtoU(vx[i]);
504 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
505 p.iKnot = iKnot;
506 p.isKnot = 0;
507 p.u = u;
508 const typename Spline1D<double>::KnotType& knot0 = mSpline.getKnot(iKnot);
509 getScoefficients(knot0, u, p.cS0, p.cZ0, p.cS1, p.cZ1);
510 }
511
512 const int32_t nKnots = mSpline.getNumberOfKnots();
513
514 TMatrixDSym A(nPar);
515 A.Zero();
516
517 for (int32_t i = 0; i < nPoints; ++i) {
518 DataPoint& p = mDataPoints[i];
519 int32_t j = p.iKnot * 2;
520 A(j + 0, j + 0) += p.cS0 * p.cS0;
521 A(j + 1, j + 0) += p.cS0 * p.cZ0;
522 A(j + 2, j + 0) += p.cS0 * p.cS1;
523 A(j + 3, j + 0) += p.cS0 * p.cZ1;
524
525 A(j + 1, j + 1) += p.cZ0 * p.cZ0;
526 A(j + 2, j + 1) += p.cZ0 * p.cS1;
527 A(j + 3, j + 1) += p.cZ0 * p.cZ1;
528
529 A(j + 2, j + 2) += p.cS1 * p.cS1;
530 A(j + 3, j + 2) += p.cS1 * p.cZ1;
531
532 A(j + 3, j + 3) += p.cZ1 * p.cZ1;
533 }
534
535 for (int32_t iKnot = 0; iKnot < nKnots - 2; ++iKnot) {
536 const typename Spline1D<double>::KnotType& knot0 = mSpline.getKnot(iKnot);
537 const typename Spline1D<double>::KnotType& knot1 = mSpline.getKnot(iKnot + 1);
538 // const typename Spline1D<double>::KnotType& knot2 = mSpline.getKnot(iKnot + 2);
539 /*
540 another way to calculate f(u):
541 T uu = T(u - knotL.u);
542 T v = uu * T(knotL.Li); // scaled u
543 T vm1 = v-1;
544 T v2 = v * v;
545 float cSr = 3*v2 - 2*v3;
546 float cSl = 1-cSr;
547 float cDl = (v3-2*v2+v)*knotL.L;
548 float cDr = (v3-v2)*knotL.L;
549 return cSl*Sl + cSr*Sr + cDl*Dl + cDr*Dr;
550 ()'v:
551 aSr = 6*v - 6*v2
552 aSl = -aSr
553 aDl = (3*v2-4*v+1)*knotL.L;
554 aDr = (3*v2-2*v)*knotL.L;
555 ()''v
556 bSr = 6 -12*v
557 bSl = -bSr
558 bDl = (6*v-4)*knotL.L;
559 bDr = (6*v-2)*knotL.L;
560 ()''u
561 dSr = (6 - 12*v)*knotL.Li*knotL.Li;
562 dSl = -dSr
563 dDl = (6*v-4)*knotL.Li;
564 dDr = (6*v-2)*knotL.Li;
565 */
566
567 double l0 = knot0.Li;
568 double l1 = knot1.Li;
569 /*
570 v1 = +6*l0*l0*s0 + 2*l0*z0 - 6*l0*l0*s1 + 4*l0*z1 ;
571 v2 = -6*l1*l1*s1 - 4*l1*z1 + 6*l1*l1*s2 - 2*l1*z2 ;
572 v2-v1 = -6*l1*l1*s1 - 4*l1*z1 + 6*l1*l1*s2 - 2*l1*z2 -6*l0*l0*s0 - 2*l0*z0 + 6*l0*l0*s1 - 4*l0*z1
573 = -6*l0*l0*s0 - 2*l0*z0 -6*(l1*l1-l0*l0)*s1 - 4*(l0+l1)*z1 + 6*l1*l1*s2 - 2*l1*z2
574 */
575 double c = 0.01;
576 double cS0 = c * -3 * l0 * l0;
577 double cZ0 = c * -l0;
578 double cS1 = c * -3 * (l1 * l1 - l0 * l0);
579 double cZ1 = c * -2 * (l0 + l1);
580 double cS2 = c * 3 * l1 * l1;
581 double cZ2 = c * -l1;
582
583 int32_t j = iKnot * 2;
584
585 A(j + 0, j + 0) += cS0 * cS0;
586 A(j + 1, j + 0) += cS0 * cZ0;
587 A(j + 2, j + 0) += cS0 * cS1;
588 A(j + 3, j + 0) += cS0 * cZ1;
589 A(j + 4, j + 0) += cS0 * cS2;
590 A(j + 5, j + 0) += cS0 * cZ2;
591
592 A(j + 1, j + 1) += cZ0 * cZ0;
593 A(j + 2, j + 1) += cZ0 * cS1;
594 A(j + 3, j + 1) += cZ0 * cZ1;
595 A(j + 4, j + 1) += cZ0 * cS2;
596 A(j + 5, j + 1) += cZ0 * cZ2;
597
598 A(j + 2, j + 2) += cS1 * cS1;
599 A(j + 3, j + 2) += cS1 * cZ1;
600 A(j + 4, j + 2) += cS1 * cS2;
601 A(j + 5, j + 2) += cS1 * cZ2;
602
603 A(j + 3, j + 3) += cZ1 * cZ1;
604 A(j + 4, j + 3) += cZ1 * cS2;
605 A(j + 5, j + 3) += cZ1 * cZ2;
606
607 A(j + 4, j + 4) += cS2 * cS2;
608 A(j + 5, j + 4) += cS2 * cZ2;
609
610 A(j + 5, j + 5) += cZ2 * cZ2;
611 }
612
613 for (int32_t iKnot = -1; iKnot < nKnots - 2; ++iKnot) {
614
615 const typename Spline1D<double>::KnotType& knot1 = mSpline.getKnot(iKnot + 1);
616 /*
617 ()''u
618 dSr = (3 - 6*v)*knotL.Li*knotL.Li;
619 dSl = -dSr
620 dDl = (3*v-2)*knotL.Li;
621 dDr = (3*v-1)*knotL.Li;
622 */
623
624 double l1 = knot1.Li;
625 /*
626 v2 = -3*l1*l1*s1 - 2*l1*z1 + 3*l1*l1*s2 - l1*z2 ;
627 */
628 double c = 0.01;
629 double cS1 = c * -3 * (l1 * l1);
630 double cZ1 = c * -2 * (l1);
631 double cS2 = c * 3 * l1 * l1;
632 double cZ2 = c * -l1;
633
634 int32_t j = iKnot * 2;
635
636 A(j + 2, j + 2) += cS1 * cS1;
637 A(j + 3, j + 2) += cS1 * cZ1;
638 A(j + 4, j + 2) += cS1 * cS2;
639 A(j + 5, j + 2) += cS1 * cZ2;
640
641 A(j + 3, j + 3) += cZ1 * cZ1;
642 A(j + 4, j + 3) += cZ1 * cS2;
643 A(j + 5, j + 3) += cZ1 * cZ2;
644
645 A(j + 4, j + 4) += cS2 * cS2;
646 A(j + 5, j + 4) += cS2 * cZ2;
647
648 A(j + 5, j + 5) += cZ2 * cZ2;
649 }
650
651 {
652 int32_t iKnot = nKnots - 2;
653 const typename Spline1D<double>::KnotType& knot0 = mSpline.getKnot(iKnot);
654 /*
655 ()''u
656 dSr = (3 - 6*v)*knotL.Li*knotL.Li;
657 dSl = -dSr
658 dDl = (3*v-2)*knotL.Li;
659 dDr = (3*v-1)*knotL.Li;
660 */
661
662 double l0 = knot0.Li;
663 /*
664 v1 = +3*l0*l0*s0 + l0*z0 - 3*l0*l0*s1 + 2*l0*z1 ;
665 */
666 double c = 0.01;
667 double cS0 = c * 3 * l0 * l0;
668 double cZ0 = c * l0;
669 double cS1 = c * -3 * l0 * l0;
670 double cZ1 = c * 2 * l0;
671
672 int32_t j = iKnot * 2;
673
674 A(j + 0, j + 0) += cS0 * cS0;
675 A(j + 1, j + 0) += cS0 * cZ0;
676 A(j + 2, j + 0) += cS0 * cS1;
677 A(j + 3, j + 0) += cS0 * cZ1;
678
679 A(j + 1, j + 1) += cZ0 * cZ0;
680 A(j + 2, j + 1) += cZ0 * cS1;
681 A(j + 3, j + 1) += cZ0 * cZ1;
682
683 A(j + 2, j + 2) += cS1 * cS1;
684 A(j + 3, j + 2) += cS1 * cZ1;
685
686 A(j + 3, j + 3) += cZ1 * cZ1;
687 }
688
689 // copy symmetric matrix elements
690
691 for (int32_t i = 0; i < nPar; i++) {
692 for (int32_t j = i + 1; j < nPar; j++) {
693 A(i, j) = A(j, i);
694 }
695 }
696
697 TMatrixDSym Z(nKnots);
698 mLSMmatrixSvalues.resize(nKnots * nKnots);
699 for (int32_t i = 0, k = 0; i < nKnots; i++) {
700 for (int32_t j = 0; j < nKnots; j++, k++) {
701 mLSMmatrixSvalues[k] = A(i * 2 + 1, j * 2);
702 Z(i, j) = A(i * 2 + 1, j * 2 + 1);
703 }
704 }
705
706 {
707 TDecompBK bk(A, 0);
708 bool ok = bk.Invert(A);
709
710 if (!ok) {
711 ret = storeError(-4, "Spline1DHelperOld::setSpline: internal error - can not invert the matrix");
712 A.Zero();
713 }
714 mLSMmatrixFull.resize(nPar * nPar);
715 for (int32_t i = 0, k = 0; i < nPar; i++) {
716 for (int32_t j = 0; j < nPar; j++, k++) {
717 mLSMmatrixFull[k] = A(i, j);
718 }
719 }
720 }
721
722 {
723 TDecompBK bk(Z, 0);
724 if (!bk.Invert(Z)) {
725 ret = storeError(-5, "Spline1DHelperOld::setSpline: internal error - can not invert the matrix");
726 Z.Zero();
727 }
728 mLSMmatrixSderivatives.resize(nKnots * nKnots);
729 for (int32_t i = 0, k = 0; i < nKnots; i++) {
730 for (int32_t j = 0; j < nKnots; j++, k++) {
731 mLSMmatrixSderivatives[k] = Z(i, j);
732 }
733 }
734 }
735
736 return ret;
737}
738
739template <typename DataT>
741 DataT* Sparameters,
742 const double DataPointF[/*getNumberOfDataPoints() x nFdim*/]) const
743{
745
746 const int32_t nPar = 2 * mSpline.getNumberOfKnots();
747 double b[nPar];
748 for (int32_t idim = 0; idim < mFdimensions; idim++) {
749 for (int32_t i = 0; i < nPar; i++) {
750 b[i] = 0.;
751 }
752 for (int32_t i = 0; i < getNumberOfDataPoints(); ++i) {
753 const DataPoint& p = mDataPoints[i];
754 double* bb = &(b[p.iKnot * 2]);
755 double f = (double)DataPointF[i * mFdimensions + idim];
756 bb[0] += f * p.cS0;
757 bb[1] += f * p.cZ0;
758 bb[2] += f * p.cS1;
759 bb[3] += f * p.cZ1;
760 }
761
762 const double* row = mLSMmatrixFull.data();
763
764 for (int32_t i = 0; i < nPar; i++, row += nPar) {
765 double s = 0.;
766 for (int32_t j = 0; j < nPar; j++) {
767 s += row[j] * b[j];
768 }
769 Sparameters[i * mFdimensions + idim] = (float)s;
770 }
771 }
772}
773
774template <typename DataT>
776 DataT* Sparameters, const double DataPointF[/*getNumberOfDataPoints() x nFdim */]) const
777{
780 copySfromDataPoints(Sparameters, DataPointF);
781 approximateDerivatives(Sparameters, DataPointF);
782}
783
784template <typename DataT>
786 DataT* Sparameters, const double DataPointF[/*getNumberOfDataPoints() x nFdim*/]) const
787{
790 for (int32_t i = 0; i < mSpline.getNumberOfKnots(); ++i) { // set F values at knots
791 int32_t ip = mKnotDataPoints[i];
792 for (int32_t d = 0; d < mFdimensions; d++) {
793 Sparameters[2 * i * mFdimensions + d] = DataPointF[ip * mFdimensions + d];
794 }
795 }
796}
797
798template <typename DataT>
800 DataT* Sparameters, const double DataPointF[/*getNumberOfDataPoints() x nFdim*/]) const
801{
805
806 const int32_t nKnots = mSpline.getNumberOfKnots();
807 const int32_t Ndim = mFdimensions;
808 double b[nKnots * mFdimensions];
809 for (int32_t i = 0; i < nKnots * Ndim; i++) {
810 b[i] = 0.;
811 }
812
813 for (int32_t i = 0; i < getNumberOfDataPoints(); ++i) {
814 const DataPoint& p = mDataPoints[i];
815 if (p.isKnot) {
816 continue;
817 }
818 for (int32_t d = 0; d < Ndim; d++) {
819 double f = (double)DataPointF[i * Ndim + d];
820 b[(p.iKnot + 0) * Ndim + d] += f * p.cZ0;
821 b[(p.iKnot + 1) * Ndim + d] += f * p.cZ1;
822 }
823 }
824
825 const double* row = mLSMmatrixSvalues.data();
826 for (int32_t i = 0; i < nKnots; ++i, row += nKnots) {
827 double s[Ndim];
828 for (int32_t d = 0; d < Ndim; d++) {
829 s[d] = 0.;
830 }
831 for (int32_t j = 0; j < nKnots; ++j) {
832 for (int32_t d = 0; d < Ndim; d++) {
833 s[d] += row[j] * Sparameters[2 * j * Ndim + d];
834 }
835 }
836 for (int32_t d = 0; d < Ndim; d++) {
837 b[i * Ndim + d] -= s[d];
838 }
839 }
840
841 row = mLSMmatrixSderivatives.data();
842 for (int32_t i = 0; i < nKnots; ++i, row += nKnots) {
843 double s[Ndim];
844 for (int32_t d = 0; d < Ndim; d++) {
845 s[d] = 0.;
846 }
847 for (int32_t j = 0; j < nKnots; ++j) {
848 for (int32_t d = 0; d < Ndim; d++) {
849 s[d] += row[j] * b[j * Ndim + d];
850 }
851 }
852 for (int32_t d = 0; d < Ndim; d++) {
853 Sparameters[(2 * i + 1) * Ndim + d] = (float)s[d];
854 }
855 }
856}
857
858template <typename DataT>
859int32_t Spline1DHelperOld<DataT>::test(const bool draw, const bool drawDataPoints)
860{
861 using namespace std;
862
863 // input function F
864
865 const int32_t Ndim = 5;
866 const int32_t Fdegree = 4;
867 double Fcoeff[Ndim][2 * (Fdegree + 1)];
868
869 auto F = [&](double x, double f[]) -> void {
870 double cosx[Fdegree + 1], sinx[Fdegree + 1];
871 double xi = 0;
872 for (int32_t i = 0; i <= Fdegree; i++, xi += x) {
873 GPUCommonMath::SinCosd(xi, sinx[i], cosx[i]);
874 }
875 for (int32_t dim = 0; dim < Ndim; dim++) {
876 f[dim] = 0; // Fcoeff[0]/2;
877 for (int32_t i = 1; i <= Fdegree; i++) {
878 f[dim] += Fcoeff[dim][2 * i] * cosx[i] + Fcoeff[dim][2 * i + 1] * sinx[i];
879 }
880 }
881 };
882
883 TCanvas* canv = nullptr;
884 TNtuple* nt = nullptr;
885 TNtuple* knots = nullptr;
886
887 auto ask = [&]() -> bool {
888 if (!canv) {
889 return 0;
890 }
891 canv->Update();
892 LOG(info) << "type 'q ' to exit";
893 std::string str;
894 std::getline(std::cin, str);
895 return (str != "q" && str != ".q");
896 };
897
898 LOG(info) << "Test 1D interpolation with the compact spline";
899
900 int32_t nTries = 100;
901
902 if (draw) {
903 canv = new TCanvas("cQA", "Spline1D QA", 1000, 600);
904 nTries = 10000;
905 }
906
907 double statDf1 = 0;
908 double statDf2 = 0;
909 double statDf1D = 0;
910 double statN = 0;
911
912 int32_t seed = 1;
913
914 for (int32_t itry = 0; itry < nTries; itry++) {
915
916 // init random F
917 for (int32_t dim = 0; dim < Ndim; dim++) {
918 gRandom->SetSeed(seed++);
919 for (int32_t i = 0; i < 2 * (Fdegree + 1); i++) {
920 Fcoeff[dim][i] = gRandom->Uniform(-1, 1);
921 }
922 }
923
924 // spline
925
926 int32_t nKnots = 4;
927 const int32_t uMax = nKnots * 3;
928
929 Spline1D<DataT, Ndim> spline1;
930 int32_t knotsU[nKnots];
931
932 do { // set knots randomly
933 knotsU[0] = 0;
934 double du = 1. * uMax / (nKnots - 1);
935 for (int32_t i = 1; i < nKnots; i++) {
936 knotsU[i] = (int32_t)(i * du); // + gRandom->Uniform(-du / 3, du / 3);
937 }
938 knotsU[nKnots - 1] = uMax;
939 spline1.recreate(nKnots, knotsU);
940 if (nKnots != spline1.getNumberOfKnots()) {
941 LOG(info) << "warning: n knots changed during the initialisation " << nKnots
942 << " -> " << spline1.getNumberOfKnots();
943 continue;
944 }
945 } while (0);
946
947 std::string err = FlatObject::stressTest(spline1);
948 if (!err.empty()) {
949 LOG(info) << "error at FlatObject functionality: " << err;
950 return -1;
951 } else {
952 // LOG(info) << "flat object functionality is ok" ;
953 }
954
955 nKnots = spline1.getNumberOfKnots();
956 int32_t nAuxiliaryPoints = 1;
957 Spline1D<DataT, Ndim> spline2(spline1);
958 spline1.approximateFunction(0., TMath::Pi(), F, nAuxiliaryPoints);
959
960 // if (itry == 0)
961 {
962 TFile outf("testSpline1D.root", "recreate");
963 if (outf.IsZombie()) {
964 LOG(info) << "Failed to open output file testSpline1D.root ";
965 } else {
966 const char* name = "Spline1Dtest";
967 spline1.writeToFile(outf, name);
968 Spline1D<DataT, Ndim>* p = spline1.readFromFile(outf, name);
969 if (p == nullptr) {
970 LOG(info) << "Failed to read Spline1D from file testSpline1D.root ";
971 } else {
972 spline1 = *p;
973 }
974 outf.Close();
975 }
976 }
977
979 helper.setSpline(spline2, Ndim, nAuxiliaryPoints);
980 helper.approximateFunctionGradually(spline2, 0., TMath::Pi(), F, nAuxiliaryPoints);
981
982 // 1-D splines for each dimension
983 Spline1D<DataT, 1> splines3[Ndim];
984 {
985 for (int32_t dim = 0; dim < Ndim; dim++) {
986 auto F3 = [&](double u, double f[]) -> void {
987 double ff[Ndim];
988 F(u, ff);
989 f[0] = ff[dim];
990 };
991 splines3[dim].recreate(nKnots, knotsU);
992 splines3[dim].approximateFunction(0., TMath::Pi(), F3, nAuxiliaryPoints);
993 }
994 }
995
996 double stepX = 1.e-2;
997 for (double x = 0; x < TMath::Pi(); x += stepX) {
998 double f[Ndim];
999 DataT s1[Ndim], s2[Ndim];
1000 F(x, f);
1001 spline1.interpolate(x, s1);
1002 spline2.interpolate(x, s2);
1003 for (int32_t dim = 0; dim < Ndim; dim++) {
1004 statDf1 += (s1[dim] - f[dim]) * (s1[dim] - f[dim]);
1005 statDf2 += (s2[dim] - f[dim]) * (s2[dim] - f[dim]);
1006 DataT s1D = splines3[dim].interpolate(x);
1007 statDf1D += (s1D - s1[dim]) * (s1D - s1[dim]);
1008 }
1009 statN += Ndim;
1010 }
1011 // LOG(info) << "std dev : " << sqrt(statDf1 / statN) ;
1012
1013 if (draw) {
1014 delete nt;
1015 delete knots;
1016 nt = new TNtuple("nt", "nt", "u:f:s");
1017 double drawMax = -1.e20;
1018 double drawMin = 1.e20;
1019 double stepX = 1.e-4;
1020 for (double x = 0; x < TMath::Pi(); x += stepX) {
1021 double f[Ndim];
1022 DataT s[Ndim];
1023 F(x, f);
1024 spline1.interpolate(x, s);
1025 nt->Fill(spline1.convXtoU(x), f[0], s[0]);
1026 drawMax = std::max(drawMax, std::max(f[0], (double)s[0]));
1027 drawMin = std::min(drawMin, std::min(f[0], (double)s[0]));
1028 }
1029
1030 nt->SetMarkerStyle(8);
1031
1032 {
1033 TNtuple* ntRange = new TNtuple("ntRange", "nt", "u:f");
1034 drawMin -= 0.1 * (drawMax - drawMin);
1035
1036 ntRange->Fill(0, drawMin);
1037 ntRange->Fill(0, drawMax);
1038 ntRange->Fill(uMax, drawMin);
1039 ntRange->Fill(uMax, drawMax);
1040 ntRange->SetMarkerColor(kWhite);
1041 ntRange->SetMarkerSize(0.1);
1042 ntRange->Draw("f:u", "", "");
1043 delete ntRange;
1044 }
1045
1046 nt->SetMarkerColor(kGray);
1047 nt->SetMarkerSize(2.);
1048 nt->Draw("f:u", "", "P,same");
1049
1050 nt->SetMarkerSize(.5);
1051 nt->SetMarkerColor(kBlue);
1052 nt->Draw("s:u", "", "P,same");
1053
1054 knots = new TNtuple("knots", "knots", "type:u:s");
1055 for (int32_t i = 0; i < nKnots; i++) {
1056 double u = spline1.getKnot(i).u;
1057 DataT s[Ndim];
1058 spline1.interpolate(spline1.convUtoX(u), s);
1059 knots->Fill(1, u, s[0]);
1060 }
1061
1062 knots->SetMarkerStyle(8);
1063 knots->SetMarkerSize(1.5);
1064 knots->SetMarkerColor(kRed);
1065 knots->SetMarkerSize(1.5);
1066 knots->Draw("s:u", "type==1", "same"); // knots
1067
1068 if (drawDataPoints) {
1069 for (int32_t j = 0; j < helper.getNumberOfDataPoints(); j++) {
1070 const typename Spline1DHelperOld<DataT>::DataPoint& p = helper.getDataPoint(j);
1071 if (p.isKnot) {
1072 continue;
1073 }
1074 DataT s[Ndim];
1075 spline1.interpolate(spline1.convUtoX(p.u), s);
1076 knots->Fill(2, p.u, s[0]);
1077 }
1078 knots->SetMarkerColor(kBlack);
1079 knots->SetMarkerSize(1.);
1080 knots->Draw("s:u", "type==2", "same"); // data points
1081 }
1082
1083 if (!ask()) {
1084 break;
1085 }
1086 } // draw
1087 }
1088 // delete canv;
1089 // delete nt;
1090 // delete knots;
1091
1092 statDf1 = sqrt(statDf1 / statN);
1093 statDf2 = sqrt(statDf2 / statN);
1094 statDf1D = sqrt(statDf1D / statN);
1095
1096 LOG(info) << "\n std dev for Compact Spline : " << statDf1 << " / " << statDf2;
1097 LOG(info) << " mean difference between 1-D and " << Ndim
1098 << "-D splines : " << statDf1D;
1099
1100 if (statDf1 < 0.05 && statDf2 < 0.06 && statDf1D < 1.e-20) {
1101 LOG(info) << "Everything is fine";
1102 } else {
1103 LOG(info) << "Something is wrong!!";
1104 return -2;
1105 }
1106 return 0;
1107}
1108
int32_t i
const int16_t bb
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
templateClassImp(o2::gpu::Spline1DHelperOld)
Definition of Spline1DHelperOld class.
Definition A.h:16
static std::string stressTest(T &obj)
Test the flat object functionality for a child class T.
Definition FlatObject.h:423
static void getDDDScoefficients(const typename Spline1D< double >::KnotType &knotL, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateFunctionClassic(Spline1DContainer< DataT, FlatObject > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F)
Create classic spline parameters for a given input function F.
Spline1DHelperOld()
_____________ Constructors / destructors __________________________
static void getDDScoefficients(const typename Spline1D< double >::KnotType &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateFunctionGradually(Spline1DContainer< DataT, FlatObject > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F, int32_t nAuxiliaryDataPoints=4)
Create best-fit spline parameters gradually for a given input function F.
static void getDScoefficients(const typename Spline1D< double >::KnotType &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
static int32_t test(const bool draw=0, const bool drawDataPoints=1)
Test the Spline1D class functionality.
void copySfromDataPoints(DataT *Fparameters, const double DataPointF[]) const
a tool for the gradual approximation: set spline values S_i at knots == function values
static void getScoefficients(const typename Spline1D< double >::KnotType &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateDataPoints(Spline1DContainer< DataT, FlatObject > &spline, double xMin, double xMax, double x[], double f[], int32_t nDataPoints)
Create best-fit spline parameters for a given input function F.
static void getDDScoefficientsRight(const typename Spline1D< double >::KnotType &knotL, double &cSl, double &cDl, double &cSr, double &cDr)
static void getDDScoefficientsLeft(const typename Spline1D< double >::KnotType &knotL, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateDerivatives(DataT *Fparameters, const double DataPointF[]) const
void approximateFunction(Spline1DContainer< DataT, FlatObject > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F, int32_t nAuxiliaryDataPoints=4)
Create best-fit spline parameters for a given input function F.
int32_t getNumberOfDataPoints() const
number of data points
const DataPoint & getDataPoint(int32_t ip) const
int32_t setSpline(const Spline1DContainer< DataT, FlatObject > &spline, int32_t nFdimensions, int32_t nAuxiliaryDataPoints)
_______________ Interface for a step-wise construction of the best-fit spline _______________________...
Forward declaration — specializations below select ClassDefNV based on FlatBase.
Definition Spline1D.h:171
GLint GLenum GLint x
Definition glcorearb.h:403
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLfloat GLfloat GLfloat v2
Definition glcorearb.h:813
TCanvas * drawDataPoints(TMultiGraph *mg, double min, double max)
DataT u
u coordinate of the knot i (an integer number in float format)
Helper structure for 1D spline construction.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row
const std::string str
uint64_t const void const *restrict const msg
Definition x9.h:153