Project
Loading...
Searching...
No Matches
Spline2DSpec.h
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#ifndef ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SPLINE2DSPEC_H
18#define ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SPLINE2DSPEC_H
19
20#include "Spline1D.h"
21#include "FlatObject.h"
22#include "GPUCommonDef.h"
23#include "SplineUtil.h"
24#if !defined(GPUCA_GPUCODE)
25#include <type_traits>
26#endif
27
28#if !defined(__CLING__) && !defined(G__ROOT) && !defined(GPUCA_GPUCODE) && !defined(GPUCA_NO_VC)
29#include <Vc/Vc>
30#include <Vc/SimdArray>
31#endif
32
33class TFile;
34
35namespace o2::gpu
36{
37
47template <typename DataT, class FlatBase = FlatObject>
48class Spline2DContainerBase : public FlatBase
49{
50 public:
52
54 GPUd() static constexpr int32_t getVersion() { return (1 << 16) + Spline1D<DataT>::getVersion(); }
55
57
60
63
66
68
69#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
71 void approximateFunction(double x1Min, double x1Max, double x2Min, double x2Max,
72 std::function<void(double x1, double x2, double f[/*mYdim*/])> F,
73 int32_t nAuxiliaryDataPointsU1 = 4, int32_t nAuxiliaryDataPointsU2 = 4);
74
75 void approximateFunctionViaDataPoints(double x1Min, double x1Max, double x2Min, double x2Max,
76 std::function<void(double x1, double x2, double f[])> F,
77 int32_t nAuxiliaryDataPointsX1, int32_t nAuxiliaryDataPointsX2);
78#endif
79
81
82#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
84 int32_t writeToFile(TFile& outf, const char* name);
85
87 static Spline2DContainerBase* readFromFile(TFile& inpf, const char* name);
88#endif
89
91
93 GPUd() int32_t getYdimensions() const { return mYdim; }
94
96 GPUd() static constexpr size_t getParameterAlignmentBytes() { return 16; }
97
99 GPUd() int32_t getNumberOfParameters() const { return this->calcNumberOfParameters(mYdim); }
100
102 GPUd() size_t getSizeOfParameters() const { return sizeof(DataT) * this->getNumberOfParameters(); }
103
105 GPUd() int32_t getNumberOfKnots() const { return mGridX1.getNumberOfKnots() * mGridX2.getNumberOfKnots(); }
106
108 GPUd() const Spline1D<DataT, 0, FlatBase>& getGridX1() const { return mGridX1; }
109
111 GPUd() const Spline1D<DataT, 0, FlatBase>& getGridX2() const { return mGridX2; }
112
114 GPUd() const Spline1D<DataT, 0, FlatBase>& getGrid(int32_t ix) const { return (ix == 0) ? mGridX1 : mGridX2; }
115
117 GPUd() void getKnotU(int32_t iKnot, int32_t& u1, int32_t& u2) const
118 {
119 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
120 u1 = mGridX1.getKnot(iKnot % mGridX1.getNumberOfKnots()).getU();
121 u2 = mGridX2.getKnot(iKnot / mGridX1.getNumberOfKnots()).getU();
122 }
123 }
124
126 GPUd() int32_t getKnotIndex(int32_t iKnotX1, int32_t iKnotX2) const
127 {
128 return mGridX1.getNumberOfKnots() * iKnotX2 + iKnotX1;
129 }
130
132 GPUd() DataT* getParameters() { return mParameters; }
133
135 GPUd() const DataT* getParameters() const { return mParameters; }
136
138
140 GPUd() size_t getGridX1Offset() const
141 {
142 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
143 return mGridX1.getFlatBufferPtr() - this->mFlatBufferPtr;
144 }
145 return 0;
146 }
147
149 GPUd() size_t getGridX2Offset() const
150 {
151 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
152 return mGridX2.getFlatBufferPtr() - this->mFlatBufferPtr;
153 }
154 return 0;
155 }
156
158 GPUd() void setXrange(DataT x1Min, DataT x1Max, DataT x2Min, DataT x2Max)
159 {
160 mGridX1.setXrange(x1Min, x1Max);
161 mGridX2.setXrange(x2Min, x2Max);
162 }
163
165 void print() const;
166
168
170 GPUd() int32_t calcNumberOfParameters(int32_t nYdim) const { return (4 * nYdim) * getNumberOfKnots(); }
171
173
174#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) // code invisible on GPU and in the standalone compilation
176 static int32_t test(const bool draw = 0, const bool drawDataPoints = 1);
177#endif
178
180#if !defined(GPUCA_GPUCODE)
181 void cloneFromObject(const Spline2DContainerBase& obj, char* newFlatBufferPtr);
182 void moveBufferTo(char* newBufferPtr);
183
186 template <class OtherFlatBase>
188#endif
189
190 void destroy();
191 void setActualBufferAddress(char* actualFlatBufferPtr);
192 void setFutureBufferAddress(char* futureFlatBufferPtr);
193
194 protected:
195#if !defined(GPUCA_GPUCODE)
197 void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2);
198
200 void recreate(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[]);
201#endif
202
204
205 int32_t mYdim = 0;
208 DataT* mParameters = nullptr;
209};
210
211template <typename DataT, typename FlatBase = FlatObject>
212class Spline2DContainer; // forward declaration
213
214template <typename DataT>
215class Spline2DContainer<DataT, FlatObject> : public Spline2DContainerBase<DataT, FlatObject>
216{
217 public:
219};
220
221template <typename DataT>
222class Spline2DContainer<DataT, NoFlatObject> : public Spline2DContainerBase<DataT, NoFlatObject>
223{
224};
225
244template <typename DataT, int32_t YdimT, int32_t SpecT, class FlatBase = FlatObject>
246
251template <typename DataT, int32_t YdimT, class FlatBase>
252class Spline2DSpec<DataT, YdimT, 0, FlatBase>
253 : public Spline2DContainerBase<DataT, FlatBase>
254{
255 public:
257
259 GPUd() void interpolate(DataT x1, DataT x2, GPUgeneric() DataT S[/*mYdim*/]) const
260 {
261 interpolateAtU<SafetyLevel::kSafe>(this->mYdim, this->mParameters, this->mGridX1.convXtoU(x1), this->mGridX2.convXtoU(x2), S);
262 }
263
265 template <SafetyLevel SafeT = SafetyLevel::kSafe>
266 GPUd() void interpolateAtUold(int32_t inpYdim, GPUgeneric() const DataT Parameters[],
267 DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const
268 {
269
270 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
271 const int32_t nYdim = nYdimTmp.get();
272
273 const auto maxYdim = SplineUtil::getMaxNdim<YdimT>(inpYdim);
274 const int32_t maxYdim4 = 4 * maxYdim.get();
275
276 const auto nYdim2 = nYdim * 2;
277 const auto nYdim4 = nYdim * 4;
278
279 const DataT& u = u1;
280 const DataT& v = u2;
281 int32_t nu = this->mGridX1.getNumberOfKnots();
282 int32_t iu = this->mGridX1.template getLeftKnotIndexForU<SafeT>(u);
283 int32_t iv = this->mGridX2.template getLeftKnotIndexForU<SafeT>(v);
284
285 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
286 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
287
288 const DataT* par00 = Parameters + (nu * iv + iu) * nYdim4; // values { {Y1,Y2,Y3}, {Y1,Y2,Y3}'v, {Y1,Y2,Y3}'u, {Y1,Y2,Y3}''vu } at {u0, v0}
289 const DataT* par10 = par00 + nYdim4; // values { ... } at {u1, v0}
290 const DataT* par01 = par00 + nYdim4 * nu; // values { ... } at {u0, v1}
291 const DataT* par11 = par01 + nYdim4; // values { ... } at {u1, v1}
292
293 DataT Su0[maxYdim4]; // values { {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v0), {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v1) }, at u0
294 DataT Du0[maxYdim4]; // derivatives {}'_u at u0
295 DataT Su1[maxYdim4]; // values { {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v0), {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v1) }, at u1
296 DataT Du1[maxYdim4]; // derivatives {}'_u at u1
297
298 for (int32_t i = 0; i < nYdim2; i++) {
299 Su0[i] = par00[i];
300 Su0[nYdim2 + i] = par01[i];
301
302 Du0[i] = par00[nYdim2 + i];
303 Du0[nYdim2 + i] = par01[nYdim2 + i];
304
305 Su1[i] = par10[i];
306 Su1[nYdim2 + i] = par11[i];
307
308 Du1[i] = par10[nYdim2 + i];
309 Du1[nYdim2 + i] = par11[nYdim2 + i];
310 }
311
312 DataT parU[maxYdim4]; // interpolated values { {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v0), {Y1,Y2,Y3,Y1'v,Y2'v,Y3'v}(v1) } at u
313
314 using GridX1Base = Spline1DSpec<DataT, 4 * YdimT, 0>;
315 const GridX1Base& gridX1 = reinterpret_cast<const GridX1Base&>(this->mGridX1);
316
317 gridX1.interpolateAtU(nYdim4, knotU, Su0, Du0, Su1, Du1, u, parU);
318
319 const DataT* Sv0 = parU + 0;
320 const DataT* Dv0 = parU + nYdim;
321 const DataT* Sv1 = parU + nYdim2;
322 const DataT* Dv1 = parU + nYdim2 + nYdim;
323
324 using GridX2Base = Spline1DSpec<DataT, YdimT, 0>;
325 const GridX2Base& gridX2 = reinterpret_cast<const GridX2Base&>(this->mGridX2);
326 gridX2.interpolateAtU(nYdim, knotV, Sv0, Dv0, Sv1, Dv1, v, S);
327 }
328
330 template <SafetyLevel SafeT = SafetyLevel::kSafe>
331 GPUd() void interpolateAtU(int32_t inpYdim, GPUgeneric() const DataT Parameters[],
332 DataT u1, DataT u2, GPUgeneric() DataT S[/*inpYdim*/]) const
333 {
334 if constexpr (!std::is_same_v<FlatBase, FlatObject>) {
335 return;
336 }
337
338 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
339 const int32_t nYdim = nYdimTmp.get();
340
341 // const auto maxYdim = SplineUtil::getMaxNdim<YdimT>(inpYdim);
342 // const int32_t maxYdim4 = 4 * maxYdim.get();
343
344 // const auto nYdim2 = nYdim * 2;
345 const auto nYdim4 = nYdim * 4;
346
347 const DataT& u = u1;
348 const DataT& v = u2;
349 int32_t nu = this->mGridX1.getNumberOfKnots();
350 int32_t iu = this->mGridX1.template getLeftKnotIndexForU<SafeT>(u);
351 int32_t iv = this->mGridX2.template getLeftKnotIndexForU<SafeT>(v);
352
353 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
354 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
355
356 const DataT* A = Parameters + (nu * iv + iu) * nYdim4; // values { {Y1,Y2,Y3}, {Y1,Y2,Y3}'v, {Y1,Y2,Y3}'u, {Y1,Y2,Y3}''vu } at {u0, v0}
357 const DataT* B = A + nYdim4 * nu; // values { ... } at {u0, v1}
358
359 DataT dSl, dDl, dSr, dDr, dSd, dDd, dSu, dDu;
360 this->mGridX1.template getSderivativesOverParsAtU<DataT>(knotU, u, dSl, dDl, dSr, dDr);
361 this->mGridX2.template getSderivativesOverParsAtU<DataT>(knotV, v, dSd, dDd, dSu, dDu);
362
363 // when nYdim == 1:
364 // S = dSl * (dSd * A[0] + dDd * A[1]) + dDl * (dSd * A[2] + dDd * A[3]) +
365 // dSr * (dSd * A[4] + dDd * A[5]) + dDr * (dSd * A[6] + dDd * A[7]) +
366 // dSl * (dSu * B[0] + dDu * B[1]) + dDl * (dSu * B[2] + dDu * B[3]) +
367 // dSr * (dSu * B[4] + dDu * B[5]) + dDr * (dSu * B[6] + dDu * B[7]);
368
369 DataT a[8] = {dSl * dSd, dSl * dDd, dDl * dSd, dDl * dDd,
370 dSr * dSd, dSr * dDd, dDr * dSd, dDr * dDd};
371 DataT b[8] = {dSl * dSu, dSl * dDu, dDl * dSu, dDl * dDu,
372 dSr * dSu, dSr * dDu, dDr * dSu, dDr * dDu};
373
374 // S = sum a[i]*A[i] + b[i]*B[i]
375
376 for (int32_t dim = 0; dim < nYdim; dim++) {
377 S[dim] = 0;
378 for (int32_t i = 0; i < 8; i++) {
379 S[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
380 }
381 }
382 }
383
385 template <SafetyLevel SafeT = SafetyLevel::kSafe>
386 GPUd() void interpolateParametersAtU(int32_t inpYdim, GPUgeneric() const DataT Parameters[],
387 DataT u1, DataT u2, GPUgeneric() DataT P[/* 4*inpYdim */]) const
388 {
389
390 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
391 const int32_t nYdim = nYdimTmp.get();
392
393 // const auto maxYdim = SplineUtil::getMaxNdim<YdimT>(inpYdim);
394 // const int32_t maxYdim4 = 4 * maxYdim.get();
395
396 // const auto nYdim2 = nYdim * 2;
397 const auto nYdim4 = nYdim * 4;
398
399 DataT *S = P,
400 *Q = P + nYdim,
401 *R = P + nYdim * 2,
402 *W = P + nYdim * 3;
403
404 const DataT& u = u1;
405 const DataT& v = u2;
406 int32_t nu = this->mGridX1.getNumberOfKnots();
407 int32_t iu = this->mGridX1.template getLeftKnotIndexForU<SafeT>(u);
408 int32_t iv = this->mGridX2.template getLeftKnotIndexForU<SafeT>(v);
409
410 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
411 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
412
413 const DataT* A = Parameters + (nu * iv + iu) * nYdim4; // values { {Y1,Y2,Y3}, {Y1,Y2,Y3}'v, {Y1,Y2,Y3}'u, {Y1,Y2,Y3}''vu } at {u0, v0}
414 const DataT* B = A + nYdim4 * nu; // values { ... } at {u0, v1}
415
416 DataT dSdSl, dSdDl, dSdSr, dSdDr, dRdSl, dRdDl, dRdSr, dRdDr;
417 this->mGridX1.template getSDderivativesOverParsAtU<DataT>(knotU, u, dSdSl, dSdDl, dSdSr, dSdDr, dRdSl, dRdDl, dRdSr, dRdDr);
418 DataT dSdSd, dSdDd, dSdSu, dSdDu, dQdSd, dQdDd, dQdSu, dQdDu;
419 this->mGridX2.template getSDderivativesOverParsAtU<DataT>(knotV, v, dSdSd, dSdDd, dSdSu, dSdDu, dQdSd, dQdDd, dQdSu, dQdDu);
420
421 // when nYdim == 1:
422
423 // Function value S
424 // S = dSdSl * (dSdSd * A[0] + dSdDd * A[1]) + dSdDl * (dSdSd * A[2] + dSdDd * A[3]) +
425 // dSdSr * (dSdSd * A[4] + dSdDd * A[5]) + dSdDr * (dSdSd * A[6] + dSdDd * A[7]) +
426 // dSdSl * (dSdSu * B[0] + dSdDu * B[1]) + dSdDl * (dSdSu * B[2] + dSdDu * B[3]) +
427 // dSdSr * (dSdSu * B[4] + dSdDu * B[5]) + dSdDr * (dSdSu * B[6] + dSdDu * B[7]);
428
429 {
430 DataT a[8] = {dSdSl * dSdSd, dSdSl * dSdDd, dSdDl * dSdSd, dSdDl * dSdDd,
431 dSdSr * dSdSd, dSdSr * dSdDd, dSdDr * dSdSd, dSdDr * dSdDd};
432 DataT b[8] = {dSdSl * dSdSu, dSdSl * dSdDu, dSdDl * dSdSu, dSdDl * dSdDu,
433 dSdSr * dSdSu, dSdSr * dSdDu, dSdDr * dSdSu, dSdDr * dSdDu};
434
435 // S = sum a[i]*A[i] + b[i]*B[i]
436
437 for (int32_t dim = 0; dim < nYdim; dim++) {
438 S[dim] = 0;
439 for (int32_t i = 0; i < 8; i++) {
440 S[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
441 }
442 }
443 }
444
445 // Derivative Q = dS / dv
446 // Q = dSdSl * (dQdSd * A[0] + dQdDd * A[1]) + dSdDl * (dQdSd * A[2] + dQdDd * A[3]) +
447 // dSdSr * (dQdSd * A[4] + dQdDd * A[5]) + dSdDr * (dQdSd * A[6] + dQdDd * A[7]) +
448 // dSdSl * (dQdSu * B[0] + dQdDu * B[1]) + dSdDl * (dQdSu * B[2] + dQdDu * B[3]) +
449 // dSdSr * (dQdSu * B[4] + dQdDu * B[5]) + dSdDr * (dQdSu * B[6] + dQdDu * B[7]);
450
451 {
452 DataT a[8] = {dSdSl * dQdSd, dSdSl * dQdDd, dSdDl * dQdSd, dSdDl * dQdDd,
453 dSdSr * dQdSd, dSdSr * dQdDd, dSdDr * dQdSd, dSdDr * dQdDd};
454 DataT b[8] = {dSdSl * dQdSu, dSdSl * dQdDu, dSdDl * dQdSu, dSdDl * dQdDu,
455 dSdSr * dQdSu, dSdSr * dQdDu, dSdDr * dQdSu, dSdDr * dQdDu};
456
457 // Q = sum a[i]*A[i] + b[i]*B[i]
458
459 for (int32_t dim = 0; dim < nYdim; dim++) {
460 Q[dim] = 0;
461 for (int32_t i = 0; i < 8; i++) {
462 Q[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
463 }
464 }
465 }
466
467 // Derivative R = dS / du
468 // R = dRdSl * (dSdSd * A[0] + dSdDd * A[1]) + dRdDl * (dSdSd * A[2] + dSdDd * A[3]) +
469 // dRdSr * (dSdSd * A[4] + dSdDd * A[5]) + dRdDr * (dSdSd * A[6] + dSdDd * A[7]) +
470 // dRdSl * (dSdSu * B[0] + dSdDu * B[1]) + dRdDl * (dSdSu * B[2] + dSdDu * B[3]) +
471 // dRdSr * (dSdSu * B[4] + dSdDu * B[5]) + dRdDr * (dSdSu * B[6] + dSdDu * B[7]);
472
473 {
474 DataT a[8] = {dRdSl * dSdSd, dRdSl * dSdDd, dRdDl * dSdSd, dRdDl * dSdDd,
475 dRdSr * dSdSd, dRdSr * dSdDd, dRdDr * dSdSd, dRdDr * dSdDd};
476 DataT b[8] = {dRdSl * dSdSu, dRdSl * dSdDu, dRdDl * dSdSu, dRdDl * dSdDu,
477 dRdSr * dSdSu, dRdSr * dSdDu, dRdDr * dSdSu, dRdDr * dSdDu};
478
479 // R = sum a[i]*A[i] + b[i]*B[i]
480
481 for (int32_t dim = 0; dim < nYdim; dim++) {
482 R[dim] = 0;
483 for (int32_t i = 0; i < 8; i++) {
484 R[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
485 }
486 }
487 }
488
489 // cross-derivative W = (dS)^2 / du / dv
490 // W = dRdSl * (dQdSd * A[0] + dQdDd * A[1]) + dRdDl * (dQdSd * A[2] + dQdDd * A[3]) +
491 // dRdSr * (dQdSd * A[4] + dQdDd * A[5]) + dRdDr * (dQdSd * A[6] + dQdDd * A[7]) +
492 // dRdSl * (dQdSu * B[0] + dQdDu * B[1]) + dRdDl * (dQdSu * B[2] + dQdDu * B[3]) +
493 // dRdSr * (dQdSu * B[4] + dQdDu * B[5]) + dRdDr * (dQdSu * B[6] + dQdDu * B[7]);
494
495 {
496 DataT a[8] = {dRdSl * dQdSd, dRdSl * dQdDd, dRdDl * dQdSd, dRdDl * dQdDd,
497 dRdSr * dQdSd, dRdSr * dQdDd, dRdDr * dQdSd, dRdDr * dQdDd};
498 DataT b[8] = {dRdSl * dQdSu, dRdSl * dQdDu, dRdDl * dQdSu, dRdDl * dQdDu,
499 dRdSr * dQdSu, dRdSr * dQdDu, dRdDr * dQdSu, dRdDr * dQdDu};
500
501 // W = sum a[i]*A[i] + b[i]*B[i]
502
503 for (int32_t dim = 0; dim < nYdim; dim++) {
504 W[dim] = 0;
505 for (int32_t i = 0; i < 8; i++) {
506 W[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
507 }
508 }
509 }
510 }
511
536 template <SafetyLevel SafeT = SafetyLevel::kSafe>
537 GPUd() void interpolateAtUZeroCopy(const char* gridX1FlatBuf,
538 const char* gridX2FlatBuf,
539 int32_t inpYdim,
540 GPUgeneric() const DataT Parameters[],
541 DataT u1, DataT u2,
542 GPUgeneric() DataT S[/*inpYdim*/]) const
543 {
544 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
545 const int32_t nYdim = nYdimTmp.get();
546 const auto nYdim4 = nYdim * 4;
547
548 const DataT& u = u1;
549 const DataT& v = u2;
550
551 // getNumberOfKnots() is safe: mNumberOfKnots is a plain int stored directly
552 // in the Spline1DContainer struct, not behind mFlatBufferPtr.
553 int32_t nu = this->mGridX1.getNumberOfKnots();
554
555 // Use buffer-aware accessors instead of mGridX1.getLeftKnotIndexForU() and
556 // mGridX1.getKnot(). Both of the standard versions dereference mFlatBufferPtr
557 // (via mUtoKnotMap and the knot array), which is stale after cross-process copy.
558 int32_t iu = this->mGridX1.getLeftKnotIndexForUFromBuffer(gridX1FlatBuf, u);
559 int32_t iv = this->mGridX2.getLeftKnotIndexForUFromBuffer(gridX2FlatBuf, v);
560
561 const auto& knotU = this->mGridX1.template getKnotFromBuffer<kNotSafe>(gridX1FlatBuf, iu);
562 const auto& knotV = this->mGridX2.template getKnotFromBuffer<kNotSafe>(gridX2FlatBuf, iv);
563
564 const DataT* A = Parameters + (nu * iv + iu) * nYdim4;
565 const DataT* B = A + nYdim4 * nu;
566
567 // getSderivativesOverParsAtU() is pure math on the Knot struct fields {u, Li}.
568 // It does NOT touch mFlatBufferPtr, so it is safe on the zero-copy path.
569 DataT dSl, dDl, dSr, dDr, dSd, dDd, dSu, dDu;
570 this->mGridX1.template getSderivativesOverParsAtU<DataT>(knotU, u, dSl, dDl, dSr, dDr);
571 this->mGridX2.template getSderivativesOverParsAtU<DataT>(knotV, v, dSd, dDd, dSu, dDu);
572
573 DataT a[8] = {dSl * dSd, dSl * dDd, dDl * dSd, dDl * dDd,
574 dSr * dSd, dSr * dDd, dDr * dSd, dDr * dDd};
575 DataT b[8] = {dSl * dSu, dSl * dDu, dDl * dSu, dDl * dDu,
576 dSr * dSu, dSr * dDu, dDr * dSu, dDr * dDu};
577
578 for (int32_t dim = 0; dim < nYdim; dim++) {
579 S[dim] = 0;
580 for (int32_t i = 0; i < 8; i++) {
581 S[dim] += a[i] * A[nYdim * i + dim] + b[i] * B[nYdim * i + dim];
582 }
583 }
584 }
585};
586
591template <typename DataT, int32_t YdimT, class FlatBase>
592class Spline2DSpec<DataT, YdimT, 1, FlatBase> : public Spline2DSpec<DataT, YdimT, 0, FlatBase>
593{
595
596 public:
597#if !defined(GPUCA_GPUCODE)
600 {
601 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
602 recreate(2, 2);
603 }
604 }
605
607 Spline2DSpec(int32_t nKnotsX1, int32_t nKnotsX2) : ParentSpec()
608 {
609 recreate(nKnotsX1, nKnotsX2);
610 }
612 Spline2DSpec(int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[]) : ParentSpec()
613 {
614 recreate(nKnotsX1, knotU1, nKnotsX2, knotU2);
615 }
618 {
619 ParentSpec::cloneFromObject(v, nullptr);
620 }
622 void recreate(int32_t nKnotsX1, int32_t nKnotsX2) { ParentSpec::recreate(YdimT, nKnotsX1, nKnotsX2); }
623
625 void recreate(int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[]) { ParentSpec::recreate(YdimT, nKnotsX1, knotU1, nKnotsX2, knotU2); }
626#endif
627
629 GPUd() constexpr int32_t getYdimensions() const { return YdimT; }
630
632 GPUd() int32_t getNumberOfParameters() const { return (4 * YdimT) * this->getNumberOfKnots(); }
633
635 GPUd() size_t getSizeOfParameters() const { return (sizeof(DataT) * 4 * YdimT) * this->getNumberOfKnots(); }
636
638
640 template <SafetyLevel SafeT = SafetyLevel::kSafe>
641 GPUd() void interpolateAtU(GPUgeneric() const DataT Parameters[], DataT u1, DataT u2, GPUgeneric() DataT S[/*YdimT*/]) const
642 {
643 ParentSpec::template interpolateAtU<SafeT>(YdimT, Parameters, u1, u2, S);
644 }
645
648 template <SafetyLevel SafeT = SafetyLevel::kSafe>
649 GPUd() void interpolateAtUZeroCopy(const char* gridX1FlatBuf, const char* gridX2FlatBuf, GPUgeneric() const DataT Parameters[], DataT u1, DataT u2, GPUgeneric() DataT S[/*YdimT*/]) const
650 {
651 ParentSpec::template interpolateAtUZeroCopy<SafeT>(gridX1FlatBuf, gridX2FlatBuf, YdimT, Parameters, u1, u2, S);
652 }
653
654 template <SafetyLevel SafeT = SafetyLevel::kSafe>
655 GPUd() void interpolateParametersAtU(GPUgeneric() const DataT Parameters[], DataT u1, DataT u2, GPUgeneric() DataT P[/* 4*YdimT */]) const
656 {
657 ParentSpec::template interpolateParametersAtU<SafeT>(YdimT, Parameters, u1, u2, P);
658 }
659
661 template <SafetyLevel SafeT = SafetyLevel::kSafe>
662 GPUd() void interpolateAtUold(GPUgeneric() const DataT Parameters[], DataT u1, DataT u2, GPUgeneric() DataT S[/*nYdim*/]) const
663 {
664 ParentSpec::template interpolateAtUold<SafeT>(YdimT, Parameters, u1, u2, S);
665 }
666};
667
672template <typename DataT, int32_t YdimT, class FlatBase>
673class Spline2DSpec<DataT, YdimT, 2, FlatBase> : public Spline2DSpec<DataT, YdimT, 0, FlatBase>
674{
676
677 public:
678#if !defined(GPUCA_GPUCODE)
681 {
682 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
683 ParentSpec::recreate(0, 2, 2);
684 }
685 }
686
688 Spline2DSpec(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2) : ParentSpec()
689 {
690 ParentSpec::recreate(nYdim, nKnotsX1, nKnotsX2);
691 }
692
694 Spline2DSpec(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[]) : ParentSpec()
695 {
696 ParentSpec::recreate(nYdim, nKnotsX1, knotU1, nKnotsX2, knotU2);
697 }
698
701 {
702 cloneFromObject(v, nullptr);
703 }
704
706 void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2) { ParentSpec::recreate(nYdim, nKnotsX1, nKnotsX2); }
707
709 void recreate(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[]) { ParentSpec::recreate(nYdim, nKnotsX1, knotU1, nKnotsX2, knotU2); }
710#endif
711};
712
716template <typename DataT, class FlatBase>
717class Spline2DSpec<DataT, 1, 3, FlatBase> : public Spline2DSpec<DataT, 1, SplineUtil::getSpec(999), FlatBase>
718{
719 using ParentSpec = Spline2DSpec<DataT, 1, SplineUtil::getSpec(999), FlatBase>;
720
721 public:
723 GPUd() DataT interpolate(DataT x1, DataT x2) const
724 {
725 DataT S = 0;
726 ParentSpec::interpolate(x1, x2, &S);
727 return S;
728 }
729};
730} // namespace o2::gpu
731
732#endif
void print() const
Definition of FlatObject class.
int32_t i
#define GPUgeneric()
Definition of Spline1D class.
Definition A.h:16
Definition B.h:16
Forward declaration — specializations below select ClassDefNV based on FlatBase.
Definition Spline1D.h:171
void recreate(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[])
Constructor for an irregular spline.
void importFrom(const Spline2DContainerBase< DataT, OtherFlatBase > &src)
void approximateFunctionViaDataPoints(double x1Min, double x1Max, double x2Min, double x2Max, std::function< void(double x1, double x2, double f[])> F, int32_t nAuxiliaryDataPointsX1, int32_t nAuxiliaryDataPointsX2)
int32_t mYdim
_____________ Data members ____________
void setFutureBufferAddress(char *futureFlatBufferPtr)
~Spline2DContainerBase()=default
Destructor.
Spline2DContainerBase()=default
_____________ C++ constructors / destructors __________________________
void moveBufferTo(char *newBufferPtr)
FlatBase & getGrid(int32_t ix) const
void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
GPUd() static const expr int32_t getVersion()
_____________ Version control __________________________
void setActualBufferAddress(char *actualFlatBufferPtr)
Spline2DContainerBase(const Spline2DContainerBase &)=delete
Disable all other constructors.
GPUd() int32_t getNumberOfKnots() const
Get a number of knots.
static Spline2DContainerBase * readFromFile(TFile &inpf, const char *name)
read a class object from the file
void approximateFunction(double x1Min, double x1Max, double x2Min, double x2Max, std::function< void(double x1, double x2, double f[])> F, int32_t nAuxiliaryDataPointsU1=4, int32_t nAuxiliaryDataPointsU2=4)
_______________ Construction interface ________________________
int32_t writeToFile(TFile &outf, const char *name)
_______________ IO ________________________
GPUd() static const expr size_t getParameterAlignmentBytes()
Get minimal required alignment for the spline parameters.
void cloneFromObject(const Spline2DContainerBase &obj, char *newFlatBufferPtr)
_____________ FlatObject functionality, see FlatObject class for description ____________
Spline1D< DataT, 0, FlatBase > mGridX1
grid for U axis
GPUd() int32_t getYdimensions() const
_______________ Getters ________________________
GPUd() size_t getSizeOfParameters() const
Size of the parameter array in bytes.
GPUd() int32_t getNumberOfParameters() const
Number of parameters.
GPUd() int32_t calcNumberOfParameters(int32_t nYdim) const
_______________ Expert tools _______________
Spline1D< DataT, 0, FlatBase > mGridX2
grid for V axis
GPUd() void interpolateAtUold(int32_t inpYdim
Get interpolated value for an inpYdim-dimensional S(u1,u2) using spline parameters Parameters.
GPUd() void interpolateAtUZeroCopy(const char *gridX1FlatBuf
GPUd() void interpolateParametersAtU(int32_t inpYdim
Get interpolated parameters (like parameters stored at knots) for an inpYdim-dimensional S(u1,...
GPUd() void interpolate(DataT x1
_______________ Interpolation math ________________________
GPUd() void interpolateAtU(int32_t inpYdim
Get interpolated value for an inpYdim-dimensional S(u1,u2) using spline parameters Parameters.
GPUd() const expr int32_t getYdimensions() const
Get number of Y dimensions.
GPUd() int32_t getNumberOfParameters() const
Number of parameters.
Spline2DSpec(int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
GPUd() void interpolateAtU(GPUgeneric() const DataT Parameters[]
_______ Expert tools: interpolation with given nYdim and external Parameters _______
GPUd() size_t getSizeOfParameters() const
Size of the parameter array in bytes.
void recreate(int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[])
Constructor for an irregular spline.
GPUd() void interpolateAtUold(GPUgeneric() const DataT Parameters[]
Get interpolated value for an YdimT-dimensional S(u1,u2) using spline parameters Parameters.
Spline2DSpec()
Default constructor — skips recreate for NoFlatObject (no owned buffer)
Spline2DSpec(int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[])
Constructor for an irregular spline.
Spline2DSpec(const Spline2DSpec &v)
Copy constructor.
GPUd() void interpolateParametersAtU(GPUgeneric() const DataT Parameters[]
void recreate(int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
GPUd() void interpolateAtUZeroCopy(const char *gridX1FlatBuf
Spline2DSpec()
Default constructor — skips recreate for NoFlatObject (no owned buffer)
void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
Spline2DSpec(const Spline2DSpec &v)
Copy constructor.
Spline2DSpec(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
void recreate(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[])
Constructor for an irregular spline.
Spline2DSpec(int32_t nYdim, int32_t nKnotsX1, const int32_t knotU1[], int32_t nKnotsX2, const int32_t knotU2[])
Constructor for an irregular spline.
static constexpr int32_t getSpec(int32_t nXdim, int32_t nYdim)
Definition SplineUtil.h:31
GLenum src
Definition glcorearb.h:1767
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat x1
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
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GPUd() const expr uint32_t MultivariatePolynomialHelper< Dim