AliRoot Core  ee782a0 (ee782a0)
AliCheb2DStackF.cxx
Go to the documentation of this file.
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 
17 #include "AliCheb2DStackF.h"
18 #include "AliLog.h"
19 #include <TMath.h>
20 
21 ClassImp(AliCheb2DStackF)
22 
23 //____________________________________________________________________
26  ,fCoeffs(0)
27 {
28  // Default constructor
29 }
30 
31 //____________________________________________________________________
32 AliCheb2DStackF::AliCheb2DStackF(stFun_t fun, int nSlices, int dimOut, const float bmin[2],const float bmax[2],
33  const int np[2], const float* dead, const float *rowXI, const float* precD)
34  :AliCheb2DStack(nSlices,dimOut,bmin,bmax,dead,rowXI)
35  ,fCoeffs(0)
36 {
37  // create stack of 2D->dimOut Chebyshev parameterizations debined in 2 dimensions between bmin and bmax,
38  // and trained with function fun on 2D grid on np points.
39  // Truncate each precision of each output dimension parameterization i to precD[i] if precD!=0, or prec
40  //
41  int *npd = new int[2*dimOut];
42  int maxcoefs=np[0]*np[1]*fNSlices, maxrows=np[0]*fNSlices;
43  for (int i=0;i<dimOut;i++) {
44  npd[2*i] = np[0];
45  npd[2*i+1] = np[1];
46  }
47  CheckDimensions(npd); // basic check
48  fNCols = new UChar_t[maxrows];
49  fCoeffs = new Float_t[maxcoefs];
50  CreateParams(fun, npd, precD);
51  delete[] npd;
52  //
53  Print();
54  //
55 }
56 
57 //____________________________________________________________________
58 AliCheb2DStackF::AliCheb2DStackF(stFun_t fun, int nSlices, int dimOut,
59  const float bmin[2],const float bmax[2],
60  const int np[][2], const float* dead, const float *rowXI, const float* precD)
61 :AliCheb2DStack(nSlices,dimOut,bmin,bmax,dead,rowXI)
62  ,fCoeffs(0)
63 {
64  // create stack of 2D->dimOut Chebyshev parameterizations debined in 2 dimensions between bmin and bmax,
65  // and trained with function fun on 2D grid on np[i][2] points for i-th output dimension.
66  // Truncate each precision of each output dimension parameterization i to precD[i] if precD!=0, or prec
67  //
68  int maxcoefs=0, maxrows=0;
69  for (int id=fDimOut;id--;) {
70  maxcoefs += np[id][0]*np[id][1];
71  maxrows += np[id][0];
72  }
73  fNCols = new UChar_t[maxrows*fNSlices];
74  fCoeffs = new Float_t[maxcoefs*fNSlices];
75  CreateParams(fun, (const int*)np, precD);
76  //
77  Print();
78 }
79 
80 //____________________________________________________________________
82 {
83  // D-tor
84  delete[] fCoeffs;
85 }
86 
87 //____________________________________________________________________
88 void AliCheb2DStackF::Eval(int sliceID, const float *par, float *res) const
89 {
90  // evaluate Chebyshev parameterization for 2d->DimOut function at sliceID
91  float p0,p1;
92  MapToInternal(sliceID, par,p0,p1);
93  const UChar_t *rows = &fNRows[sliceID*fDimOut]; // array of fDimOut rows for current slice
94  const UChar_t *cols = &fNCols[fColEntry[sliceID]]; // array of columns per row for current slice
95  const Float_t *cfs = &fCoeffs[fCoeffsEntry[sliceID]]; // array of coefficients for current slice
96  for (int id=0;id<fDimOut;id++) {
97  int nr = *rows++; // N rows in the matrix of coeffs for given dimension
98  for (int ir=0;ir<nr;ir++) {
99  int nc = *cols++; // N of significant colums at this row
100  fWSpace[ir] = ChebEval1D(p1,cfs,nc); // interpolation of Cheb. coefs along row
101  cfs += nc; // prepare coefs for the next row
102  }
103  res[id] = ChebEval1D(p0,fWSpace,nr);
104  }
105  //
106 }
107 
108 //____________________________________________________________________
109 Float_t AliCheb2DStackF::Eval(int sliceID, int dimOut, const float *par) const
110 {
111  // evaluate Chebyshev parameterization for requested output dimension only at requested sliceID
112  float p0,p1;
113  MapToInternal(sliceID,par,p0,p1);
114  int pid = sliceID*fDimOut;
115  const UChar_t *rows = &fNRows[pid]; // array of fDimOut rows for current slice
116  const UChar_t *cols = &fNCols[fColEntry[sliceID]]; // array of columns per row for current slice
117  const Float_t *cfs = &fCoeffs[fCoeffsEntry[sliceID]]; // array of coefficients for current slice
118  while (dimOut) {
119  for (int ir=*rows++;ir--;) cfs += *cols++; // go to the matrix of needed row
120  dimOut--;
121  }
122  int nr = *rows++; // N rows in the matrix of coeffs for given dimension
123  for (int ir=0;ir<nr;ir++) {
124  int nc = *cols++; // N of significant colums at this row
125  fWSpace[ir] = ChebEval1D(p1,cfs,nc); // interpolation of Cheb. coefs along row
126  cfs += nc; // prepare coefs for the next row
127  }
128  return ChebEval1D(p0,fWSpace,nr);
129  //
130 }
131 
132 //____________________________________________________________________
133 void AliCheb2DStackF::EvalDeriv(int sliceID, int dim, const float *par, float *res) const
134 {
135  // evaluate Chebyshev parameterization derivative over input dimension dim
136  float p0,p1;
137  MapToInternal(sliceID,par,p0,p1);
138  int pid = sliceID*fDimOut;
139  const UChar_t *rows = &fNRows[pid]; // array of fDimOut rows for current slice
140  const UChar_t *cols = &fNCols[fColEntry[sliceID]]; // array of columns per row for current slice
141  const Float_t *cfs = &fCoeffs[fCoeffsEntry[sliceID]]; // array of coefficients for current slice
142  float sclMap = fBScaleZ; // to convert derivative from -1:1 mapped range to real one
143  if (dim==0) {
144  float tmn = fBMin[ktgp], tmx = fBMax[ktgp];
145  if (fRowXI) {
146  tmn += fDead[0]*fRowXI[sliceID];
147  tmx -= fDead[1]*fRowXI[sliceID];
148  }
149  sclMap = 2./(tmx-tmn);
150  }
151  for (int id=0;id<fDimOut;id++) {
152  int nr = *rows++; // N rows in the matrix of coeffs for given dimension
153  for (int ir=0;ir<nr;ir++) {
154  int nc = *cols++; // N of significant colums at this row
155  if (dim==1) fWSpace[ir] = ChebEval1Deriv(p1,cfs,nc); // coeffs of derivative over internal var.
156  else fWSpace[ir] = ChebEval1D(p1,cfs,nc); // coeffs for external var.
157  cfs += nc; // prepare coefs for the next row
158  }
159  if (dim==1) res[id] = ChebEval1D(p0,fWSpace,nr) * sclMap;
160  else res[id] = ChebEval1Deriv(p0,fWSpace,nr) * sclMap;
161  }
162  //
163 }
164 
165 //____________________________________________________________________
166 void AliCheb2DStackF::CreateParams(stFun_t fun, const int *np, const float* prc)
167 {
168  // create parameterizations
169  //
170  // temporary space for max possible coeffs, rows etc
171  float **grids = new float*[fDimOut]; // Chebyshev grids for each output dimension
172  int maxSpace = 1, totSpace = 1;
173  Bool_t sameGrid = kTRUE;
174  int ref0=np[0],ref1=np[1];
175  for (int id=fDimOut;id--;) {
176  int nsp = np[2*id]*np[2*id+1];
177  if (maxSpace<nsp) maxSpace = nsp;
178  totSpace += nsp;
179  if (ref0!=np[2*id] || ref1!=np[2*id+1]) sameGrid = kFALSE;
180  }
181  //
182  // save pointers to recover the beggining of arrays later
183  UChar_t* nRows0 = fNRows;
184  UChar_t* nCols0 = fNCols;
185  float* coeffs0 = fCoeffs;
186  //
187  float *tmpCoef2D = new float[maxSpace]; // temporary workspace
188  float *tmpVals = new float[totSpace]; // temporary workspace for function values
189  //
190  for (int isl=0;isl<fNSlices;isl++) {
191  for (int id=fDimOut;id--;) grids[id] = DefineGrid(isl, id, &np[2*id]);
192  fCoeffsEntry[isl] = fCoeffs - coeffs0; // offset of the given slice coeffs
193  fColEntry[isl] = fNCols - nCols0; // offset of the given slice columns dimensions
194  //
195  if (sameGrid) FillFunValues(fun, isl, grids[0], &np[0], tmpVals);
196  else {
197  int slot = 0;
198  for (int id=0;id<fDimOut;id++) {
199  FillFunValues(fun, isl, id, grids[id], &np[2*id], tmpVals+slot); // get values for single dimensions
200  slot += np[2*id]*np[2*id+1];
201  }
202  }
203  //
204  int slot = 0;
205  for (int id=0;id<fDimOut;id++) {
206  ChebFit(&np[2*id], tmpVals+slot, tmpCoef2D, prc ? prc[id] : fgkDefPrec);
207  slot += np[2*id]*np[2*id+1];
208  }
209  for (int id=fDimOut;id--;) delete[] grids[id];
210  }
211  delete[] grids;
212  delete[] tmpCoef2D;
213  //
214  fNCoefsTot = fCoeffs-coeffs0; // size of final coeffs array
215  //
216  fNRows = nRows0;
217  // redefine arrays in compressed form, clean temp. stuff
218  fNCols = new UChar_t[fNRowsTot];
219  memcpy(fNCols, nCols0, fNRowsTot*sizeof(UChar_t));
220  delete[] nCols0;
221  fCoeffs = new Float_t[fNCoefsTot];
222  memcpy(fCoeffs, coeffs0, fNCoefsTot*sizeof(Float_t));
223  delete[] coeffs0;
224  //
225 }
226 
227 //____________________________________________________________________
228 void AliCheb2DStackF::ChebFit(const int np[2], const float* tmpVals, float* tmpCoef2D, float prec)
229 {
230  // prepare Cheb.fit for 2D -> single output dimension
231  //
232  int ncmax=0, maxDim = TMath::Max(np[0],np[1]);
233  memset(tmpCoef2D,0,np[0]*np[1]*sizeof(float));
234  //
235  float rTiny = 0.5*prec/maxDim; // neglect coefficient below this threshold
236  //
237  for (int id1=np[1];id1--;) { // create Cheb.param for each node of 2nd input dimension
238  int nc = CalcChebCoefs(&tmpVals[id1*np[0]], np[0], fWSpace, -1);
239  for (int id0=nc;id0--;) tmpCoef2D[id1 + id0*np[1]] = fWSpace[id0];
240  if (ncmax<nc) ncmax = nc; // max coefs to be kept in dim0 to guarantee needed precision
241  }
242  //
243  // once each 1d slice of given 2d slice is parametrized, parametrize the Cheb.coeffs
244  for (int id0=np[0];id0--;) {
245  CalcChebCoefs(&tmpCoef2D[id0*np[1]], np[1], fWSpace, -1);
246  for (int id1=np[1];id1--;) tmpCoef2D[id1+id0*np[1]] = fWSpace[id1];
247  }
248  //
249  // now find 1D curve which separates significant coefficients of 2D matrix from nonsignificant ones (up to prec)
250  // double resid = 0;
251  int ncNZero=0, nRows = np[0]; // find max significant row
252  for (int id0=np[0];id0--;) {
253  fNCols[id0]=0;
254  double resid = 0;
255  for (int id1=np[1];id1--;) {
256  int id = id1 + id0*np[1];
257  float cfa = TMath::Abs(tmpCoef2D[id]);
258  if (cfa < rTiny) {tmpCoef2D[id] = 0; continue;} // neglect coefs below the threshold
259  resid += cfa;
260  // if (resid<prec) continue; // this coeff is negligible
261  if (resid<rTiny) continue; // this coeff is negligible
262  // resid -= cfa; // otherwise go back 1 step
263  fNCols[id0] = id1+1; // how many coefs to keep
264  break;
265  }
266  if (fNCols[id0]) ncNZero++;
267  else if (!ncNZero) nRows--; // decrease N significant rows untile 1st non-0 column met
268  }
269  //
270  // find max significant column and fill the storage
271  // for the max sigificant column of each row
272  for (int id0=0;id0<nRows;id0++) {
273  int nc = *fNCols++;
274  for (int id1=0;id1<nc;id1++) *fCoeffs++ = tmpCoef2D[id1+id0*np[1]];
275  }
276  *fNRows++ = nRows;
277  fNRowsTot += nRows;
278  //
279 }
280 
281 //____________________________________________________________________
282 void AliCheb2DStackF::FillFunValues(stFun_t fun, int slice, int dim, const float *grid,
283  const int np[2], float* vals)
284 {
285  // fill function values on the grid
286  float args[2];
287  for (int id1=np[1];id1--;) {
288  args[1] = grid[id1];
289  for (int id0=np[0];id0--;) { //
290  args[0] = grid[np[1]+id0];
291  fun(slice, args, fWSpace);
292  vals[id1*np[0] + id0] = fWSpace[dim];
293  }
294  }
295 }
296 
297 //____________________________________________________________________
298 void AliCheb2DStackF::FillFunValues(stFun_t fun, int slice, const float *grid, const int np[2], float* vals)
299 {
300  // fill function values on the grid for all dimensions at once (if grids are the same)
301  float args[2];
302  int slotStep = np[0]*np[1];
303  for (int id1=np[1];id1--;) {
304  args[1] = grid[id1];
305  for (int id0=np[0];id0--;) { //
306  args[0] = grid[np[1]+id0];
307  fun(slice, args, fWSpace);
308  int slotDim = 0;
309  for (int dim=0;dim<fDimOut;dim++) {
310  vals[slotDim + id1*np[0] + id0] = fWSpace[dim];
311  slotDim += slotStep;
312  }
313  }
314  }
315 }
316 
317 //__________________________________________________________________________________________
318 void AliCheb2DStackF::Print(const Option_t* opt) const
319 {
320  printf("F*");
322 }
323 
324 //__________________________________________________________________________________________
325 void AliCheb2DStackF::PrintSlice(int isl, const Option_t* opt) const
326 {
327  // print slice info
328  //
329  TString opts = opt; opts.ToLower();
330  Bool_t showcf = opts.Contains("c");
331  int par0 = isl*fDimOut;
332  const UChar_t* rows = &fNRows[par0];
333  const UChar_t* cols = &fNCols[fColEntry[isl]];
334  const Float_t* cfs = &fCoeffs[fCoeffsEntry[isl]];
335  printf("#%3d ",isl);
336  if (showcf) printf("\n");
337  for (int id=0;id<fDimOut;id++) {
338  int nr = *rows++;
339  int ncmax=0,ncf=0;
340  for (int ir=0;ir<nr;ir++) {
341  ncf += cols[ir];
342  if (cols[ir]>ncmax) ncmax = cols[ir];
343  }
344  printf("D%d: %4d coefs in %3dx%3d| ",id,ncf,nr,ncmax);
345  if (showcf) {
346  printf("\n");
347  for (int ir=0;ir<nr;ir++) {
348  for (int ic=0;ic<cols[ir];ic++) printf("%+.2e ",*cfs++); printf("\n");
349  }
350  }
351  cols += nr; // cols entry for next dimension
352  //
353  }
354  if (!showcf) printf("\n");
355  //
356 }
void FillFunValues(stFun_t fun, int slice, int dim, const float *grid, const int np[2], float *vals)
printf("Chi2/npoints = %f\n", TMath::Sqrt(chi2/npoints))
AliTPCcalibPID * pid
Definition: CalibPID.C:69
void MapToInternal(int slice, const float *xy, float *xyint) const
const Float_t * fRowXI
Int_t CalcChebCoefs(const float *funval, int np, float *outCoefs, float prec)
UChar_t * fNRows
optional external!!! set 1/X for each row if dead zones to be accounted
void PrintSlice(int isl, const Option_t *opt) const
virtual ~AliCheb2DStackF()
Int_t * fCoeffsEntry
Float_t fDead[2]
void CreateParams(stFun_t fun, const int *np, const float *prc)
Float_t fBMax[2]
UChar_t * fNCols
static Float_t fWSpace[kMaxPoints]
Float_t fBMin[2]
static float ChebEval1D(float x, const float *array, int ncf)
void Print(const Option_t *opt="") const
static float ChebEval1Deriv(float x, const float *array, int ncf)
void(* stFun_t)(int, float *, float *)
void Eval(int sliceID, const float *par, float *res) const
void CheckDimensions(const int *np) const
float * DefineGrid(int slice, int dim, const int np[2]) const
void Print(const Option_t *opt="") const
static Float_t fgkDefPrec
void res(Char_t i)
Definition: Resolution.C:2
void ChebFit(const int np[2], const float *tmpVals, float *wspace, float prec)
void EvalDeriv(int sliceID, int dim, const Float_t *par, float *res) const