41template <
typename DataT>
46template <
typename DataT>
53template <
typename DataT>
55 DataT* Fparameters,
double x1Min,
double x1Max,
double x2Min,
double x2Max,
56 std::function<
void(
double x1,
double x2,
double f[])> F)
const
61 std::vector<double> dataPointF(getNumberOfDataPoints() * mFdimensions);
63 double scaleX1 = (x1Max - x1Min) / ((
double)mHelperU1.getSpline().getUmax());
64 double scaleX2 = (x2Max - x2Min) / ((
double)mHelperU2.getSpline().getUmax());
66 for (int32_t iv = 0; iv < getNumberOfDataPointsU2(); iv++) {
67 double x2 = x2Min + mHelperU2.getDataPoint(iv).u * scaleX2;
68 for (int32_t iu = 0; iu < getNumberOfDataPointsU1(); iu++) {
69 double x1 = x1Min + mHelperU1.getDataPoint(iu).u * scaleX1;
70 F(
x1, x2, &dataPointF[(iv * getNumberOfDataPointsU1() + iu) * mFdimensions]);
73 approximateFunction(Fparameters, dataPointF.data());
76template <
typename DataT>
78 DataT* Fparameters,
double x1Min,
double x1Max,
double x2Min,
double x2Max,
79 std::function<
void(
const std::vector<double>&
x1,
const std::vector<double>& x2, std::vector<double>
f[])> F,
80 uint32_t batchsize)
const
86 std::vector<double> dataPointF(getNumberOfDataPoints() * mFdimensions);
88 double scaleX1 = (x1Max - x1Min) / ((
double)mHelperU1.getSpline().getUmax());
89 double scaleX2 = (x2Max - x2Min) / ((
double)mHelperU2.getSpline().getUmax());
91 std::vector<double>
x1;
92 x1.reserve(batchsize);
94 std::vector<double> x2;
95 x2.reserve(batchsize);
97 std::vector<int32_t>
index;
98 index.reserve(batchsize);
100 std::vector<double> dataPointFTmp[mFdimensions];
101 for (int32_t iDim = 0; iDim < mFdimensions; ++iDim) {
102 dataPointFTmp[iDim].reserve(batchsize);
106 for (int32_t iv = 0; iv < getNumberOfDataPointsU2(); iv++) {
107 double x2Tmp = x2Min + mHelperU2.getDataPoint(iv).u * scaleX2;
108 for (int32_t iu = 0; iu < getNumberOfDataPointsU1(); iu++) {
109 double x1Tmp = x1Min + mHelperU1.getDataPoint(iu).u * scaleX1;
110 x1.emplace_back(x1Tmp);
111 x2.emplace_back(x2Tmp);
112 index.emplace_back((iv * getNumberOfDataPointsU1() + iu) * mFdimensions);
115 if (
counter == batchsize || (iu == (getNumberOfDataPointsU1() - 1) && (iv == (getNumberOfDataPointsU2() - 1)))) {
117 F(
x1, x2, dataPointFTmp);
118 uint32_t entries =
index.size();
120 for (uint32_t
i = 0;
i < entries; ++
i) {
121 const uint32_t indexTmp =
index[
i];
122 for (int32_t iDim = 0; iDim < mFdimensions; ++iDim) {
123 dataPointF[indexTmp + iDim] = dataPointFTmp[iDim][
i];
130 for (int32_t iDim = 0; iDim < mFdimensions; ++iDim) {
131 dataPointFTmp[iDim].clear();
136 approximateFunction(Fparameters, dataPointF.data());
139template <
typename DataT>
141 DataT* Fparameters,
const double DataPointF[])
const
145 const int32_t Ndim = mFdimensions;
146 const int32_t Ndim2 = 2 * Ndim;
147 const int32_t Ndim3 = 3 * Ndim;
148 const int32_t Ndim4 = 4 * Ndim;
150 int32_t nDataPointsU = getNumberOfDataPointsU1();
151 int32_t nDataPointsV = getNumberOfDataPointsU2();
153 int32_t nKnotsU = mHelperU1.getSpline().getNumberOfKnots();
154 int32_t nKnotsV = mHelperU2.getSpline().getNumberOfKnots();
156 std::unique_ptr<double[]> rotDataPointF(
new double[nDataPointsU * nDataPointsV * Ndim]);
157 std::unique_ptr<double[]> Dv(
new double[nKnotsV * nDataPointsU * Ndim]);
159 std::unique_ptr<DataT[]> parU(
new DataT[mHelperU1.getSpline().calcNumberOfParameters(Ndim)]);
160 std::unique_ptr<DataT[]> parV(
new DataT[mHelperU2.getSpline().calcNumberOfParameters(Ndim)]);
162 std::unique_ptr<double[]> parUdbl(
new double[mHelperU1.getSpline().calcNumberOfParameters(Ndim)]);
163 std::unique_ptr<double[]> parVdbl(
new double[mHelperU2.getSpline().calcNumberOfParameters(Ndim)]);
167 for (int32_t ipu = 0; ipu < nDataPointsU; ipu++) {
168 for (int32_t ipv = 0; ipv < nDataPointsV; ipv++) {
169 for (int32_t dim = 0; dim < Ndim; dim++) {
170 rotDataPointF[Ndim * (ipu * nDataPointsV + ipv) + dim] = DataPointF[Ndim * (ipv * nDataPointsU + ipu) + dim];
177 for (int32_t iKnotV = 0; iKnotV < nKnotsV; ++iKnotV) {
178 int32_t ipv = mHelperU2.getKnotDataPoint(iKnotV);
179 const double* DataPointFrow = &(DataPointF[Ndim * ipv * nDataPointsU]);
180 mHelperU1.approximateFunctionGradually(parU.get(), DataPointFrow);
182 for (int32_t
i = 0;
i < mHelperU1.getSpline().calcNumberOfParameters(Ndim);
i++) {
183 parUdbl[
i] = parU[
i];
185 for (int32_t iKnotU = 0; iKnotU < nKnotsU; ++iKnotU) {
186 DataT* knotPar = &Fparameters[Ndim4 * (iKnotV * nKnotsU + iKnotU)];
187 for (int32_t dim = 0; dim < Ndim; ++dim) {
188 knotPar[dim] = parU[Ndim * (2 * iKnotU) + dim];
189 knotPar[Ndim2 + dim] = parU[Ndim * (2 * iKnotU) + Ndim + dim];
194 for (int32_t ipu = 0; ipu < nDataPointsU; ipu++) {
195 double splineF[Ndim];
196 double u = mHelperU1.getDataPoint(ipu).u;
197 mHelperU1.getSpline().interpolateU(Ndim, parUdbl.get(), u, splineF);
198 for (int32_t dim = 0; dim < Ndim; dim++) {
199 rotDataPointF[(ipu * nDataPointsV + ipv) * Ndim + dim] = splineF[dim];
206 for (int32_t ipu = 0; ipu < nDataPointsU; ipu++) {
207 const double* DataPointFcol = &(rotDataPointF[ipu * nDataPointsV * Ndim]);
208 mHelperU2.approximateFunctionGradually(parV.get(), DataPointFcol);
209 for (int32_t iKnotV = 0; iKnotV < nKnotsV; iKnotV++) {
210 for (int32_t dim = 0; dim < Ndim; dim++) {
211 double dv = parV[(iKnotV * 2 + 1) * Ndim + dim];
212 Dv[(iKnotV * nDataPointsU + ipu) * Ndim + dim] = dv;
219 for (int32_t iKnotV = 0; iKnotV < nKnotsV; ++iKnotV) {
220 const double* Dvrow = &(Dv[iKnotV * nDataPointsU * Ndim]);
221 mHelperU1.approximateFunction(parU.get(), Dvrow);
222 for (int32_t iKnotU = 0; iKnotU < nKnotsU; ++iKnotU) {
223 for (int32_t dim = 0; dim < Ndim; ++dim) {
224 Fparameters[Ndim4 * (iKnotV * nKnotsU + iKnotU) + Ndim + dim] = parU[Ndim * 2 * iKnotU + dim];
225 Fparameters[Ndim4 * (iKnotV * nKnotsU + iKnotU) + Ndim3 + dim] = parU[Ndim * 2 * iKnotU + Ndim + dim];
231template <
typename DataT>
234 double x1Min,
double x1Max,
double x2Min,
double x2Max,
235 std::function<
void(
double x1,
double x2,
double f[])> F,
236 int32_t nAuxiliaryDataPointsU1, int32_t nAuxiliaryDataPointsU2)
240 setSpline(spline, nAuxiliaryDataPointsU1, nAuxiliaryDataPointsU2);
241 mFdimensions = spline.getYdimensions();
242 std::vector<double> dataPointX1(getNumberOfDataPoints());
243 std::vector<double> dataPointX2(getNumberOfDataPoints());
244 std::vector<double> dataPointF(getNumberOfDataPoints() * mFdimensions);
246 double scaleX1 = (x1Max - x1Min) / ((
double)mHelperU1.getSpline().getUmax());
247 double scaleX2 = (x2Max - x2Min) / ((
double)mHelperU2.getSpline().getUmax());
249 for (int32_t iv = 0; iv < getNumberOfDataPointsU2(); iv++) {
250 double x2 = x2Min + mHelperU2.getDataPoint(iv).u * scaleX2;
251 for (int32_t iu = 0; iu < getNumberOfDataPointsU1(); iu++) {
252 double x1 = x1Min + mHelperU1.getDataPoint(iu).u * scaleX1;
253 int32_t ind = iv * getNumberOfDataPointsU1() + iu;
254 dataPointX1[ind] =
x1;
255 dataPointX2[ind] = x2;
256 F(
x1, x2, &dataPointF[ind * mFdimensions]);
259 approximateDataPoints(spline, spline.getParameters(), x1Min, x1Max, x2Min, x2Max, &dataPointX1[0], &dataPointX2[0], &dataPointF[0], getNumberOfDataPoints());
262template <
typename DataT>
265 mFdimensions = spline.getYdimensions();
266 spline.
setXrange(x1Min, x1Max, x2Min, x2Max);
268 std::vector<int32_t> knots;
269 for (int32_t
i = 0;
i < spline.getGridX1().getNumberOfKnots();
i++) {
270 knots.push_back(spline.getGridX1().getKnot(
i).getU());
272 fGridU.recreate(0, knots.size(), knots.data());
273 fGridU.setXrange(x1Min, x1Max);
276 std::vector<int32_t> knots;
277 for (int32_t
i = 0;
i < spline.getGridX2().getNumberOfKnots();
i++) {
278 knots.push_back(spline.getGridX2().getKnot(
i).getU());
280 fGridV.recreate(0, knots.size(), knots.data());
281 fGridV.setXrange(x2Min, x2Max);
285template <
typename DataT>
287 double coeff[16], int32_t
indices[16])
291 int32_t nu = fGridU.getNumberOfKnots();
294 int32_t i00 = (nu * iv + iu) * 4;
295 int32_t i01 = i00 + 4 * nu;
296 int32_t i10 = i00 + 4;
297 int32_t i11 = i01 + 4;
299 double dSl, dDl, dSr, dDr;
301 double dSd, dDd, dSu, dDu;
310 double c[16] = {dSl * dSd, dSl * dDd, dDl * dSd, dDl * dDd,
311 dSr * dSd, dSr * dDd, dDr * dSd, dDr * dDd,
312 dSl * dSu, dSl * dDu, dDl * dSu, dDl * dDu,
313 dSr * dSu, dSr * dDu, dDr * dSu, dDr * dDu};
314 for (int32_t
i = 0;
i < 16;
i++) {
317 for (int32_t
i = 0;
i < 4;
i++) {
325template <
typename DataT>
328 const double dataPointX1[],
const double dataPointX2[],
const double dataPointF[],
333 setGrid(spline, x1Min, x1Max, x2Min, x2Max);
335 int32_t nFdim = spline.getYdimensions();
336 int32_t nu = fGridU.getNumberOfKnots();
337 int32_t nv = fGridV.getNumberOfKnots();
339 const int32_t nPar = 4 * spline.getNumberOfKnots();
343 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
344 double u = fGridU.convXtoU(dataPointX1[iPoint]);
345 double v = fGridV.convXtoU(dataPointX2[iPoint]);
346 int32_t iu = fGridU.getLeftKnotIndexForU(u);
347 int32_t iv = fGridV.getLeftKnotIndexForU(
v);
350 getScoefficients(iu, iv, u,
v,
c, ind);
354 for (int32_t
i = 0;
i < 16;
i++) {
355 for (int32_t
j =
i;
j < 16;
j++) {
356 solver.
A(ind[
i], ind[
j]) +=
c[
i] *
c[
j];
360 for (int32_t iDim = 0; iDim < nFdim; iDim++) {
361 double f = (double)dataPointF[iPoint * nFdim + iDim];
362 for (int32_t
i = 0;
i < 16;
i++) {
363 solver.
B(ind[
i], iDim) +=
f *
c[
i];
370 for (int32_t iu = 0; iu < nu - 1; iu++) {
371 for (int32_t iv = 0; iv < nv - 1; iv++) {
372 int32_t smoothPoint[4][2] = {
377 for (int32_t iSet = 0; iSet < 4; iSet++) {
378 int32_t pu = iu + smoothPoint[iSet][0];
379 int32_t pv = iv + smoothPoint[iSet][1];
380 int32_t ip = (nu * pv + pu) * 4;
381 if (pu < 0 || pv < 0 || pu >= nu || pv >= nv) {
386 getScoefficients(iu, iv, fGridU.getKnot(pu).u, fGridV.getKnot(pv).u,
c, ind);
391 for (int32_t
i = 0;
i < 17;
i++) {
392 for (int32_t
j =
i;
j < 17;
j++) {
393 solver.
A(ind[
i], ind[
j]) +=
w *
c[
i] *
c[
j];
401 for (int32_t
i = 0;
i < nPar;
i++) {
402 for (int32_t iDim = 0; iDim < nFdim; iDim++) {
403 splineParameters[
i * nFdim + iDim] = solver.
B(
i, iDim);
408template <
typename DataT>
413 const int32_t Ndim = 3;
415 const int32_t Fdegree = 4;
417 double Fcoeff[Ndim][4 * (Fdegree + 1) * (Fdegree + 1)];
419 constexpr int32_t nKnots = 10;
420 constexpr int32_t nAuxiliaryPoints = 2;
421 constexpr int32_t uMax = nKnots;
423 auto F = [&](
double u,
double v,
double Fuv[]) {
424 const double scale = TMath::Pi() / uMax;
425 double uu = u * scale;
426 double vv =
v * scale;
427 double cosu[Fdegree + 1], sinu[Fdegree + 1], cosv[Fdegree + 1], sinv[Fdegree + 1];
428 double ui = 0, vi = 0;
429 for (int32_t
i = 0;
i <= Fdegree;
i++, ui += uu, vi += vv) {
430 GPUCommonMath::SinCosd(ui, sinu[
i], cosu[
i]);
431 GPUCommonMath::SinCosd(vi, sinv[
i], cosv[
i]);
433 for (int32_t dim = 0; dim < Ndim; dim++) {
435 for (int32_t
i = 1;
i <= Fdegree;
i++) {
436 for (int32_t
j = 1;
j <= Fdegree;
j++) {
437 double*
c = &(Fcoeff[dim][4 * (
i * Fdegree +
j)]);
438 f +=
c[0] * cosu[
i] * cosv[
j];
439 f +=
c[1] * cosu[
i] * sinv[
j];
440 f +=
c[2] * sinu[
i] * cosv[
j];
441 f +=
c[3] * sinu[
i] * sinv[
j];
448 TCanvas* canv =
nullptr;
449 TNtuple* nt =
nullptr;
450 TNtuple* knots =
nullptr;
452 auto ask = [&]() ->
bool {
457 LOG(info) <<
"type 'q ' to exit";
459 std::getline(std::cin,
str);
460 return (
str !=
"q" &&
str !=
".q");
463 LOG(info) <<
"Test 2D interpolation with the compact spline";
465 int32_t nTries = 100;
468 canv =
new TCanvas(
"cQA",
"Spline2D QA", 1500, 800);
476 auto statTime = std::chrono::nanoseconds::zero();
478 for (int32_t seed = 1; seed < nTries + 1; seed++) {
481 gRandom->SetSeed(seed);
483 for (int32_t dim = 0; dim < Ndim; dim++) {
484 for (int32_t
i = 0;
i < 4 * (Fdegree + 1) * (Fdegree + 1);
i++) {
485 Fcoeff[dim][
i] = gRandom->Uniform(-1, 1);
491 int32_t knotsU[nKnots], knotsV[nKnots];
495 double du = 1. * uMax / (nKnots - 1);
496 for (int32_t
i = 1;
i < nKnots;
i++) {
497 knotsU[
i] = (int32_t)(
i * du);
498 knotsV[
i] = (int32_t)(
i * du);
500 knotsU[nKnots - 1] = uMax;
501 knotsV[nKnots - 1] = uMax;
502 spline.recreate(nKnots, knotsU, nKnots, knotsV);
504 if (nKnots != spline.getGridX1().getNumberOfKnots() ||
505 nKnots != spline.getGridX2().getNumberOfKnots()) {
506 LOG(info) <<
"warning: n knots changed during the initialisation " << nKnots
507 <<
" -> " << spline.getNumberOfKnots();
514 LOG(info) <<
"error at FlatObject functionality: " << err;
522 auto startTime = std::chrono::high_resolution_clock::now();
523 spline.approximateFunctionViaDataPoints(0., uMax, 0., uMax, F, nAuxiliaryPoints, nAuxiliaryPoints);
524 auto stopTime = std::chrono::high_resolution_clock::now();
525 statTime += std::chrono::duration_cast<std::chrono::nanoseconds>(stopTime - startTime);
529 TFile outf(
"testSpline2D.root",
"recreate");
530 if (outf.IsZombie()) {
531 LOG(info) <<
"Failed to open output file testSpline2D.root ";
533 const char*
name =
"spline2Dtest";
534 spline.writeToFile(outf,
name);
537 LOG(info) <<
"Failed to read Spline1DOld from file testSpline1DOld.root ";
549 for (int32_t dim = 0; dim < Ndim; dim++) {
550 auto F1 = [&](
double x1,
double x2,
double f[]) {
555 splines1D[dim].recreate(nKnots, knotsU, nKnots, knotsV);
556 splines1D[dim].approximateFunctionViaDataPoints(0., uMax, 0., uMax, F1, nAuxiliaryPoints, nAuxiliaryPoints);
560 for (
double u = 0; u < uMax; u += stepU) {
561 for (
double v = 0;
v < uMax;
v += stepU) {
565 spline.interpolate(u,
v, s);
566 for (int32_t dim = 0; dim < Ndim; dim++) {
567 statDf += (s[dim] -
f[dim]) * (s[dim] -
f[dim]);
568 DataT
s1 = splines1D[dim].interpolate(u,
v);
569 statDf1D += (s[dim] -
s1) * (s[dim] -
s1);
582 nt =
new TNtuple(
"nt",
"nt",
"u:v:f:s");
583 knots =
new TNtuple(
"knots",
"knots",
"type:u:v:s");
585 for (
double u = 0; u < uMax; u += stepU) {
586 for (
double v = 0;
v < uMax;
v += stepU) {
590 spline.interpolate(u,
v, s);
591 nt->Fill(u,
v,
f[0], s[0]);
594 nt->SetMarkerStyle(8);
596 nt->SetMarkerSize(.5);
597 nt->SetMarkerColor(kBlue);
598 nt->Draw(
"s:u:v",
"",
"");
600 nt->SetMarkerColor(kGray);
601 nt->SetMarkerSize(2.);
602 nt->Draw(
"f:u:v",
"",
"same");
604 nt->SetMarkerSize(.5);
605 nt->SetMarkerColor(kBlue);
606 nt->Draw(
"s:u:v",
"",
"same");
608 for (int32_t
i = 0;
i < nKnots;
i++) {
609 for (int32_t
j = 0;
j < nKnots;
j++) {
610 double u = spline.getGridX1().getKnot(
i).u;
611 double v = spline.getGridX2().getKnot(
j).u;
613 spline.interpolate(u,
v, s);
614 knots->Fill(1, u,
v, s[0]);
618 knots->SetMarkerStyle(8);
619 knots->SetMarkerSize(1.5);
620 knots->SetMarkerColor(kRed);
621 knots->SetMarkerSize(1.5);
622 knots->Draw(
"s:u:v",
"type==1",
"same");
624 if (drawDataPoints) {
627 for (int32_t ipu = 0; ipu < helper.
getHelperU1().getNumberOfDataPoints(); ipu++) {
629 for (int32_t ipv = 0; ipv < helper.
getHelperU2().getNumberOfDataPoints(); ipv++) {
635 spline.interpolate(pu.
u, pv.
u, s);
636 knots->Fill(2, pu.
u, pv.
u, s[0]);
639 knots->SetMarkerColor(kBlack);
640 knots->SetMarkerSize(1.);
641 knots->Draw(
"s:u:v",
"type==2",
"same");
653 statDf = sqrt(statDf / statN);
654 statDf1D = sqrt(statDf1D / statN);
656 LOG(info) <<
"\n std dev for Spline2D : " << statDf;
657 LOG(info) <<
" mean difference between 1-D and " << Ndim
658 <<
"-D splines : " << statDf1D;
659 LOG(info) <<
" approximation time " << statTime.count() / 1000. / nTries <<
" ms";
661 if (statDf < 0.15 && statDf1D < 1.e-20) {
662 LOG(info) <<
"Everything is fine";
664 LOG(info) <<
"Something is wrong!!";
Definition of Spline1DHelper class.
Definition of Spline2DHelper class.
static std::string stressTest(T &obj)
Test the flat object functionality for a child class T.
static void getScoefficients(const typename Spline1D< double >::Knot &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
mGridX2 setXrange(x2Min, x2Max)
int32_t setSpline(const Spline2DContainer< DataT > &spline, int32_t nAuxiliaryPointsU1, int32_t nAuxiliaryPointsU2)
_______________ Interface for a step-wise construction of the best-fit spline _______________________...
const Spline1DHelperOld< DataT > & getHelperU2() const
const Spline1DHelperOld< DataT > & getHelperU1() const
void approximateFunction(Spline2DContainer< DataT > &spline, 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)
_______________ Main functionality ________________________
void approximateFunctionViaDataPoints(Spline2DContainer< DataT > &spline, 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)
void approximateFunctionBatch(DataT *Fparameters, double x1Min, double x1Max, double x2Min, double x2Max, std::function< void(const std::vector< double > &x1, const std::vector< double > &x2, std::vector< double > f[])> F, uint32_t batchsize) const
approximate std::function, output in Fparameters. F calculates values for a batch of points.
void approximateDataPoints(Spline2DContainer< DataT > &spline, DataT *splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[], const double dataPointX2[], const double dataPointF[], int32_t nDataPoints)
Create best-fit spline parameters for a given set of data points.
Spline2DHelper()
_____________ Constructors / destructors __________________________
static int32_t test(const bool draw=0, const bool drawDataPoints=1)
Test the Spline2D class functionality.
static Spline2D * 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 x1
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLuint const GLchar * name
GLsizei GLenum const void * indices
GLubyte GLubyte GLubyte GLubyte w
Defining DataPointCompositeObject explicitly as copiable.
Helper structure for 1D spline construction.
bool isKnot
is the point placed at a knot
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
uint64_t const void const *restrict const msg