17#ifndef ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SPLINE2DSPEC_H
18#define ALICEO2_GPUCOMMON_TPCFASTTRANSFORMATION_SPLINE2DSPEC_H
24#if !defined(GPUCA_GPUCODE)
28#if !defined(__CLING__) && !defined(G__ROOT) && !defined(GPUCA_GPUCODE) && !defined(GPUCA_NO_VC)
30#include <Vc/SimdArray>
47template <
typename DataT,
class FlatBase = FlatObject>
69#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
72 std::function<
void(
double x1,
double x2,
double f[])> F,
73 int32_t nAuxiliaryDataPointsU1 = 4, int32_t nAuxiliaryDataPointsU2 = 4);
76 std::function<
void(
double x1,
double x2,
double f[])> F,
77 int32_t nAuxiliaryDataPointsX1, int32_t nAuxiliaryDataPointsX2);
82#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
93 GPUd() int32_t getYdimensions()
const {
return mYdim; }
96 GPUd() static constexpr
size_t getParameterAlignmentBytes() {
return 16; }
99 GPUd() int32_t getNumberOfParameters()
const {
return this->calcNumberOfParameters(
mYdim); }
102 GPUd() size_t getSizeOfParameters()
const {
return sizeof(DataT) * this->getNumberOfParameters(); }
105 GPUd() int32_t getNumberOfKnots()
const {
return mGridX1.getNumberOfKnots() *
mGridX2.getNumberOfKnots(); }
117 GPUd()
void getKnotU(int32_t iKnot, int32_t&
u1, int32_t& u2)
const
119 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
126 GPUd() int32_t getKnotIndex(int32_t iKnotX1, int32_t iKnotX2)
const
128 return mGridX1.getNumberOfKnots() * iKnotX2 + iKnotX1;
140 GPUd() size_t getGridX1Offset()
const
142 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
149 GPUd() size_t getGridX2Offset()
const
151 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
158 GPUd()
void setXrange(DataT x1Min, DataT x1Max, DataT x2Min, DataT x2Max)
160 mGridX1.setXrange(x1Min, x1Max);
161 mGridX2.setXrange(x2Min, x2Max);
170 GPUd() int32_t calcNumberOfParameters(int32_t nYdim)
const {
return (4 * nYdim) * getNumberOfKnots(); }
174#if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE)
176 static int32_t test(const bool draw = 0, const bool drawDataPoints = 1);
180#if !defined(GPUCA_GPUCODE)
186 template <
class OtherFlatBase>
195#if !defined(GPUCA_GPUCODE)
197 void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2);
200 void recreate(int32_t nYdim, int32_t nKnotsX1,
const int32_t knotU1[], int32_t nKnotsX2,
const int32_t knotU2[]);
211template <
typename DataT,
typename FlatBase = FlatObject>
214template <
typename DataT>
221template <
typename DataT>
244template <
typename DataT,
int32_t YdimT,
int32_t SpecT,
class FlatBase = FlatObject>
251template <
typename DataT,
int32_t YdimT,
class FlatBase>
261 interpolateAtU<SafetyLevel::kSafe>(this->mYdim, this->mParameters, this->mGridX1.convXtoU(
x1), this->mGridX2.convXtoU(x2),
S);
265 template <SafetyLevel SafeT = SafetyLevel::kSafe>
270 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
271 const int32_t nYdim = nYdimTmp.get();
273 const auto maxYdim = SplineUtil::getMaxNdim<YdimT>(inpYdim);
274 const int32_t maxYdim4 = 4 * maxYdim.get();
276 const auto nYdim2 = nYdim * 2;
277 const auto nYdim4 = nYdim * 4;
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);
285 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
286 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
288 const DataT* par00 =
Parameters + (nu * iv + iu) * nYdim4;
289 const DataT* par10 = par00 + nYdim4;
290 const DataT* par01 = par00 + nYdim4 * nu;
291 const DataT* par11 = par01 + nYdim4;
298 for (int32_t
i = 0;
i < nYdim2;
i++) {
300 Su0[nYdim2 +
i] = par01[
i];
302 Du0[
i] = par00[nYdim2 +
i];
303 Du0[nYdim2 +
i] = par01[nYdim2 +
i];
306 Su1[nYdim2 +
i] = par11[
i];
308 Du1[
i] = par10[nYdim2 +
i];
309 Du1[nYdim2 +
i] = par11[nYdim2 +
i];
312 DataT parU[maxYdim4];
315 const GridX1Base& gridX1 =
reinterpret_cast<const GridX1Base&
>(this->mGridX1);
317 gridX1.interpolateAtU(nYdim4, knotU, Su0, Du0, Su1, Du1, u, parU);
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;
325 const GridX2Base& gridX2 =
reinterpret_cast<const GridX2Base&
>(this->mGridX2);
326 gridX2.interpolateAtU(nYdim, knotV, Sv0, Dv0, Sv1, Dv1,
v,
S);
330 template <SafetyLevel SafeT = SafetyLevel::kSafe>
334 if constexpr (!std::is_same_v<FlatBase, FlatObject>) {
338 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
339 const int32_t nYdim = nYdimTmp.get();
345 const auto nYdim4 = nYdim * 4;
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);
353 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
354 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
356 const DataT*
A =
Parameters + (nu * iv + iu) * nYdim4;
357 const DataT*
B =
A + nYdim4 * nu;
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);
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};
376 for (int32_t dim = 0; dim < nYdim; dim++) {
378 for (int32_t
i = 0;
i < 8;
i++) {
379 S[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
385 template <SafetyLevel SafeT = SafetyLevel::kSafe>
390 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
391 const int32_t nYdim = nYdimTmp.get();
397 const auto nYdim4 = nYdim * 4;
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);
410 const auto& knotU = this->mGridX1.template getKnot<SafetyLevel::kNotSafe>(iu);
411 const auto& knotV = this->mGridX2.template getKnot<SafetyLevel::kNotSafe>(iv);
413 const DataT*
A =
Parameters + (nu * iv + iu) * nYdim4;
414 const DataT*
B =
A + nYdim4 * nu;
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);
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};
437 for (int32_t dim = 0; dim < nYdim; dim++) {
439 for (int32_t
i = 0;
i < 8;
i++) {
440 S[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
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};
459 for (int32_t dim = 0; dim < nYdim; dim++) {
461 for (int32_t
i = 0;
i < 8;
i++) {
462 Q[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
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};
481 for (int32_t dim = 0; dim < nYdim; dim++) {
483 for (int32_t
i = 0;
i < 8;
i++) {
484 R[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
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};
503 for (int32_t dim = 0; dim < nYdim; dim++) {
505 for (int32_t
i = 0;
i < 8;
i++) {
506 W[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
536 template <SafetyLevel SafeT = SafetyLevel::kSafe>
537 GPUd()
void interpolateAtUZeroCopy(const
char* gridX1FlatBuf,
538 const
char* gridX2FlatBuf,
544 const auto nYdimTmp = SplineUtil::getNdim<YdimT>(inpYdim);
545 const int32_t nYdim = nYdimTmp.get();
546 const auto nYdim4 = nYdim * 4;
553 int32_t nu = this->mGridX1.getNumberOfKnots();
558 int32_t iu = this->mGridX1.getLeftKnotIndexForUFromBuffer(gridX1FlatBuf, u);
559 int32_t iv = this->mGridX2.getLeftKnotIndexForUFromBuffer(gridX2FlatBuf,
v);
561 const auto& knotU = this->mGridX1.template getKnotFromBuffer<kNotSafe>(gridX1FlatBuf, iu);
562 const auto& knotV = this->mGridX2.template getKnotFromBuffer<kNotSafe>(gridX2FlatBuf, iv);
564 const DataT*
A =
Parameters + (nu * iv + iu) * nYdim4;
565 const DataT*
B =
A + nYdim4 * nu;
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);
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};
578 for (int32_t dim = 0; dim < nYdim; dim++) {
580 for (int32_t
i = 0;
i < 8;
i++) {
581 S[dim] +=
a[
i] *
A[nYdim *
i + dim] +
b[
i] *
B[nYdim *
i + dim];
591template <
typename DataT,
int32_t YdimT,
class FlatBase>
597#if !defined(GPUCA_GPUCODE)
601 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
609 recreate(nKnotsX1, nKnotsX2);
614 recreate(nKnotsX1, knotU1, nKnotsX2, knotU2);
619 ParentSpec::cloneFromObject(
v,
nullptr);
622 void recreate(int32_t nKnotsX1, int32_t nKnotsX2) { ParentSpec::recreate(YdimT, nKnotsX1, nKnotsX2); }
625 void recreate(int32_t nKnotsX1,
const int32_t knotU1[], int32_t nKnotsX2,
const int32_t knotU2[]) { ParentSpec::recreate(YdimT, nKnotsX1, knotU1, nKnotsX2, knotU2); }
629 GPUd() constexpr int32_t getYdimensions()
const {
return YdimT; }
632 GPUd() int32_t getNumberOfParameters()
const {
return (4 * YdimT) * this->getNumberOfKnots(); }
635 GPUd() size_t getSizeOfParameters()
const {
return (
sizeof(DataT) * 4 * YdimT) * this->getNumberOfKnots(); }
640 template <SafetyLevel SafeT = SafetyLevel::kSafe>
643 ParentSpec::template interpolateAtU<SafeT>(YdimT,
Parameters, u1, u2,
S);
648 template <SafetyLevel SafeT = SafetyLevel::kSafe>
651 ParentSpec::template interpolateAtUZeroCopy<SafeT>(gridX1FlatBuf, gridX2FlatBuf, YdimT,
Parameters, u1, u2,
S);
654 template <SafetyLevel SafeT = SafetyLevel::kSafe>
657 ParentSpec::template interpolateParametersAtU<SafeT>(YdimT,
Parameters, u1, u2,
P);
661 template <SafetyLevel SafeT = SafetyLevel::kSafe>
664 ParentSpec::template interpolateAtUold<SafeT>(YdimT,
Parameters, u1, u2,
S);
672template <
typename DataT,
int32_t YdimT,
class FlatBase>
678#if !defined(GPUCA_GPUCODE)
682 if constexpr (!std::is_same_v<FlatBase, NoFlatObject>) {
683 ParentSpec::recreate(0, 2, 2);
690 ParentSpec::recreate(nYdim, nKnotsX1, nKnotsX2);
694 Spline2DSpec(int32_t nYdim, int32_t nKnotsX1,
const int32_t knotU1[], int32_t nKnotsX2,
const int32_t knotU2[]) :
ParentSpec()
696 ParentSpec::recreate(nYdim, nKnotsX1, knotU1, nKnotsX2, knotU2);
702 cloneFromObject(
v,
nullptr);
706 void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2) { ParentSpec::recreate(nYdim, nKnotsX1, nKnotsX2); }
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); }
716template <
typename DataT,
class FlatBase>
723 GPUd() DataT interpolate(DataT
x1, DataT x2)
const
726 ParentSpec::interpolate(
x1, x2, &
S);
Definition of FlatObject class.
Definition of Spline1D class.
Forward declaration — specializations below select ClassDefNV based on FlatBase.
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 __________________________
int32_t int32_t &u2 const
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 __________________________
FlatBase & getGridX2() const
void setActualBufferAddress(char *actualFlatBufferPtr)
FlatBase & getGridX1() const
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
ClassDefNV(Spline2DContainer, 1)
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)
GLuint GLfloat GLfloat GLfloat x1
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean GLboolean GLboolean a
GPUd() const expr uint32_t MultivariatePolynomialHelper< Dim