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().interpolateAtU(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> dataPointWeight(getNumberOfDataPoints(), 1.);
245 std::vector<double> dataPointF(getNumberOfDataPoints() * mFdimensions);
247 double scaleX1 = (x1Max - x1Min) / ((
double)mHelperU1.getSpline().getUmax());
248 double scaleX2 = (x2Max - x2Min) / ((
double)mHelperU2.getSpline().getUmax());
250 for (int32_t iv = 0; iv < getNumberOfDataPointsU2(); iv++) {
251 double x2 = x2Min + mHelperU2.getDataPoint(iv).u * scaleX2;
252 for (int32_t iu = 0; iu < getNumberOfDataPointsU1(); iu++) {
253 double x1 = x1Min + mHelperU1.getDataPoint(iu).u * scaleX1;
254 int32_t ind = iv * getNumberOfDataPointsU1() + iu;
255 dataPointX1[ind] =
x1;
256 dataPointX2[ind] = x2;
257 F(
x1, x2, &dataPointF[ind * mFdimensions]);
260 approximateDataPoints(spline, spline.getParameters(), x1Min, x1Max, x2Min, x2Max, dataPointX1.data(), dataPointX2.data(), dataPointF.data(),
261 dataPointWeight.data(), getNumberOfDataPoints());
264template <
typename DataT>
267 mFdimensions = spline.getYdimensions();
268 spline.setXrange(x1Min, x1Max, x2Min, x2Max);
270 std::vector<int32_t> knots;
271 for (int32_t
i = 0;
i < spline.
getGridX1().getNumberOfKnots();
i++) {
272 knots.push_back(spline.
getGridX1().getKnot(
i).getU());
274 fGridU.
recreate(0, knots.size(), knots.data());
275 fGridU.setXrange(x1Min, x1Max);
278 std::vector<int32_t> knots;
279 for (int32_t
i = 0;
i < spline.
getGridX2().getNumberOfKnots();
i++) {
280 knots.push_back(spline.
getGridX2().getKnot(
i).getU());
282 fGridV.recreate(0, knots.size(), knots.data());
283 fGridV.setXrange(x2Min, x2Max);
287template <
typename DataT>
289 double coeff[16], int32_t
indices[16])
293 int32_t nu = fGridU.getNumberOfKnots();
296 int32_t i00 = (nu * iv + iu) * 4;
297 int32_t i01 = i00 + 4 * nu;
298 int32_t i10 = i00 + 4;
299 int32_t i11 = i01 + 4;
301 double dSl, dDl, dSr, dDr;
303 double dSd, dDd, dSu, dDu;
312 double c[16] = {dSl * dSd, dSl * dDd, dDl * dSd, dDl * dDd,
313 dSr * dSd, dSr * dDd, dDr * dSd, dDr * dDd,
314 dSl * dSu, dSl * dDu, dDl * dSu, dDl * dDu,
315 dSr * dSu, dSr * dDu, dDr * dSu, dDr * dDu};
316 for (int32_t
i = 0;
i < 16;
i++) {
319 for (int32_t
i = 0;
i < 4;
i++) {
327template <
typename DataT>
330 const double dataPointX1[],
const double dataPointX2[],
const double dataPointF[],
331 const double dataPointWeight[], int32_t nDataPoints)
335 setGrid(spline, x1Min, x1Max, x2Min, x2Max);
337 int32_t nFdim = spline.getYdimensions();
338 int32_t nu = fGridU.getNumberOfKnots();
339 int32_t nv = fGridV.getNumberOfKnots();
341 const int32_t nPar = 4 * spline.getNumberOfKnots();
345 for (int32_t iPoint = 0; iPoint < nDataPoints; ++iPoint) {
346 double u = fGridU.convXtoU(dataPointX1[iPoint]);
347 double v = fGridV.convXtoU(dataPointX2[iPoint]);
348 double weight = dataPointWeight[iPoint];
352 int32_t iu = fGridU.getLeftKnotIndexForU(u);
353 int32_t iv = fGridV.getLeftKnotIndexForU(
v);
356 getScoefficients(iu, iv, u,
v,
c, ind);
360 for (int32_t
i = 0;
i < 16;
i++) {
361 for (int32_t
j =
i;
j < 16;
j++) {
366 for (int32_t iDim = 0; iDim < nFdim; iDim++) {
367 double f = (double)dataPointF[iPoint * nFdim + iDim];
368 for (int32_t
i = 0;
i < 16;
i++) {
376 for (int32_t iu = 0; iu < nu - 1; iu++) {
377 for (int32_t iv = 0; iv < nv - 1; iv++) {
378 int32_t smoothPoint[4][2] = {
383 for (int32_t iSet = 0; iSet < 4; iSet++) {
384 int32_t pu = iu + smoothPoint[iSet][0];
385 int32_t pv = iv + smoothPoint[iSet][1];
386 int32_t ip = (nu * pv + pu) * 4;
387 if (pu < 0 || pv < 0 || pu >= nu || pv >= nv) {
392 getScoefficients(iu, iv, fGridU.getKnot(pu).u, fGridV.getKnot(pv).u,
c, ind);
397 for (int32_t
i = 0;
i < 17;
i++) {
398 for (int32_t
j =
i;
j < 17;
j++) {
399 solver.
A(ind[
i], ind[
j]) +=
w *
c[
i] *
c[
j];
407 for (int32_t
i = 0;
i < nPar;
i++) {
408 for (int32_t iDim = 0; iDim < nFdim; iDim++) {
409 splineParameters[
i * nFdim + iDim] = solver.
B(
i, iDim);
414template <
typename DataT>
419 const int32_t Ndim = 3;
421 const int32_t Fdegree = 4;
423 double Fcoeff[Ndim][4 * (Fdegree + 1) * (Fdegree + 1)];
425 constexpr int32_t nKnots = 10;
426 constexpr int32_t nAuxiliaryPoints = 2;
427 constexpr int32_t uMax = nKnots;
429 auto F = [&](
double u,
double v,
double Fuv[]) {
430 const double scale = TMath::Pi() / uMax;
431 double uu = u * scale;
432 double vv =
v * scale;
433 double cosu[Fdegree + 1], sinu[Fdegree + 1], cosv[Fdegree + 1], sinv[Fdegree + 1];
434 double ui = 0, vi = 0;
435 for (int32_t
i = 0;
i <= Fdegree;
i++, ui += uu, vi += vv) {
436 GPUCommonMath::SinCosd(ui, sinu[
i], cosu[
i]);
437 GPUCommonMath::SinCosd(vi, sinv[
i], cosv[
i]);
439 for (int32_t dim = 0; dim < Ndim; dim++) {
441 for (int32_t
i = 1;
i <= Fdegree;
i++) {
442 for (int32_t
j = 1;
j <= Fdegree;
j++) {
443 double*
c = &(Fcoeff[dim][4 * (
i * Fdegree +
j)]);
444 f +=
c[0] * cosu[
i] * cosv[
j];
445 f +=
c[1] * cosu[
i] * sinv[
j];
446 f +=
c[2] * sinu[
i] * cosv[
j];
447 f +=
c[3] * sinu[
i] * sinv[
j];
454 TCanvas* canv =
nullptr;
455 TNtuple* nt =
nullptr;
456 TNtuple* knots =
nullptr;
458 auto ask = [&]() ->
bool {
463 LOG(info) <<
"type 'q ' to exit";
465 std::getline(std::cin,
str);
466 return (
str !=
"q" &&
str !=
".q");
469 LOG(info) <<
"Test 2D interpolation with the compact spline";
471 int32_t nTries = 100;
474 canv =
new TCanvas(
"cQA",
"Spline2D QA", 1500, 800);
482 auto statTime = std::chrono::nanoseconds::zero();
484 for (int32_t seed = 1; seed < nTries + 1; seed++) {
487 gRandom->SetSeed(seed);
489 for (int32_t dim = 0; dim < Ndim; dim++) {
490 for (int32_t
i = 0;
i < 4 * (Fdegree + 1) * (Fdegree + 1);
i++) {
491 Fcoeff[dim][
i] = gRandom->Uniform(-1, 1);
497 int32_t knotsU[nKnots], knotsV[nKnots];
501 double du = 1. * uMax / (nKnots - 1);
502 for (int32_t
i = 1;
i < nKnots;
i++) {
503 knotsU[
i] = (int32_t)(
i * du);
504 knotsV[
i] = (int32_t)(
i * du);
506 knotsU[nKnots - 1] = uMax;
507 knotsV[nKnots - 1] = uMax;
508 spline.recreate(nKnots, knotsU, nKnots, knotsV);
510 if (nKnots != spline.getGridX1().getNumberOfKnots() ||
511 nKnots != spline.getGridX2().getNumberOfKnots()) {
512 LOG(info) <<
"warning: n knots changed during the initialisation " << nKnots
513 <<
" -> " << spline.getNumberOfKnots();
520 LOG(info) <<
"error at FlatObject functionality: " << err;
528 auto startTime = std::chrono::high_resolution_clock::now();
529 spline.approximateFunctionViaDataPoints(0., uMax, 0., uMax, F, nAuxiliaryPoints, nAuxiliaryPoints);
530 auto stopTime = std::chrono::high_resolution_clock::now();
531 statTime += std::chrono::duration_cast<std::chrono::nanoseconds>(stopTime - startTime);
535 TFile outf(
"testSpline2D.root",
"recreate");
536 if (outf.IsZombie()) {
537 LOG(info) <<
"Failed to open output file testSpline2D.root ";
539 const char*
name =
"spline2Dtest";
540 spline.writeToFile(outf,
name);
543 LOG(info) <<
"Failed to read Spline1DOld from file testSpline1DOld.root ";
555 for (int32_t dim = 0; dim < Ndim; dim++) {
556 auto F1 = [&](
double x1,
double x2,
double f[]) {
561 splines1D[dim].recreate(nKnots, knotsU, nKnots, knotsV);
562 splines1D[dim].approximateFunctionViaDataPoints(0., uMax, 0., uMax, F1, nAuxiliaryPoints, nAuxiliaryPoints);
566 for (
double u = 0; u < uMax; u += stepU) {
567 for (
double v = 0;
v < uMax;
v += stepU) {
571 spline.interpolate(u,
v, s);
572 for (int32_t dim = 0; dim < Ndim; dim++) {
573 statDf += (s[dim] -
f[dim]) * (s[dim] -
f[dim]);
574 DataT
s1 = splines1D[dim].interpolate(u,
v);
575 statDf1D += (s[dim] -
s1) * (s[dim] -
s1);
588 nt =
new TNtuple(
"nt",
"nt",
"u:v:f:s");
589 knots =
new TNtuple(
"knots",
"knots",
"type:u:v:s");
591 for (
double u = 0; u < uMax; u += stepU) {
592 for (
double v = 0;
v < uMax;
v += stepU) {
596 spline.interpolate(u,
v, s);
597 nt->Fill(u,
v,
f[0], s[0]);
600 nt->SetMarkerStyle(8);
602 nt->SetMarkerSize(.5);
603 nt->SetMarkerColor(kBlue);
604 nt->Draw(
"s:u:v",
"",
"");
606 nt->SetMarkerColor(kGray);
607 nt->SetMarkerSize(2.);
608 nt->Draw(
"f:u:v",
"",
"same");
610 nt->SetMarkerSize(.5);
611 nt->SetMarkerColor(kBlue);
612 nt->Draw(
"s:u:v",
"",
"same");
614 for (int32_t
i = 0;
i < nKnots;
i++) {
615 for (int32_t
j = 0;
j < nKnots;
j++) {
616 double u = spline.getGridX1().getKnot(
i).u;
617 double v = spline.getGridX2().getKnot(
j).u;
619 spline.interpolate(u,
v, s);
620 knots->Fill(1, u,
v, s[0]);
624 knots->SetMarkerStyle(8);
625 knots->SetMarkerSize(1.5);
626 knots->SetMarkerColor(kRed);
627 knots->SetMarkerSize(1.5);
628 knots->Draw(
"s:u:v",
"type==1",
"same");
633 for (int32_t ipu = 0; ipu < helper.
getHelperU1().getNumberOfDataPoints(); ipu++) {
635 for (int32_t ipv = 0; ipv < helper.
getHelperU2().getNumberOfDataPoints(); ipv++) {
641 spline.interpolate(pu.
u, pv.
u, s);
642 knots->Fill(2, pu.
u, pv.
u, s[0]);
645 knots->SetMarkerColor(kBlack);
646 knots->SetMarkerSize(1.);
647 knots->Draw(
"s:u:v",
"type==2",
"same");
659 statDf = sqrt(statDf / statN);
660 statDf1D = sqrt(statDf1D / statN);
662 LOG(info) <<
"\n std dev for Spline2D : " << statDf;
663 LOG(info) <<
" mean difference between 1-D and " << Ndim
664 <<
"-D splines : " << statDf1D;
665 LOG(info) <<
" approximation time " << statTime.count() / 1000. / nTries <<
" ms";
667 if (statDf < 0.15 && statDf1D < 1.e-20) {
668 LOG(info) <<
"Everything is fine";
670 LOG(info) <<
"Something is wrong!!";
Definition of SymMatrixSolver class.
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 >::KnotType &knotL, double u, double &cSl, double &cDl, double &cSr, double &cDr)
void recreate(int32_t nYdim, int32_t nKnotsX1, int32_t nKnotsX2)
Constructor for a regular spline.
FlatBase & getGridX2() const
FlatBase & getGridX1() const
const Spline1DHelperOld< DataT > & getHelperU2() const
void approximateFunctionViaDataPoints(Spline2DContainerBase< DataT, FlatObject > &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 approximateFunction(Spline2DContainerBase< DataT, FlatObject > &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 ________________________
int32_t setSpline(const Spline2DContainerBase< DataT, FlatObject > &spline, int32_t nAuxiliaryPointsU1, int32_t nAuxiliaryPointsU2)
_______________ Interface for a step-wise construction of the best-fit spline _______________________...
const Spline1DHelperOld< DataT > & getHelperU1() const
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(Spline2DContainerBase< DataT, FlatObject > &spline, DataT *splineParameters, double x1Min, double x1Max, double x2Min, double x2Max, const double dataPointX1[], const double dataPointX2[], const double dataPointF[], const double dataPointWeight[], 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.
Forward declaration — specializations below select ClassDefNV based on FlatBase.
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
GLuint GLuint GLfloat weight
GLsizei GLenum const void * indices
GLubyte GLubyte GLubyte GLubyte w
TCanvas * drawDataPoints(TMultiGraph *mg, double min, double max)
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