Project
Loading...
Searching...
No Matches
Chebyshev3D.cxx
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
15
17#include <TH1.h> // for TH1D, TH1
18#include <TMath.h> // for Cos, Pi
19#include <TMethodCall.h> // for TMethodCall
20#include <TROOT.h> // for TROOT, gROOT
21#include <TRandom.h> // for TRandom, gRandom
22#include <TString.h> // for TString
23#include <TSystem.h> // for TSystem, gSystem
24#include <cstdio> // for printf, fprintf, FILE, fclose, fflush, etc
25#include "MathUtils/Chebyshev3DCalc.h" // for Chebyshev3DCalc, etc
26#include "TMathBase.h" // for Max, Abs
27#include "TNamed.h" // for TNamed
28#include "TObjArray.h" // for TObjArray
29#include <fairlogger/Logger.h> // for FairLogger
30
31using namespace o2::math_utils;
32
34
35const Float_t Chebyshev3D::sMinimumPrecision = 1.e-12f;
36
38 : mOutputArrayDimension(0),
39 mPrecision(sMinimumPrecision),
40 mChebyshevParameter(1),
41 mMaxCoefficients(0),
42 mTemporaryUserResults(nullptr),
43 mTemporaryChebyshevGrid(nullptr),
44 mUserFunctionName(""),
45 mUserMacro(nullptr)
46{
47 // Default constructor
48 for (int i = 3; i--;) {
49 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] =
50 mTemporaryCoefficient[i] = 0;
51 mNumberOfPoints[i] = 0;
52 mTemporaryChebyshevGridOffs[i] = 0;
53 }
54}
55
57 : TNamed(src),
58 mOutputArrayDimension(src.mOutputArrayDimension),
59 mPrecision(src.mPrecision),
60 mChebyshevParameter(1),
61 mMaxCoefficients(src.mMaxCoefficients),
62 mTemporaryUserResults(nullptr),
63 mTemporaryChebyshevGrid(nullptr),
64 mUserFunctionName(src.mUserFunctionName),
65 mUserMacro(nullptr)
66{
67 // read coefs from text file
68 for (int i = 3; i--;) {
69 mMinBoundaries[i] = src.mMinBoundaries[i];
70 mMaxBoundaries[i] = src.mMaxBoundaries[i];
71 mBoundaryMappingScale[i] = src.mBoundaryMappingScale[i];
72 mBoundaryMappingOffset[i] = src.mBoundaryMappingOffset[i];
73 mNumberOfPoints[i] = src.mNumberOfPoints[i];
74 mTemporaryChebyshevGridOffs[i] = src.mTemporaryChebyshevGridOffs[i];
75 mTemporaryCoefficient[i] = 0;
76 }
77 for (int i = 0; i < mOutputArrayDimension; i++) {
78 Chebyshev3DCalc* cbc = src.getChebyshevCalc(i);
79 if (cbc) {
80 mChebyshevParameter.AddAtAndExpand(new Chebyshev3DCalc(*cbc), i);
81 }
82 }
83}
84
85Chebyshev3D::Chebyshev3D(const char* inpFile)
86 : mOutputArrayDimension(0),
87 mPrecision(0),
88 mChebyshevParameter(1),
89 mMaxCoefficients(0),
90 mTemporaryUserResults(nullptr),
91 mTemporaryChebyshevGrid(nullptr),
92 mUserFunctionName(""),
93 mUserMacro(nullptr)
94{
95 // read coefs from text file
96 for (int i = 3; i--;) {
97 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
98 mNumberOfPoints[i] = 0;
99 mTemporaryChebyshevGridOffs[i] = 0;
100 mTemporaryCoefficient[i] = 0;
101 }
102 loadData(inpFile);
103}
104
106 : mOutputArrayDimension(0),
107 mPrecision(0),
108 mChebyshevParameter(1),
109 mMaxCoefficients(0),
110 mTemporaryUserResults(nullptr),
111 mTemporaryChebyshevGrid(nullptr),
112 mUserFunctionName(""),
113 mUserMacro(nullptr)
114{
115 // read coefs from stream
116 for (int i = 3; i--;) {
117 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
118 mNumberOfPoints[i] = 0;
119 mTemporaryChebyshevGridOffs[i] = 0;
120 mTemporaryCoefficient[i] = 0;
121 }
123}
124
125#ifdef _INC_CREATION_Chebyshev3D_
126Chebyshev3D::Chebyshev3D(const char* funName, int dimOut, const Float_t* bmin, const Float_t* bmax,
127 const Int_t* npoints, Float_t prec, const Float_t* precD)
128 : TNamed(funName, funName),
129 mOutputArrayDimension(0),
130 mPrecision(TMath::Max(sMinimumPrecision, prec)),
131 mChebyshevParameter(1),
132 mMaxCoefficients(0),
133 mTemporaryUserResults(nullptr),
134 mTemporaryChebyshevGrid(nullptr),
135 mUserFunctionName(""),
136 mUserMacro(nullptr)
137{
138 if (dimOut < 1) {
139 LOG(error) << "Chebyshev3D: Requested output dimension is " << mOutputArrayDimension << "\nStop\n";
140 exit(1);
141 }
142 for (int i = 3; i--;) {
143 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
144 mNumberOfPoints[i] = 0;
145 mTemporaryChebyshevGridOffs[i] = 0.;
146 mTemporaryCoefficient[i] = 0;
147 }
148 setDimOut(dimOut, precD);
149 prepareBoundaries(bmin, bmax);
150 defineGrid(npoints);
151 setuserFunction(funName);
152 chebyshevFit();
153}
154#endif
155
156#ifdef _INC_CREATION_Chebyshev3D_
157Chebyshev3D::Chebyshev3D(void (*ptr)(float*, float*), int dimOut, const Float_t* bmin, const Float_t* bmax,
158 const Int_t* npoints, Float_t prec, const Float_t* precD)
159 : mOutputArrayDimension(0),
160 mPrecision(TMath::Max(sMinimumPrecision, prec)),
161 mChebyshevParameter(1),
162 mMaxCoefficients(0),
163 mTemporaryUserResults(nullptr),
164 mTemporaryChebyshevGrid(nullptr),
165 mUserFunctionName(""),
166 mUserMacro(nullptr)
167{
168 if (dimOut < 1) {
169 LOG(error) << "Chebyshev3D: Requested output dimension is " << mOutputArrayDimension << " \nStop\n";
170 exit(1);
171 }
172 for (int i = 3; i--;) {
173 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
174 mNumberOfPoints[i] = 0;
175 mTemporaryChebyshevGridOffs[i] = 0.;
176 mTemporaryCoefficient[i] = 0;
177 }
178 setDimOut(dimOut, precD);
179 prepareBoundaries(bmin, bmax);
180 defineGrid(npoints);
181 setuserFunction(ptr);
182 chebyshevFit();
183}
184#endif
185
186#ifdef _INC_CREATION_Chebyshev3D_
187Chebyshev3D::Chebyshev3D(void (*ptr)(float*, float*), int dimOut, const Float_t* bmin, const Float_t* bmax,
188 const Int_t* npX, const Int_t* npY, const Int_t* npZ, Float_t prec, const Float_t* precD)
189 : mOutputArrayDimension(0),
190 mPrecision(TMath::Max(sMinimumPrecision, prec)),
191 mChebyshevParameter(1),
192 mMaxCoefficients(0),
193 mTemporaryUserResults(nullptr),
194 mTemporaryChebyshevGrid(nullptr),
195 mUserFunctionName(""),
196 mUserMacro(nullptr)
197{
198 if (dimOut < 1) {
199 LOG(error) << "Chebyshev3D: Requested output dimension is " << mOutputArrayDimension << "%d\nStop\n";
200 exit(1);
201 }
202 for (int i = 3; i--;) {
203 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
204 mNumberOfPoints[i] = 0;
205 mTemporaryChebyshevGridOffs[i] = 0.;
206 mTemporaryCoefficient[i] = 0;
207 }
208 setDimOut(dimOut, precD);
209 prepareBoundaries(bmin, bmax);
210 setuserFunction(ptr);
211
212 defineGrid(npX);
213 chebyshevFit(0);
214 defineGrid(npY);
215 chebyshevFit(1);
216 defineGrid(npZ);
217 chebyshevFit(2);
218}
219#endif
220
221#ifdef _INC_CREATION_Chebyshev3D_
222Chebyshev3D::Chebyshev3D(void (*ptr)(float*, float*), int dimOut, const Float_t* bmin, const Float_t* bmax,
223 Float_t prec, Bool_t run, const Float_t* precD)
224 : mOutputArrayDimension(0),
225 mPrecision(TMath::Max(sMinimumPrecision, prec)),
226 mChebyshevParameter(1),
227 mMaxCoefficients(0),
228 mTemporaryUserResults(nullptr),
229 mTemporaryChebyshevGrid(nullptr),
230 mUserFunctionName(""),
231 mUserMacro(nullptr)
232{
233 if (dimOut != 3) {
234 LOG(error) << "Chebyshev3D: This constructor works only for 3D fits, " << mOutputArrayDimension << "D fit was requested\n";
235 exit(1);
236 }
237 if (dimOut < 1) {
238 LOG(error) << "Chebyshev3D: Requested output dimension is " << mOutputArrayDimension << "\nStop\n";
239 exit(1);
240 }
241 for (int i = 3; i--;) {
242 mMinBoundaries[i] = mMaxBoundaries[i] = mBoundaryMappingScale[i] = mBoundaryMappingOffset[i] = 0;
243 mNumberOfPoints[i] = 0;
244 mTemporaryChebyshevGridOffs[i] = 0.;
245 mTemporaryCoefficient[i] = 0;
246 }
247 setDimOut(dimOut, precD);
248 prepareBoundaries(bmin, bmax);
249 setuserFunction(ptr);
250
251 if (run) {
252 int gridNC[3][3];
253 estimateNumberOfPoints(prec, gridNC);
254 defineGrid(gridNC[0]);
255 chebyshevFit(0);
256 defineGrid(gridNC[1]);
257 chebyshevFit(1);
258 defineGrid(gridNC[2]);
259 chebyshevFit(2);
260 }
261}
262#endif
263
265{
266 // assignment operator
267 if (this != &rhs) {
268 Clear();
269 mOutputArrayDimension = rhs.mOutputArrayDimension;
270 mPrecision = rhs.mPrecision;
271 mMaxCoefficients = rhs.mMaxCoefficients;
272 mUserFunctionName = rhs.mUserFunctionName;
273 mUserMacro = nullptr;
274 for (int i = 3; i--;) {
275 mMinBoundaries[i] = rhs.mMinBoundaries[i];
276 mMaxBoundaries[i] = rhs.mMaxBoundaries[i];
277 mBoundaryMappingScale[i] = rhs.mBoundaryMappingScale[i];
278 mBoundaryMappingOffset[i] = rhs.mBoundaryMappingOffset[i];
279 mNumberOfPoints[i] = rhs.mNumberOfPoints[i];
280 }
281 for (int i = 0; i < mOutputArrayDimension; i++) {
282 Chebyshev3DCalc* cbc = rhs.getChebyshevCalc(i);
283 if (cbc) {
284 mChebyshevParameter.AddAtAndExpand(new Chebyshev3DCalc(*cbc), i);
285 }
286 }
287 }
288 return *this;
289}
290
291void Chebyshev3D::Clear(const Option_t*)
292{
293 // clear all dynamic structures
294 if (mTemporaryUserResults) {
295 delete[] mTemporaryUserResults;
296 mTemporaryUserResults = nullptr;
297 }
298 if (mTemporaryChebyshevGrid) {
299 delete[] mTemporaryChebyshevGrid;
300 mTemporaryChebyshevGrid = nullptr;
301 }
302 if (mUserMacro) {
303 delete mUserMacro;
304 mUserMacro = nullptr;
305 }
306 mChebyshevParameter.SetOwner(kTRUE);
307 mChebyshevParameter.Delete();
308}
309
310void Chebyshev3D::Print(const Option_t* opt) const
311{
312 // print info
313 printf("%s: Chebyshev parameterization for 3D->%dD function. Precision: %e\n", GetName(), mOutputArrayDimension,
314 mPrecision);
315 printf("Region of validity: [%+.5e:%+.5e] [%+.5e:%+.5e] [%+.5e:%+.5e]\n", mMinBoundaries[0], mMaxBoundaries[0],
316 mMinBoundaries[1], mMaxBoundaries[1], mMinBoundaries[2], mMaxBoundaries[2]);
317 TString opts = opt;
318 opts.ToLower();
319 if (opts.Contains("l")) {
320 for (int i = 0; i < mOutputArrayDimension; i++) {
321 printf("Output dimension %d:\n", i + 1);
323 }
324 }
325}
326
327void Chebyshev3D::prepareBoundaries(const Float_t* bmin, const Float_t* bmax)
328{
329 // Set and check boundaries defined by user, prepare coefficients for their conversion to [-1:1] interval
330 for (int i = 3; i--;) {
331 mMinBoundaries[i] = bmin[i];
332 mMaxBoundaries[i] = bmax[i];
333 mBoundaryMappingScale[i] = bmax[i] - bmin[i];
334 if (mBoundaryMappingScale[i] <= 0) {
335 LOG(fatal) << "Boundaries for " << i << "-th dimension are not increasing: "
336 << mMinBoundaries[i] << " " << mMaxBoundaries[i] << "\nStop\n";
337 }
338 mBoundaryMappingOffset[i] = bmin[i] + mBoundaryMappingScale[i] / 2.0;
339 mBoundaryMappingScale[i] = 2. / mBoundaryMappingScale[i];
340 }
341}
342
343#ifdef _INC_CREATION_Chebyshev3D_
344
345// Pointer on user function (faster altrnative to TMethodCall)
346void (*gUsrFunChebyshev3D)(float*, float*);
347
348void Chebyshev3D::evaluateUserFunction()
349{
350 // call user supplied function
351 if (gUsrFunChebyshev3D) {
352 gUsrFunChebyshev3D(mTemporaryCoefficient, mTemporaryUserResults);
353 } else {
354 mUserMacro->Execute();
355 }
356}
357
358void Chebyshev3D::setuserFunction(const char* name)
359{
360 // load user macro with function definition and compile it
361 gUsrFunChebyshev3D = nullptr;
362 mUserFunctionName = name;
363 gSystem->ExpandPathName(mUserFunctionName);
364
365 if (mUserMacro) {
366 delete mUserMacro;
367 }
368
369 TString tmpst = mUserFunctionName;
370 tmpst += "+"; // prepare filename to compile
371
372 if (gROOT->LoadMacro(tmpst.Data())) {
373 LOG(error) << "SetUsrFunction: Failed to load user function from " << name << " \nStop\n";
374 exit(1);
375 }
376
377 mUserMacro = new TMethodCall();
378 tmpst = tmpst.Data() + tmpst.Last('/') + 1; // Strip away any path preceding the macro file name
379 int dot = tmpst.Last('.');
380
381 if (dot > 0) {
382 tmpst.Resize(dot);
383 }
384 mUserMacro->InitWithPrototype(tmpst.Data(), "Float_t *,Float_t *");
385 long args[2];
386 args[0] = (long)mTemporaryCoefficient;
387 args[1] = (long)mTemporaryUserResults;
388 mUserMacro->SetParamPtrs(args);
389}
390#endif
391
392#ifdef _INC_CREATION_Chebyshev3D_
393void Chebyshev3D::setuserFunction(void (*ptr)(float*, float*))
394{
395 // assign user training function
396 if (mUserMacro) {
397 delete mUserMacro;
398 }
399 mUserMacro = nullptr;
400 mUserFunctionName = "";
401 gUsrFunChebyshev3D = ptr;
402}
403#endif
404
405#ifdef _INC_CREATION_Chebyshev3D_
406void Chebyshev3D::evaluateUserFunction(const Float_t* x, Float_t* res)
407{
408 // evaluate user function value
409 for (int i = 3; i--;) {
410 mTemporaryCoefficient[i] = x[i];
411 }
412
413 if (gUsrFunChebyshev3D) {
414 gUsrFunChebyshev3D(mTemporaryCoefficient, mTemporaryUserResults);
415 } else {
416 mUserMacro->Execute();
417 }
418
419 for (int i = mOutputArrayDimension; i--;) {
420 res[i] = mTemporaryUserResults[i];
421 }
422}
423#endif
424
425#ifdef _INC_CREATION_Chebyshev3D_
426Int_t Chebyshev3D::calculateChebyshevCoefficients(const Float_t* funval, int np, Float_t* outCoefs, Float_t prec)
427{
428 // Calculate Chebyshev coeffs using precomputed function values at np roots.
429 // If prec>0, estimate the highest coeff number providing the needed precision
430 double sm; // do summations in double to minimize the roundoff error
431 for (int ic = 0; ic < np; ic++) { // compute coeffs
432 sm = 0;
433 for (int ir = 0; ir < np; ir++) {
434 float rt = TMath::Cos(ic * (ir + 0.5) * TMath::Pi() / np);
435 sm += funval[ir] * rt;
436 }
437 outCoefs[ic] = Float_t(sm * ((ic == 0) ? 1. / np : 2. / np));
438 }
439
440 if (prec <= 0) {
441 return np;
442 }
443
444 sm = 0;
445 int cfMax = 0;
446 for (cfMax = np; cfMax--;) {
447 sm += TMath::Abs(outCoefs[cfMax]);
448 if (sm >= prec) {
449 break;
450 }
451 }
452 if (++cfMax == 0) {
453 cfMax = 1;
454 }
455 return cfMax;
456}
457#endif
458
459#ifdef _INC_CREATION_Chebyshev3D_
460void Chebyshev3D::defineGrid(const Int_t* npoints)
461{
462 // prepare the grid of Chebyshev roots in each dimension
463 const int kMinPoints = 1;
464 int ntot = 0;
465 mMaxCoefficients = 1;
466 for (int id = 3; id--;) {
467 mNumberOfPoints[id] = npoints[id];
468 if (mNumberOfPoints[id] < kMinPoints) {
469 LOG(error) << "DefineGrid: at " << id << "-th dimension " << mNumberOfPoints[id] << " point is requested, at least " << kMinPoints << " is needed\nStop\n";
470 exit(1);
471 }
472 ntot += mNumberOfPoints[id];
473 mMaxCoefficients *= mNumberOfPoints[id];
474 }
475 printf("Computing Chebyshev nodes on [%2d/%2d/%2d] grid\n", npoints[0], npoints[1], npoints[2]);
476 if (mTemporaryChebyshevGrid) {
477 delete[] mTemporaryChebyshevGrid;
478 }
479 mTemporaryChebyshevGrid = new Float_t[ntot];
480
481 int curp = 0;
482 for (int id = 3; id--;) {
483 int np = mNumberOfPoints[id];
484 mTemporaryChebyshevGridOffs[id] = curp;
485 for (int ip = 0; ip < np; ip++) {
486 Float_t x = TMath::Cos(TMath::Pi() * (ip + 0.5) / np);
487 mTemporaryChebyshevGrid[curp++] = mapToExternal(x, id);
488 }
489 }
490}
491#endif
492
493#ifdef _INC_CREATION_Chebyshev3D_
494Int_t Chebyshev3D::chebyshevFit()
495{
496 // prepare parameterization for all output dimensions
497 int ir = 0;
498 for (int i = mOutputArrayDimension; i--;) {
499 ir += chebyshevFit(i);
500 }
501 return ir;
502}
503#endif
504
505#ifdef _INC_CREATION_Chebyshev3D_
506Int_t Chebyshev3D::chebyshevFit(int dmOut)
507{
508 // prepare paramaterization of 3D function for dmOut-th dimension
509 int maxDim = 0;
510 for (int i = 0; i < 3; i++) {
511 if (maxDim < mNumberOfPoints[i]) {
512 maxDim = mNumberOfPoints[i];
513 }
514 }
515 auto* fvals = new Float_t[mNumberOfPoints[0]];
516 auto* tmpCoef3D = new Float_t[mNumberOfPoints[0] * mNumberOfPoints[1] * mNumberOfPoints[2]];
517 auto* tmpCoef2D = new Float_t[mNumberOfPoints[0] * mNumberOfPoints[1]];
518 auto* tmpCoef1D = new Float_t[maxDim];
519
520 // 1D Cheb.fit for 0-th dimension at current steps of remaining dimensions
521 int ncmax = 0;
522
523 printf("Dim%d : 00.00%% Done", dmOut);
524 fflush(stdout);
525 Chebyshev3DCalc* cheb = getChebyshevCalc(dmOut);
526
527 Float_t prec = cheb->getPrecision();
528 if (prec < sMinimumPrecision) {
529 prec = mPrecision; // no specific precision for this dim.
530 }
531 Float_t rTiny = 0.1 * prec / Float_t(maxDim); // neglect coefficient below this threshold
532
533 float ncals2count = mNumberOfPoints[2] * mNumberOfPoints[1] * mNumberOfPoints[0];
534 float ncals = 0;
535 float frac = 0;
536 float fracStep = 0.001;
537
538 for (int id2 = mNumberOfPoints[2]; id2--;) {
539 mTemporaryCoefficient[2] = mTemporaryChebyshevGrid[mTemporaryChebyshevGridOffs[2] + id2];
540
541 for (int id1 = mNumberOfPoints[1]; id1--;) {
542 mTemporaryCoefficient[1] = mTemporaryChebyshevGrid[mTemporaryChebyshevGridOffs[1] + id1];
543
544 for (int id0 = mNumberOfPoints[0]; id0--;) {
545 mTemporaryCoefficient[0] = mTemporaryChebyshevGrid[mTemporaryChebyshevGridOffs[0] + id0];
546 evaluateUserFunction(); // compute function values at Chebyshev roots of 0-th dimension
547 fvals[id0] = mTemporaryUserResults[dmOut];
548 float fr = (++ncals) / ncals2count;
549 if (fr - frac >= fracStep) {
550 frac = fr;
551 printf("\b\b\b\b\b\b\b\b\b\b\b");
552 printf("%05.2f%% Done", fr * 100);
553 fflush(stdout);
554 }
555 }
556 int nc = calculateChebyshevCoefficients(fvals, mNumberOfPoints[0], tmpCoef1D, prec);
557 for (int id0 = mNumberOfPoints[0]; id0--;) {
558 tmpCoef2D[id1 + id0 * mNumberOfPoints[1]] = tmpCoef1D[id0];
559 }
560 if (ncmax < nc) {
561 ncmax = nc; // max coefs to be kept in dim0 to guarantee needed precision
562 }
563 }
564 // once each 1d slice of given 2d slice is parametrized, parametrize the Cheb.coeffs
565 for (int id0 = mNumberOfPoints[0]; id0--;) {
566 calculateChebyshevCoefficients(tmpCoef2D + id0 * mNumberOfPoints[1], mNumberOfPoints[1], tmpCoef1D, -1);
567 for (int id1 = mNumberOfPoints[1]; id1--;) {
568 tmpCoef3D[id2 + mNumberOfPoints[2] * (id1 + id0 * mNumberOfPoints[1])] = tmpCoef1D[id1];
569 }
570 }
571 }
572 // now fit the last dimensions Cheb.coefs
573 for (int id0 = mNumberOfPoints[0]; id0--;) {
574 for (int id1 = mNumberOfPoints[1]; id1--;) {
575 calculateChebyshevCoefficients(tmpCoef3D + mNumberOfPoints[2] * (id1 + id0 * mNumberOfPoints[1]),
576 mNumberOfPoints[2], tmpCoef1D, -1);
577 for (int id2 = mNumberOfPoints[2]; id2--;) {
578 tmpCoef3D[id2 + mNumberOfPoints[2] * (id1 + id0 * mNumberOfPoints[1])] = tmpCoef1D[id2]; // store on place
579 }
580 }
581 }
582
583 // now find 2D surface which separates significant coefficients of 3D matrix from nonsignificant ones (up to
584 // prec)
585 auto* tmpCoefSurf = new UShort_t[mNumberOfPoints[0] * mNumberOfPoints[1]];
586 for (int id0 = mNumberOfPoints[0]; id0--;) {
587 for (int id1 = mNumberOfPoints[1]; id1--;) {
588 tmpCoefSurf[id1 + id0 * mNumberOfPoints[1]] = 0;
589 }
590 }
591 Double_t resid = 0;
592 for (int id0 = mNumberOfPoints[0]; id0--;) {
593 for (int id1 = mNumberOfPoints[1]; id1--;) {
594 for (int id2 = mNumberOfPoints[2]; id2--;) {
595 int id = id2 + mNumberOfPoints[2] * (id1 + id0 * mNumberOfPoints[1]);
596 Float_t cfa = TMath::Abs(tmpCoef3D[id]);
597 if (cfa < rTiny) {
598 tmpCoef3D[id] = 0;
599 continue;
600 } // neglect coefs below the threshold
601 resid += cfa;
602 if (resid < prec) {
603 continue; // this coeff is negligible
604 }
605 // otherwise go back 1 step
606 resid -= cfa;
607 tmpCoefSurf[id1 + id0 * mNumberOfPoints[1]] = id2 + 1; // how many coefs to keep
608 break;
609 }
610 }
611 }
612
613 // printf("\n\nCoeffs\n");
614 // int cnt = 0;
615 // for (int id0=0;id0<mNumberOfPoints[0];id0++) {
616 // for (int id1=0;id1<mNumberOfPoints[1];id1++) {
617 // for (int id2=0;id2<mNumberOfPoints[2];id2++) {
618 // printf("%2d%2d%2d %+.4e |",id0,id1,id2,tmpCoef3D[cnt++]);
619 // }
620 // printf("\n");
621 // }
622 // printf("\n");
623 //}
624
625 // see if there are rows to reject, find max.significant column at each row
626 int nRows = mNumberOfPoints[0];
627 auto* tmpCols = new UShort_t[nRows];
628 for (int id0 = mNumberOfPoints[0]; id0--;) {
629 int id1 = mNumberOfPoints[1];
630 while (id1 > 0 && tmpCoefSurf[(id1 - 1) + id0 * mNumberOfPoints[1]] == 0) {
631 id1--;
632 }
633 tmpCols[id0] = id1;
634 }
635 // find max significant row
636 for (int id0 = nRows; id0--;) {
637 if (tmpCols[id0] > 0) {
638 break;
639 }
640 nRows--;
641 }
642 // find max significant column and fill the permanent storage for the max sigificant column of each row
643 cheb->initializeRows(nRows); // create needed arrays;
644 UShort_t* nColsAtRow = cheb->getNumberOfColumnsAtRow();
645 UShort_t* colAtRowBg = cheb->getColAtRowBg();
646 int nCols = 0;
647 int nElemBound2D = 0;
648 for (int id0 = 0; id0 < nRows; id0++) {
649 nColsAtRow[id0] = tmpCols[id0]; // number of columns to store for this row
650 colAtRowBg[id0] = nElemBound2D; // begining of this row in 2D boundary surface
651 nElemBound2D += tmpCols[id0];
652 if (nCols < nColsAtRow[id0]) {
653 nCols = nColsAtRow[id0];
654 }
655 }
656 cheb->initializeColumns(nCols);
657 delete[] tmpCols;
658
659 // create the 2D matrix defining the boundary of significance for 3D coeffs.matrix
660 // and count the number of siginifacnt coefficients
661 cheb->initializeElementBound2D(nElemBound2D);
662 UShort_t* coefBound2D0 = cheb->getCoefficientBound2D0();
663 UShort_t* coefBound2D1 = cheb->getCoefficientBound2D1();
664 mMaxCoefficients = 0; // redefine number of coeffs
665 for (int id0 = 0; id0 < nRows; id0++) {
666 int nCLoc = nColsAtRow[id0];
667 int col0 = colAtRowBg[id0];
668 for (int id1 = 0; id1 < nCLoc; id1++) {
669 coefBound2D0[col0 + id1] =
670 tmpCoefSurf[id1 + id0 * mNumberOfPoints[1]]; // number of coefs to store for 3-d dimension
671 coefBound2D1[col0 + id1] = mMaxCoefficients;
672 mMaxCoefficients += coefBound2D0[col0 + id1];
673 }
674 }
675
676 // create final compressed 3D matrix for significant coeffs
677 cheb->initializeCoefficients(mMaxCoefficients);
678 Float_t* coefs = cheb->getCoefficients();
679 int count = 0;
680 for (int id0 = 0; id0 < nRows; id0++) {
681 int ncLoc = nColsAtRow[id0];
682 int col0 = colAtRowBg[id0];
683 for (int id1 = 0; id1 < ncLoc; id1++) {
684 int ncf2 = coefBound2D0[col0 + id1];
685 for (int id2 = 0; id2 < ncf2; id2++) {
686 coefs[count++] = tmpCoef3D[id2 + mNumberOfPoints[2] * (id1 + id0 * mNumberOfPoints[1])];
687 }
688 }
689 }
690
691 // printf("\n\nNewSurf\n");
692 // for (int id0=0;id0<mNumberOfPoints[0];id0++) {
693 // for (int id1=0;id1<mNumberOfPoints[1];id1++) {
694 // printf("(%2d %2d) %2d |",id0,id1,tmpCoefSurf[id1+id0*mNumberOfPoints[1]]);
695 // }
696 // printf("\n");
697 //}
698
699 delete[] tmpCoefSurf;
700 delete[] tmpCoef1D;
701 delete[] tmpCoef2D;
702 delete[] tmpCoef3D;
703 delete[] fvals;
704
705 printf("\b\b\b\b\b\b\b\b\b\b\b\b");
706 printf("100.00%% Done\n");
707 return 1;
708}
709#endif
710
711#ifdef _INC_CREATION_Chebyshev3D_
712void Chebyshev3D::saveData(const char* outfile, Bool_t append) const
713{
714 // writes coefficients data to output text file, optionallt appending on the end of existing file
715 TString strf = outfile;
716 gSystem->ExpandPathName(strf);
717 FILE* stream = fopen(strf, append ? "a" : "w");
718 saveData(stream);
719 fclose(stream);
720}
721#endif
722
723#ifdef _INC_CREATION_Chebyshev3D_
724void Chebyshev3D::saveData(FILE* stream) const
725{
726 // writes coefficients data to existing output stream
727 fprintf(stream, "\n# These are automatically generated data for the Chebyshev interpolation of 3D->%dD function\n",
728 mOutputArrayDimension);
729 fprintf(stream, "#\nSTART %s\n", GetName());
730 fprintf(stream, "# Dimensionality of the output\n%d\n", mOutputArrayDimension);
731 fprintf(stream, "# Interpolation abs. precision\n%+.8e\n", mPrecision);
732
733 fprintf(stream, "# Lower boundaries of interpolation region\n");
734 for (int i = 0; i < 3; i++) {
735 fprintf(stream, "%+.8e\n", mMinBoundaries[i]);
736 }
737 fprintf(stream, "# Upper boundaries of interpolation region\n");
738 for (int i = 0; i < 3; i++) {
739 fprintf(stream, "%+.8e\n", mMaxBoundaries[i]);
740 }
741 fprintf(stream, "# Parameterization for each output dimension follows:\n");
742
743 for (int i = 0; i < mOutputArrayDimension; i++) {
745 }
746 fprintf(stream, "#\nEND %s\n#\n", GetName());
747}
748#endif
749
750#ifdef _INC_CREATION_Chebyshev3D_
751void Chebyshev3D::invertSign()
752{
753 // invert the sign of all parameterizations
754 for (int i = mOutputArrayDimension; i--;) {
756 int ncf = par->getNumberOfCoefficients();
757 float* coefs = par->getCoefficients();
758 for (int j = ncf; j--;) {
759 coefs[j] = -coefs[j];
760 }
761 }
762}
763#endif
764
765void Chebyshev3D::loadData(const char* inpFile)
766{
767 // load coefficients data from txt file
768 TString strf = inpFile;
769 gSystem->ExpandPathName(strf);
770 FILE* stream = fopen(strf.Data(), "r");
772 fclose(stream);
773}
774
776{
777 // load coefficients data from stream
778 if (!stream) {
779 LOG(fatal) << "No stream provided.\nStop";
780 }
781 TString buffs;
782 Clear();
784 if (!buffs.BeginsWith("START")) {
785 LOG(fatal) << R"(Expected: "START <fit_name>", found ")" << buffs.Data() << "\"\nStop\n";
786 }
787 SetName(buffs.Data() + buffs.First(' ') + 1);
788
789 Chebyshev3DCalc::readLine(buffs, stream); // N output dimensions
790 mOutputArrayDimension = buffs.Atoi();
791 if (mOutputArrayDimension < 1) {
792 LOG(fatal) << R"(Expected: '<number_of_output_dimensions>', found ")" << buffs.Data() << "\"\nStop\n";
793 }
794
795 setDimOut(mOutputArrayDimension);
796
797 Chebyshev3DCalc::readLine(buffs, stream); // Interpolation abs. precision
798 mPrecision = buffs.Atof();
799 if (mPrecision <= 0) {
800 LOG(fatal) << R"(Expected: '<abs.precision>', found ")" << buffs.Data() << "\"\nStop\n";
801 }
802
803 for (int i = 0; i < 3; i++) { // Lower boundaries of interpolation region
805 mMinBoundaries[i] = buffs.Atof();
806 }
807
808 for (int i = 0; i < 3; i++) { // Upper boundaries of interpolation region
810 mMaxBoundaries[i] = buffs.Atof();
811 }
812 prepareBoundaries(mMinBoundaries, mMaxBoundaries);
813
814 // data for each output dimension
815 for (int i = 0; i < mOutputArrayDimension; i++) {
817 }
818
819 // check end_of_data record
821 if (!buffs.BeginsWith("END") || !buffs.Contains(GetName())) {
822 LOG(fatal) << R"(Expected "END )" << GetName() << R"(", found ")" << buffs.Data() << "\".\nStop\n";
823 }
824}
825
826void Chebyshev3D::setDimOut(const int d, const float* prec)
827{
828 // init output dimensions
829 mOutputArrayDimension = d;
830 if (mTemporaryUserResults) {
831 delete mTemporaryUserResults;
832 }
833 mTemporaryUserResults = new Float_t[mOutputArrayDimension];
834 mChebyshevParameter.Delete();
835 for (int i = 0; i < d; i++) {
836 auto* clc = new Chebyshev3DCalc();
837 clc->setPrecision(prec && prec[i] > sMinimumPrecision ? prec[i] : mPrecision);
838 mChebyshevParameter.AddAtAndExpand(new Chebyshev3DCalc(), i);
839 }
840}
841
842void Chebyshev3D::shiftBound(int id, float dif)
843{
844 // modify the bounds of the grid
845 if (id < 0 || id > 2) {
846 printf("Maximum 3 dimensions are supported\n");
847 return;
848 }
849 mMinBoundaries[id] += dif;
850 mMaxBoundaries[id] += dif;
851 mBoundaryMappingOffset[id] += dif;
852}
853
854#ifdef _INC_CREATION_Chebyshev3D_
855TH1* Chebyshev3D::TestRMS(int idim, int npoints, TH1* histo)
856{
857 // fills the difference between the original function and parameterization (for idim-th component of the output)
858 // to supplied histogram. Calculations are done in npoints random points.
859 // If the hostgram was not supplied, it will be created. It is up to the user to delete it!
860 if (!mUserMacro) {
861 printf("No user function is set\n");
862 return nullptr;
863 }
864 if (!histo) {
865 histo = new TH1D(GetName(), "Control: Function - Parametrization", 100, -2 * mPrecision, 2 * mPrecision);
866 }
867
868 float prc = getChebyshevCalc(idim)->getPrecision();
869 if (prc < sMinimumPrecision) {
870 prc = mPrecision; // no dimension specific precision
871 }
872
873 for (int ip = npoints; ip--;) {
874 gRandom->RndmArray(3, (Float_t*)mTemporaryCoefficient);
875 for (int i = 3; i--;) {
876 mTemporaryCoefficient[i] = mMinBoundaries[i] + mTemporaryCoefficient[i] * (mMaxBoundaries[i] - mMinBoundaries[i]);
877 }
878 evaluateUserFunction();
879 Float_t valFun = mTemporaryUserResults[idim];
880 Eval(mTemporaryCoefficient, mTemporaryUserResults);
881 Float_t valPar = mTemporaryUserResults[idim];
882 histo->Fill(valFun - valPar);
883 }
884 return histo;
885}
886#endif
887
888#ifdef _INC_CREATION_Chebyshev3D_
889
890void Chebyshev3D::estimateNumberOfPoints(float prec, int gridBC[3][3], Int_t npd1, Int_t npd2, Int_t npd3)
891{
892 // Estimate number of points to generate a training data
893 const int kScp = 9;
894 const float kScl[9] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
895
896 const float sclDim[2] = {0.001, 0.999};
897 const int compDim[3][2] = {{1, 2}, {2, 0}, {0, 1}};
898 static float xyz[3];
899 Int_t npdTst[3] = {npd1, npd2, npd3};
900
901 for (int i = 3; i--;) {
902 for (int j = 3; j--;) {
903 gridBC[i][j] = -1;
904 }
905 }
906
907 for (int idim = 0; idim < 3; idim++) {
908 float dimMN = mMinBoundaries[idim] + sclDim[0] * (mMaxBoundaries[idim] - mMinBoundaries[idim]);
909 float dimMX = mMinBoundaries[idim] + sclDim[1] * (mMaxBoundaries[idim] - mMinBoundaries[idim]);
910
911 int id1 = compDim[idim][0]; // 1st fixed dim
912 int id2 = compDim[idim][1]; // 2nd fixed dim
913 for (int i1 = 0; i1 < kScp; i1++) {
914 xyz[id1] = mMinBoundaries[id1] + kScl[i1] * (mMaxBoundaries[id1] - mMinBoundaries[id1]);
915 for (int i2 = 0; i2 < kScp; i2++) {
916 xyz[id2] = mMinBoundaries[id2] + kScl[i2] * (mMaxBoundaries[id2] - mMinBoundaries[id2]);
917 int* npt = getNcNeeded(xyz, idim, dimMN, dimMX, prec, npdTst[idim]); // npoints for Bx,By,Bz
918 for (int ib = 0; ib < 3; ib++) {
919 if (npt[ib] > gridBC[ib][idim]) {
920 gridBC[ib][idim] = npt[ib];
921 }
922 }
923 }
924 }
925 }
926}
927
928// void Chebyshev3D::estimateNumberOfPoints(float Prec, int gridBC[3][3])
929// {
930// // Estimate number of points to generate a training data
931//
932// const float sclA[9] = {0.1, 0.5, 0.9, 0.1, 0.5, 0.9, 0.1, 0.5, 0.9} ;
933// const float sclB[9] = {0.1, 0.1, 0.1, 0.5, 0.5, 0.5, 0.9, 0.9, 0.9} ;
934// const float sclDim[2] = {0.01,0.99};
935// const int compDim[3][2] = { {1,2}, {2,0}, {0,1} };
936// static float xyz[3];
937//
938// for (int i=3;i--;)for (int j=3;j--;) gridBC[i][j] = -1;
939//
940// for (int idim=0;idim<3;idim++) {
941// float dimMN = mMinBoundaries[idim] + sclDim[0]*(mMaxBoundaries[idim]-mMinBoundaries[idim]);
942// float dimMX = mMinBoundaries[idim] + sclDim[1]*(mMaxBoundaries[idim]-mMinBoundaries[idim]);
943//
944// for (int it=0;it<9;it++) { // test in 9 points
945// int id1 = compDim[idim][0]; // 1st fixed dim
946// int id2 = compDim[idim][1]; // 2nd fixed dim
947// xyz[ id1 ] = mMinBoundaries[id1] + sclA[it]*( mMaxBoundaries[id1]-mMinBoundaries[id1] );
948// xyz[ id2 ] = mMinBoundaries[id2] + sclB[it]*( mMaxBoundaries[id2]-mMinBoundaries[id2] );
949//
950// int* npt = getNcNeeded(xyz,idim, dimMN,dimMX, Prec); // npoints for Bx,By,Bz
951// for (int ib=0;ib<3;ib++) if (npt[ib]>gridBC[ib][idim]) gridBC[ib][idim] = npt[ib];//+2;
952//
953// }
954// }
955// }
956//
957//
958// int* Chebyshev3D::getNcNeeded(float xyz[3],int DimVar, float mn,float mx, float prec)
959// {
960// // estimate needed number of chebyshev coefs for given function description in DimVar dimension
961// // The values for two other dimensions must be set beforehand
962//
963// static int curNC[3];
964// static int retNC[3];
965// const int kMaxPoint = 400;
966// float* gridVal = new float[3*kMaxPoint];
967// float* coefs = new float[3*kMaxPoint];
968//
969// float scale = mx-mn;
970// float offs = mn + scale/2.0;
971// scale = 2./scale;
972//
973// int curNP;
974// int maxNC=-1;
975// int maxNCPrev=-1;
976// for (int i=0;i<3;i++) retNC[i] = -1;
977// for (int i=0;i<3;i++) mTemporaryCoefficient[i] = xyz[i];
978//
979// for (curNP=3; curNP<kMaxPoint; curNP+=3) {
980// maxNCPrev = maxNC;
981//
982// for (int i=0;i<curNP;i++) { // get function values on Cheb. nodes
983// float x = TMath::Cos( TMath::Pi()*(i+0.5)/curNP );
984// mTemporaryCoefficient[DimVar] = x/scale+offs; // map to requested interval
985// evaluateUserFunction();
986// for (int ib=3;ib--;) gridVal[ib*kMaxPoint + i] = mTemporaryUserResults[ib];
987// }
988//
989// for (int ib=0;ib<3;ib++) {
990// curNC[ib] = Chebyshev3D::calculateChebyshevCoefficients(&gridVal[ib*kMaxPoint], curNP,
991// &coefs[ib*kMaxPoint],prec);
992// if (maxNC < curNC[ib]) maxNC = curNC[ib];
993// if (retNC[ib] < curNC[ib]) retNC[ib] = curNC[ib];
994// }
995// if ( (curNP-maxNC)>3 && (maxNC-maxNCPrev)<1 ) break;
996// maxNCPrev = maxNC;
997//
998// }
999// delete[] gridVal;
1000// delete[] coefs;
1001// return retNC;
1002// }
1003
1004int* Chebyshev3D::getNcNeeded(float xyz[3], int DimVar, float mn, float mx, float prec, Int_t npCheck)
1005{
1006 // estimate needed number of chebyshev coefs for given function description in DimVar dimension
1007 // The values for two other dimensions must be set beforehand
1008 static int retNC[3];
1009 static int npChLast = 0;
1010 static float *gridVal = nullptr, *coefs = nullptr;
1011 if (npCheck < 3) {
1012 npCheck = 3;
1013 }
1014 if (npChLast < npCheck) {
1015 if (gridVal) {
1016 delete[] gridVal;
1017 }
1018 if (coefs) {
1019 delete[] coefs;
1020 }
1021 gridVal = new float[3 * npCheck];
1022 coefs = new float[3 * npCheck];
1023 npChLast = npCheck;
1024 }
1025 float scale = mx - mn;
1026 float offs = mn + scale / 2.0;
1027 scale = 2. / scale;
1028
1029 for (int i = 0; i < 3; i++) {
1030 mTemporaryCoefficient[i] = xyz[i];
1031 }
1032 for (int i = 0; i < npCheck; i++) {
1033 mTemporaryCoefficient[DimVar] =
1034 TMath::Cos(TMath::Pi() * (i + 0.5) / npCheck) / scale + offs; // map to requested interval
1035 evaluateUserFunction();
1036 for (int ib = 3; ib--;) {
1037 gridVal[ib * npCheck + i] = mTemporaryUserResults[ib];
1038 }
1039 }
1040 for (int ib = 0; ib < 3; ib++) {
1041 retNC[ib] =
1042 Chebyshev3D::calculateChebyshevCoefficients(&gridVal[ib * npCheck], npCheck, &coefs[ib * npCheck], prec);
1043 }
1044 return retNC;
1045}
1046
1047#endif
ClassImp(Chebyshev3D)
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
TBranch * ptr
void Print(const Option_t *opt="") const override
Prints info.
UShort_t * getNumberOfColumnsAtRow() const
void saveData(const char *outfile, Bool_t append=kFALSE) const
Writes coefficients data to output text file, optionally appending on the end of existing file.
void loadData(FILE *stream)
Loads coefficients from the stream.
UShort_t * getCoefficientBound2D0() const
void initializeElementBound2D(int ne)
Sets maximum number of significant coefficients for given row/column of coefficients 3D matrix.
static void readLine(TString &str, FILE *stream)
Reads single line from the stream, skipping empty and commented lines. EOF is not expected.
void initializeRows(int nr)
Sets maximum number of significant rows in the coefficients matrix.
UShort_t * getCoefficientBound2D1() const
void initializeCoefficients(int nc)
Sets total number of significant coefficients.
void initializeColumns(int nc)
Sets maximum number of significant columns in the coefficients matrix.
void prepareBoundaries(const Float_t *bmin, const Float_t *bmax)
void loadData(const char *inpFile)
void Clear(const Option_t *option="") override
Float_t mapToExternal(Float_t x, Int_t d) const
void shiftBound(int id, float dif)
Chebyshev3DCalc * getChebyshevCalc(int i) const
void setDimOut(const int d, const float *prec=nullptr)
void Print(const Option_t *opt="") const override
void Eval(const Float_t *par, Float_t *res)
Evaluates Chebyshev parameterization for 3d->DimOut function.
Chebyshev3D & operator=(const Chebyshev3D &rhs)
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
GLint GLsizei count
Definition glcorearb.h:399
GLuint const GLchar * name
Definition glcorearb.h:781
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLuint stream
Definition glcorearb.h:1806
GLuint id
Definition glcorearb.h:650
auto dot(const Vertex< T > &a, const Vertex< T > &b) -> decltype(a.x *b.x)
Definition Vertex.h:104
@ Max
Definition Defs.h:71
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)