]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/AliCheb3D.cxx
Parameterisation of the measured mag. field map. (R. Shahoyan)
[u/mrichter/AliRoot.git] / STEER / AliCheb3D.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 // Author: ruben.shahoyan@cern.ch   09/09/2006
19 //
20 ////////////////////////////////////////////////////////////////////////////////
21 //                                                                            //
22 // AliCheb3D produces the interpolation of the user 3D->NDimOut arbitrary     //
23 // function supplied in "void (*fcn)(float* inp,float* out)" format           //
24 // either in a separate macro file or as a function pointer.                  //
25 // Only coefficients needed to guarantee the requested precision are kept.    //
26 //                                                                            //
27 // The user-callable methods are:                                             //
28 // To create the interpolation use:                                           //
29 // AliCheb3D(const char* funName,  // name of the file with user function     //
30 //          or                                                                //
31 // AliCheb3D(void (*ptr)(float*,float*),// pointer on the  user function      //
32 //        Int_t     DimOut,     // dimensionality of the function's output    // 
33 //        Float_t  *bmin,       // lower 3D bounds of interpolation domain    // 
34 //        Float_t  *bmax,       // upper 3D bounds of interpolation domain    // 
35 //        Int_t    *npoints,    // number of points in each of 3 input        //
36 //                              // dimension, defining the interpolation grid //
37 //        Float_t   prec=1E-6); // requested max.absolute difference between  //
38 //                              // the interpolation and any point on grid    //
39 //                                                                            //
40 // To test obtained parameterization use the method                           //
41 // TH1* TestRMS(int idim,int npoints = 1000,TH1* histo=0);                    // 
42 // it will compare the user output of the user function and interpolation     //
43 // for idim-th output dimension and fill the difference in the supplied       //
44 // histogram. If no histogram is supplied, it will be created.                //
45 //                                                                            //
46 // To save the interpolation data:                                            //
47 // SaveData(const char* filename, Bool_t append )                             //
48 // write text file with data. If append is kTRUE and the output file already  //
49 // exists, data will be added in the end of the file.                         //
50 // Alternatively, SaveData(FILE* stream) will write the data to               //
51 // already existing stream.                                                   //
52 //                                                                            //
53 // To read back already stored interpolation use either the constructor       // 
54 // AliCheb3D(const char* inpFile);                                            //
55 // or the default constructor AliCheb3D() followed by                         //
56 // AliCheb3D::LoadData(const char* inpFile);                                  //
57 //                                                                            //
58 // To compute the interpolation use Eval(float* par,float *res) method, with  //
59 // par being 3D vector of arguments (inside the validity region) and res is   //
60 // the array of DimOut elements for the output.                               //
61 //                                                                            //
62 // If only one component (say, idim-th) of the output is needed, use faster   //
63 // Float_t Eval(Float_t *par,int idim) method.                                //
64 //                                                                            //
65 // void Print(option="") will print the name, the ranges of validity and      //
66 // the absolute precision of the parameterization. Option "l" will also print //
67 // the information about the number of coefficients for each output           //
68 // dimension.                                                                 //
69 //                                                                            //
70 // NOTE: during the evaluation no check is done for parameter vector being    //
71 // outside the interpolation region. If there is such a risk, use             //
72 // Bool_t IsInside(float *par) method. Chebyshev parameterization is not      //
73 // good for extrapolation!                                                    //
74 //                                                                            //
75 // For the properties of Chebyshev parameterization see:                      //
76 // H.Wind, CERN EP Internal Report, 81-12/Rev.                                //
77 //                                                                            //
78 ////////////////////////////////////////////////////////////////////////////////
79
80 #include <TString.h>
81 #include <TSystem.h>
82 #include <TRandom.h>
83 #include <TROOT.h>
84 #include "AliCheb3D.h"
85
86
87
88 ClassImp(AliCheb3DCalc)
89
90
91 AliCheb3DCalc::AliCheb3DCalc():
92     TNamed("", ""),
93     fNCoefs(0),  
94     fNRows(0),
95     fNCols(0),
96     fNElemBound2D(0),
97     fNColsAtRow(0),
98     fColAtRowBg(0),
99     fCoefBound2D0(0),
100     fCoefBound2D1(0),
101     fCoefs(0),
102     fTmpCf1(0),
103     fTmpCf0(0)
104 {
105     // Default constructor
106     Init0();
107 }
108
109 AliCheb3DCalc::AliCheb3DCalc(FILE* stream):
110     TNamed("", ""),
111     fNCoefs(0),  
112     fNRows(0),
113     fNCols(0),
114     fNElemBound2D(0),
115     fNColsAtRow(0),
116     fColAtRowBg(0),
117     fCoefBound2D0(0),
118     fCoefBound2D1(0),
119     fCoefs(0),
120     fTmpCf1(0),
121     fTmpCf0(0)
122 {
123     // Default constructor
124     Init0();
125     LoadData(stream);
126 }
127
128 //__________________________________________________________________________________________
129 void AliCheb3DCalc::Clear(Option_t*)
130 {
131   // delete all dynamycally allocated structures
132   if (fTmpCf1)       { delete[] fTmpCf1;  fTmpCf1 = 0;}
133   if (fTmpCf0)       { delete[] fTmpCf0;  fTmpCf0 = 0;}
134   if (fCoefs)        { delete[] fCoefs;   fCoefs  = 0;}
135   if (fCoefBound2D0) { delete[] fCoefBound2D0; fCoefBound2D0 = 0; }
136   if (fCoefBound2D1) { delete[] fCoefBound2D1; fCoefBound2D1 = 0; }
137   if (fNColsAtRow)   { delete[] fNColsAtRow;   fNColsAtRow = 0; }
138   if (fColAtRowBg)   { delete[] fColAtRowBg;   fColAtRowBg = 0; }
139   //
140 }
141
142 //__________________________________________________________________________________________
143 void AliCheb3DCalc::Init0()
144 {
145   // reset everything to 0
146   fNCoefs = fNRows = fNCols = fNElemBound2D = 0;
147   fCoefs = 0;
148   fCoefBound2D0 = fCoefBound2D1 = 0;
149   fNColsAtRow = fColAtRowBg = 0;
150   fTmpCf0 = fTmpCf1 = 0;
151 }
152
153 //__________________________________________________________________________________________
154 void AliCheb3DCalc::Print(Option_t* ) const
155 {
156   printf("Chebyshev parameterization data %s for 3D->1 function.\n",GetName());
157   int nmax3d = 0; 
158   for (int i=fNElemBound2D;i--;) if (fCoefBound2D0[i]>nmax3d) nmax3d = fCoefBound2D0[i];
159   printf("%d coefficients in %dx%dx%d matrix\n",fNCoefs,fNRows,fNCols,nmax3d);
160   //
161 }
162
163 //__________________________________________________________________________________________
164 Float_t  AliCheb3DCalc::Eval(Float_t  *par) const
165 {
166   // evaluate Chebyshev parameterization for 3D function.
167   // VERY IMPORTANT: par must contain the function arguments ALREADY MAPPED to [-1:1] interval
168   Float_t  &z = par[2];
169   Float_t  &y = par[1];
170   Float_t  &x = par[0];
171   //
172   int ncfRC;
173   for (int id0=fNRows;id0--;) {
174     int nCLoc = fNColsAtRow[id0];                   // number of significant coefs on this row
175     int Col0  = fColAtRowBg[id0];                   // beginning of local column in the 2D boundary matrix
176     for (int id1=nCLoc;id1--;) {
177       int id = id1+Col0;
178       fTmpCf1[id1] = (ncfRC=fCoefBound2D0[id]) ? ChebEval1D(z,fCoefs + fCoefBound2D1[id], ncfRC) : 0.0;
179     }
180     fTmpCf0[id0] = nCLoc>0 ? ChebEval1D(y,fTmpCf1,nCLoc):0.0;
181   }
182   return ChebEval1D(x,fTmpCf0,fNRows);
183   //
184 }
185
186 //_______________________________________________
187 #ifdef _INC_CREATION_ALICHEB3D_
188 void AliCheb3DCalc::SaveData(const char* outfile,Bool_t append) const
189 {
190   // writes coefficients data to output text file, optionallt appending on the end of existing file
191   TString strf = outfile;
192   gSystem->ExpandPathName(strf);
193   FILE* stream = fopen(strf,append ? "a":"w");
194   SaveData(stream);
195   fclose(stream);
196   //
197 }
198 #endif
199
200 //_______________________________________________
201 #ifdef _INC_CREATION_ALICHEB3D_
202 void AliCheb3DCalc::SaveData(FILE* stream) const
203 {
204   // writes coefficients data to existing output stream
205   // Note: fNCols, fNElemBound2D and fColAtRowBg is not stored, will be computed on fly during the loading of this file
206   fprintf(stream,"#\nSTART %s\n",GetName());
207   fprintf(stream,"# Number of rows\n%d\n",fNRows);
208   //
209   fprintf(stream,"# Number of columns per row\n");
210   for (int i=0;i<fNRows;i++) fprintf(stream,"%d\n",fNColsAtRow[i]);
211   //
212   fprintf(stream,"# Number of Coefs in each significant block of third dimension\n");
213   for (int i=0;i<fNElemBound2D;i++) fprintf(stream,"%d\n",fCoefBound2D0[i]);
214   //
215   fprintf(stream,"# Coefficients\n");
216   for (int i=0;i<fNCoefs;i++) fprintf(stream,"%+.8e\n",fCoefs[i]);
217   fprintf(stream,"END %s\n",GetName());
218   //
219 }
220 #endif
221
222 //_______________________________________________
223 void AliCheb3DCalc::LoadData(FILE* stream)
224 {
225   // Load coefs. from the stream 
226   if (!stream) {Error("LoadData","No stream provided.\nStop"); exit(1);}
227   TString buffs;
228   Clear();
229   ReadLine(buffs,stream);
230   if (!buffs.BeginsWith("START")) {Error("LoadData","Expected: \"START <fit_name>\", found \"%s\"\nStop\n",buffs.Data());exit(1);}
231   if (buffs.First(' ')>0) SetName(buffs.Data()+buffs.First(' ')+1);
232   //
233   ReadLine(buffs,stream); // NRows
234   fNRows = buffs.Atoi(); 
235   if (fNRows<1) {Error("LoadData","Expected: '<number_of_rows>', found \"%s\"\nStop\n",buffs.Data());exit(1);}
236   //
237   fNCols = 0;
238   fNElemBound2D = 0;
239   InitRows(fNRows);
240   //
241   for (int id0=0;id0<fNRows;id0++) {
242     ReadLine(buffs,stream);               // n.cols at this row
243     fNColsAtRow[id0] = buffs.Atoi();
244     fColAtRowBg[id0] = fNElemBound2D;     // begining of this row in 2D boundary surface
245     fNElemBound2D   += fNColsAtRow[id0];
246     if (fNCols<fNColsAtRow[id0]) fNCols = fNColsAtRow[id0];
247   }
248   InitCols(fNCols);
249   //  
250   fNCoefs = 0; 
251   InitElemBound2D(fNElemBound2D);
252   //
253   for (int i=0;i<fNElemBound2D;i++) {
254     ReadLine(buffs,stream);               // n.coeffs at 3-d dimension for the given column/row
255     fCoefBound2D0[i] = buffs.Atoi();
256     fCoefBound2D1[i] = fNCoefs;
257     fNCoefs += fCoefBound2D0[i];
258   }
259   //
260   if (fNCoefs<=0) {Error("LoadData","Negtive (%d) number of Chebychef coeffs. is obtained.\nStop\n",fNCoefs);exit(1);}
261   //
262   InitCoefs(fNCoefs);
263   for (int i=0;i<fNCoefs;i++) {
264     ReadLine(buffs,stream);
265     fCoefs[i] = buffs.Atof();
266   }
267   // check end_of_data record
268   ReadLine(buffs,stream);
269   if (!buffs.BeginsWith("END") || !buffs.Contains(GetName())) {
270     Error("LoadData","Expected \"END %s\", found \"%s\".\nStop\n",GetName(),buffs.Data());
271     exit(1);
272   }
273   //
274 }
275
276 //_______________________________________________
277 void AliCheb3DCalc::ReadLine(TString& str,FILE* stream) 
278 {
279   // read single line from the stream, skipping empty and commented lines. EOF is not expected
280   while (str.Gets(stream)) {
281     str = str.Strip(TString::kBoth,' ');
282     if (str.IsNull()||str.BeginsWith("#")) continue;
283     return;
284   }
285   fprintf(stderr,"AliCheb3D::ReadLine: Failed to read from stream.\nStop");exit(1); // normally, should not reach here
286 }
287
288 //_______________________________________________
289 void AliCheb3DCalc::InitCols(int nc)
290 {
291   // Set max.number of significant columns in the coefs matrix
292   fNCols = nc;
293   if (fTmpCf1) delete[] fTmpCf1;
294   fTmpCf1 = new Float_t [fNCols];
295 }
296
297 //_______________________________________________
298 void AliCheb3DCalc::InitRows(int nr)
299 {
300   // Set max.number of significant rows in the coefs matrix
301   if (fNColsAtRow) delete[] fNColsAtRow;
302   if (fColAtRowBg) delete[] fColAtRowBg;
303   if (fTmpCf0)     delete[] fTmpCf0;
304   fNRows = nr;
305   fNColsAtRow = new Int_t[fNRows];
306   fTmpCf0     = new Float_t [fNRows];
307   fColAtRowBg = new Int_t[fNRows];
308   for (int i=fNRows;i--;) fNColsAtRow[i] = fColAtRowBg[i] = 0;
309 }
310
311 //_______________________________________________
312 void AliCheb3DCalc::InitElemBound2D(int ne)
313 {
314   // Set max number of significant coefs for given row/column of coefs 3D matrix
315   if (fCoefBound2D0) delete[] fCoefBound2D0; 
316   if (fCoefBound2D1) delete[] fCoefBound2D1; 
317   fNElemBound2D = ne;
318   fCoefBound2D0 = new Int_t[fNElemBound2D];
319   fCoefBound2D1 = new Int_t[fNElemBound2D];
320   for (int i=fNElemBound2D;i--;) fCoefBound2D0[i] = fCoefBound2D1[i] = 0;
321 }
322
323 //_______________________________________________
324 void AliCheb3DCalc::InitCoefs(int nc)
325 {
326   // Set total number of significant coefs
327   if (fCoefs) delete[] fCoefs; 
328   fNCoefs = nc;
329   fCoefs = new Float_t [fNCoefs];
330   for (int i=fNCoefs;i--;) fCoefs[i] = 0.0;
331 }
332
333
334
335
336 ClassImp(AliCheb3D)
337
338 AliCheb3D::AliCheb3D():
339     TNamed("", ""),
340     fDimOut(0),
341     fPrec(0.),
342     fMaxCoefs(0),
343     fResTmp(0),
344     fGrid(0),
345     fUsrMacro(0)             
346 {
347     // Default constructor
348     Init0();
349 }
350
351 AliCheb3D::AliCheb3D(const char* inputFile):
352     TNamed("", ""),
353     fDimOut(0),
354     fPrec(0.),
355     fMaxCoefs(0),
356     fResTmp(0),
357     fGrid(0),
358     fUsrMacro(0)             
359 {
360     // Default constructor
361     Init0();
362     LoadData(inputFile);
363 }
364
365
366
367 AliCheb3D::AliCheb3D(FILE* stream):
368     TNamed("", ""),
369     fDimOut(0),
370     fPrec(0.),
371     fMaxCoefs(0),
372     fResTmp(0),
373     fGrid(0),
374     fUsrMacro(0)             
375 {
376     // Default constructor
377     Init0();
378     LoadData(stream);
379 }
380
381
382 //__________________________________________________________________________________________
383 #ifdef _INC_CREATION_ALICHEB3D_
384 AliCheb3D::AliCheb3D(const char* funName, int DimOut, Float_t  *bmin,Float_t  *bmax, Int_t *npoints, Float_t prec) : TNamed(funName,funName)
385 {
386   // Construct the parameterization for the function
387   // funName : name of the file containing the function: void funName(Float_t * inp,Float_t * out)
388   // DimOut  : dimension of the vector computed by the user function
389   // bmin    : array of 3 elements with the lower boundaries of the region where the function is defined
390   // bmax    : array of 3 elements with the upper boundaries of the region where the function is defined
391   // npoints : array of 3 elements with the number of points to compute in each of 3 dimension
392   // prec    : max allowed absolute difference between the user function and computed parameterization on the requested grid
393   //
394   Init0();
395   fPrec = TMath::Max(1.E-12f,prec);
396   if (DimOut<1) {Error("AliCheb3D","Requested output dimension is %d\nStop\n",fDimOut); exit(1);}
397   SetDimOut(DimOut);
398   PrepareBoundaries(bmin,bmax);
399   DefineGrid(npoints);
400   SetUsrFunction(funName);
401   ChebFit();
402   //
403 }
404 #endif
405
406 //__________________________________________________________________________________________
407 #ifdef _INC_CREATION_ALICHEB3D_
408 AliCheb3D::AliCheb3D(void (*ptr)(float*,float*), int DimOut, Float_t  *bmin,Float_t  *bmax, Int_t *npoints, Float_t prec) : TNamed("AliCheb3D","AliCheb3D")
409 {
410   // Construct the parameterization for the function
411   // ptr     : pointer on the function: void fun(Float_t * inp,Float_t * out)
412   // DimOut  : dimension of the vector computed by the user function
413   // bmin    : array of 3 elements with the lower boundaries of the region where the function is defined
414   // bmax    : array of 3 elements with the upper boundaries of the region where the function is defined
415   // npoints : array of 3 elements with the number of points to compute in each of 3 dimension
416   // prec    : max allowed absolute difference between the user function and computed parameterization on the requested grid
417   //
418   Init0();
419   fPrec = TMath::Max(1.E-12f,prec);
420   if (DimOut<1) {Error("AliCheb3D","Requested output dimension is %d\nStop\n",fDimOut); exit(1);}
421   SetDimOut(DimOut);
422   PrepareBoundaries(bmin,bmax);
423   DefineGrid(npoints);
424   SetUsrFunction(ptr);
425   ChebFit();
426   //
427 }
428 #endif
429
430 //__________________________________________________________________________________________
431 void AliCheb3D::Clear(Option_t*)
432 {
433   if (fResTmp)        { delete[] fResTmp; fResTmp = 0; }
434   if (fGrid)          { delete[] fGrid;   fGrid   = 0; }
435   if (fUsrMacro)      { delete fUsrMacro; fUsrMacro = 0;}
436   fChebCalc.Delete();
437   //
438 }
439
440 //__________________________________________________________________________________________
441 void AliCheb3D::Print(Option_t* opt) const
442 {
443   printf("%s: Chebyshev parameterization for 3D->%dD function. Precision: %e\n",GetName(),fDimOut,fPrec);
444   printf("Region of validity: [%+.5e:%+.5e] [%+.5e:%+.5e] [%+.5e:%+.5e]\n",fBMin[0],fBMax[0],fBMin[1],fBMax[1],fBMin[2],fBMax[2]);
445   TString opts = opt; opts.ToLower();
446   if (opts.Contains("l")) for (int i=0;i<fDimOut;i++) {printf("Output dimension %d:\n",i+1); GetChebCalc(i)->Print();}
447   //
448 }
449
450 //__________________________________________________________________________________________
451 void AliCheb3D::Init0()
452 {
453   for (int i=3;i--;) fBMin[i] = fBMax[i] = fBScale[i] = fBOffset[i] = 0;
454   fMaxCoefs = 0;
455   fGrid = 0;
456   fResTmp = 0;
457   fUsrFunName = "";
458   fUsrMacro = 0;
459 #ifdef _INC_CREATION_ALICHEB3D_
460   gUsrFunAliCheb3D = 0;
461 #endif
462 }
463
464 //__________________________________________________________________________________________
465 void AliCheb3D::PrepareBoundaries(Float_t  *bmin,Float_t  *bmax)
466 {
467   // Set and check boundaries defined by user, prepare coefficients for their conversion to [-1:1] interval
468   //
469   for (int i=3;i--;) {
470     fBMin[i]   = bmin[i];
471     fBMax[i]   = bmax[i];
472     fBScale[i] = bmax[i]-bmin[i];
473     if (fBScale[i]<=0) { 
474       Error("PrepareBoundaries","Boundaries for %d-th dimension are not increasing: %+.4e %+.4e\nStop\n",i,fBMin[i],fBMax[i]);
475       exit(1);
476     }
477     fBOffset[i] = bmin[i] + fBScale[i]/2.0;
478     fBScale[i] = 2./fBScale[i];
479   }
480   //
481 }
482
483 //__________________________________________________________________________________________
484 #ifdef _INC_CREATION_ALICHEB3D_
485 void AliCheb3D::SetUsrFunction(const char* name)
486 {
487   // load user macro with function definition and compile it
488   gUsrFunAliCheb3D = 0; 
489   fUsrFunName = name;
490   gSystem->ExpandPathName(fUsrFunName);
491   if (fUsrMacro) delete fUsrMacro;
492   TString tmpst = fUsrFunName;
493   tmpst += "+"; // prepare filename to compile
494   if (gROOT->LoadMacro(tmpst.Data())) {Error("SetUsrFunction","Failed to load user function from %s\nStop\n",name); exit(1);}
495   fUsrMacro = new TMethodCall();        
496   tmpst = tmpst.Data() + tmpst.Last('/')+1; //Strip away any path preceding the macro file name
497   int dot = tmpst.Last('.');
498   if (dot>0) tmpst.Resize(dot);
499   fUsrMacro->InitWithPrototype(tmpst.Data(),"Float_t *,Float_t *");
500   long args[2];
501   args[0] = (long)fArgsTmp;
502   args[1] = (long)fResTmp;
503   fUsrMacro->SetParamPtrs(args); 
504   //
505 }
506 #endif
507
508 //__________________________________________________________________________________________
509 #ifdef _INC_CREATION_ALICHEB3D_
510 void AliCheb3D::SetUsrFunction(void (*ptr)(float*,float*))
511 {
512   if (fUsrMacro) delete fUsrMacro;
513   fUsrMacro = 0;
514   fUsrFunName = "";
515   gUsrFunAliCheb3D = ptr;
516 }
517 #endif
518
519 //__________________________________________________________________________________________
520 #ifdef _INC_CREATION_ALICHEB3D_
521 void AliCheb3D::EvalUsrFunction(Float_t  *x, Float_t  *res) {
522   for (int i=3;i--;) fArgsTmp[i] = x[i];
523   if   (gUsrFunAliCheb3D) gUsrFunAliCheb3D(fArgsTmp,fResTmp);
524   else fUsrMacro->Execute(); 
525   for (int i=fDimOut;i--;) res[i] = fResTmp[i];
526 }
527 #endif
528
529 //__________________________________________________________________________________________
530 #ifdef _INC_CREATION_ALICHEB3D_
531 Int_t AliCheb3D::CalcChebCoefs(Float_t  *funval,int np, Float_t  *outCoefs, Float_t  prec)
532 {
533   // Calculate Chebyshev coeffs using precomputed function values at np roots.
534   // If prec>0, estimate the highest coeff number providing the needed precision
535   //
536   double sm;                 // do summations in double to minimize the roundoff error
537   for (int ic=0;ic<np;ic++) { // compute coeffs
538     sm = 0;          
539     for (int ir=0;ir<np;ir++) {
540       float  rt = TMath::Cos( ic*(ir+0.5)*TMath::Pi()/np);
541       sm += funval[ir]*rt;
542     }
543     outCoefs[ic] = Float_t( sm * ((ic==0) ? 1./np : 2./np) );
544   }
545   //
546   if (prec<=0) return np;
547   //
548   sm = 0;
549   int cfMax = 0;
550   for (cfMax=np;cfMax--;) {
551     sm += TMath::Abs(outCoefs[cfMax]);
552     if (sm>=prec) break;
553   }
554   if (++cfMax==0) cfMax=1;
555   return cfMax;
556   //
557 }
558 #endif
559
560 //__________________________________________________________________________________________
561 #ifdef _INC_CREATION_ALICHEB3D_
562 void AliCheb3D::DefineGrid(Int_t* npoints)
563 {
564   // prepare the grid of Chebyshev roots in each dimension
565   const int kMinPoints = 1;
566   int ntot = 0;
567   fMaxCoefs = 1;
568   for (int id=3;id--;) { 
569     fNPoints[id] = npoints[id];
570     if (fNPoints[id]<kMinPoints) {
571       Error("DefineGrid","at %d-th dimension %d point is requested, at least %d is needed\nStop\n",fNPoints[id],kMinPoints);
572       exit(1);
573     }
574     ntot += fNPoints[id];
575     fMaxCoefs *= fNPoints[id];
576   }
577   fGrid = new Float_t [ntot];
578   //
579   int curp = 0;
580   for (int id=3;id--;) { 
581     int np = fNPoints[id];
582     fGridOffs[id] = curp;
583     for (int ip=0;ip<np;ip++) {
584       Float_t x = TMath::Cos( TMath::Pi()*(ip+0.5)/np );
585       fGrid[curp++] = MapToExternal(x,id);
586     }
587   }
588   //
589 }
590 #endif
591
592 //__________________________________________________________________________________________
593 #ifdef _INC_CREATION_ALICHEB3D_
594 Int_t AliCheb3D::ChebFit()
595 {
596   // prepare parameterization for all output dimensions
597   int ir=0; 
598   for (int i=fDimOut;i--;) ir+=ChebFit(i); 
599   return ir;
600 }
601 #endif
602
603 //__________________________________________________________________________________________
604 #ifdef _INC_CREATION_ALICHEB3D_
605 Int_t AliCheb3D::ChebFit(int dmOut)
606 {
607   // prepare paramaterization of 3D function for dmOut-th dimension 
608   int maxDim = 0;
609   for (int i=0;i<3;i++) if (maxDim<fNPoints[i]) maxDim = fNPoints[i];
610   Float_t  *fvals      = new Float_t [ fNPoints[0] ];
611   Float_t  *tmpCoef3D  = new Float_t [ fNPoints[0]*fNPoints[1]*fNPoints[2] ]; 
612   Float_t  *tmpCoef2D  = new Float_t [ fNPoints[0]*fNPoints[1] ]; 
613   Float_t  *tmpCoef1D  = new Float_t [ maxDim ];
614   //
615   Float_t RTiny = fPrec/Float_t(maxDim); // neglect coefficient below this threshold
616   //
617   // 1D Cheb.fit for 0-th dimension at current steps of remaining dimensions
618   int ncmax = 0;
619   //
620   AliCheb3DCalc* cheb =  GetChebCalc(dmOut);
621   //
622   for (int id2=fNPoints[2];id2--;) {
623     fArgsTmp[2] = fGrid[ fGridOffs[2]+id2 ];
624     //
625     for (int id1=fNPoints[1];id1--;) {
626       fArgsTmp[1] = fGrid[ fGridOffs[1]+id1 ];
627       //
628       for (int id0=fNPoints[0];id0--;) {
629         fArgsTmp[0] = fGrid[ fGridOffs[0]+id0 ];
630         EvalUsrFunction();     // compute function values at Chebyshev roots of 0-th dimension
631         fvals[id0] =  fResTmp[dmOut];
632       }
633       int nc = CalcChebCoefs(fvals,fNPoints[0], tmpCoef1D, fPrec);
634       for (int id0=fNPoints[0];id0--;) tmpCoef2D[id1 + id0*fNPoints[1]] = tmpCoef1D[id0];
635       if (ncmax<nc) ncmax = nc;              // max coefs to be kept in dim0 to guarantee needed precision
636     }
637     //
638     // once each 1d slice of given 2d slice is parametrized, parametrize the Cheb.coeffs
639     for (int id0=fNPoints[0];id0--;) {
640       CalcChebCoefs( tmpCoef2D+id0*fNPoints[1], fNPoints[1], tmpCoef1D, -1);
641       for (int id1=fNPoints[1];id1--;) tmpCoef3D[id2 + fNPoints[2]*(id1+id0*fNPoints[1])] = tmpCoef1D[id1];
642     }
643   }
644   //
645   // now fit the last dimensions Cheb.coefs
646   for (int id0=fNPoints[0];id0--;) {
647     for (int id1=fNPoints[1];id1--;) {
648       CalcChebCoefs( tmpCoef3D+ fNPoints[2]*(id1+id0*fNPoints[1]), fNPoints[2], tmpCoef1D, -1);
649       for (int id2=fNPoints[2];id2--;) tmpCoef3D[id2+ fNPoints[2]*(id1+id0*fNPoints[1])] = tmpCoef1D[id2]; // store on place
650     }
651   }
652   //
653   // now find 2D surface which separates significant coefficients of 3D matrix from nonsignificant ones (up to fPrec)
654   int *tmpCoefSurf = new Int_t[ fNPoints[0]*fNPoints[1] ];
655   for (int id0=fNPoints[0];id0--;) for (int id1=fNPoints[1];id1--;) tmpCoefSurf[id1+id0*fNPoints[1]]=0;  
656   Double_t resid = 0;
657   for (int id0=fNPoints[0];id0--;) {
658     for (int id1=fNPoints[1];id1--;) {
659       for (int id2=fNPoints[2];id2--;) {
660         int id = id2 + fNPoints[2]*(id1+id0*fNPoints[1]);
661         Float_t  cfa = TMath::Abs(tmpCoef3D[id]);
662         if (cfa < RTiny) {tmpCoef3D[id] = 0; continue;} // neglect coeefs below the threshold
663
664         resid += cfa;
665         if (resid<fPrec) continue; // this coeff is negligible
666         // otherwise go back 1 step
667         resid -= cfa;
668         tmpCoefSurf[id1+id0*fNPoints[1]] = id2+1; // how many coefs to keep
669         break;
670       }
671     }
672   }
673   /*
674   printf("\n\nCoeffs\n");  
675   int cnt = 0;
676   for (int id0=0;id0<fNPoints[0];id0++) {
677     for (int id1=0;id1<fNPoints[1];id1++) {
678       for (int id2=0;id2<fNPoints[2];id2++) {
679         printf("%2d%2d%2d %+.4e |",id0,id1,id2,tmpCoef3D[cnt++]);
680       }
681       printf("\n");
682     }
683     printf("\n");
684   }
685   */
686   // see if there are rows to reject, find max.significant column at each row
687   int NRows = fNPoints[0];
688   int *tmpCols = new int[NRows]; 
689   for (int id0=fNPoints[0];id0--;) {
690     int id1 = fNPoints[1];
691     while (id1>0 && tmpCoefSurf[(id1-1)+id0*fNPoints[1]]==0) id1--;
692     tmpCols[id0] = id1;
693   }
694   // find max significant row
695   for (int id0=NRows;id0--;) {if (tmpCols[id0]>0) break; NRows--;}
696   // find max significant column and fill the permanent storage for the max sigificant column of each row
697   cheb->InitRows(NRows);                  // create needed arrays;
698   int *NColsAtRow = cheb->GetNColsAtRow();
699   int *ColAtRowBg = cheb->GetColAtRowBg();
700   int NCols = 0;
701   int NElemBound2D = 0;
702   for (int id0=0;id0<NRows;id0++) {
703     NColsAtRow[id0] = tmpCols[id0];     // number of columns to store for this row
704     ColAtRowBg[id0] = NElemBound2D;     // begining of this row in 2D boundary surface
705     NElemBound2D += tmpCols[id0];
706     if (NCols<NColsAtRow[id0]) NCols = NColsAtRow[id0];
707   }
708   cheb->InitCols(NCols);
709   delete[] tmpCols;
710   //  
711   // create the 2D matrix defining the boundary of significance for 3D coeffs.matrix 
712   // and count the number of siginifacnt coefficients
713   //
714   cheb->InitElemBound2D(NElemBound2D);
715   int *CoefBound2D0 = cheb->GetCoefBound2D0();
716   int *CoefBound2D1 = cheb->GetCoefBound2D1();
717   fMaxCoefs = 0; // redefine number of coeffs
718   for (int id0=0;id0<NRows;id0++) {
719     int nCLoc = NColsAtRow[id0];
720     int Col0  = ColAtRowBg[id0];
721     for (int id1=0;id1<nCLoc;id1++) {
722       CoefBound2D0[Col0 + id1] = tmpCoefSurf[id1+id0*fNPoints[1]];  // number of coefs to store for 3-d dimension
723       CoefBound2D1[Col0 + id1] = fMaxCoefs;
724       fMaxCoefs += CoefBound2D0[Col0 + id1];
725     }
726   }
727   //
728   // create final compressed 3D matrix for significant coeffs
729   cheb->InitCoefs(fMaxCoefs);
730   Float_t  *Coefs = cheb->GetCoefs();
731   int count = 0;
732   for (int id0=0;id0<NRows;id0++) {
733     int ncLoc = NColsAtRow[id0];
734     int Col0  = ColAtRowBg[id0];
735     for (int id1=0;id1<ncLoc;id1++) {
736       int ncf2 = CoefBound2D0[Col0 + id1];
737       for (int id2=0;id2<ncf2;id2++) {
738         Coefs[count++] = tmpCoef3D[id2 + fNPoints[2]*(id1+id0*fNPoints[1])];
739       }
740     }
741   }
742   /*
743   printf("\n\nNewSurf\n");
744   for (int id0=0;id0<fNPoints[0];id0++) {
745     for (int id1=0;id1<fNPoints[1];id1++) {
746       printf("(%2d %2d) %2d |",id0,id1,tmpCoefSurf[id1+id0*fNPoints[1]]);  
747     }
748     printf("\n");
749   }
750   */
751   //
752   delete[] tmpCoefSurf;
753   delete[] tmpCoef1D;
754   delete[] tmpCoef2D;
755   delete[] tmpCoef3D;
756   delete[] fvals;
757   //
758   return 1;
759 }
760 #endif
761
762 //_______________________________________________
763 #ifdef _INC_CREATION_ALICHEB3D_
764 void AliCheb3D::SaveData(const char* outfile,Bool_t append) const
765 {
766   // writes coefficients data to output text file, optionallt appending on the end of existing file
767   TString strf = outfile;
768   gSystem->ExpandPathName(strf);
769   FILE* stream = fopen(strf,append ? "a":"w");
770   SaveData(stream);
771   fclose(stream);
772   //
773 }
774 #endif
775
776 //_______________________________________________
777 #ifdef _INC_CREATION_ALICHEB3D_
778 void AliCheb3D::SaveData(FILE* stream) const
779 {
780   // writes coefficients data to existing output stream
781   //
782   fprintf(stream,"\n# These are automatically generated data for the Chebyshev interpolation of 3D->%dD function\n",fDimOut); 
783   fprintf(stream,"#\nSTART %s\n",GetName());
784   fprintf(stream,"# Dimensionality of the output\n%d\n",fDimOut);
785   fprintf(stream,"# Interpolation abs. precision\n%+.8e\n",fPrec);
786   //
787   fprintf(stream,"# Lower boundaries of interpolation region\n");
788   for (int i=0;i<3;i++) fprintf(stream,"%+.8e\n",fBMin[i]);
789   fprintf(stream,"# Upper boundaries of interpolation region\n");
790   for (int i=0;i<3;i++) fprintf(stream,"%+.8e\n",fBMax[i]);
791   fprintf(stream,"# Parameterization for each output dimension follows:\n",GetName());
792   //
793   for (int i=0;i<fDimOut;i++) GetChebCalc(i)->SaveData(stream);
794   fprintf(stream,"#\nEND %s\n#\n",GetName());
795   //
796 }
797 #endif
798
799 //_______________________________________________
800 void AliCheb3D::LoadData(const char* inpFile)
801 {
802   TString strf = inpFile;
803   gSystem->ExpandPathName(strf);
804   FILE* stream = fopen(strf.Data(),"r");
805   LoadData(stream);
806   fclose(stream);
807   //
808 }
809
810 //_______________________________________________
811 void AliCheb3D::LoadData(FILE* stream)
812 {
813   if (!stream) {Error("LoadData","No stream provided.\nStop"); exit(1);}
814   TString buffs;
815   Clear();
816   AliCheb3DCalc::ReadLine(buffs,stream);
817   if (!buffs.BeginsWith("START")) {Error("LoadData","Expected: \"START <fit_name>\", found \"%s\"\nStop\n",buffs.Data());exit(1);}
818   SetName(buffs.Data()+buffs.First(' ')+1);
819   //
820   AliCheb3DCalc::ReadLine(buffs,stream); // N output dimensions
821   fDimOut = buffs.Atoi(); 
822   if (fDimOut<1) {Error("LoadData","Expected: '<number_of_output_dimensions>', found \"%s\"\nStop\n",buffs.Data());exit(1);}
823   //
824   SetDimOut(fDimOut);
825   //
826   AliCheb3DCalc::ReadLine(buffs,stream); // Interpolation abs. precision
827   fPrec = buffs.Atof();
828   if (fPrec<=0) {Error("LoadData","Expected: '<abs.precision>', found \"%s\"\nStop\n",buffs.Data());exit(1);}
829   //
830   for (int i=0;i<3;i++) { // Lower boundaries of interpolation region
831     AliCheb3DCalc::ReadLine(buffs,stream);
832     fBMin[i] = buffs.Atof(); 
833   }
834   for (int i=0;i<3;i++) { // Upper boundaries of interpolation region
835     AliCheb3DCalc::ReadLine(buffs,stream);
836     fBMax[i] = buffs.Atof(); 
837   }
838   PrepareBoundaries(fBMin,fBMax);
839   //
840   // data for each output dimension
841   for (int i=0;i<fDimOut;i++) GetChebCalc(i)->LoadData(stream);
842   //
843   // check end_of_data record
844   AliCheb3DCalc::ReadLine(buffs,stream);
845   if (!buffs.BeginsWith("END") || !buffs.Contains(GetName())) {
846     Error("LoadData","Expected \"END %s\", found \"%s\".\nStop\n",GetName(),buffs.Data());
847     exit(1);
848   }
849   //
850 }
851
852 //_______________________________________________
853 void AliCheb3D::SetDimOut(int d)
854 {
855   fDimOut = d;
856   if (fResTmp) delete fResTmp;
857   fResTmp = new Float_t[fDimOut]; // RRR
858   fChebCalc.Delete();
859   for (int i=0;i<d;i++) fChebCalc.AddAtAndExpand(new AliCheb3DCalc(),i);
860 }
861
862 //_______________________________________________
863 void AliCheb3D::ShiftBound(int id,float dif)
864 {
865   if (id<0||id>2) {printf("Maximum 3 dimensions are supported\n"); return;}
866   fBMin[id] += dif;
867   fBMax[id] += dif;
868   fBOffset[id] += dif;
869 }
870
871 //_______________________________________________
872 #ifdef _INC_CREATION_ALICHEB3D_
873 TH1* AliCheb3D::TestRMS(int idim,int npoints,TH1* histo)
874 {
875   // fills the difference between the original function and parameterization (for idim-th component of the output)
876   // to supplied histogram. Calculations are done in npoints random points. 
877   // If the hostgram was not supplied, it will be created. It is up to the user to delete it! 
878   if (!fUsrMacro) {
879     printf("No user function is set\n");
880     return 0;
881   }
882   if (!histo) histo = new TH1D(GetName(),"Control: Function - Parametrization",100,-2*fPrec,2*fPrec);
883   for (int ip=npoints;ip--;) {
884     gRandom->RndmArray(3,(Float_t *)fArgsTmp);
885     for (int i=3;i--;) fArgsTmp[i] = fBMin[i] + fArgsTmp[i]*(fBMax[i]-fBMin[i]);
886     EvalUsrFunction();
887     Float_t valFun = fResTmp[idim];
888     Eval(fArgsTmp,fResTmp);
889     Float_t valPar = fResTmp[idim];
890     histo->Fill(valFun - valPar);
891   }
892   return histo;
893   //
894 }
895 #endif