Project
Loading...
Searching...
No Matches
Spline1DHelper.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 "Spline1DHelper.h"
18#include "BandMatrixSolver.h"
19#include "SymMatrixSolver.h"
20#include "GPUCommonLogger.h"
21
22#include "TMath.h"
23#include "TMatrixD.h"
24#include "TVectorD.h"
25#include "TDecompBK.h"
26#include <vector>
27
28#include "TRandom.h"
29#include "TMath.h"
30#include "TCanvas.h"
31#include "TNtuple.h"
32#include "TFile.h"
33#include "GPUCommonMath.h"
34#include <iostream>
35
37
38using namespace o2::gpu;
39
40template <typename DataT>
42{
43}
44
45template <typename DataT>
46int32_t Spline1DHelper<DataT>::storeError(int32_t code, const char* msg)
47{
48 mError = msg;
49 return code;
50}
51
52template <typename DataT>
54 double& cSl, double& cDl, double& cSr, double& cDr)
55{
58
59 // F(u) = cSl * Sl + cSr * Sr + cDl * Dl + cDr * Dr;
60
61 u = u - knotL.u;
62 double v = u * double(knotL.Li); // scaled u
63 double vm1 = v - 1.;
64 double a = u * vm1;
65 double v2 = v * v;
66 cSl = v2 * (2 * v - 3.) + 1.; // == 2*v3 - 3*v2 + 1
67 cDl = vm1 * a; // == (v2 - 2v + 1)*u
68 cSr = 1. - cSl;
69 cDr = v * a; // == (v2 - v)*u
70}
71
72template <typename DataT>
74 double& cSl, double& cDl, double& cSr, double& cDr)
75{
76 u = u - knotL.u;
77 double dv = double(knotL.Li);
78 double v = u * dv; // scaled u
79 double v2 = v * v;
80 cSl = 6 * (v2 - v) * dv;
81 cDl = 3 * v2 - 4 * v + 1.;
82 cSr = -cSl;
83 cDr = 3 * v2 - 2 * v;
84 // at v==0 : 0, 1, 0, 0
85 // at v==1 : 0, 0, 0, 1
86}
87
88template <typename DataT>
90 double& cSl, double& cDl, double& cSr, double& cDr)
91{
92 u = u - knotL.u;
93 double dv = double(knotL.Li);
94 double v = u * dv; // scaled u
95 cSl = (12 * v - 6) * dv * dv;
96 cDl = (6 * v - 4) * dv;
97 cSr = -cSl;
98 cDr = (6 * v - 2) * dv;
99}
100
101template <typename DataT>
103 double& cSl, double& cDl, double& cSr, double& cDr)
104{
105 double dv = double(knotL.Li);
106 cSl = -6 * dv * dv;
107 cDl = -4 * dv;
108 cSr = -cSl;
109 cDr = -2 * dv;
110}
111
112template <typename DataT>
114 double& cSl, double& cDl, double& cSr, double& cDr)
115{
116 double dv = double(knotL.Li);
117 cSl = 6 * dv * dv;
118 cDl = 2 * dv;
119 cSr = -cSl;
120 cDr = 4 * dv;
121}
122
123template <typename DataT>
125 double& cSl, double& cDl, double& cSr, double& cDr)
126{
127 double dv = double(knotL.Li);
128 cSl = 12 * dv * dv * dv;
129 cDl = 6 * dv * dv;
130 cSr = -cSl;
131 cDr = cDl;
132}
133
134template <typename DataT>
137 double xMin, double xMax,
138 const double vx[], const double vf[], int32_t nDataPoints)
139{
141
142 assert(spline.isConstructed());
143
144 const int32_t nYdim = spline.getYdimensions();
145 spline.setXrange(xMin, xMax);
146
147 // create the same spline in double precision
148 setSpline(spline);
149
150 const int32_t nPar = 2 * spline.getNumberOfKnots(); // n parameters for 1-Dimentional Y
151
152 // BandMatrixSolver<6> band(nPar, nYdim);
153 SymMatrixSolver band(nPar, nYdim);
154
155 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
156 double u = mSpline.convXtoU(vx[iPoint]);
157 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
158 const typename Spline1D<double>::Knot& knot0 = mSpline.getKnot(iKnot);
159 double cS0, cZ0, cS1, cZ1;
160 getScoefficients(knot0, u, cS0, cZ0, cS1, cZ1);
161 double c[4] = {cS0, cZ0, cS1, cZ1};
162
163 // chi2 += (c[0]*S0 + c[1]*Z0 + c[2]*S1 + c[3]*Z1 - f)^2
164
165 int32_t i = 2 * iKnot; // index of parameter S0
166 for (int32_t j = 0; j < 4; j++) { // parameters S0, Z0, S1, Z1
167 for (int32_t k = j; k < 4; k++) { // loop over the second parameter
168 band.A(i + j, i + k) += c[j] * c[k];
169 }
170 }
171 const double* f = &vf[iPoint * nYdim];
172 for (int32_t j = 0; j < 4; j++) { // parameters S0, Z0, S1, Z1
173 for (int32_t dim = 0; dim < nYdim; dim++) {
174 band.B(i + j, dim) += c[j] * f[dim];
175 }
176 }
177 }
178
179 for (int32_t iKnot = 0; iKnot < spline.getNumberOfKnots() - 2; ++iKnot) {
180 const typename Spline1D<double>::Knot& knot0 = mSpline.getKnot(iKnot);
181 const typename Spline1D<double>::Knot& knot1 = mSpline.getKnot(iKnot + 1);
182 // const typename Spline1D<double>::Knot& knot2 = mSpline.getKnot(iKnot + 2);
183
184 // set S'' and S''' at knot1 equal at both sides
185 // chi2 += w^2*(S''from the left - S'' from the right)^2
186 // chi2 += w^2*(S'''from the left - S''' from the right)^2
187
188 for (int32_t order = 2; order <= 3; order++) {
189 double cS0, cZ0, cS1r, cZ1r;
190 double cS1l, cZ1l, cS2, cZ2;
191 if (order == 2) {
192 getDDScoefficientsRight(knot0, cS0, cZ0, cS1r, cZ1r);
193 getDDScoefficientsLeft(knot1, cS1l, cZ1l, cS2, cZ2);
194 } else {
195 getDDDScoefficients(knot0, cS0, cZ0, cS1r, cZ1r);
196 getDDDScoefficients(knot1, cS1l, cZ1l, cS2, cZ2);
197 }
198
199 double w = 0.01;
200 double c[6] = {w * cS0, w * cZ0,
201 w * (cS1r - cS1l), w * (cZ1r - cZ1l),
202 -w * cS2, -w * cZ2};
203
204 // chi2 += w^2*(c[0]*S0 + c[1]*Z0 + c[2]*S1 + c[3]*Z1 + c[4]*S2 + c[5]*Z2)^2
205
206 int32_t i = 2 * iKnot; // index of parameter S0
207 for (int32_t j = 0; j < 6; j++) { // loop over 6 parameters
208 for (int32_t k = j; k < 6; k++) { // loop over the second parameter
209 band.A(i + j, i + k) += c[j] * c[k];
210 }
211 }
212 }
213 } // iKnot
214
215 // experimental: set slopes at neighbouring knots equal - doesn't work
216 /*
217 for (int32_t iKnot = 0; iKnot < spline.getNumberOfKnots() - 2; ++iKnot) {
218 const typename Spline1D<double>::Knot& knot0 = mSpline.getKnot(iKnot);
219 const typename Spline1D<double>::Knot& knot1 = mSpline.getKnot(iKnot + 1);
220 double w = 1.;
221 int32_t i = 2 * iKnot; // index of parameter S0
222 double d = knot1.u - knot0.u;
223 {
224 double c1[4] = {1, d, -1, 0};
225 double c2[4] = {1, 0, -1, d};
226 // chi2 += w*(c1[0]*S0 + c1[1]*Z0 + c1[2]*S1 + c1[3]*Z1)^2
227 // chi2 += w*(c2[0]*S0 + c2[1]*Z0 + c2[2]*S1 + c2[3]*Z1)^2
228 for (int32_t j = 0; j < 4; j++) { // parameters S0, Z0, S1, Z1
229 for (int32_t k = j; k < 4; k++) { // loop over the second parameter
230 band.A(i + j, i + k) += w * (c1[j] * c1[k] + c2[j] * c2[k]);
231 }
232 }
233 }
234 } // iKnot
235 }
236 */
237
238 band.solve();
239
240 for (int32_t i = 0; i < nPar; i++) {
241 for (int32_t j = 0; j < nYdim; j++) {
242 spline.getParameters()[i * nYdim + j] = band.B(i, j);
243 }
244 }
245}
246
247template <typename DataT>
250 const double vx[], const double vf[], int32_t nDataPoints)
251{
253
254 assert(spline.isConstructed());
255
256 const int32_t nYdim = spline.getYdimensions();
257
258 // create the same spline in double precision
259 setSpline(spline);
260
261 const int32_t nPar = spline.getNumberOfKnots(); // n parameters for 1-Dimentional Y
262
263 BandMatrixSolver<2> band(nPar, nYdim);
264
265 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
266 double u = mSpline.convXtoU(vx[iPoint]);
267 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
268 const typename Spline1D<double>::Knot& knot0 = mSpline.getKnot(iKnot);
269 double cS0, cZ0, cS1, cZ1;
270 getScoefficients(knot0, u, cS0, cZ0, cS1, cZ1);
271 double c[2] = {cZ0, cZ1};
272
273 // chi2 += (cS0*S0 + c[0]*Z0 + cS1*S1 + c[1]*Z1 - f)^2
274 // == (c[0]*Z0 + c[1]*Z1 - (f - cS0*S0 - cS1*S1))^2
275
276 int32_t i = iKnot; // index of parameter Z0
277 band.A(i + 0, i + 0) += c[0] * c[0];
278 band.A(i + 0, i + 1) += c[0] * c[1];
279 band.A(i + 1, i + 1) += c[1] * c[1];
280
281 const double* f = &vf[iPoint * nYdim];
282 const DataT* S0 = &spline.getParameters()[2 * iKnot * nYdim];
283 const DataT* S1 = &spline.getParameters()[2 * (iKnot + 1) * nYdim];
284 for (int32_t j = 0; j < 2; j++) { // parameters Z0, Z1
285 for (int32_t dim = 0; dim < nYdim; dim++) {
286 band.B(i + j, dim) += c[j] * (f[dim] - cS0 * S0[dim] - cS1 * S1[dim]);
287 }
288 }
289 }
290
291 band.solve();
292
293 for (int32_t i = 0; i < nPar; i++) {
294 for (int32_t j = 0; j < nYdim; j++) {
295 spline.getParameters()[(2 * i + 1) * nYdim + j] = band.B(i, j);
296 }
297 }
298}
299
300template <typename DataT>
302 double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F)
303{
306
307 int32_t Ndim = spline.getYdimensions();
308 const int32_t nKnots = spline.getNumberOfKnots();
309
310 TMatrixD A(nKnots, nKnots);
311
312 A.Zero();
313
314 /*
315 const Spline1D::Knot& knot0 = spline.getKnot(i);
316 double x = (u - knot0.u) * knot0.Li; // scaled u
317 double cS1 = (6 - 12*x)*knot0.Li*knot0.Li;
318 double cZ0 = (6*x-4)*knot0.Li;
319 double cZ1 = (6*x-2)*knot0.Li;
320 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
321 */
322
323 // second derivative at knot0 is 0
324 {
325 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(0);
326 double cZ0 = (-4) * knot0.Li;
327 double cZ1 = (-2) * knot0.Li;
328 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
329 A(0, 0) = cZ0;
330 A(0, 1) = cZ1;
331 }
332
333 // second derivative at knot nKnots-1 is 0
334 {
335 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(nKnots - 2);
336 double cZ0 = (6 - 4) * knot0.Li;
337 double cZ1 = (6 - 2) * knot0.Li;
338 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
339 A(nKnots - 1, nKnots - 2) = cZ0;
340 A(nKnots - 1, nKnots - 1) = cZ1;
341 }
342
343 // second derivative at other knots is same from the left and from the right
344 for (int32_t i = 1; i < nKnots - 1; i++) {
345 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(i - 1);
346 double cZ0 = (6 - 4) * knot0.Li;
347 double cZ1_0 = (6 - 2) * knot0.Li;
348 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
349
350 const typename Spline1D<DataT>::Knot& knot1 = spline.getKnot(i);
351 double cZ1_1 = (-4) * knot1.Li;
352 double cZ2 = (-2) * knot1.Li;
353 // f''(u) = cS2*(f2-f1) + cZ1_1*z1 + cZ2*z2;
354 A(i, i - 1) = cZ0;
355 A(i, i) = cZ1_0 - cZ1_1;
356 A(i, i + 1) = -cZ2;
357 }
358
359 A.Invert();
360
361 spline.setXrange(xMin, xMax);
362 DataT* parameters = spline.getParameters();
363
364 TVectorD b(nKnots);
365 b.Zero();
366
367 double uToXscale = (((double)xMax) - xMin) / spline.getUmax();
368
369 for (int32_t i = 0; i < nKnots; ++i) {
370 const typename Spline1D<DataT>::Knot& knot = spline.getKnot(i);
371 double u = knot.u;
372 double f[Ndim];
373 F(xMin + u * uToXscale, f);
374 for (int32_t dim = 0; dim < Ndim; dim++) {
375 parameters[(2 * i) * Ndim + dim] = f[dim];
376 }
377 }
378
379 for (int32_t dim = 0; dim < Ndim; dim++) {
380
381 // second derivative at knot0 is 0
382 {
383 double f0 = parameters[(2 * 0) * Ndim + dim];
384 double f1 = parameters[(2 * 1) * Ndim + dim];
385 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(0);
386 double cS1 = (6) * knot0.Li * knot0.Li;
387 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
388 b(0) = -cS1 * (f1 - f0);
389 }
390
391 // second derivative at knot nKnots-1 is 0
392 {
393 double f0 = parameters[2 * (nKnots - 2) * Ndim + dim];
394 double f1 = parameters[2 * (nKnots - 1) * Ndim + dim];
395 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(nKnots - 2);
396 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
397 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
398 b(nKnots - 1) = -cS1 * (f1 - f0);
399 }
400
401 // second derivative at other knots is same from the left and from the right
402 for (int32_t i = 1; i < nKnots - 1; i++) {
403 double f0 = parameters[2 * (i - 1) * Ndim + dim];
404 double f1 = parameters[2 * (i)*Ndim + dim];
405 double f2 = parameters[2 * (i + 1) * Ndim + dim];
406 const typename Spline1D<DataT>::Knot& knot0 = spline.getKnot(i - 1);
407 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
408 // f''(u) = cS1*(f1-f0) + cZ0*z0 + cZ1*z1;
409
410 const typename Spline1D<DataT>::Knot& knot1 = spline.getKnot(i);
411 double cS2 = (6) * knot1.Li * knot1.Li;
412 // f''(u) = cS2*(f2-f1) + cZ1_1*z1 + cZ2*z2;
413 b(i) = -cS1 * (f1 - f0) + cS2 * (f2 - f1);
414 }
415
416 TVectorD c = A * b;
417 for (int32_t i = 0; i < nKnots; i++) {
418 parameters[(2 * i + 1) * Ndim + dim] = c[i];
419 }
420 }
421}
422
423template <typename DataT>
425 Spline1DContainer<DataT>& spline, double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F,
426 int32_t nAuxiliaryDataPoints, std::vector<double>& vx, std::vector<double>& vf)
427{
429 assert(spline.isConstructed());
430 int32_t nFdimensions = spline.getYdimensions();
431 int32_t nDataPoints = 0;
432 if (nAuxiliaryDataPoints < 2) {
433 storeError(-3, "Spline1DHelper::setSpline: too few nAuxiliaryDataPoints, increase to 2");
434 nAuxiliaryDataPoints = 2;
435 }
436 spline.setXrange(xMin, xMax);
437 setSpline(spline);
438 nDataPoints = 1 + mSpline.getUmax() + mSpline.getUmax() * nAuxiliaryDataPoints;
439
440 vx.resize(nDataPoints);
441 vf.resize(nDataPoints * nFdimensions);
442
443 double scalePoints2Knots = ((double)mSpline.getUmax()) / (nDataPoints - 1.);
444 for (int32_t i = 0; i < nDataPoints; ++i) {
445 double u = i * scalePoints2Knots;
446 double x = mSpline.convUtoX(u);
447 vx[i] = x;
448 F(x, &vf[i * nFdimensions]);
449 }
450}
451
452template <typename DataT>
454 Spline1DContainer<DataT>& spline, double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F,
455 int32_t nAuxiliaryDataPoints)
456{
458 std::vector<double> vx;
459 std::vector<double> vf;
460 makeDataPoints(spline, xMin, xMax, F, nAuxiliaryDataPoints, vx, vf);
461 approximateDataPoints(spline, xMin, xMax, &vx[0], &vf[0], vx.size());
462}
463
464template <typename DataT>
466 Spline1DContainer<DataT>& spline, double xMin, double xMax, std::function<void(double x, double f[/*spline.getFdimensions()*/])> F,
467 int32_t nAuxiliaryDataPoints)
468{
470
471 std::vector<double> vx;
472 std::vector<double> vf;
473 makeDataPoints(spline, xMin, xMax, F, nAuxiliaryDataPoints, vx, vf);
474 int32_t nDataPoints = vx.size();
475 spline.setXrange(xMin, xMax);
476 setSpline(spline);
477
478 int32_t nFdimensions = spline.getYdimensions();
479
480 // set F values at knots
481 for (int32_t iKnot = 0; iKnot < mSpline.getNumberOfKnots(); ++iKnot) {
482 const typename Spline1D<double>::Knot& knot = mSpline.getKnot(iKnot);
483 double x = mSpline.convUtoX(knot.u);
484 double s[nFdimensions];
485 F(x, s);
486 for (int32_t dim = 0; dim < nFdimensions; dim++) {
487 spline.getParameters()[2 * iKnot * nFdimensions + dim] = s[dim];
488 }
489 }
490 approximateDerivatives(spline, &vx[0], &vf[0], nDataPoints);
491}
492
493template <typename DataT>
495{
496 const int32_t nKnots = spline.getNumberOfKnots();
497 std::vector<int32_t> knots(nKnots);
498 for (int32_t i = 0; i < nKnots; i++) {
499 knots[i] = spline.getKnot(i).getU();
500 }
501 mSpline.recreate(0, nKnots, knots.data());
502 mSpline.setXrange(spline.getXmin(), spline.getXmax());
503}
504
505template <typename DataT>
506int32_t Spline1DHelper<DataT>::test(const bool draw, const bool drawDataPoints)
507{
508 using namespace std;
509
511
512 // input function F
513
514 const int32_t Ndim = 5;
515 const int32_t Fdegree = 4;
516 double Fcoeff[Ndim][2 * (Fdegree + 1)];
517
518 auto F = [&](double x, double f[]) -> void {
519 double cosx[Fdegree + 1], sinx[Fdegree + 1];
520 double xi = 0;
521 for (int32_t i = 0; i <= Fdegree; i++, xi += x) {
522 GPUCommonMath::SinCosd(xi, sinx[i], cosx[i]);
523 }
524 for (int32_t dim = 0; dim < Ndim; dim++) {
525 f[dim] = 0; // Fcoeff[0]/2;
526 for (int32_t i = 1; i <= Fdegree; i++) {
527 f[dim] += Fcoeff[dim][2 * i] * cosx[i] + Fcoeff[dim][2 * i + 1] * sinx[i];
528 }
529 }
530 };
531
532 TCanvas* canv = nullptr;
533 TNtuple* nt = nullptr;
534 TNtuple* knots = nullptr;
535
536 auto ask = [&]() -> bool {
537 if (!canv) {
538 return 0;
539 }
540 canv->Update();
541 LOG(info) << "type 'q ' to exit";
542 std::string str;
543 std::getline(std::cin, str);
544 return (str != "q" && str != ".q");
545 };
546
547 LOG(info) << "Test 1D interpolation with the compact spline";
548
549 int32_t nTries = 100;
550
551 if (draw) {
552 canv = new TCanvas("cQA", "Spline1D QA", 1000, 600);
553 nTries = 10000;
554 }
555
556 double statDf1 = 0;
557 double statDf2 = 0;
558 double statDf1D = 0;
559 double statN = 0;
560
561 int32_t seed = 1;
562
563 for (int32_t itry = 0; itry < nTries; itry++) {
564
565 // init random F
566 for (int32_t dim = 0; dim < Ndim; dim++) {
567 gRandom->SetSeed(seed++);
568 for (int32_t i = 0; i < 2 * (Fdegree + 1); i++) {
569 Fcoeff[dim][i] = gRandom->Uniform(-1, 1);
570 }
571 }
572
573 // spline
574
575 int32_t nKnots = 4;
576 const int32_t uMax = nKnots * 3;
577
578 Spline1D<DataT, Ndim> spline1;
579 int32_t knotsU[nKnots];
580
581 do { // set knots randomly
582 knotsU[0] = 0;
583 double du = 1. * uMax / (nKnots - 1);
584 for (int32_t i = 1; i < nKnots; i++) {
585 knotsU[i] = (int32_t)(i * du); // + gRandom->Uniform(-du / 3, du / 3);
586 }
587 knotsU[nKnots - 1] = uMax;
588 spline1.recreate(nKnots, knotsU);
589 if (nKnots != spline1.getNumberOfKnots()) {
590 LOG(info) << "warning: n knots changed during the initialisation " << nKnots
591 << " -> " << spline1.getNumberOfKnots();
592 continue;
593 }
594 } while (0);
595
596 std::string err = FlatObject::stressTest(spline1);
597 if (!err.empty()) {
598 LOG(info) << "error at FlatObject functionality: " << err;
599 return -1;
600 } else {
601 // LOG(info) << "flat object functionality is ok" ;
602 }
603
604 nKnots = spline1.getNumberOfKnots();
605 int32_t nAuxiliaryPoints = 2;
606 Spline1D<DataT, Ndim> spline2(spline1);
607 spline1.approximateFunction(0., TMath::Pi(), F, nAuxiliaryPoints);
608
609 //if (itry == 0)
610 {
611 TFile outf("testSpline1D.root", "recreate");
612 if (outf.IsZombie()) {
613 LOG(info) << "Failed to open output file testSpline1D.root ";
614 } else {
615 const char* name = "Spline1Dtest";
616 spline1.writeToFile(outf, name);
617 Spline1D<DataT, Ndim>* p = spline1.readFromFile(outf, name);
618 if (p == nullptr) {
619 LOG(info) << "Failed to read Spline1D from file testSpline1D.root ";
620 } else {
621 spline1 = *p;
622 }
623 outf.Close();
624 }
625 }
626
628 helper.approximateFunctionGradually(spline2, 0., TMath::Pi(), F, nAuxiliaryPoints);
629
630 // 1-D splines for each dimension
631 Spline1D<DataT, 1> splines3[Ndim];
632 {
633 for (int32_t dim = 0; dim < Ndim; dim++) {
634 auto F3 = [&](double u, double f[]) -> void {
635 double ff[Ndim];
636 F(u, ff);
637 f[0] = ff[dim];
638 };
639 splines3[dim].recreate(nKnots, knotsU);
640 splines3[dim].approximateFunction(0., TMath::Pi(), F3, nAuxiliaryPoints);
641 }
642 }
643
644 double stepX = 1.e-2;
645 for (double x = 0; x < TMath::Pi(); x += stepX) {
646 double f[Ndim];
647 DataT s1[Ndim], s2[Ndim];
648 F(x, f);
649 spline1.interpolate(x, s1);
650 spline2.interpolate(x, s2);
651 for (int32_t dim = 0; dim < Ndim; dim++) {
652 statDf1 += (s1[dim] - f[dim]) * (s1[dim] - f[dim]);
653 statDf2 += (s2[dim] - f[dim]) * (s2[dim] - f[dim]);
654 DataT s1D = splines3[dim].interpolate(x);
655 statDf1D += (s1D - s1[dim]) * (s1D - s1[dim]);
656 }
657 statN += Ndim;
658 }
659 // LOG(info) << "std dev : " << sqrt(statDf1 / statN) ;
660
661 if (draw) {
662 delete nt;
663 delete knots;
664 nt = new TNtuple("nt", "nt", "u:f:s");
665 double drawMax = -1.e20;
666 double drawMin = 1.e20;
667 double stepX = 1.e-4;
668 for (double x = 0; x < TMath::Pi(); x += stepX) {
669 double f[Ndim];
670 DataT s[Ndim];
671 F(x, f);
672 spline1.interpolate(x, s);
673 nt->Fill(spline1.convXtoU(x), f[0], s[0]);
674 drawMax = std::max(drawMax, std::max(f[0], (double)s[0]));
675 drawMin = std::min(drawMin, std::min(f[0], (double)s[0]));
676 }
677
678 nt->SetMarkerStyle(8);
679
680 {
681 TNtuple* ntRange = new TNtuple("ntRange", "nt", "u:f");
682 drawMin -= 0.1 * (drawMax - drawMin);
683
684 ntRange->Fill(0, drawMin);
685 ntRange->Fill(0, drawMax);
686 ntRange->Fill(uMax, drawMin);
687 ntRange->Fill(uMax, drawMax);
688 ntRange->SetMarkerColor(kWhite);
689 ntRange->SetMarkerSize(0.1);
690 ntRange->Draw("f:u", "", "");
691 delete ntRange;
692 }
693
694 nt->SetMarkerColor(kGray);
695 nt->SetMarkerSize(2.);
696 nt->Draw("f:u", "", "P,same");
697
698 nt->SetMarkerSize(.5);
699 nt->SetMarkerColor(kBlue);
700 nt->Draw("s:u", "", "P,same");
701
702 knots = new TNtuple("knots", "knots", "type:u:s");
703 for (int32_t i = 0; i < nKnots; i++) {
704 double u = spline1.getKnot(i).u;
705 DataT s[Ndim];
706 spline1.interpolate(spline1.convUtoX(u), s);
707 knots->Fill(1, u, s[0]);
708 }
709
710 knots->SetMarkerStyle(8);
711 knots->SetMarkerSize(1.5);
712 knots->SetMarkerColor(kRed);
713 knots->SetMarkerSize(1.5);
714 knots->Draw("s:u", "type==1", "same"); // knots
715
716 if (drawDataPoints) {
717 std::vector<double> vx;
718 std::vector<double> vf;
719 helper.makeDataPoints(spline1, 0., TMath::Pi(), F, nAuxiliaryPoints, vx, vf);
720 for (uint32_t j = 0; j < vx.size(); j++) {
721 DataT s[Ndim];
722 spline1.interpolate(vx[j], s);
723 knots->Fill(2, spline1.convXtoU(vx[j]), s[0]);
724 }
725 knots->SetMarkerColor(kBlack);
726 knots->SetMarkerSize(1.);
727 knots->Draw("s:u", "type==2", "same"); // data points
728 }
729 if (!ask()) {
730 break;
731 }
732 } // draw
733 }
734 //delete canv;
735 //delete nt;
736 //delete knots;
737
738 statDf1 = sqrt(statDf1 / statN);
739 statDf2 = sqrt(statDf2 / statN);
740 statDf1D = sqrt(statDf1D / statN);
741
742 LOG(info) << std::defaultfloat;
743
744 LOG(info) << "\n std dev for Compact Spline : " << statDf1 << " / " << statDf2;
745 LOG(info) << " mean difference between 1-D and " << Ndim
746 << "-D splines : " << statDf1D;
747
748 if (statDf1 < 0.05 && statDf2 < 0.06 && statDf1D < 1.e-20) {
749 LOG(info) << "Everything is fine";
750 } else {
751 LOG(info) << "Something is wrong!!";
752 return -2;
753 }
754 return 0;
755}
756
757template class o2::gpu::Spline1DHelper<float>;
Definition of BandMatrixSolver class.
int32_t i
Definition of SymMatrixSolver class.
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
templateClassImp(o2::gpu::Spline1DHelper)
Definition of Spline1DHelper class.
Definition A.h:16
double & A(int32_t i, int32_t j)
access to A elements
double & B(int32_t i, int32_t j)
access to B elements
static int32_t test(bool prn=0)
Test the class functionality. Returns 1 when ok, 0 when not ok.
void solve()
solve the equation
bool isConstructed() const
Tells if the object is constructed.
Definition FlatObject.h:262
static std::string stressTest(T &obj)
Test the flat object functionality for a child class T.
Definition FlatObject.h:411
void recreate(int32_t nYdim, int32_t numberOfKnots)
Constructor for a regular spline.
static void getDDScoefficientsRight(const typename Spline1D< double >::Knot &knotL, double &cSl, double &cDl, double &cSr, double &cDr)
static void getDDScoefficientsLeft(const typename Spline1D< double >::Knot &knotL, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateFunction(Spline1DContainer< DataT > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F, int32_t nAuxiliaryDataPoints=4)
Create best-fit spline parameters for a function F.
void approximateFunctionClassic(Spline1DContainer< DataT > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F)
Create classic spline parameters for a given input function F.
void approximateDataPoints(Spline1DContainer< DataT > &spline, double xMin, double xMax, const double vx[], const double vf[], int32_t nDataPoints)
_______________ Main functionality ________________________
void approximateFunctionGradually(Spline1DContainer< DataT > &spline, double xMin, double xMax, std::function< void(double x, double f[])> F, int32_t nAuxiliaryDataPoints)
static void getDDScoefficients(const typename Spline1D< double >::Knot &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
Spline1DHelper()
_____________ Constructors / destructors __________________________
static void getDDDScoefficients(const typename Spline1D< double >::Knot &knotL, 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.
static void getDScoefficients(const typename Spline1D< double >::Knot &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
void approximateDerivatives(Spline1DContainer< DataT > &spline, const double vx[], const double vf[], int32_t nDataPoints)
Approximate only derivatives assuming the spline values at knozts are already set.
static void getScoefficients(const typename Spline1D< double >::Knot &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
static Spline1D * readFromFile(TFile &inpf, const char *name)
read a class object from the file
Definition Spline1D.h:170
double & B(int32_t i, int32_t j)
access to B elements
double & A(int32_t i, int32_t j)
access to A elements
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
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLfloat GLfloat GLfloat v2
Definition glcorearb.h:813
Defining DataPointCompositeObject explicitly as copiable.
DataT u
u coordinate of the knot i (an integer number in float format)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
const std::string str
uint64_t const void const *restrict const msg
Definition x9.h:153