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