08-feb-2003 NvE Class AliSignal modified such that the maximum number of signal slots is
[u/mrichter/AliRoot.git] / RALICE / AliCalcluster.cxx
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 // $Id$
17
18 ///////////////////////////////////////////////////////////////////////////
19 // Class AliCalcluster
20 // Description of a cluster of calorimeter modules.
21 // A 2D (matrix) geometry is assumed in which a cluster center is identified
22 // by two integer indices (i,j), e.g. row and column indicators.
23 //
24 // The 1st signal value is the signal of the complete cluster.
25 // This is the signal which is provided as default by invoking GetSignal().
26 //
27 // In case clustering/grouping of module signals was performed over several
28 // rings around the center (see e.g. AliCalorimeter::Group), the following
29 // additional information is provided by the various signal values :
30 //
31 // The 2nd signal value is the original signal of the central module.
32 // The 3rd signal value is the total signal within the 1st (i.e. 3x3) ring of
33 // modules around the cluster center.
34 // The 4th signal value is the total signal within the 2nd (i.e. 5x5) ring of
35 // modules around the cluster center.
36 // Etc....
37 //
38 // Note : In case the cluster consists of only 1 module, then only the
39 //        1st signal value will be present (for obvious reasons).
40 //
41 // Some dispersion info about cluster topology is provided in order
42 // to enable EM or hadronic cluster identification.
43 //
44 //--- Author: Nick van Eijndhoven 13-jun-1997 UU-SAP Utrecht
45 //- Modified: NvE $Date$ UU-SAP Utrecht
46 ///////////////////////////////////////////////////////////////////////////
47
48 #include "AliCalcluster.h"
49  
50 ClassImp(AliCalcluster) // Class implementation to enable ROOT I/O
51  
52 AliCalcluster::AliCalcluster()
53 {
54 // Default constructer, all data is set to 0
55  fCenter=0;
56  fNmods=0;
57  fRowdisp=0.;
58  fColdisp=0.;
59  fNvetos=0;
60  fVetos=0;
61  SetName("AliCalcluster [sig, sig11, sig33, sig55, ...]");
62 }
63 ///////////////////////////////////////////////////////////////////////////
64 AliCalcluster::~AliCalcluster()
65 {
66 // Destructor to delete dynamically allocated memory
67  if (fVetos)
68  {
69   delete fVetos;
70   fVetos=0;
71  }
72 }
73 ///////////////////////////////////////////////////////////////////////////
74 AliCalcluster::AliCalcluster(AliCalmodule& m)
75 {
76 // Cluster constructor with module m as center.
77 // Module data is only entered for a module which contains a signal,
78 // has not been used in a cluster yet, and is not declared dead.
79 //
80 // Note :
81 // It is advised NOT to start a cluster with modules situated at a detector edge.
82 // This feature is automatically checked when using the built-in clustering
83 // of AliCalorimeter.  
84
85  Ali3Vector r;
86
87  Float_t sig=m.GetClusteredSignal();
88
89  if (sig>0. && m.GetDeadValue()==0)
90  {
91   fCenter=&m;
92   r=m.GetPosition();
93   SetPosition(r);
94   SetSignal(sig);
95   fNmods=1;
96   fRowdisp=0.;
97   fColdisp=0.;
98   m.SetClusteredSignal(0.); // mark module as used in cluster
99   fNvetos=0;
100   fVetos=0;
101  }
102  else
103  {
104   fCenter=0;
105   SetPosition(r);
106   fNmods=0;
107   fRowdisp=0.;
108   fColdisp=0.;
109   fNvetos=0;
110   fVetos=0;
111  }
112  SetName("AliCalcluster [sig, sig11, sig33, sig55, ...]");
113 }
114 ///////////////////////////////////////////////////////////////////////////
115 Int_t AliCalcluster::GetRow()
116 {
117 // Provide the row number of the cluster center
118  if (fCenter)
119  {
120   return fCenter->GetRow();
121  }
122  else
123  {
124   return 0;
125  }
126 }
127 ///////////////////////////////////////////////////////////////////////////
128 Int_t AliCalcluster::GetColumn()
129 {
130 // Provide the column number of the cluster center
131  if (fCenter)
132  {
133   return fCenter->GetColumn();
134  }
135  else
136  {
137   return 0;
138  }
139 }
140 ///////////////////////////////////////////////////////////////////////////
141 Int_t AliCalcluster::GetNmodules()
142 {
143 // Provide the number of modules in the cluster
144  return fNmods;
145 }
146 ///////////////////////////////////////////////////////////////////////////
147 Float_t AliCalcluster::GetRowDispersion()
148 {
149 // Provide the normalised row dispersion of the cluster.
150  Float_t sig=GetSignal();
151  if (sig > 0.)
152  {
153   return fRowdisp/sig;
154  }
155  else
156  {
157   return 0.;
158  }
159 }
160 ///////////////////////////////////////////////////////////////////////////
161 Float_t AliCalcluster::GetColumnDispersion()
162 {
163 // Provide the normalised column dispersion of the cluster
164  Float_t sig=GetSignal();
165  if (sig > 0.)
166  {
167   return fColdisp/sig;
168  }
169  else
170  {
171   return 0.;
172  }
173 }
174 ///////////////////////////////////////////////////////////////////////////
175 void AliCalcluster::Start(AliCalmodule& m)
176 {
177 // Reset cluster data and start with module m.
178 // A module can only start a cluster when it contains a signal,
179 // has not been used in a cluster yet, and is not declared dead.
180 //
181 // Note :
182 // It is advised NOT to start a cluster with modules situated at a detector edge.
183 // This feature is automatically checked when using the built-in clustering
184 // of AliCalorimeter.  
185
186  AliSignal::Reset();
187
188  Ali3Vector r;
189
190  if (m.GetClusteredSignal()>0. && m.GetDeadValue()==0)
191  {
192   fCenter=&m;
193   r=m.GetPosition();
194   SetPosition(r);
195   SetSignal(m.GetSignal());
196   fNmods=1;
197   fRowdisp=0.;
198   fColdisp=0.;
199   m.SetClusteredSignal(0.); // mark module as used in cluster
200  }
201  else
202  {
203   fCenter=0;
204   SetPosition(r);
205   fNmods=0;
206   fRowdisp=0.;
207   fColdisp=0.;
208  }
209 }
210 ///////////////////////////////////////////////////////////////////////////
211 void AliCalcluster::Add(AliCalmodule& m)
212 {
213 // Add module data to the cluster.
214 // Dead modules are NOT added to the cluster.
215 // According to the distance of the module w.r.t. the cluster center
216 // the various signal values are updated.
217
218  if (fNmods)
219  {
220   Float_t sigm=m.GetClusteredSignal();
221  
222   if (sigm>0. && m.GetDeadValue()==0) // only add unused modules
223   {
224    Int_t drow=int(fabs(double(GetRow()-m.GetRow())));       // row distance to center
225    Int_t dcol=int(fabs(double(GetColumn()-m.GetColumn()))); // column distance to center 
226
227    // Determine the ring index for this module around the cluster center
228    Int_t jring=drow;
229    if (dcol>drow) jring=dcol;
230
231    Int_t nvalues=GetNvalues();
232
233    if ((jring+2)<=nvalues) // Module within existing ring(s) ==> Add module signal to the enclosing ring(s)
234    {
235     for (Int_t i=(jring+2); i<=nvalues; i++)
236     {
237      AddSignal(sigm,i);
238     }
239    }
240    else  // Module outside all existing rings ==> Init. new ring signals with existing enclosed signal(s)
241    {
242     for (Int_t j=(nvalues+1); j<=(jring+2); j++)
243     {
244      SetSignal(GetSignal(j-1),j);
245     }
246     // Add current module signal to the signal value for the corresponding ring
247     AddSignal(sigm,(jring+2));
248    }
249
250    // Update total cluster signal
251    AddSignal(sigm);
252  
253    fNmods+=1;
254    fRowdisp+=sigm*float(drow*drow);
255    fColdisp+=sigm*float(dcol*dcol);
256    m.SetClusteredSignal(0.); // mark module as used in cluster
257   }
258  }
259  else
260  {
261   cout << " *AliCalcluster::Add* No action. Cluster should be started first."
262        << endl;
263  }
264 }
265 ///////////////////////////////////////////////////////////////////////////
266 void AliCalcluster::AddVetoSignal(AliSignal& s,Int_t extr)
267 {
268 // Associate an (extrapolated) AliSignal as veto to the cluster.
269 // By default a straight line extrapolation is performed which extrapolates
270 // the signal position until the length of its position vector matches that
271 // of the position vector of the cluster.
272 // In this extrapolation procedure the error propagation is performed 
273 // automatically.  
274 // Based on the cluster and extrapolated veto signal (x,y) positions and
275 // position errors the confidence level of association is calculated
276 // and stored as an additional signal value.
277 // By means of the GetVetoSignal memberfunction the confidence level of
278 // association can always be updated by the user.
279 // In case the user wants to invoke a more detailed extrapolation procedure,
280 // the automatic extrapolation can be suppressed by setting the argument
281 // extr=0. In this case it is assumed that the AliSignal as entered via
282 // the argument contains already the extrapolated position vector and
283 // corresponding errors. 
284 // Note : Three additional values are added to the original AliSignal
285 //        to hold the chi2, ndf and confidence level values of the association. 
286  if (!fVetos)
287  {
288   fNvetos=0;
289   fVetos=new TObjArray();
290   fVetos->SetOwner();
291  } 
292
293  Int_t nvalues=s.GetNvalues();
294  AliSignal* sx=new AliSignal(nvalues+3); // Additional value added
295  TString name=s.GetName();
296  name.Append(" + additional chi2, ndf and CL values");
297  sx->SetName(name);
298
299  Double_t vecc[3],vecv[3];
300  if (!extr)
301  {
302   sx->SetPosition((Ali3Vector&)s);
303  }
304  else
305  {
306   // Extrapolate the veto hit position
307   Double_t scale=1;
308   GetPosition(vecc,"sph");
309   s.GetPosition(vecv,"sph"); 
310   if (vecv[0]) scale=vecc[0]/vecv[0];
311   Ali3Vector r=s*scale;
312   sx->SetPosition(r);
313  }
314
315  Double_t sig,err;
316  for (Int_t i=1; i<=nvalues; i++)
317  {
318   sig=s.GetSignal(i);
319   err=s.GetSignalError(i);
320   sx->SetSignal(sig,i);
321   sx->SetSignalError(err,i);
322  }
323
324  // Calculate the confidence level of association
325  GetPosition(vecc,"car");
326  sx->GetPosition(vecv,"car"); 
327  Double_t dx=vecc[0]-vecv[0];
328  Double_t dy=vecc[1]-vecv[1];
329  GetPositionErrors(vecc,"car");
330  sx->GetPositionErrors(vecv,"car"); 
331  Double_t sxc2=vecc[0]*vecc[0];
332  Double_t syc2=vecc[1]*vecc[1];
333  Double_t sxv2=vecv[0]*vecv[0];
334  Double_t syv2=vecv[1]*vecv[1];
335  Double_t sumx2=sxc2+sxv2;
336  Double_t sumy2=syc2+syv2;
337  Double_t chi2=0;
338  if (sumx2>0 && sumy2>0) chi2=(dx*dx/sumx2)+(dy*dy/sumy2);
339  Int_t ndf=2;
340  AliMath m;
341  Double_t prob=m.Prob(chi2,ndf);
342  if (chi2>0) sx->SetSignal(chi2,nvalues+1);
343  if (ndf>0) sx->SetSignal(ndf,nvalues+2);
344  if (prob>0) sx->SetSignal(prob,nvalues+3);
345
346  fVetos->Add(sx);
347  fNvetos++;
348 }
349 ///////////////////////////////////////////////////////////////////////////
350 Int_t AliCalcluster::GetNvetos()
351 {
352 // Provide the number of veto signals associated to the cluster
353  return fNvetos;
354 }
355 ///////////////////////////////////////////////////////////////////////////
356 AliSignal* AliCalcluster::GetVetoSignal(Int_t i)
357 {
358 // Provide access to the i-th veto signal of this cluster.
359 // Note : The first hit corresponds to i=1.
360  if (!fVetos)
361  {
362   cout << " *AliCalcluster::GetVetoSignal* No veto signals present." << endl;
363   return 0;
364  }
365  else
366  {
367   if (i>0 && i<=fNvetos)
368   {
369    return (AliSignal*)fVetos->At(i-1);
370   }
371   else
372   {
373    cout << " *AliCalcluster::GetVetoSignal* Signal number " << i << " out of range."
374         << " Nvetos = " << fNvetos << endl;
375    return 0;
376   }
377  }
378 }
379 ///////////////////////////////////////////////////////////////////////////
380 Float_t AliCalcluster::GetVetoLevel()
381 {
382 // Provide the confidence level of best associated veto signal.
383  Float_t cl=0;
384  Float_t clmax=0;
385  AliSignal* s=0;
386  Int_t nvalues=0;
387  if (fVetos)
388  {
389   for (Int_t i=0; i<fNvetos; i++)
390   {
391    s=((AliSignal*)fVetos->At(i));
392    if (s)
393    {
394     nvalues=s->GetNvalues();
395     cl=s->GetSignal(nvalues);
396     if (cl>clmax) clmax=cl;
397    }
398   }
399  }
400  return clmax;
401 }
402 ///////////////////////////////////////////////////////////////////////////
403 Int_t AliCalcluster::HasVetoHit(Double_t cl)
404 {
405 // Investigate if cluster has an associated veto hit with conf. level > cl.
406 // Returns 1 if there is such an associated veto hit, otherwise returns 0.
407 // Note : This function is faster than GetVetoLevel().
408  AliSignal* s=0;
409  Int_t nvalues=0;
410  if (fVetos)
411  {
412   for (Int_t i=0; i<fNvetos; i++)
413   {
414    s=((AliSignal*)fVetos->At(i));
415    if (s)
416    {
417     nvalues=s->GetNvalues();
418     if (s->GetSignal(nvalues) > cl) return 1;
419    }
420   }
421  }
422  return 0;
423 }
424 ///////////////////////////////////////////////////////////////////////////