1 /*******************************************************************************
2 * Copyright(c) 2003, IceCube Experiment at the South Pole. All rights reserved.
4 * Author: The IceCube RALICE-based Offline Project.
5 * Contributors are mentioned in the code where appropriate.
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 *******************************************************************************/
18 ///////////////////////////////////////////////////////////////////////////
20 // TTask derived class to perform Pandel fitting.
22 // The code in this processor is based on the algorithms as developed
23 // by Oladipo Fadiran and George Japaridze (Clark Atlanta University, USA).
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.
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.
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).
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.
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.
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.
73 // An example of how the various data can be accessed is given below,
74 // where "evt" indicates the pointer to the IceEvent structure.
76 // Example for accessing data :
77 // ----------------------------
78 // TObjArray* tracks=evt->GetTracks("IcePandel");
79 // if (!tracks) return;
82 // for (Int_t jtk=0; jtk<tracks->GetEntries(); jtk++)
84 // AliTrack* tx=(AliTrack*)tracks->At(jtk);
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;
94 // r0=tx2->GetReferencePoint();
95 // if (r0) r0->Data();
100 // 1) This processor only works properly on data which are Time and ADC
101 // calibrated and contain tracks from first guess algorithms like
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.
110 //--- Author: Nick van Eijndhoven 09-feb-2006 Utrecht University
111 //- Modified: NvE $Date$ Utrecht University
112 ///////////////////////////////////////////////////////////////////////////
114 #include "IcePandel.h"
115 #include "Riostream.h"
117 // Global pointer to the instance of this object
118 IcePandel* gIcePandel=0;
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)
123 if (gIcePandel) gIcePandel->FitFCN(npar,gin,f,u,flag);
126 ClassImp(IcePandel) // Class implementation to enable ROOT I/O
128 IcePandel::IcePandel(const char* name,const char* title) : TTask(name,title)
130 // Default constructor.
140 fTrackname="IcePandel";
144 // Set the global pointer to this instance
147 ///////////////////////////////////////////////////////////////////////////
148 IcePandel::~IcePandel()
150 // Default destructor.
172 ///////////////////////////////////////////////////////////////////////////
173 void IcePandel::Exec(Option_t* opt)
175 // Implementation of the hit fitting procedure.
178 AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
182 fEvt=(IceEvent*)parent->GetObject("IceEvent");
185 if (!fUseNames) UseTracks("IceDwalk",1);
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
194 cout << " *IcePandel* First guess selections to be processed (-1=all)." << endl;
195 for (Int_t i=0; i<nclasses; i++)
197 strx=(TObjString*)fUseNames->At(i);
199 str=strx->GetString();
200 ntkmax=fUseNtk->At(i);
201 cout << " Maximally " << ntkmax << " track(s) per event for procedure : " << str.Data() << endl;
203 cout << " *IcePandel* Hit selection mode : " << fSelhits << endl;
204 cout << " *IcePandel* Penalty value for minimiser : " << fPenalty << " dB." << endl;
209 Double_t pi=acos(-1.);
211 // Initialisation of the minimisation processor
212 Double_t arglist[100];
213 if (!fFitter) fFitter=new TFitter();
215 // The number of reconstructed tracks already present in the event
216 Int_t ntkreco=fEvt->GetNtracks(1);
220 fHits=new TObjArray();
227 // If selected, use all the good quality hits of the complete event
230 TObjArray* hits=fEvt->GetHits("IceGOM");
231 for (Int_t ih=0; ih<hits->GetEntries(); ih++)
233 AliSignal* sx=(AliSignal*)hits->At(ih);
235 if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
240 // Track by track processing of the selected first guess classes
243 Float_t margin,minmarg=25; // (minimal) margin for the fitter r0 search area
247 tkfit.SetNameTitle(fTrackname.Data(),"IcePandel fit result");
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
260 for (Int_t iclass=0; iclass<nclasses; iclass++) // Loop over first guess classes
262 strx=(TObjString*)fUseNames->At(iclass);
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;
270 for (Int_t jtk=0; jtk<ntk; jtk++) // Loop over tracks of a certain class
272 fTrack=(AliTrack*)tracks->At(jtk);
273 if (!fTrack) continue;
275 AliPosition* r0=fTrack->GetReferencePoint();
278 // If selected, use only the first guess track associated hits
282 nsig=fTrack->GetNsignals();
283 for (Int_t is=1; is<=nsig; is++)
285 AliSignal* sx=fTrack->GetSignal(is);
287 if (!sx->GetDevice()->InheritsFrom("IceGOM")) continue;
288 if (sx->GetDeadValue("ADC") || sx->GetDeadValue("LE") || sx->GetDeadValue("TOT")) continue;
293 if (!fHits->GetEntries()) continue;
295 r0->GetVector(vec,"car");
296 r0->GetErrors(err,"car");
302 if (margin<minmarg) margin=minmarg;
306 if (margin<minmarg) margin=minmarg;
310 if (margin<minmarg) margin=minmarg;
314 p=fTrack->Get3Momentum();
315 p.GetVector(vec,"sph");
319 thetamin=theta-(pi/3.);
320 if (thetamin<0) thetamin=0;
321 thetamax=theta+(pi/3.);
322 if (thetamax>pi) thetamax=pi;
326 // Process this first guess track with its associated hits
330 if (fPrint==-2) arglist[0]=-1;
331 fFitter->ExecuteCommand("SET PRINT",arglist,1);
332 if (fPrint==-2) fFitter->ExecuteCommand("SET NOWARNINGS",arglist,0);
334 fFitter->SetFitMethod("loglikelihood");
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);
342 fFitter->SetFCN(IcePandelFCN);
345 ier=fFitter->ExecuteCommand("MINIMIZE",arglist,0);
347 fFitter->GetStats(amin,edm,errdef,nvpar,nparx);
349 fitstats.SetSignal(ier,1);
350 fitstats.SetSignal(amin,2);
351 fitstats.SetSignal(edm,3);
352 fitstats.SetSignal(nvpar,4);
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");
365 vec[1]=fFitter->GetParameter(3);
366 vec[2]=fFitter->GetParameter(4);
368 err[1]=fFitter->GetParError(3);
369 err[2]=fFitter->GetParError(4);
370 p.SetVector(vec,"sph");
371 p.SetErrors(err,"sph");
373 // Enter the fit result as a track in the event structure
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++)
387 AliSignal* sx=(AliSignal*)fHits->At(ihit);
388 if (sx) tkfit.AddSignal(*sx);
390 fEvt->AddTrack(tkfit);
391 } // End loop over tracks
392 } // End loop over first guess classes
395 ///////////////////////////////////////////////////////////////////////////
396 void IcePandel::SetPrintLevel(Int_t level)
398 // Set the fitter (Minuit) print level.
399 // See the TFitter and TMinuit docs for details.
401 // Note : level=-2 suppresses also all fit processor warnings.
403 // The default in the constructor is level=-2.
407 ///////////////////////////////////////////////////////////////////////////
408 void IcePandel::UseTracks(TString classname,Int_t n)
410 // Specification of the first guess tracks to be used.
412 // classname : Specifies the first guess algorithm (e.g. "IceDwalk");
413 // n : Specifies the max. number of these tracks to be used
415 // Note : n<0 will use all the existing tracks of the specified classname
417 // The default is n=-1.
419 // Consecutive invokations of this memberfunction with different classnames
420 // will result in an incremental effect.
424 // UseTracks("IceDwalk",5);
425 // UseTracks("IceLfit",2);
426 // UseTracks("IceJams");
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.
433 fUseNames=new TObjArray();
434 fUseNames->SetOwner();
437 if (!fUseNtk) fUseNtk=new TArrayI();
439 // Check if this classname has already been specified before
441 Int_t nen=fUseNames->GetEntries();
442 for (Int_t i=0; i<nen; i++)
444 TObjString* sx=(TObjString*)fUseNames->At(i);
447 if (s==classname) return;
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);
454 TObjString* name=new TObjString();
455 name->SetString(classname);
456 fUseNames->Add(name);
457 fUseNtk->AddAt(n,nen);
459 ///////////////////////////////////////////////////////////////////////////
460 void IcePandel::SelectHits(Int_t mode)
462 // Specification of the hits to be used in the minimisation.
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
467 // The default is mode=1.
469 if (mode==0 || mode==1) fSelhits=mode;
471 ///////////////////////////////////////////////////////////////////////////
472 void IcePandel::SetTrackName(TString s)
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.
481 ///////////////////////////////////////////////////////////////////////////
482 void IcePandel::SetCharge(Float_t charge)
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.
490 ///////////////////////////////////////////////////////////////////////////
491 void IcePandel::SetPenalty(Float_t val)
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
496 // By default the penalty val=3 dB is set in the constructor of this class.
499 ///////////////////////////////////////////////////////////////////////////
500 void IcePandel::FitFCN(Int_t&,Double_t*,Double_t& f,Double_t* x,Int_t)
502 // The Pandel function used for the minimisation process.
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.);
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();
522 // The new r0 and p vectors from the minimisation
529 r0.SetPosition(vec,"car");
535 p.SetVector(vec,"sph");
537 Int_t nhits=fHits->GetEntries();
540 Float_t d,dist,thit,tgeo;
541 Double_t tres,zeta,pandel;
542 for (Int_t i=0; i<nhits; i++)
544 AliSignal* sx=(AliSignal*)fHits->At(i);
546 IceGOM* omx=(IceGOM*)sx->GetDevice();
548 rhit=omx->GetPosition();
549 d=fTrack->GetDistance(rhit);
553 dist=p.Dot(r12)+d*tan(thetac);
555 thit=sx->GetSignal("LE",7);
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)
564 pandel=-10.*((zeta*log10(rho))+((zeta-1.)*log10(tres))-(rho*tres*log10(e))-log10(TMath::Gamma(zeta)));
569 f+=fPenalty; // Penalty in case tres and/or zeta outside range
573 ///////////////////////////////////////////////////////////////////////////