]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RALICE/icepack/IceDwalk.cxx
3b457f35ad24cd3e83360f59b9b189f1263c658b
[u/mrichter/AliRoot.git] / RALICE / icepack / IceDwalk.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 IceDwalk
20 // TTask derived class to perform direct walk track reconstruction.
21 // The procedure is based on the method described in the Amanda publication
22 // in Nuclear Instruments and Methods A524 (2004) 179-180.
23 // However, the Amanda method has been extended with the intention to
24 // take also multiple (muon) tracks within 1 event into account.
25 // This will not only provide a means to reconstruct muon bundles and
26 // multiple track events in IceCube, but will also allow to reduce the
27 // background of faked upgoing muons as a result of multiple downgoing
28 // muons hitting the top and bottom parts of the detector. 
29 // The various reconstruction steps are summarised as follows :
30 //
31 // 1) Construction of track elements (TE's).
32 //    A track element is a straight line connecting two hits that
33 //    appeared at some minimum distance d and within some maximum
34 //    time difference dt.
35 //    The default values for d and dt are given in eq. (20) of the
36 //    NIM article, but can be modified by the appropriate Set functions.
37 //    For dt a default margin of 30 ns is used (according to eq. (20)),
38 //    but also this margin may be modified via the appropriate Set function.    
39 //    The reference point r0 of the TE is taken as the center between
40 //    the two hit positions and the TE timestamp t0 at the position r0
41 //    is taken as the IceEvent timestamp increased by the average of the
42 //    two hit times. So, all timestamps contain the overall IceEvent
43 //    timestamp as a basis. This means that time differences can be
44 //    obtained via the AliTimestamp facilities (supporting upto picosecond
45 //    precision when available).
46 //    The TE direction is given by the relative position of the two hits.
47 //
48 // 2) Each TE will obtain so called associated hits.
49 //    A hit is associated to a TE when it fulfills both the conditions
50 //
51 //      -30 < tres < 300 ns
52 //      dhit < 25*(tres+30)^(1/4) meter
53 //
54 //    tres : time residual
55 //           Difference between the observed hit time and the time expected
56 //           for a direct photon hit.     
57 //    dhit : Distance between the hit and the TE
58 //
59 // 3) Construction of track candidates (TC's).
60 //    These are TE's that fulfill both the conditions
61 //
62 //      nah >= 10
63 //      sigmal >= 20 meter
64 // 
65 //    nah    : Number of associated hits.
66 //    sigmal : rms variance of the distances between r0 and the point on
67 //             the track which is closest to the various associated hits. 
68 //
69 // 4) Only track candidates are kept which fulfill the quality criterion
70 //    (see eq. (21) in the NIM article)
71 //
72 //     qtc >= 0.7*qtcmax
73 //
74 //     qtc=min(nah,0.3*sigmal+7)
75 //     qtcmax=max(qtc)
76 //
77 // 5) The surviving track candidates are clustered into jets when
78 //    their directions are within a certain maximum opening angle.
79 //    The default maximum opening angle is 15 degrees, but can be modified
80 //    via the SetTangsep memberfunction.
81 //
82 // 6) The jets are merged when their directions are within
83 //    a certain maximum opening angle. 
84 //    The default maximum opening angle is half the TC maximum opening angle,
85 //    but can be modified via the SetJangsep memberfunction.
86 //    Note : Setting the maximum jet opening angle to <=0 will prevent
87 //           the merging of jets.
88 //
89 // 7) The remaining jets are ordered w.r.t. decreasing number of tracks.
90 //    Each remaining jet will provide the parameters (e.g. direction)
91 //    for a reconstructed track.
92 //    The track 3-momentum is set to the total jet 3-momentum, normalised
93 //    to 1 GeV. The mass and charge of the track are left 0.
94 //    The average of all the r0 and t0 values of the constituent TC's
95 //    of the jet will provide the r0 and t0 of the track.
96 //    All these tracks will be stored in the IceEvent structure with "IceDwalk"
97 //    as the name of the track.
98 //    Note : In case the maximum jet opening angle was specified <0,
99 //           only the jet with the maximum number of tracks will appear
100 //           as a reconstructed track in the IceEvent structure.
101 //           This will allow comparison with the standard Sieglinde
102 //           single track direct walk reconstruction results. 
103 //    
104 // For further details the user is referred to NIM A524 (2004) 169.
105 //
106 // Note : This algorithm works best on data which has been calibrated
107 //        (IceCalibrate), cross talk corrected (IceXtalk) and cleaned
108 //        from noise hits etc. (IceCleanHits).
109 //
110 //--- Author: Nick van Eijndhoven 07-oct-2005 Utrecht University
111 //- Modified: NvE $Date$ Utrecht University
112 ///////////////////////////////////////////////////////////////////////////
113  
114 #include "IceDwalk.h"
115 #include "Riostream.h"
116
117 ClassImp(IceDwalk) // Class implementation to enable ROOT I/O
118
119 IceDwalk::IceDwalk(const char* name,const char* title) : TTask(name,title)
120 {
121 // Default constructor.
122 // The various reconstruction parameters are initialised to the values
123 // as mentioned in NIM A524 (2004) 179-180.
124 // The newly introduced angular separation parameter for jet merging
125 // is initialised as half the value of the angular separation parameter
126 // for track candidate clustering.    
127  fDmin=50;
128  fDtmarg=30;
129  fTangsep=15;
130  fJangsep=fTangsep/2.;
131 }
132 ///////////////////////////////////////////////////////////////////////////
133 IceDwalk::~IceDwalk()
134 {
135 // Default destructor.
136 }
137 ///////////////////////////////////////////////////////////////////////////
138 void IceDwalk::SetDmin(Float_t d)
139 {
140 // Set minimum hit distance (in m) to form a track element.
141 // In the constructor the default has been set to 50 meter, in accordance
142 // to eq.(20) of NIM A524 (2004) 179.
143  fDmin=d;
144 }
145 ///////////////////////////////////////////////////////////////////////////
146 void IceDwalk::SetDtmarg(Int_t dt)
147 {
148 // Set maximum hit time difference margin (in ns) for track elements.
149 // In the constructor the default has been set to 30 ns, in accordance
150 // to eq.(20) of NIM A524 (2004) 179.
151  fDtmarg=dt;
152 }
153 ///////////////////////////////////////////////////////////////////////////
154 void IceDwalk::SetTangsep(Float_t ang)
155 {
156 // Set angular separation (in deg) within which track candidates are
157 // clustered into jets.
158 // In the constructor the default has been set to 15 deg, in accordance
159 // to NIM A524 (2004) 180.
160 //
161 // Note : This function also sets automatically the value of the angular
162 //        separation within which jets are merged into 1 single track
163 //        to ang/2.
164 //        In order to specify a different jet merging separation angle,
165 //        one has to invoke the memberfunction SetJangsep afterwards.
166  
167  fTangsep=ang;
168  fJangsep=ang/2.;
169 }
170 ///////////////////////////////////////////////////////////////////////////
171 void IceDwalk::SetJangsep(Float_t ang)
172 {
173 // Set angular separation (in deg) within which jets are merged into 1
174 // single track.
175 // In the constructor the default has been set 7.5 deg, being half of the
176 // value of the default track candidate clustering separation angle. 
177 //
178 // Notes :
179 // -------
180 // 1)  Setting ang=0 will prevent jet merging.
181 //     Consequently, every jet will appear as a separate track in the
182 //     reconstruction result.  
183 // 2)  Setting ang<0 will prevent jet merging.
184 //     In addition, only the jet with the maximum number of tracks will
185 //     appear as a track in the reconstruction result.
186 //     This situation resembles the standard Sieglinde direct walk processing
187 //     and as such can be used to perform comparison studies.
188
189  fJangsep=ang;
190 }
191 ///////////////////////////////////////////////////////////////////////////
192 void IceDwalk::Exec(Option_t* opt)
193 {
194 // Implementation of the direct walk track reconstruction.
195
196  TString name=opt;
197  AliJob* parent=(AliJob*)(gROOT->GetListOfTasks()->FindObject(name.Data()));
198
199  if (!parent) return;
200
201  IceEvent* evt=(IceEvent*)parent->GetObject("IceEvent");
202  if (!evt) return;
203
204  Float_t c=0.3;                // Light speed in vacuum in meters per ns
205  Float_t nice=1.33;            // Refractive index of ice
206  Float_t thetac=acos(1./nice); // Cherenkov angle (in radians)
207
208  // Storage of track elements with various time difference margins.
209  // temap(i,j) holds the i-th track element (TE) with a time difference margin
210  // of j*3 nanoseconds. Currently we use a maximum margin of 30 ns.
211  TObjArray tes;
212  tes.SetOwner();
213  AliObjMatrix temap;
214
215  Int_t* ntes=new Int_t[fDtmarg/3]; // Counter of TEs for each 3 ns margin slot
216  for (Int_t i=0; i<fDtmarg/3; i++)
217  {
218   ntes[i]=0;
219  }  
220
221  AliPosition r1;
222  AliPosition r2;
223  Ali3Vector r12;
224  Ali3Vector rsum;
225  AliPosition r0;
226  TObjArray hits1;
227  TObjArray hits2;
228  Int_t nh1,nh2;
229  AliSignal* sx1=0;
230  AliSignal* sx2=0;
231  Float_t dist=0;
232  Float_t t1,t2,dt,t0;
233  Float_t dtmax,dttest;
234  TObjArray hits;
235
236  // Check the hits of Amanda OM pairs for posible track elements.
237  // Also all the good hits are stored in the meantime (to save CPU time)
238  // for hit association with the various track elements lateron.
239  TObjArray* aoms=evt->GetDevices("IceAOM");
240  Int_t naoms=aoms->GetEntries();
241  AliTrack* te=0;
242  Int_t ite=0;
243  for (Int_t i1=0; i1<naoms; i1++) // First OM of the pair
244  {
245   IceGOM* omx1=(IceGOM*)aoms->At(i1);
246   if (!omx1) continue;
247   if (omx1->GetDeadValue("LE")) continue;
248   r1=omx1->GetPosition();
249   // Select all the good hits of this first OM
250   hits1.Clear();
251   for (Int_t j1=1; j1<=omx1->GetNhits(); j1++)
252   {
253    sx1=omx1->GetHit(j1);
254    if (!sx1) continue;
255    if (sx1->GetDeadValue("ADC") || sx1->GetDeadValue("LE") || sx1->GetDeadValue("TOT")) continue;
256    hits1.Add(sx1);
257    // Also store all good hits in the total hit array
258    hits.Add(sx1);
259   }
260
261   // No further pair to be formed with the last OM in the list 
262   if (i1==(naoms-1)) break;
263
264   nh1=hits1.GetEntries();
265   if (!nh1) continue;
266
267   for (Int_t i2=i1+1; i2<naoms; i2++) // Second OM of the pair
268   {
269    IceGOM* omx2=(IceGOM*)aoms->At(i2);
270    if (!omx2) continue;
271    if (omx2->GetDeadValue("LE")) continue;
272    r2=omx2->GetPosition();
273    r12=r2-r1;
274    dist=r12.GetNorm();
275    dtmax=dist/c+float(fDtmarg);
276    if (dist<=fDmin) continue;
277    // Select all the good hits of this second OM
278    hits2.Clear();
279    for (Int_t j2=1; j2<=omx2->GetNhits(); j2++)
280    {
281     sx2=omx2->GetHit(j2);
282     if (!sx2) continue;
283     if (sx2->GetDeadValue("ADC") || sx2->GetDeadValue("LE") || sx2->GetDeadValue("TOT")) continue;
284     hits2.Add(sx2);
285    }
286  
287    nh2=hits2.GetEntries();
288    if (!nh2) continue;
289
290    // Check all hit pair combinations of these two OMs for possible track elements  
291    for (Int_t ih1=0; ih1<nh1; ih1++) // Hits of first OM
292    {
293     sx1=(AliSignal*)hits1.At(ih1);
294     if (!sx1) continue;
295     for (Int_t ih2=0; ih2<nh2; ih2++) // Hits of second OM
296     {
297      sx2=(AliSignal*)hits2.At(ih2);
298      if (!sx2) continue;
299      t1=sx1->GetSignal("LE",7);
300      t2=sx2->GetSignal("LE",7);
301      dt=t2-t1;
302      t0=(t1+t2)/2.;
303      if (dt && fabs(dt)<dtmax)
304      {
305       te=new AliTrack();
306       tes.Add(te);
307       ite++;
308       if (dt<0) r12*=-1.;
309       rsum=(r1+r2)/2.;
310       r0.SetPosition((Ali3Vector&)rsum);
311       te->SetReferencePoint(r0);
312       te->SetTimestamp((AliTimestamp&)*evt);
313       AliTimestamp* tsx=te->GetTimestamp();
314       tsx->Add(0,0,(int)t0);
315       r12/=r12.GetNorm();
316       te->Set3Momentum(r12);
317       dttest=dtmax;
318       for (Int_t jt=fDtmarg/3; jt>0; jt--)
319       {
320        if (fabs(dt)>=dttest) break;
321        temap.EnterObject(ite,jt,te);
322        ntes[jt-1]++;
323        dttest-=3.;
324       }
325      }
326     }
327    }
328   } // end of loop over the second OM of the pair
329  } // end of loop over first OM of the pair
330
331  // Association of hits to the various track elements
332  // For the time being all track elements will be treated,
333  // but in a later stage one could select only the TE's of a certain
334  // 3 ns margin slot in the TE map to save CPU time.
335  Int_t nte=tes.GetEntries();
336  Int_t nh=hits.GetEntries();
337  Float_t d=0;
338  Ali3Vector p;
339  Float_t tgeo,tres;
340  AliSample levers;  // Statistics of the assoc. hit lever arms
341  AliSignal fit;     // Storage of Q value etc... for each track candidate
342  fit.SetSlotName("QTC",1);
343  fit.SetSlotName("SIGMAL",2);
344  Float_t qtc=0,qmax=0;
345  Int_t nah;      // Number of associated hits for a certain TE
346  Float_t sigmal; // The mean lever arm of the various associated hits
347  for (Int_t jte=0; jte<nte; jte++)
348  {
349   te=(AliTrack*)tes.At(jte);
350   if (!te) continue;
351   p=te->Get3Momentum();
352   AliTimestamp* tt0=te->GetTimestamp();
353   t0=evt->GetDifference(tt0,"ns");
354   AliPosition* tr0=te->GetReferencePoint();
355   levers.Reset();
356   for (Int_t jh=0; jh<nh; jh++)
357   {
358    sx1=(AliSignal*)hits.At(jh);
359    if (!sx1) continue;
360    IceGOM* omx=(IceGOM*)sx1->GetDevice();
361    if (!omx) continue;
362    r1=omx->GetPosition();
363    d=tr0->GetDistance(r1);
364    d*=sin(thetac);
365    r12=r1-(*tr0);
366    dist=p.Dot(r12)+d*tan(thetac);
367    tgeo=t0+dist/c;
368    t1=sx1->GetSignal("LE",7);
369    tres=t1-tgeo;
370
371    if (tres<-30 || tres>300 || d>25.*pow(tres+30.,0.25)) continue;
372
373    // Associate this hit to the TE
374    te->AddSignal(*sx1);
375    levers.Enter(d/tan(thetac));
376   }
377   // Quality check of the various TE's.
378   // Survivors will be called track candidates (TC's)
379   // and their Q quality value will be determined.
380   nah=te->GetNsignals();
381   sigmal=levers.GetSigma(1);
382   if (nah<10 || sigmal<20)  // Remove the TE's of poor quality
383   {
384    temap.RemoveObjects(te);
385    tes.RemoveAt(jte);
386    delete te;
387   }
388   else // Specify the Q factor for this TC
389   {
390    qtc=0.3*sigmal+7.;
391    if (qtc>nah) qtc=nah;
392    fit.SetSignal(qtc,"QTC");
393    fit.SetSignal(sigmal,"SIGMAL");
394    te->SetFitDetails(fit);
395    if (qtc>qmax) qmax=qtc;
396   }
397  }
398  tes.Compress();
399  nte=tes.GetEntries();
400
401  // Perform selection on Q value in case of multiple track candidates
402  for (Int_t jtc=0; jtc<nte; jtc++)
403  {
404   te=(AliTrack*)tes.At(jtc);
405   if (!te) continue;
406   sx1=(AliSignal*)te->GetFitDetails();
407   if (!sx1) continue;
408   qtc=sx1->GetSignal("QTC");
409   if (qtc<0.7*qmax)
410   {
411    temap.RemoveObjects(te);
412    tes.RemoveAt(jtc);
413    delete te;
414   }
415  } 
416  tes.Compress();
417  nte=tes.GetEntries();
418
419  // Exit in case no track candidates are left
420  if (!nte)
421  {
422   if (ntes) delete [] ntes;
423   return;
424  }
425
426  // Cluster track candidates within a certain opening angle into jets. 
427  TObjArray jets;
428  jets.SetOwner();
429  AliTrack* te2=0;
430  Float_t ang=0;
431  for (Int_t jtc1=0; jtc1<nte; jtc1++)
432  {
433   te=(AliTrack*)tes.At(jtc1);
434   if (!te) continue;
435   AliJet* jx=new AliJet();
436   jx->AddTrack(te);
437   jets.Add(jx);
438   for (Int_t jtc2=0; jtc2<nte; jtc2++)
439   {
440    te2=(AliTrack*)tes.At(jtc2);
441    if (!te2) continue;
442    ang=te->GetOpeningAngle(*te2,"deg");
443    if (ang<fTangsep) jx->AddTrack(te2);
444   }
445  }
446
447  // Order the jets w.r.t. decreasing number of tracks
448  TObjArray* ordered=evt->SortJets(-1,&jets);
449  TObjArray jets2(*ordered);
450  Int_t njets=jets2.GetEntries();
451
452  // Merge jets within a certain opening to provide the final track(s).
453  AliJet* jx1=0;
454  AliJet* jx2=0;
455  if (fJangsep>0)
456  {
457   for (Int_t jet1=0; jet1<njets; jet1++)
458   {
459    jx1=(AliJet*)jets2.At(jet1);
460    if (!jx1) continue;
461    for (Int_t jet2=jet1+1; jet2<njets; jet2++)
462    {
463     jx2=(AliJet*)jets2.At(jet2);
464     if (!jx2) continue;
465     ang=jx1->GetOpeningAngle(*jx2,"deg");
466     if (ang<fJangsep)
467     {
468      for (Int_t jtk=1; jtk<=jx2->GetNtracks(); jtk++)
469      {
470       te=jx2->GetTrack(jtk);
471       if (!te) continue;
472       jx1->AddTrack(te);
473      }
474      jets2.RemoveAt(jet2);    
475     }
476    }
477   }
478   jets2.Compress();
479   njets=jets2.GetEntries();
480  }
481
482  // Store every jet as a reconstructed track in the event structure.
483  // The jet 3-momentum (normalised to 1) and the average r0 and t0
484  // of the constituent tracks will make up the final track parameters.
485  // All the associated hits of all the constituent tracks of the jet
486  // will be associated to the final track.
487  // In case the jet angular separation was set <0, only the jet with
488  // the maximum number of tracks (i.e. the first one in the array)
489  // will be used to form a track. This will allow comparison with
490  // the standard Sieglinde processing.
491  AliSample pos;
492  AliSample time;
493  AliPosition* ref=0;
494  AliTrack t; 
495  t.SetNameTitle("IceDwalk","Direct walk track");
496  t.SetTimestamp((AliTimestamp&)*evt);
497  Float_t vec[3],err[3];
498  for (Int_t jet=0; jet<njets; jet++)
499  {
500   AliJet* jx=(AliJet*)jets2.At(jet);
501   if (!jx) continue;
502   evt->AddTrack(t);
503   AliTrack* trk=evt->GetTrack(evt->GetNtracks());
504   if (!trk) continue;
505   trk->SetId(evt->GetNtracks(1)+1);
506   p=jx->Get3Momentum();
507   p/=p.GetNorm();
508   trk->Set3Momentum(p);
509   pos.Reset();
510   time.Reset();
511   for (Int_t jt=1; jt<=jx->GetNtracks(); jt++)
512   {
513    AliTrack* tx=jx->GetTrack(jt);
514    if (!tx) continue;
515    AliTimestamp* tsx=tx->GetTimestamp();
516    t0=evt->GetDifference(tsx,"ns");
517    time.Enter(t0);
518    ref=tx->GetReferencePoint();
519    if (ref)
520    {
521     ref->GetPosition(vec,"car");
522     pos.Enter(vec[0],vec[1],vec[2]);
523    }
524    for (Int_t is=1; is<=tx->GetNsignals(); is++)
525    {
526     sx1=tx->GetSignal(is);
527     if (sx1) sx1->AddLink(trk);
528    }
529   }
530   for (Int_t k=1; k<=3; k++)
531   {
532    vec[k-1]=pos.GetMean(k);
533    err[k-1]=pos.GetSigma(k);
534   }
535   r0.SetPosition(vec,"car");
536   r0.SetPositionErrors(err,"car");
537   t0=time.GetMean(1);
538   AliTimestamp* tt0=trk->GetTimestamp();
539   tt0->Add(0,0,(int)t0);
540   trk->SetReferencePoint(r0);
541
542   // Only take the jet with the maximum number of tracks
543   // (i.e. the first jet in the list) when the user had selected
544   // this reconstruction mode.
545   if (fJangsep<0) break;
546  }
547
548  if (ntes) delete [] ntes;
549 }
550 ///////////////////////////////////////////////////////////////////////////