40template <
typename DataT>
45template <
typename DataT>
52template <
typename DataT>
54 double& cSl,
double& cDl,
double& cSr,
double& cDr)
62 double v = u * double(knotL.
Li);
66 cSl =
v2 * (2 *
v - 3.) + 1.;
72template <
typename DataT>
74 double& cSl,
double& cDl,
double& cSr,
double& cDr)
77 double dv = double(knotL.
Li);
80 cSl = 6 * (
v2 -
v) * dv;
81 cDl = 3 *
v2 - 4 *
v + 1.;
88template <
typename DataT>
90 double& cSl,
double& cDl,
double& cSr,
double& cDr)
93 double dv = double(knotL.
Li);
95 cSl = (12 *
v - 6) * dv * dv;
96 cDl = (6 *
v - 4) * dv;
98 cDr = (6 *
v - 2) * dv;
101template <
typename DataT>
103 double& cSl,
double& cDl,
double& cSr,
double& cDr)
105 double dv = double(knotL.
Li);
112template <
typename DataT>
114 double& cSl,
double& cDl,
double& cSr,
double& cDr)
116 double dv = double(knotL.
Li);
123template <
typename DataT>
125 double& cSl,
double& cDl,
double& cSr,
double& cDr)
127 double dv = double(knotL.
Li);
128 cSl = 12 * dv * dv * dv;
134template <
typename DataT>
137 double xMin,
double xMax,
138 const double vx[],
const double vf[], int32_t nDataPoints)
144 const int32_t nYdim = spline.getYdimensions();
145 spline.setXrange(xMin, xMax);
150 const int32_t nPar = 2 * spline.getNumberOfKnots();
155 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
156 double u = mSpline.convXtoU(vx[iPoint]);
157 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
159 double cS0, cZ0, cS1, cZ1;
160 getScoefficients(knot0, u, cS0, cZ0, cS1, cZ1);
161 double c[4] = {cS0, cZ0, cS1, cZ1};
165 int32_t
i = 2 * iKnot;
166 for (int32_t
j = 0;
j < 4;
j++) {
167 for (int32_t k =
j; k < 4; k++) {
168 band.
A(
i +
j,
i + k) +=
c[
j] *
c[k];
171 const double*
f = &vf[iPoint * nYdim];
172 for (int32_t
j = 0;
j < 4;
j++) {
173 for (int32_t dim = 0; dim < nYdim; dim++) {
174 band.
B(
i +
j, dim) +=
c[
j] *
f[dim];
179 for (int32_t iKnot = 0; iKnot < spline.getNumberOfKnots() - 2; ++iKnot) {
188 for (int32_t order = 2; order <= 3; order++) {
189 double cS0, cZ0, cS1r, cZ1r;
190 double cS1l, cZ1l, cS2, cZ2;
192 getDDScoefficientsRight(knot0, cS0, cZ0, cS1r, cZ1r);
193 getDDScoefficientsLeft(knot1, cS1l, cZ1l, cS2, cZ2);
195 getDDDScoefficients(knot0, cS0, cZ0, cS1r, cZ1r);
196 getDDDScoefficients(knot1, cS1l, cZ1l, cS2, cZ2);
200 double c[6] = {
w * cS0,
w * cZ0,
201 w * (cS1r - cS1l),
w * (cZ1r - cZ1l),
206 int32_t
i = 2 * iKnot;
207 for (int32_t
j = 0;
j < 6;
j++) {
208 for (int32_t k =
j; k < 6; k++) {
209 band.
A(
i +
j,
i + k) +=
c[
j] *
c[k];
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);
247template <
typename DataT>
250 const double vx[],
const double vf[], int32_t nDataPoints)
256 const int32_t nYdim = spline.getYdimensions();
261 const int32_t nPar = spline.getNumberOfKnots();
265 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
266 double u = mSpline.convXtoU(vx[iPoint]);
267 int32_t iKnot = mSpline.getLeftKnotIndexForU(u);
269 double cS0, cZ0, cS1, cZ1;
270 getScoefficients(knot0, u, cS0, cZ0, cS1, cZ1);
271 double c[2] = {cZ0, cZ1};
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];
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++) {
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]);
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);
300template <
typename DataT>
302 double xMin,
double xMax, std::function<
void(
double x,
double f[])> F)
307 int32_t Ndim = spline.getYdimensions();
308 const int32_t nKnots = spline.getNumberOfKnots();
310 TMatrixD
A(nKnots, nKnots);
326 double cZ0 = (-4) * knot0.
Li;
327 double cZ1 = (-2) * knot0.
Li;
336 double cZ0 = (6 - 4) * knot0.
Li;
337 double cZ1 = (6 - 2) * knot0.
Li;
339 A(nKnots - 1, nKnots - 2) = cZ0;
340 A(nKnots - 1, nKnots - 1) = cZ1;
344 for (int32_t
i = 1;
i < nKnots - 1;
i++) {
346 double cZ0 = (6 - 4) * knot0.
Li;
347 double cZ1_0 = (6 - 2) * knot0.
Li;
351 double cZ1_1 = (-4) * knot1.
Li;
352 double cZ2 = (-2) * knot1.
Li;
355 A(
i,
i) = cZ1_0 - cZ1_1;
361 spline.setXrange(xMin, xMax);
362 DataT* parameters = spline.getParameters();
367 double uToXscale = (((double)xMax) - xMin) / spline.getUmax();
369 for (int32_t
i = 0;
i < nKnots; ++
i) {
373 F(xMin + u * uToXscale,
f);
374 for (int32_t dim = 0; dim < Ndim; dim++) {
375 parameters[(2 *
i) * Ndim + dim] =
f[dim];
379 for (int32_t dim = 0; dim < Ndim; dim++) {
383 double f0 = parameters[(2 * 0) * Ndim + dim];
384 double f1 = parameters[(2 * 1) * Ndim + dim];
386 double cS1 = (6) * knot0.Li * knot0.Li;
388 b(0) = -cS1 * (f1 - f0);
393 double f0 = parameters[2 * (nKnots - 2) * Ndim + dim];
394 double f1 = parameters[2 * (nKnots - 1) * Ndim + dim];
396 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
398 b(nKnots - 1) = -cS1 * (f1 - f0);
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];
407 double cS1 = (6 - 12) * knot0.Li * knot0.Li;
411 double cS2 = (6) * knot1.
Li * knot1.
Li;
413 b(
i) = -cS1 * (f1 - f0) + cS2 * (f2 - f1);
417 for (int32_t
i = 0;
i < nKnots;
i++) {
418 parameters[(2 *
i + 1) * Ndim + dim] =
c[
i];
423template <
typename DataT>
426 int32_t nAuxiliaryDataPoints, std::vector<double>& vx, std::vector<double>& vf)
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;
436 spline.setXrange(xMin, xMax);
438 nDataPoints = 1 + mSpline.getUmax() + mSpline.getUmax() * nAuxiliaryDataPoints;
440 vx.resize(nDataPoints);
441 vf.resize(nDataPoints * nFdimensions);
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);
448 F(
x, &vf[
i * nFdimensions]);
452template <
typename DataT>
455 int32_t nAuxiliaryDataPoints)
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());
464template <
typename DataT>
467 int32_t nAuxiliaryDataPoints)
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);
478 int32_t nFdimensions = spline.getYdimensions();
481 for (int32_t iKnot = 0; iKnot < mSpline.getNumberOfKnots(); ++iKnot) {
483 double x = mSpline.convUtoX(knot.
u);
484 double s[nFdimensions];
486 for (int32_t dim = 0; dim < nFdimensions; dim++) {
487 spline.getParameters()[2 * iKnot * nFdimensions + dim] = s[dim];
490 approximateDerivatives(spline, &vx[0], &vf[0], nDataPoints);
493template <
typename DataT>
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();
501 mSpline.
recreate(0, nKnots, knots.data());
502 mSpline.setXrange(spline.getXmin(), spline.getXmax());
505template <
typename DataT>
514 const int32_t Ndim = 5;
515 const int32_t Fdegree = 4;
516 double Fcoeff[Ndim][2 * (Fdegree + 1)];
518 auto F = [&](
double x,
double f[]) ->
void {
519 double cosx[Fdegree + 1], sinx[Fdegree + 1];
521 for (int32_t
i = 0;
i <= Fdegree;
i++, xi +=
x) {
522 GPUCommonMath::SinCosd(xi, sinx[
i], cosx[
i]);
524 for (int32_t dim = 0; dim < Ndim; dim++) {
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];
532 TCanvas* canv =
nullptr;
533 TNtuple* nt =
nullptr;
534 TNtuple* knots =
nullptr;
536 auto ask = [&]() ->
bool {
541 LOG(info) <<
"type 'q ' to exit";
543 std::getline(std::cin,
str);
544 return (
str !=
"q" &&
str !=
".q");
547 LOG(info) <<
"Test 1D interpolation with the compact spline";
549 int32_t nTries = 100;
552 canv =
new TCanvas(
"cQA",
"Spline1D QA", 1000, 600);
563 for (int32_t itry = 0; itry < nTries; itry++) {
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);
576 const int32_t uMax = nKnots * 3;
579 int32_t knotsU[nKnots];
583 double du = 1. * uMax / (nKnots - 1);
584 for (int32_t
i = 1;
i < nKnots;
i++) {
585 knotsU[
i] = (int32_t)(
i * du);
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();
598 LOG(info) <<
"error at FlatObject functionality: " << err;
604 nKnots = spline1.getNumberOfKnots();
605 int32_t nAuxiliaryPoints = 2;
607 spline1.approximateFunction(0., TMath::Pi(), F, nAuxiliaryPoints);
611 TFile outf(
"testSpline1D.root",
"recreate");
612 if (outf.IsZombie()) {
613 LOG(info) <<
"Failed to open output file testSpline1D.root ";
615 const char*
name =
"Spline1Dtest";
616 spline1.writeToFile(outf,
name);
619 LOG(info) <<
"Failed to read Spline1D from file testSpline1D.root ";
633 for (int32_t dim = 0; dim < Ndim; dim++) {
634 auto F3 = [&](
double u,
double f[]) ->
void {
639 splines3[dim].recreate(nKnots, knotsU);
640 splines3[dim].approximateFunction(0., TMath::Pi(), F3, nAuxiliaryPoints);
644 double stepX = 1.e-2;
645 for (
double x = 0;
x < TMath::Pi();
x += stepX) {
647 DataT
s1[Ndim], s2[Ndim];
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]);
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) {
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]));
678 nt->SetMarkerStyle(8);
681 TNtuple* ntRange =
new TNtuple(
"ntRange",
"nt",
"u:f");
682 drawMin -= 0.1 * (drawMax - drawMin);
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",
"",
"");
694 nt->SetMarkerColor(kGray);
695 nt->SetMarkerSize(2.);
696 nt->Draw(
"f:u",
"",
"P,same");
698 nt->SetMarkerSize(.5);
699 nt->SetMarkerColor(kBlue);
700 nt->Draw(
"s:u",
"",
"P,same");
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;
706 spline1.interpolate(spline1.convUtoX(u), s);
707 knots->Fill(1, u, s[0]);
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");
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++) {
722 spline1.interpolate(vx[
j], s);
723 knots->Fill(2, spline1.convXtoU(vx[
j]), s[0]);
725 knots->SetMarkerColor(kBlack);
726 knots->SetMarkerSize(1.);
727 knots->Draw(
"s:u",
"type==2",
"same");
738 statDf1 = sqrt(statDf1 / statN);
739 statDf2 = sqrt(statDf2 / statN);
740 statDf1D = sqrt(statDf1D / statN);
742 LOG(info) << std::defaultfloat;
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;
748 if (statDf1 < 0.05 && statDf2 < 0.06 && statDf1D < 1.e-20) {
749 LOG(info) <<
"Everything is fine";
751 LOG(info) <<
"Something is wrong!!";
Definition of BandMatrixSolver class.
templateClassImp(o2::gpu::Spline1DHelper)
Definition of Spline1DHelper class.
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.
static std::string stressTest(T &obj)
Test the flat object functionality for a child class T.
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
double & B(int32_t i, int32_t j)
access to B elements
double & A(int32_t i, int32_t j)
access to A elements
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLfloat GLfloat GLfloat v2
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"
uint64_t const void const *restrict const msg