]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RALICE/icepack/IcePandel.cxx
14-jun-2006 NvE TWR polarity reversed in IceF2k::PutHits() to be compatible with
[u/mrichter/AliRoot.git] / RALICE / icepack / IcePandel.cxx
1 /*******************************************************************************
2  * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
3  *
4  * Author: The IceCube RALICE-based Offline 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.
12  * The authors make no claims about the suitability of this software for
13  * any purpose. It is provided "as is" without express or implied warranty.
14  *******************************************************************************/
15
16 // $Id$
17
18 ///////////////////////////////////////////////////////////////////////////
19 // Class IcePandel
20 // TTask derived class to perform Pandel fitting.
21 //
22 // The code in this processor is based on the algorithms as developed
23 // by Oladipo Fadiran and George Japaridze (Clark Atlanta University, USA).
24 //
25 // Use the UseTracks memberfunction to specify the first guess tracks
26 // to be processed by the minimiser.
27 // By default only the first encountered IceDwalk track will be processed.
28 //
29 // Use the SelectHits memberfunction to specify the hits to be used.
30 // By default only the hits associated to the first guess track are used.
31 //
32 // The fit processor (TFitter which is basically Minuit) printlevel
33 // can be selected via the memberfunction SetPrintLevel.
34 // By default all printout is suppressed (i.e. level=-2).
35 //
36 // In case of bad parameter values as input for the minimiser, the
37 // value of the Pandel sometimes cannot be evaluated.
38 // In such a case a penalty value will be added.
39 // By default this penalty value amounts to 3 dB, but the user can
40 // modify this penalty value via the memberfunction SetPenalty.
41 // This allows investigation/tuning of the sensitivity to hits with
42 // bad time residuals.
43 // 
44 // An example of how to invoke this processor after Xtalk, hit cleaning
45 // and a direct walk first guess estimate can be found in the ROOT example
46 // macro icepandel.cc which resides in the /macros subdirectory.
47 // 
48 // The minimisation results are stored in the IceEvent structure as
49 // tracks with as default the name "IcePandel" (just like the first guess
50 // results of e.g. IceDwalk).
51 // This track name identifier can be modified by the user via the
52 // SetTrackName() memberfunction. This will allow unique identification
53 // of tracks which are produced when re-processing existing data with
54 // different criteria.
55 // By default the charge of the produced tracks is set to 0, since
56 // no distinction can be made between positive or negative tracks.
57 // However, the user can define the track charge by invokation
58 // of the memberfunction SetCharge().
59 // This facility may be used to distinguish tracks produced by the
60 // various reconstruction algorithms in a (3D) colour display
61 // (see the class AliHelix for further details).  
62 // A pointer to the first guess track which was used as input is available
63 // via the GetParentTrack facility of these "IcePandel" tracks.
64 // Furthermore, all the hits that were used in the minisation are available
65 // via the GetSignal facility of a certain track.
66 // The statistics of the TFitter result are stored as an AliSignal object
67 // in the track, which can be obtained via the GetFitDetails memberfunction.
68 // Currently no overall probability has yet been defined to indicate the
69 // quality of a certain fit result. So, for the time being the user has
70 // to judge the fit quality his/herself by means of the various TFitter stats
71 // as accessible via the GetFitDetails facility.
72 //
73 // An example of how the various data can be accessed is given below,
74 // where "evt" indicates the pointer to the IceEvent structure.
75 //
76 // Example for accessing data :
77 // ----------------------------
78 // TObjArray* tracks=evt->GetTracks("IcePandel");
79 // if (!tracks) return;
80 // AliPosition* r0=0;
81 // Float_t fcn=0;
82 // for (Int_t jtk=0; jtk<tracks->GetEntries(); jtk++)
83 // {
84 //  AliTrack* tx=(AliTrack*)tracks->At(jtk);
85 //  if (!tx) continue;
86 //  tx->Data("sph");
87 //  r0=tx->GetReferencePoint();
88 //  if (r0) r0->Data();
89 //  sx=(AliSignal*)tx->GetFitDetails();
90 //  if (sx) fcn=sx->GetSignal("FCN");
91 //  AliTrack* tx2=tx->GetParentTrack();
92 //  if (!tx2) continue;
93 //  tx2->Data("sph");
94 //  r0=tx2->GetReferencePoint();
95 //  if (r0) r0->Data();
96 // }
97 //
98 // Notes :
99 // -------
100 // 1) This processor only works properly on data which are Time and ADC
101 //    calibrated and contain tracks from first guess algorithms like
102 //    e.g. IceDwalk.
103 // 2) In view of the usage of TFitter/Minuit minimisation, a global pointer
104 //    to the instance of this class (gIcePandel) and a global static
105 //    wrapper function (IcePandelFCN) have been introduced, to allow the
106 //    actual minimisation to be performed via the memberfunction FitFCN.
107 //    This implies that in a certain processing job only 1 instance of
108 //    this IcePandel class may occur.
109 //
110 //--- Author: Nick van Eijndhoven 09-feb-2006 Utrecht University
111 //- Modified: NvE $Date$ Utrecht University
112 ///////////////////////////////////////////////////////////////////////////
113  
114 #include "IcePandel.h"
115 #include "Riostream.h"
116
117 // Global pointer to the instance of this object
118  IcePandel* gIcePandel=0;
119
120 // TFitter/Minuit interface to IcePandel::FitFCN
121  void IcePandelFCN(Int_t& npar,Double_t* gin,Double_t& f,Double_t* u,Int_t flag)
122  {
123   if (gIcePandel) gIcePandel->FitFCN(npar,gin,f,u,flag);
124  }
125
126 ClassImp(IcePandel) // Class implementation to enable ROOT I/O
127
128 IcePandel::IcePandel(const char* name,const char* title) : TTask(name,title)
129 {
130 // Default constructor.
131  fFirst=1;
132  fPrint=-2;
133  fSelhits=1;
134  fEvt=0;
135  fUseNames=0;
136  fUseNtk=0;
137  fTrack=0;
138  fHits=0;
139  fFitter=0;
140  fTrackname="IcePandel";
141  fCharge=0;
142  fPenalty=3;
143
144  // Set the global pointer to this instance
145  gIcePandel=this;
146 }
147 ///////////////////////////////////////////////////////////////////////////
148 IcePandel::~IcePandel()
149 {
150 // Default destructor.
151  if (fUseNames)
152  {
153   delete fUseNames;
154   fUseNames=0;
155  }
156  if (fUseNtk)
157  {
158   delete fUseNtk;
159   fUseNtk=0;
160  }
161  if (fHits)
162  {
163   delete fHits;
164   fHits=0;
165  }
166  if (fFitter)
167  {
168   delete fFitter;
169   fFitter=0;
170  }
171 }
172 ///////////////////////////////////////////////////////////////////////////
173 void IcePandel::Exec(Option_t* opt)
174 {
175 // Implementation of the hit fitting procedure.
176
177  TString name=opt;
178  AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
179
180  if (!parent) return;
181
182  fEvt=(IceEvent*)parent->GetObject("IceEvent");
183  if (!fEvt) return;
184
185  if (!fUseNames) UseTracks("IceDwalk",1);
186
187  Int_t nclasses=fUseNames->GetEntries(); // Number of first guess classes to be processed
188  Int_t ntkmax=0; // Max. number of tracks for a certain class
189  TObjString* strx=0;
190  TString str;
191
192  if (fFirst)
193  {
194   cout << " *IcePandel* First guess selections to be processed (-1=all)." << endl;
195   for (Int_t i=0; i<nclasses; i++)
196   {
197    strx=(TObjString*)fUseNames->At(i);
198    if (!strx) continue;
199    str=strx->GetString();
200    ntkmax=fUseNtk->At(i);
201    cout << " Maximally " << ntkmax << " track(s) per event for procedure : " << str.Data() << endl;
202   }
203   cout << " *IcePandel* Hit selection mode : " << fSelhits << endl;
204   cout << " *IcePandel* Penalty value for minimiser : " << fPenalty << " dB." << endl;
205   cout << endl;
206   fFirst=0;
207  }
208
209  Double_t pi=acos(-1.);
210
211  // Initialisation of the minimisation processor
212  Double_t arglist[100];
213  if (!fFitter) fFitter=new TFitter();
214
215  // The number of reconstructed tracks already present in the event
216  Int_t ntkreco=fEvt->GetNtracks(1);
217
218  if (!fHits)
219  {
220   fHits=new TObjArray();
221  }
222  else
223  {
224   fHits->Clear();
225  }
226
227  // If selected, use all the good quality hits of the complete event
228  if (fSelhits==0)
229  {
230   TObjArray* hits=fEvt->GetHits("IceGOM");
231   for (Int_t ih=0; ih<hits->GetEntries(); ih++)
232   {
233    AliSignal* sx=(AliSignal*)hits->At(ih);
234    if (!sx) continue;
235    if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
236    fHits->Add(sx);
237   }
238  }
239
240  // Track by track processing of the selected first guess classes
241  Float_t vec[3];
242  Float_t err[3];
243  Float_t margin,minmarg=25; // (minimal) margin for the fitter r0 search area
244  Ali3Vector p;
245  AliPosition pos;
246  AliTrack tkfit;
247  tkfit.SetNameTitle(fTrackname.Data(),"IcePandel fit result");
248  AliSignal fitstats;
249  fitstats.SetNameTitle("Fitstats","TFitter stats for Pandel fit");
250  fitstats.SetSlotName("IER",1);
251  fitstats.SetSlotName("FCN",2);
252  fitstats.SetSlotName("EDM",3);
253  fitstats.SetSlotName("NVARS",4);
254  Float_t x,y,z,theta,phi;
255  Float_t xmin,xmax,ymin,ymax,zmin,zmax,thetamin,thetamax,phimin,phimax;
256  Double_t amin,edm,errdef; // Minimisation stats
257  Int_t ier,nvpar,nparx;    // Minimisation stats
258  Int_t ntk=0;
259  Int_t nsig=0;
260  for (Int_t iclass=0; iclass<nclasses; iclass++) // Loop over first guess classes
261  {
262   strx=(TObjString*)fUseNames->At(iclass);
263   if (!strx) continue;
264   str=strx->GetString();
265   ntkmax=fUseNtk->At(iclass);
266   TObjArray* tracks=fEvt->GetTracks(str);
267   ntk=tracks->GetEntries();
268   if (ntkmax>0 && ntk>ntkmax) ntk=ntkmax;
269
270   for (Int_t jtk=0; jtk<ntk; jtk++) // Loop over tracks of a certain class
271   {
272    fTrack=(AliTrack*)tracks->At(jtk);
273    if (!fTrack) continue;
274
275    AliPosition* r0=fTrack->GetReferencePoint();
276    if (!r0) continue;
277
278    // If selected, use only the first guess track associated hits
279    if (fSelhits==1)
280    {
281     fHits->Clear();
282     nsig=fTrack->GetNsignals();
283     for (Int_t is=1; is<=nsig; is++)
284     {
285      AliSignal* sx=fTrack->GetSignal(is);
286      if (!sx) continue;
287      if (!sx->GetDevice()->InheritsFrom("IceGOM")) continue;
288      if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
289      fHits->Add(sx);
290     }
291    }
292    
293    if (!fHits->GetEntries()) continue;
294
295    r0->GetVector(vec,"car");
296    r0->GetErrors(err,"car");
297
298    x=vec[0];
299    y=vec[1];
300    z=vec[2];
301    margin=5.*err[0];
302    if (margin<minmarg) margin=minmarg;
303    xmin=x-margin;
304    xmax=x+margin;
305    margin=5.*err[1];
306    if (margin<minmarg) margin=minmarg;
307    ymin=y-margin;
308    ymax=y+margin;
309    margin=5.*err[2];
310    if (margin<minmarg) margin=minmarg;
311    zmin=z-margin;
312    zmax=z+margin;
313
314    p=fTrack->Get3Momentum();
315    p.GetVector(vec,"sph");
316
317    theta=vec[1];
318    phi=vec[2];
319    thetamin=theta-(pi/3.);
320    if (thetamin<0) thetamin=0;
321    thetamax=theta+(pi/3.);
322    if (thetamax>pi) thetamax=pi;
323    phimin=phi-(pi/2.);
324    phimax=phi+(pi/2.);
325
326    // Process this first guess track with its associated hits
327    fFitter->Clear();
328
329    arglist[0]=fPrint;
330    if (fPrint==-2) arglist[0]=-1;
331    fFitter->ExecuteCommand("SET PRINT",arglist,1);
332    if (fPrint==-2) fFitter->ExecuteCommand("SET NOWARNINGS",arglist,0);
333
334    fFitter->SetFitMethod("loglikelihood");
335
336    fFitter->SetParameter(0,"r0x",x,0.001,xmin,xmax);
337    fFitter->SetParameter(1,"r0y",y,0.001,ymin,ymax);
338    fFitter->SetParameter(2,"r0z",z,0.001,zmin,zmax);
339    fFitter->SetParameter(3,"theta",theta,0.001,thetamin,thetamax);
340    fFitter->SetParameter(4,"phi",phi,0.001,phimin,phimax);
341
342    fFitter->SetFCN(IcePandelFCN);
343
344    arglist[0]=0;
345    ier=fFitter->ExecuteCommand("MINIMIZE",arglist,0);
346
347    fFitter->GetStats(amin,edm,errdef,nvpar,nparx);
348    fitstats.Reset();
349    fitstats.SetSignal(ier,1);
350    fitstats.SetSignal(amin,2);
351    fitstats.SetSignal(edm,3);
352    fitstats.SetSignal(nvpar,4);
353
354    // Resulting parameters after minimisation
355    vec[0]=fFitter->GetParameter(0);
356    vec[1]=fFitter->GetParameter(1);
357    vec[2]=fFitter->GetParameter(2);
358    err[0]=fFitter->GetParError(0);
359    err[1]=fFitter->GetParError(1);
360    err[2]=fFitter->GetParError(2);
361    pos.SetPosition(vec,"car");
362    pos.SetPositionErrors(err,"car");
363
364    vec[0]=1.;
365    vec[1]=fFitter->GetParameter(3);
366    vec[2]=fFitter->GetParameter(4);
367    err[0]=0.;
368    err[1]=fFitter->GetParError(3);
369    err[2]=fFitter->GetParError(4);
370    p.SetVector(vec,"sph");
371    p.SetErrors(err,"sph");
372
373    // Enter the fit result as a track in the event structure
374    tkfit.Reset();
375    ntkreco++;
376    tkfit.SetId(ntkreco);
377    tkfit.SetCharge(fCharge);
378    tkfit.SetParentTrack(fTrack);
379    AliTimestamp* tt0=r0->GetTimestamp();
380    pos.SetTimestamp(*tt0);
381    tkfit.SetTimestamp(*tt0);
382    tkfit.SetReferencePoint(pos);
383    tkfit.Set3Momentum(p);
384    tkfit.SetFitDetails(fitstats);
385    for (Int_t ihit=0; ihit<fHits->GetEntries(); ihit++)
386    {
387     AliSignal* sx=(AliSignal*)fHits->At(ihit);
388     if (sx) tkfit.AddSignal(*sx);
389    }
390    fEvt->AddTrack(tkfit);
391   } // End loop over tracks
392  } // End loop over first guess classes
393
394 }
395 ///////////////////////////////////////////////////////////////////////////
396 void IcePandel::SetPrintLevel(Int_t level)
397 {
398 // Set the fitter (Minuit) print level.
399 // See the TFitter and TMinuit docs for details.
400 //
401 // Note : level=-2 suppresses also all fit processor warnings.
402 //        
403 // The default in the constructor is level=-2. 
404
405  fPrint=level;
406 }
407 ///////////////////////////////////////////////////////////////////////////
408 void IcePandel::UseTracks(TString classname,Int_t n)
409 {
410 // Specification of the first guess tracks to be used.
411 //
412 // classname : Specifies the first guess algorithm (e.g. "IceDwalk");
413 // n : Specifies the max. number of these tracks to be used
414 //
415 // Note : n<0 will use all the existing tracks of the specified classname
416 //
417 // The default is n=-1.
418 //
419 // Consecutive invokations of this memberfunction with different classnames
420 // will result in an incremental effect.
421 //
422 // Example :
423 // ---------
424 // UseTracks("IceDwalk",5);
425 // UseTracks("IceLfit",2);
426 // UseTracks("IceJams");
427 //
428 // This will use the first 5 IceDwalk, the first 2 IceLfit and all the
429 // IceJams tracks which are encountered in the event structure.
430
431  if (!fUseNames)
432  {
433   fUseNames=new TObjArray();
434   fUseNames->SetOwner();
435  }
436  
437  if (!fUseNtk) fUseNtk=new TArrayI();
438
439  // Check if this classname has already been specified before 
440  TString s;
441  Int_t nen=fUseNames->GetEntries();
442  for (Int_t i=0; i<nen; i++)
443  {
444   TObjString* sx=(TObjString*)fUseNames->At(i);
445   if (!sx) continue;
446   s=sx->GetString();
447   if (s==classname) return;
448  }
449
450  // New classname to be added into the storage
451  if (nen >= fUseNames->GetSize()) fUseNames->Expand(nen+1);
452  if (nen >= fUseNtk->GetSize()) fUseNtk->Set(nen+1);
453  
454  TObjString* name=new TObjString();
455  name->SetString(classname);
456  fUseNames->Add(name);
457  fUseNtk->AddAt(n,nen);
458 }
459 ///////////////////////////////////////////////////////////////////////////
460 void IcePandel::SelectHits(Int_t mode)
461 {
462 // Specification of the hits to be used in the minimisation.
463 //
464 // mode = 0 : All hit cleaning survived hits of the complete event are used
465 //        1 : Only the associated hits are used for each first guess track
466 //
467 // The default is mode=1.
468
469  if (mode==0 || mode==1) fSelhits=mode;
470 }
471 ///////////////////////////////////////////////////////////////////////////
472 void IcePandel::SetTrackName(TString s)
473 {
474 // Set (alternative) name identifier for the produced tracks.
475 // This allows unique identification of (newly) produced pandel tracks
476 // in case of re-processing of existing data with different criteria.
477 // By default the produced tracks have the name "IcePandel" which is
478 // set in the constructor of this class.
479  fTrackname=s;
480 }
481 ///////////////////////////////////////////////////////////////////////////
482 void IcePandel::SetCharge(Float_t charge)
483 {
484 // Set user defined charge for the produced tracks.
485 // This allows identification of these tracks on color displays.
486 // By default the produced tracks have charge=0 which is set in the
487 // constructor of this class.
488  fCharge=charge;
489 }
490 ///////////////////////////////////////////////////////////////////////////
491 void IcePandel::SetPenalty(Float_t val)
492 {
493 // Set user defined penalty value in dB for the minimiser outside the range.
494 // This allows investigation/tuning of the sensitivity to hits with bad
495 // time residuals.
496 // By default the penalty val=3 dB is set in the constructor of this class.
497  fPenalty=val;
498 }
499 ///////////////////////////////////////////////////////////////////////////
500 void IcePandel::FitFCN(Int_t&,Double_t*,Double_t& f,Double_t* x,Int_t)
501 {
502 // The Pandel function used for the minimisation process.
503
504  const Float_t c=0.299792;           // Light speed in vacuum in meters per ns
505  const Float_t nice=1.35634;         // Refractive index of ice
506  const Float_t thetac=acos(1./nice); // Cherenkov angle (in radians)
507  const Float_t lambda=33.3;          // Light scattering length in ice
508  const Float_t labs=98;              // Light absorbtion length in ice
509  const Float_t cice=c/nice;          // Light speed in ice in meters per ns
510  const Float_t tau=557;
511  const Double_t rho=((1./tau)+(cice/labs));
512  const Double_t e=exp(1.);
513
514  f=0;
515
516  // The first original guess track parameters
517  AliPosition* tr0=fTrack->GetReferencePoint();
518  AliTimestamp* tt0=tr0->GetTimestamp();
519  Float_t t0=fEvt->GetDifference(tt0,"ns");
520  Ali3Vector tp=fTrack->Get3Momentum();
521
522  // The new r0 and p vectors from the minimisation
523  Float_t vec[3];
524  
525  AliPosition r0;
526  vec[0]=x[0];
527  vec[1]=x[1];
528  vec[2]=x[2];
529  r0.SetPosition(vec,"car");
530
531  Ali3Vector p;
532  vec[0]=1;
533  vec[1]=x[3];
534  vec[2]=x[4];
535  p.SetVector(vec,"sph");
536
537  Int_t nhits=fHits->GetEntries();
538  AliPosition rhit;
539  Ali3Vector r12;
540  Float_t d,dist,thit,tgeo;
541  Double_t tres,zeta,pandel;
542  for (Int_t i=0; i<nhits; i++)
543  {
544   AliSignal* sx=(AliSignal*)fHits->At(i);
545   if (!sx) continue;
546   IceGOM* omx=(IceGOM*)sx->GetDevice();
547   if (!omx) continue;
548   rhit=omx->GetPosition();
549   d=fTrack->GetDistance(rhit);
550   zeta=d/lambda;
551   d*=sin(thetac);
552   r12=rhit-r0;
553   dist=p.Dot(r12)+d*tan(thetac);
554   tgeo=t0+dist/c;
555   thit=sx->GetSignal("LE",7);
556   tres=thit-tgeo;
557
558   // LLH optimisation based on a decibel scaled Pandel function
559   // Avoid minimiser problem for infinite derivative on Pandel surface
560   // This problem will be absent when using a smooth convoluted Pandel
561   // Use -10*log10(p) expression to obtain intuitive decibel scale for return value "f"
562   if (tres>=0.001 && tres<=10000 && zeta>=0.001 && zeta<=10000)
563   {
564    pandel=-10.*((zeta*log10(rho))+((zeta-1.)*log10(tres))-(rho*tres*log10(e))-log10(TMath::Gamma(zeta)));
565    f+=pandel;
566   }
567   else
568   {
569    f+=fPenalty; // Penalty in case tres and/or zeta outside range
570   }
571  }
572 }
573 ///////////////////////////////////////////////////////////////////////////