df4711185d4a5cf444675e386878396886944412
[u/mrichter/AliRoot.git] / RALICE / AliCalorimeter.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 AliCalorimeter
20 // Description of a modular calorimeter system.
21 // A generic 2D geometry is used in which a module is identified by (row,col).
22 // Obviously this geometry can be a matrix, but also any other regular
23 // structure is supported, provided the user has adopted a proper convention
24 // to uniquely address a module via the (row,col) indices.  
25 // Note : First module is identified as (1,1).
26 //
27 // This is the way to define and enter signals into a calorimeter :
28 //
29 //   AliCalorimeter cal;
30 //
31 //   cal.AddSignal(5,7,85.4);
32 //   cal.AddSignal(5,7,25.9);
33 //   cal.AddSignal(3,5,1000);
34 //   cal.SetSignal(5,7,10.3);
35 //   cal.Reset(3,5);             // Reset module (3,5) as being 'not fired'
36 //                               // All module data are re-initialised.
37 //   cal.SetEdgeOn(1,1);         // Declare module (1,1) as an 'edge module'
38 //   cal.SetDead(8,3);
39 //   cal.SetGain(2,8,3.2);
40 //
41 //   Float_t vec[3]={6,1,20};
42 //   cal.SetPosition(2,8,vec,"car");
43 //
44 //   AliSignal s;
45 //   Float_t loc[3]={-1,12,3};
46 //   s.SetPosition(loc,"car");
47 //   s.SetSignal(328);
48 //   cal.AddVetoSignal(s); // Associate (extrapolated) signal as a veto
49 //
50 //   cal.Group(2);      // Group 'fired' modules into clusters
51 //                      // Perform grouping over 2 rings around the center
52 //   cal.Reset();       // Reset the complete calorimeter
53 //                      // Normally to prepare for the next event data
54 //                      // Note : Module gain, offset, edge and dead flags remain
55 //
56 //--- Author: Nick van Eijndhoven 13-jun-1997 UU-SAP Utrecht
57 //- Modified: NvE $Date$ UU-SAP Utrecht
58 ///////////////////////////////////////////////////////////////////////////
59
60 #include "AliCalorimeter.h"
61 #include "Riostream.h"
62
63 ClassImp(AliCalorimeter) // Class implementation to enable ROOT I/O
64  
65 AliCalorimeter::AliCalorimeter() : TNamed()
66 {
67 // Default constructor, all parameters set to 0.
68 // Create a calorimeter module matrix with fixed row and column size.
69 // Note : Due to the dynamic size extension when signals are set,
70 //        the  "edge modules" can NOT be marked automatically.
71 //        This has to be done manually by the user via the SetEdgeOn() 
72 //        memberfunction.
73  fNrows=0;
74  fNcolumns=0;
75  fSwap=0;
76  fMatrix=0;
77  fClusters=0;
78  fHmodules=0;
79  fHclusters=0;
80  fVetos=0;
81  fAttributes=0;
82  fPositions=0;
83  SetName("Unspecified");
84  SetTitle("Unspecified");
85 }
86 ///////////////////////////////////////////////////////////////////////////
87 AliCalorimeter::~AliCalorimeter()
88 {
89 // Destructor to delete memory allocated to the various arrays and matrices
90  if (fClusters)
91  {
92   delete fClusters;
93   fClusters=0;
94  }
95  if (fVetos)
96  {
97   delete fVetos;
98   fVetos=0;
99  }
100  if (fHmodules)
101  {
102   delete fHmodules;
103   fHmodules=0;
104  }
105  if (fHclusters)
106  {
107   delete fHclusters;
108   fHclusters=0;
109  }
110  if (fMatrix)
111  {
112   delete fMatrix;
113   fMatrix=0;
114  }
115  if (fPositions)
116  {
117   delete fPositions;
118   fPositions=0;
119  }
120  if (fAttributes)
121  {
122   delete fAttributes;
123   fAttributes=0;
124  }
125 }
126 ///////////////////////////////////////////////////////////////////////////
127 AliCalorimeter::AliCalorimeter(Int_t nrow,Int_t ncol) : TNamed()
128 {
129 // Create a calorimeter module matrix with fixed row and column size.
130 // The modules at the edges are automatically marked as "edge modules".
131  fNrows=nrow;
132  fNcolumns=ncol;
133  fClusters=0;
134
135  fSwap=0;
136  fMatrix=0;
137  fPositions=0;
138
139  fAttributes=new TObjArray(nrow);
140  fAttributes->SetOwner();
141  
142  // Mark the edge modules
143  for (Int_t row=1; row<=nrow; row++)
144  {
145   AliAttribObj* a=new AliAttribObj();
146   if (row==1 || row==nrow)
147   {
148    for (Int_t col=1; col<=ncol; col++)
149    {
150     a->SetEdgeOn(col);
151    }
152   }
153   else
154   {
155    a->SetEdgeOn(1);
156    a->SetEdgeOn(ncol);
157   }
158   fAttributes->Add(a);
159  }
160  
161  fHmodules=0;
162  fHclusters=0;
163
164  fVetos=0;
165
166  SetName("Unspecified");
167  SetTitle("Unspecified");
168 }
169 ///////////////////////////////////////////////////////////////////////////
170 AliCalorimeter::AliCalorimeter(AliCalorimeter& c) : TNamed(c)
171 {
172 // Copy constructor
173  fClusters=0;
174  fVetos=0;
175
176  fAttributes=0;
177
178  fHmodules=0;
179  fHclusters=0;
180
181  fMatrix=0;
182  fPositions=0;
183
184  fNrows=c.fNrows;
185  fNcolumns=c.fNcolumns;
186
187  fSwap=c.fSwap;
188
189  if (c.fPositions)
190  {
191   Int_t nrows=(c.fPositions)->GetMaxRow();
192   Int_t ncols=(c.fPositions)->GetMaxColumn();
193   for (Int_t irow=1; irow<=nrows; irow++)
194   {
195    for (Int_t icol=1; icol<=ncols; icol++)
196    {
197     AliPosition* p=c.GetPosition(irow,icol);
198     if (p) SetPosition(irow,icol,*p);
199    } 
200   }  
201  }
202
203  Int_t size=0;
204  if (c.fAttributes) size=c.fAttributes->GetSize();
205  if (size)
206  {
207   fAttributes=new TObjArray(size);
208   fAttributes->SetOwner();
209   for (Int_t ia=0; ia<size; ia++)
210   {
211    AliAttribObj* a=(AliAttribObj*)(c.fAttributes->At(ia));
212    if (a) fAttributes->AddAt(new AliAttribObj(*a),ia);
213   }
214  }
215
216  Int_t n=0;
217  n=c.GetNclusters();
218  if (n)
219  {
220   fClusters=new TObjArray();
221   fClusters->SetOwner();
222   for (Int_t icl=1; icl<=n; icl++)
223   {
224    AliCalcluster* cl=c.GetCluster(icl);
225    if (cl) fClusters->Add(new AliCalcluster(*cl));
226   }
227  }
228
229  n=c.GetNsignals();
230  if (n)
231  {
232   fMatrix=new AliObjMatrix();
233   fMatrix->SetOwner();
234   fMatrix->SetSwapMode(fSwap);
235   for (Int_t im=1; im<=n; im++)
236   {
237    AliCalmodule* m=c.GetModule(im);
238    if (m) fMatrix->EnterObject(m->GetRow(),m->GetColumn(),new AliCalmodule(*m));
239   }
240  }
241
242  n=c.GetNvetos();
243  for (Int_t iv=1; iv<=n; iv++)
244  {
245   AliSignal* s=c.GetVetoSignal(iv);
246   if (s) AddVetoSignal(s);
247  }
248 }
249 ///////////////////////////////////////////////////////////////////////////
250 Int_t AliCalorimeter::GetNrows()
251 {
252 // Provide the number of rows for the calorimeter module matrix
253  Int_t nrows=fNrows;
254  if (fMatrix && !nrows) nrows=fMatrix->GetMaxRow();
255  return nrows;
256 }
257 ///////////////////////////////////////////////////////////////////////////
258 Int_t AliCalorimeter::GetNcolumns()
259 {
260 // Provide the number of columns for the calorimeter module matrix
261  Int_t ncols=fNcolumns;
262  if (fMatrix && !ncols) ncols=fMatrix->GetMaxColumn();
263  return ncols;
264 }
265 ///////////////////////////////////////////////////////////////////////////
266 void AliCalorimeter::SetSignal(Int_t row,Int_t col,Float_t sig)
267 {
268 // Set the signal for a certain calorimeter module.
269
270  // Check for (row,col) boundaries.
271  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
272  {
273   cout << " *AliCalorimeter::SetSignal* row,col : " << row << "," << col
274        << " out of range." << endl;
275   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
276   return;
277  }
278  
279  if (!fMatrix)
280  {
281   fMatrix=new AliObjMatrix();
282   fMatrix->SetOwner();
283   fMatrix->SetSwapMode(fSwap);
284  }
285
286  AliCalmodule* m=GetModule(row,col);
287  if (!m) // initialise for a new module
288  {
289   m=new AliCalmodule();
290   m->SetRow(row);
291   m->SetColumn(col);
292   AliPosition* r=0;
293   if (fPositions) r=(AliPositionObj*)fPositions->GetObject(row,col);
294   if (r) m->SetPosition(*r);
295   if (fAttributes)
296   {
297    AliAttribObj* a=0;
298    if (row <= fAttributes->GetSize()) a=(AliAttribObj*)fAttributes->At(row-1);
299    if (a)
300    {
301     if (a->GetGainFlag(col)) m->SetGain(a->GetGain(col));
302     if (a->GetOffsetFlag(col)) m->SetOffset(a->GetOffset(col));
303     if (a->GetDeadValue(col)) m->SetDead();
304     if (a->GetEdgeValue(col)) m->SetEdgeValue(a->GetEdgeValue(col));
305    }
306   }
307   fMatrix->EnterObject(row,col,m);
308  }
309
310  m->SetSignal(sig);
311 }
312 ///////////////////////////////////////////////////////////////////////////
313 void AliCalorimeter::AddSignal(Int_t row, Int_t col, Float_t sig)
314 {
315 // Add the signal to a certain calorimeter module.
316
317  // Check for (row,col) boundaries.
318  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
319  {
320   cout << " *AliCalorimeter::AddSignal* row,col : " << row << "," << col
321        << " out of range." << endl;
322   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
323   return;
324  }
325  
326   AliCalmodule* m=GetModule(row,col);
327   if (!m) // initialise for new modules
328   {
329    SetSignal(row,col,sig);
330   }
331   else
332   {
333    m->AddSignal(sig);
334   }
335 }
336 ///////////////////////////////////////////////////////////////////////////
337 void AliCalorimeter::AddSignal(AliCalmodule* mod)
338 {
339 // Add the signal of module mod to the current calorimeter data.
340 // This enables mixing of calorimeter data of various events.
341 //
342 // Note : The position and attributes according to the user provided data
343 //        for the corresponding (row,col) location will be used.
344 //        In case there is no user provided data present, the position and
345 //        attributes of the first module added to the corresponding (row,col)
346 //        location will be taken, except for the "edge" and "dead" indicators.
347 //        The latter will then both be set to 0.
348
349  if (!mod) return;
350  
351  Int_t row=mod->GetRow();
352  Int_t col=mod->GetColumn();
353  Float_t sig=mod->GetSignal();
354
355  // Check for (row,col) boundaries.
356  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
357  {
358   cout << " *AliCalorimeter::AddSignal* row,col : " << row << "," << col
359        << " out of range." << endl;
360   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
361   return;
362  }
363  
364  if (!fMatrix)
365  {
366   fMatrix=new AliObjMatrix();
367   fMatrix->SetOwner();
368   fMatrix->SetSwapMode(fSwap);
369  }
370
371  AliCalmodule* m=GetModule(row,col);
372  if (!m) // No module existed yet at this position
373  {
374   m=new AliCalmodule(*mod);
375   AliPosition* r=0;
376   if (fPositions) r=(AliPositionObj*)fPositions->GetObject(row,col);
377   if (r) m->SetPosition(*r);
378   // Don't take the dead and edge attributes from this module,
379   // but from the calorimeter dbase, if present.
380   m->SetEdgeOff();
381   m->SetAlive();
382   if (fAttributes)
383   {
384    AliAttribObj* a=0;
385    if (row <= fAttributes->GetSize()) a=(AliAttribObj*)fAttributes->At(row-1);
386    if (a)
387    {
388     if (a->GetGainFlag(col)) m->SetGain(a->GetGain(col));
389     if (a->GetOffsetFlag(col)) m->SetOffset(a->GetOffset(col));
390     if (a->GetDeadValue(col)) m->SetDead();
391     if (a->GetEdgeValue(col)) m->SetEdgeValue(a->GetEdgeValue(col));
392    }
393   }
394   fMatrix->EnterObject(row,col,m);
395  }
396  else
397  {
398   m->AddSignal(sig);
399  }
400 }
401 ///////////////////////////////////////////////////////////////////////////
402 void AliCalorimeter::Reset(Int_t row,Int_t col)
403 {
404 // Reset the signal for a certain calorimeter module.
405 // Note : Module position and attributes remain unchanged.
406
407  // Check for (row,col) boundaries.
408  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
409  {
410   cout << " *AliCalorimeter::Reset* row,col : " << row << "," << col
411        << " out of range." << endl;
412   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
413   return;
414  }
415  
416  AliCalmodule* m=GetModule(row,col);
417  if (m) fMatrix->RemoveObject(row,col);
418 }
419 ///////////////////////////////////////////////////////////////////////////
420 void AliCalorimeter::Reset(Int_t mode)
421 {
422 // Reset the signals for the complete calorimeter.
423 // Normally this is done to prepare for the data of the next event.
424 //
425 // mode = 0 : Swap mode, module positions and attributes remain unchanged.
426 //        1 : Swap mode, module positions and attributes are cleared.
427 //
428 // The default is mode=0.
429 //
430 // Note : In the case of reading AliCalorimeter objects from a data file,
431 //        one has to reset the AliCalorimeter object with mode=1
432 //        (or explicitly delete it) before reading-in the next object
433 //        in order to prevent memory leaks.
434
435  if (mode<0 || mode>1)
436  {
437   cout << " *AliCalorimeter::Reset* Wrong argument. mode = " << mode << endl;
438   return;
439  }
440
441  if (fClusters)
442  {
443   delete fClusters;
444   fClusters=0;
445  }
446
447  if (fVetos)
448  {
449   delete fVetos;
450   fVetos=0;
451  }
452
453  if (mode==1)
454  {
455   if (fMatrix)
456   {
457    delete fMatrix;
458    fMatrix=0;
459   }
460   if (fPositions)
461   {
462    delete fPositions;
463    fPositions=0;
464   }
465  }
466  else
467  {
468   if (fMatrix) fMatrix->Reset();
469  }
470
471  // Free memory allocated for the various arrays.
472  if (mode==1)
473  {
474   if (fAttributes)
475   {
476    delete fAttributes;
477    fAttributes=0;
478   }
479   if (fHmodules)
480   {
481    delete fHmodules;
482    fHmodules=0;
483   }
484   if (fHclusters)
485   {
486    delete fHclusters;
487    fHclusters=0;
488   }
489  }
490 }
491 ///////////////////////////////////////////////////////////////////////////
492 Float_t AliCalorimeter::GetSignal(Int_t row,Int_t col,Int_t mode)
493 {
494 // Provide the signal of a certain calorimeter module.
495 // In case the module was marked dead, 0 is returned.
496 //
497 // mode = 0 : Just the module signal is returned
498 //        1 : The module signal is corrected for the gain and offset.
499 //            In case the gain value was not set, gain=1 will be assumed.
500 //            In case the gain value was 0, a signal value of 0 is returned.
501 //            In case the offset value was not set, offset=0 will be assumed.
502 //
503 // The corrected signal (sigc) is determined as follows :
504 //
505 //              sigc=(signal/gain)-offset 
506 //
507 // The default is mode=0.
508
509  // Check for (row,col) boundaries.
510  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
511  {
512   cout << " *AliCalorimeter::GetSignal* row,col : " << row << "," << col
513        << " out of range." << endl;
514   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
515   return 0;
516  }
517  
518  Float_t signal=0;
519  Float_t gain=1;
520  Float_t offset=0;
521  AliCalmodule* m=GetModule(row,col);
522  if (m)
523  {
524   Int_t dead=m->GetDeadValue();
525   if (!dead) signal=m->GetSignal();
526
527   if (mode==0 || dead) return signal;
528
529   // Correct the signal for the gain and offset
530   if (GetGainFlag(row,col))
531   {
532    gain=GetGain(row,col);
533   }
534   else
535   {
536    if (m->GetGainFlag()) gain=m->GetGain();
537   }
538
539   if (GetOffsetFlag(row,col))
540   {
541    offset=GetOffset(row,col);
542   }
543   else
544   {
545    if (m->GetOffsetFlag()) offset=m->GetOffset();
546   }
547
548   if (fabs(gain)>0.)
549   {
550    signal=(signal/gain)-offset;
551   }
552   else
553   {
554    signal=0;
555   }
556  }
557  return signal;
558 }
559 ///////////////////////////////////////////////////////////////////////////
560 void AliCalorimeter::SetEdgeOn(Int_t row,Int_t col)
561 {
562 // Indicate a certain calorimeter module as 'edge module'.
563
564  // Check for (row,col) boundaries.
565  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
566  {
567   cout << " *AliCalorimeter::SetEdgeOn* row,col : " << row << "," << col
568        << " out of range." << endl;
569   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
570   return;
571  }
572
573  if (!fAttributes)
574  {
575   fAttributes=new TObjArray(row);
576   fAttributes->SetOwner();
577  }
578  else
579  {
580   if (row > fAttributes->GetSize()) fAttributes->Expand(row);
581  }
582
583  AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
584  if (a)
585  {
586   a->SetEdgeOn(col);
587  }
588  else
589  {
590   a=new AliAttribObj();
591   a->SetEdgeOn(col);
592   fAttributes->AddAt(a,row-1);
593  } 
594
595  AliCalmodule* m=GetModule(row,col);
596  if (m) m->SetEdgeOn();
597 }
598 ///////////////////////////////////////////////////////////////////////////
599 void AliCalorimeter::SetEdgeOff(Int_t row,Int_t col)
600 {
601 // Indicate a certain calorimeter module as 'non-edge module'.
602
603  // Check for (row,col) boundaries.
604  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
605  {
606   cout << " *AliCalorimeter::SetEdgeOff* row,col : " << row << "," << col
607        << " out of range." << endl;
608   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
609   return;
610  }
611
612  // Only action on fAttributes in case an attribute is present at (row,col),
613  // since by default a module has edge=0 unless explicitly set otherwise.
614  if (fAttributes)
615  {
616   if (row <= fAttributes->GetSize())
617   {
618    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
619    if (a) a->SetEdgeOff(col);
620   }
621  } 
622
623  AliCalmodule* m=GetModule(row,col);
624  if (m) m->SetEdgeOff();
625 }
626 ///////////////////////////////////////////////////////////////////////////
627 void AliCalorimeter::SetDead(Int_t row,Int_t col)
628 {
629 // Indicate a certain calorimeter module as 'dead module'
630
631  // Check for (row,col) boundaries in case of a fixed size calorimeter
632  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
633  {
634   cout << " *AliCalorimeter::SetDead* row,col : " << row << "," << col
635        << " out of range." << endl;
636   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
637   return;
638  }
639
640  // Make Attributes storage 1 row (and also 1 column) larger than needed
641  // because the 'edge value' of the (future) surrounding modules has
642  // to be updated as well.
643  if (!fAttributes)
644  {
645   fAttributes=new TObjArray(row+1);
646   fAttributes->SetOwner();
647  }
648  else
649  {
650   if (row >= fAttributes->GetSize()) fAttributes->Expand(row+1);
651  }
652
653  AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
654  if (a)
655  {
656   a->SetDead(col);
657  }
658  else
659  {
660   a=new AliAttribObj();
661   a->SetDead(col);
662   fAttributes->AddAt(a,row-1);
663  } 
664
665  AliCalmodule* m=GetModule(row,col);
666  if (m) m->SetDead();
667  
668  // Increase the 'edge value' of surrounding modules
669  Int_t rlow=row-1;
670  Int_t rup=row+1;
671  Int_t clow=col-1;
672  Int_t cup=col+1;
673  
674  if (rlow < 1) rlow=row;
675  if (clow < 1) clow=col;
676  
677  for (Int_t i=rlow; i<=rup; i++)
678  {
679   for (Int_t j=clow; j<=cup; j++)
680   {
681    if (i!=row || j!=col) // No increase of edge value for the 'dead' module itself
682    {
683     AliAttribObj* a=(AliAttribObj*)fAttributes->At(i-1);
684     if (a)
685     {
686      a->IncreaseEdgeValue(j);
687     }
688     else
689     {
690     a=new AliAttribObj();
691     a->SetEdgeOn(j);
692     fAttributes->AddAt(a,i-1);
693     } 
694
695     AliCalmodule* m=GetModule(i,j);
696     if (m) m->IncreaseEdgeValue();
697    }
698   }
699  }
700 }
701 ///////////////////////////////////////////////////////////////////////////
702 void AliCalorimeter::SetAlive(Int_t row,Int_t col)
703 {
704 // Indicate a certain calorimeter module as 'active module'.
705
706  // Check for (row,col) boundaries.
707  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
708  {
709   cout << " *AliCalorimeter::SetAlive* row,col : " << row << "," << col
710        << " out of range." << endl;
711   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
712   return;
713  }
714
715  // Only action on fAttributes in case an attribute is present at (row,col),
716  // since by default a module has dead=0 unless explicitly set otherwise.
717  if (fAttributes)
718  {
719   if (row <= fAttributes->GetSize())
720   {
721    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
722    if (a) a->SetAlive(col);
723   }
724  } 
725
726  AliCalmodule* m=GetModule(row,col);
727  if (m) m->SetAlive();
728  
729  // Decrease the 'edge value' of surrounding modules
730  Int_t rlow=row-1;
731  Int_t rup=row+1;
732  Int_t clow=col-1;
733  Int_t cup=col+1;
734  
735  if (rlow < 1) rlow=row;
736  if (clow < 1) clow=col;
737
738  for (Int_t i=rlow; i<=rup; i++)
739  {
740   for (Int_t j=clow; j<=cup; j++)
741   {
742    if (i!=row || j!=col) // No decrease of edge value for the 'alive' module itself
743    {
744     if (i <= fAttributes->GetSize())
745     {
746      AliAttribObj* a=(AliAttribObj*)fAttributes->At(i-1);
747      if (a) a->DecreaseEdgeValue(j);
748     }
749     AliCalmodule* m=GetModule(i,j);
750     if (m) m->DecreaseEdgeValue();
751    }
752   }
753  }
754 }
755 ///////////////////////////////////////////////////////////////////////////
756 void AliCalorimeter::SetGain(Int_t row,Int_t col,Float_t gain)
757 {
758 // Set the gain value for a certain calorimeter module.
759 // See the memberfunction GetSignal() for a definition of the gain value.
760
761  // Check for (row,col) boundaries.
762  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
763  {
764   cout << " *AliCalorimeter::SetGain* row,col : " << row << "," << col
765        << " out of range." << endl;
766   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
767   return;
768  }
769
770  if (!fAttributes)
771  {
772   fAttributes=new TObjArray(row);
773   fAttributes->SetOwner();
774  }
775  else
776  {
777   if (row > fAttributes->GetSize()) fAttributes->Expand(row);
778  }
779
780  AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
781  if (a)
782  {
783   a->SetGain(gain,col);
784  }
785  else
786  {
787   a=new AliAttribObj();
788   a->SetGain(gain,col);
789   fAttributes->AddAt(a,row-1);
790  } 
791
792  AliCalmodule* m=GetModule(row,col);
793  if (m) m->SetGain(gain);
794 }
795 ///////////////////////////////////////////////////////////////////////////
796 void AliCalorimeter::SetOffset(Int_t row,Int_t col,Float_t offset)
797 {
798 // Set the offset value for a certain calorimeter module.
799 // See the memberfunction GetSignal() for a definition of the offset value.
800
801  // Check for (row,col) boundaries.
802  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
803  {
804   cout << " *AliCalorimeter::SetOffset* row,col : " << row << "," << col
805        << " out of range." << endl;
806   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
807   return;
808  }
809
810  if (!fAttributes)
811  {
812   fAttributes=new TObjArray(row);
813   fAttributes->SetOwner();
814  }
815  else
816  {
817   if (row > fAttributes->GetSize()) fAttributes->Expand(row);
818  }
819
820  AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
821  if (a)
822  {
823   a->SetOffset(offset,col);
824  }
825  else
826  {
827   a=new AliAttribObj();
828   a->SetOffset(offset,col);
829   fAttributes->AddAt(a,row-1);
830  } 
831
832  AliCalmodule* m=GetModule(row,col);
833  if (m) m->SetOffset(offset);
834 }
835 ///////////////////////////////////////////////////////////////////////////
836 void AliCalorimeter::SetPosition(Int_t row,Int_t col,Float_t* vec,TString f)
837 {
838 // Set the position in user coordinates for a certain calorimeter module
839  Ali3Vector r;
840  r.SetVector(vec,f);
841  SetPosition(row,col,r);
842
843 ///////////////////////////////////////////////////////////////////////////
844 void AliCalorimeter::SetPosition(Int_t row,Int_t col,Ali3Vector& r)
845 {
846 // Set the position for a certain calorimeter module
847
848  // Check for (row,col) boundaries.
849  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
850  {
851   cout << " *AliCalorimeter::SetPosition* row,col : " << row << "," << col
852        << " out of range." << endl;
853   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
854   return;
855  }
856
857  if (!fPositions)
858  {
859   fPositions=new AliObjMatrix();
860   fPositions->SetOwner();
861   fPositions->SetSwapMode(fSwap);
862  }
863
864  AliPositionObj* p=(AliPositionObj*)fPositions->GetObject(row,col);
865
866  if (p)
867  {
868   p->Load(r);
869  }
870  else
871  {
872   p=new AliPositionObj();
873   p->Load(r);
874   fPositions->EnterObject(row,col,p);
875  }
876
877  // Update the position of the calorimeter module itself as well if it exists
878  AliCalmodule* m=GetModule(row,col);
879  if (m) m->SetPosition(r);
880 }
881 ///////////////////////////////////////////////////////////////////////////
882 Int_t AliCalorimeter::GetEdgeValue(Int_t row,Int_t col)
883 {
884 // Provide the value of the edge flag of a certain module.
885
886  // Check for (row,col) boundaries.
887  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
888  {
889   cout << " *AliCalorimeter::GetEdgeValue* row,col : " << row << "," << col
890        << " out of range." << endl;
891   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
892   return 0;
893  }
894
895  Int_t edge=0;
896
897  if (fAttributes)
898  {
899   if (row <= fAttributes->GetSize())
900   {
901    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
902    if (a)
903    {
904     if (col <= a->GetNcalflags())
905     {
906      edge=a->GetEdgeValue(col);
907      return edge;
908     }
909    }
910   }
911  }
912
913  AliCalmodule* m=GetModule(row,col);
914  if (m) edge=m->GetEdgeValue();
915  return edge;
916 }
917 ///////////////////////////////////////////////////////////////////////////
918 Int_t AliCalorimeter::GetDeadValue(Int_t row,Int_t col)
919 {
920 // Provide the value of the dead flag of a certain module
921
922  // Check for (row,col) boundaries.
923  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
924  {
925   cout << " *AliCalorimeter::GetDeadValue* row,col : " << row << "," << col
926        << " out of range." << endl;
927   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
928   return 0;
929  }
930
931  Int_t dead=0;
932
933  if (fAttributes)
934  {
935   if (row <= fAttributes->GetSize())
936   {
937    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
938    if (a)
939    {
940     if (col <= a->GetNcalflags())
941     {
942      dead=a->GetDeadValue(col);
943      return dead;
944     }
945    }
946   }
947  }
948
949  AliCalmodule* m=GetModule(row,col);
950  if (m) dead=m->GetDeadValue();
951  return dead;
952 }
953 ///////////////////////////////////////////////////////////////////////////
954 Int_t AliCalorimeter::GetGainFlag(Int_t row,Int_t col)
955 {
956 // Provide the value of the gain flag of a certain module.
957
958  // Check for (row,col) boundaries.
959  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
960  {
961   cout << " *AliCalorimeter::GetGainFlag* row,col : " << row << "," << col
962        << " out of range." << endl;
963   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
964   return 0;
965  }
966
967  Int_t gf=0;
968
969  if (fAttributes)
970  {
971   if (row <= fAttributes->GetSize())
972   {
973    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
974    if (a)
975    {
976     if (col <= a->GetNcalflags())
977     {
978      gf=a->GetGainFlag(col);
979      return gf;
980     }
981    }
982   }
983  }
984
985  AliCalmodule* m=GetModule(row,col);
986  if (m) gf=m->GetGainFlag();
987  return gf;
988 }
989 ///////////////////////////////////////////////////////////////////////////
990 Int_t AliCalorimeter::GetOffsetFlag(Int_t row,Int_t col)
991 {
992 // Provide the value of the offset flag of a certain module.
993
994  // Check for (row,col) boundaries.
995  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
996  {
997   cout << " *AliCalorimeter::GetOffsetFlag* row,col : " << row << "," << col
998        << " out of range." << endl;
999   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
1000   return 0;
1001  }
1002
1003  Int_t of=0;
1004
1005  if (fAttributes)
1006  {
1007   if (row <= fAttributes->GetSize())
1008   {
1009    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
1010    if (a)
1011    {
1012     if (col <= a->GetNcalflags())
1013     {
1014      of=a->GetOffsetFlag(col);
1015      return of;
1016     }
1017    }
1018   }
1019  }
1020
1021  AliCalmodule* m=GetModule(row,col);
1022  if (m) of=m->GetOffsetFlag();
1023  return of;
1024 }
1025 ///////////////////////////////////////////////////////////////////////////
1026 Float_t AliCalorimeter::GetGain(Int_t row,Int_t col)
1027 {
1028 // Provide the gain value of a certain module.
1029 // See the memberfunction GetSignal() for a definition of the gain value.
1030 //
1031 // In case the gain value is unknown, the value 0 will be returned. 
1032
1033  // Check for (row,col) boundaries.
1034  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
1035  {
1036   cout << " *AliCalorimeter::GetGain* row,col : " << row << "," << col
1037        << " out of range." << endl;
1038   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
1039   return 0;
1040  }
1041
1042  Float_t gain=0;
1043
1044  if (fAttributes)
1045  {
1046   if (row <= fAttributes->GetSize())
1047   {
1048    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
1049    if (a)
1050    {
1051     if (col <= a->GetNcalflags())
1052     {
1053      if (a->GetGainFlag(col))
1054      {
1055       gain=a->GetGain(col);
1056       return gain;
1057      }
1058     }
1059    }
1060   }
1061  }
1062
1063  AliCalmodule* m=GetModule(row,col);
1064  if (m)
1065  {
1066   if (m->GetGainFlag())
1067   {
1068    gain=m->GetGain();
1069   }
1070  }
1071  return gain;
1072 }
1073 ///////////////////////////////////////////////////////////////////////////
1074 Float_t AliCalorimeter::GetOffset(Int_t row,Int_t col)
1075 {
1076 // Provide the offset value of a certain module.
1077 // See the memberfunction GetSignal() for a definition of the offset value.
1078 //
1079 // In case the offset value is unknown, the value 0 will be returned. 
1080
1081  // Check for (row,col) boundaries.
1082  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
1083  {
1084   cout << " *AliCalorimeter::GetOffset* row,col : " << row << "," << col
1085        << " out of range." << endl;
1086   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
1087   return 0;
1088  }
1089
1090  Float_t offset=0;
1091
1092  if (fAttributes)
1093  {
1094   if (row <= fAttributes->GetSize())
1095   {
1096    AliAttribObj* a=(AliAttribObj*)fAttributes->At(row-1);
1097    if (a)
1098    {
1099     if (col <= a->GetNcalflags())
1100     {
1101      if (a->GetOffsetFlag(col))
1102      {
1103       offset=a->GetOffset(col);
1104       return offset;
1105      }
1106     }
1107    }
1108   }
1109  }
1110
1111  AliCalmodule* m=GetModule(row,col);
1112  if (m)
1113  {
1114   if (m->GetOffsetFlag())
1115   {
1116    offset=m->GetOffset();
1117   }
1118  }
1119  return offset;
1120 }
1121 ///////////////////////////////////////////////////////////////////////////
1122 void AliCalorimeter::GetPosition(Int_t row,Int_t col,Float_t* vec,TString f)
1123 {
1124 // Return the position in user coordinates for a certain calorimeter module
1125  vec[0]=0;
1126  vec[1]=0;
1127  vec[2]=0;
1128
1129  AliPosition* p=GetPosition(row,col);
1130  if (p) p->GetVector(vec,f);
1131 }
1132 ///////////////////////////////////////////////////////////////////////////
1133 AliPosition* AliCalorimeter::GetPosition(Int_t row,Int_t col)
1134 {
1135 // Access to the position of a certain calorimeter module.
1136
1137  // Check for (row,col) boundaries.
1138  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
1139  {
1140   cout << " *AliCalorimeter::GetPosition* row,col : " << row << "," << col
1141        << " out of range." << endl;
1142   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
1143   return 0;
1144  }
1145
1146  if (!fPositions && !fMatrix) return 0;
1147
1148  AliPositionObj* po=0;
1149  if (fPositions) po=(AliPositionObj*)fPositions->GetObject(row,col);
1150  if (po) return po;
1151
1152  AliCalmodule* m=GetModule(row,col);
1153  return m;
1154 }
1155 ///////////////////////////////////////////////////////////////////////////
1156 Float_t AliCalorimeter::GetClusteredSignal(Int_t row,Int_t col)
1157 {
1158 // Provide the module signal after clustering.
1159
1160  // Check for (row,col) boundaries.
1161  if (row<1 || col<1 || (fNrows && fNcolumns && (row>fNrows || col>fNcolumns)))
1162  {
1163   cout << " *AliCalorimeter::GetClusteredSignal* row,col : " << row << "," << col
1164        << " out of range." << endl;
1165   if (fNrows && fNcolumns) cout << " Nrows,Ncols = " << fNrows << "," << fNcolumns << endl;
1166   return 0;
1167  }
1168  
1169  Float_t sig=0;
1170
1171  AliCalmodule* m=GetModule(row,col);
1172  if (m) sig=m->GetClusteredSignal();
1173
1174  return sig;
1175 }
1176 ///////////////////////////////////////////////////////////////////////////
1177 Int_t AliCalorimeter::GetNsignals()
1178 {
1179 // Provide the number of modules that contain a signal
1180 // Note : The number of modules marked 'dead' but which had a signal
1181 //        are included.
1182  Int_t nsig=0;
1183  if (fMatrix) nsig=fMatrix->GetNobjects();
1184  return nsig;
1185 }
1186 ///////////////////////////////////////////////////////////////////////////
1187 void AliCalorimeter::Group(Int_t n,Int_t mode)
1188 {
1189 // Group the individual modules into clusters.
1190 // Module signals of n rings around the central module will be grouped.
1191 // The grouping process will start with the module containing the highest signal
1192 // in an iterative way.
1193 // For this all fired modules are ordered w.r.t. decreasing signal.
1194 // The search mode for the module signal hierarchy can be specified by the user.
1195 //
1196 // mode = 1 : Search performed via the (row,col) structure of the matrix (SortM)
1197 //        2 : Search performed via the linear array of fired modules (SortA)
1198 //
1199 // See the docs of the memberfunctions SortM and SortA for additional details.
1200 //
1201 // Default values : n=1 mode=1.
1202
1203  if (mode<1 || mode>2)
1204  {
1205   cout << " *AliCalorimeter::Group* Invalid mode : " << mode << endl;
1206   cout << " Default value mode=1 will be used." << endl;
1207   mode=1;
1208  }
1209
1210  if (!fMatrix) return;
1211  
1212  Int_t nsignals=GetNsignals();
1213  if (nsignals > 0) // Only continue if there are fired modules
1214  {
1215   if (GetNclusters() > 0) Ungroup(); // Restore unclustered situation if needed
1216  
1217   // Order the modules with decreasing signal
1218   AliCalmodule** ordered=new AliCalmodule*[nsignals]; // temp. array for ordered modules
1219   Int_t nord=0;
1220   if (mode==1) SortM(ordered,nord);
1221   if (mode==2) SortA(ordered,nord);
1222  
1223   // Clustering of modules. Start with the highest signal.
1224   if (fClusters)
1225   {
1226    delete fClusters;
1227    fClusters=0;
1228   }
1229   fClusters=new TObjArray();
1230   fClusters->SetOwner();
1231   Int_t row=0;
1232   Int_t col=0;
1233   AliCalcluster* c=0;
1234   AliCalmodule* m=0;
1235   for (Int_t i=0; i<nord; i++)
1236   {
1237    row=ordered[i]->GetRow();    // row number of cluster center
1238    col=ordered[i]->GetColumn(); // column number of cluster center
1239
1240    m=(AliCalmodule*)fMatrix->GetObject(row,col);
1241    if (!m) continue;
1242
1243    // only use modules not yet used in a cluster
1244    if (m->GetClusteredSignal() > 0.)
1245    {
1246     Int_t edge=GetEdgeValue(row,col);
1247     c=new AliCalcluster();
1248     if (!edge) c->Start(*m);   // module to start the cluster if not on edge
1249     if (c->GetNmodules() > 0)  // cluster started successfully (no edge)
1250     {
1251      fClusters->Add(c);
1252      AddRing(row,col,n); // add signals of n rings around the center
1253     }
1254     else
1255     {
1256      if (c) delete c;
1257      c=0;
1258     }
1259    }
1260   }
1261  
1262   // Delete the temp. array
1263   if (ordered)
1264   { 
1265    for (Int_t j=0; j<nord; j++)
1266    {
1267     ordered[j]=0;
1268    }
1269    delete [] ordered;
1270   }
1271  }
1272 }
1273 ///////////////////////////////////////////////////////////////////////////
1274 void AliCalorimeter::SortM(AliCalmodule** ordered,Int_t& nord)
1275 {
1276 // Order the modules with decreasing signal by looping over the (row,col) grid
1277 // of the matrix.
1278 // Modules which were declared as "Dead" will be rejected.
1279 // The gain etc... corrected module signals will be used in the ordering process.
1280 //
1281 // Note : This method may become slow for large, very finely granulated calorimeters.
1282 //
1283 // Very specific case :
1284 // ====================
1285 // In case of various overlapping showers of which the central modules have
1286 // EXACTLY the same signal this ordering procedure may have the following
1287 // advantages and disadvantages.
1288 //
1289 // Advantages :
1290 // ------------
1291 // * In case of multi-overlapping showers, the central shower will NOT
1292 //   be "eaten-up" from both sides, resulting in a slightly more accurate
1293 //   cluster signal.
1294 // * This method produces re-producable results, irrespective of the filling
1295 //   order of the matrix modules.
1296 //
1297 // Disadvantages :
1298 // ---------------
1299 // * In case of a very high occupancy, there might be a slight effect on the
1300 //   cluster signals depending on the geometrical location in the detector matrix.
1301  
1302  Int_t nrows=fMatrix->GetMaxRow();
1303  Int_t ncols=fMatrix->GetMaxColumn();
1304
1305  Float_t signal=0.;
1306  nord=0;
1307  for (Int_t irow=1; irow<=nrows; irow++) // loop over all modules of the matrix
1308  {
1309   for (Int_t icol=1; icol<=ncols; icol++)
1310   {
1311    signal=GetSignal(irow,icol,1); // get the gain etc... corrected signal
1312    if (signal <= 0.) continue;    // only take alive modules with a signal
1313  
1314    if (nord == 0) // store the first module with a signal at the first ordered position
1315    {
1316     nord++;
1317     ordered[nord-1]=(AliCalmodule*)fMatrix->GetObject(irow,icol);
1318     continue;
1319    }
1320  
1321    for (Int_t j=0; j<=nord; j++) // put module in the right ordered position
1322    {
1323     if (j == nord) // module has smallest signal seen so far
1324     {
1325      nord++;
1326      ordered[j]=(AliCalmodule*)fMatrix->GetObject(irow,icol); // add module at the end
1327      break; // go for next matrix module
1328     }
1329  
1330     if (signal < ordered[j]->GetSignal(1,1)) continue;
1331  
1332     nord++;
1333     for (Int_t k=nord-1; k>j; k--) // create empty position
1334     {
1335      ordered[k]=ordered[k-1];
1336     }
1337     ordered[j]=(AliCalmodule*)fMatrix->GetObject(irow,icol); // put module at empty position
1338     break; // go for next matrix module
1339    }
1340   }
1341  }
1342 }
1343 ///////////////////////////////////////////////////////////////////////////
1344 void AliCalorimeter::SortA(AliCalmodule** ordered,Int_t& nord)
1345 {
1346 // Order the modules with decreasing signal by looping over the linear array
1347 // of fired modules.
1348 // Modules which were declared as "Dead" will be rejected.
1349 // The gain etc... corrected module signals will be used in the ordering process.
1350 //
1351 // Note : This method is rather fast even for large, very finely granulated calorimeters.
1352 //
1353 // Very specific case :
1354 // ====================
1355 // In case of various overlapping showers of which the central modules have
1356 // EXACTLY the same signal this ordering procedure may have the following
1357 // advantages and disadvantages.
1358 //
1359 // Advantages :
1360 // ------------
1361 // * Even in case of a very high occupancy, the resulting cluster signals
1362 //   will in general NOT depend on the geometrical location in the detector matrix.
1363 //
1364 // Disadvantages :
1365 // ---------------
1366 // * In case of multi-overlapping showers, the central shower might be
1367 //   "eaten-up" from both sides, resulting in a slightly too low value
1368 //   of the resulting cluster signal.
1369 // * This method might produce results depending on the filling
1370 //   order of the matrix modules.
1371  
1372  Int_t nmods=0;
1373  if (fMatrix) nmods=fMatrix->GetNobjects();
1374
1375  nord=0;
1376  for (Int_t i=1; i<=nmods; i++) // loop over all fired modules of the matrix
1377  {
1378   AliCalmodule* m=(AliCalmodule*)fMatrix->GetObject(i);
1379
1380   if (!m) continue;
1381   if (m->GetDeadValue()) continue; // only take alive modules with a signal
1382  
1383   if (nord == 0) // store the first module with a signal at the first ordered position
1384   {
1385    nord++;
1386    ordered[nord-1]=m;
1387    continue;
1388   }
1389  
1390   for (Int_t j=0; j<=nord; j++) // put module in the right ordered position
1391   {
1392    if (j == nord) // module has smallest signal seen so far
1393    {
1394     nord++;
1395     ordered[j]=m; // add module at the end
1396     break; // go for next matrix module
1397    }
1398  
1399    if (m->GetSignal(1,1) < ordered[j]->GetSignal(1,1)) continue;
1400  
1401    nord++;
1402    for (Int_t k=nord-1; k>j; k--) // create empty position
1403    {
1404     ordered[k]=ordered[k-1];
1405    }
1406    ordered[j]=m; // put module at empty position
1407    break; // go for next matrix module
1408   }
1409  }
1410 }
1411 ///////////////////////////////////////////////////////////////////////////
1412 void AliCalorimeter::AddRing(Int_t row, Int_t col, Int_t n)
1413 {
1414 // Add module signals of 1 ring around (row,col) to current cluster.
1415 // The gain etc... corrected module signals will be used in this process.
1416 // The parameter n denotes the maximum number of rings around cluster center.
1417 // Note : This function is used recursively.
1418
1419  if (!fMatrix) return;
1420
1421  Int_t nrows=fMatrix->GetMaxRow();
1422  Int_t ncols=fMatrix->GetMaxColumn();
1423  
1424  if (n >= 1) // Check if any rings left for recursive calls
1425  {
1426   Float_t signal=GetSignal(row,col,1); // Gain etc... corrected signal of (row,col) module
1427  
1428   Int_t lrow=row-1; if (lrow < 1) lrow=1;         // row lowerbound for ring
1429   Int_t urow=row+1; if (urow > nrows) urow=nrows; // row upperbound for ring
1430   Int_t lcol=col-1; if (lcol < 1) lcol=1;         // col lowerbound for ring
1431   Int_t ucol=col+1; if (ucol > ncols) ucol=ncols; // row upperbound for ring
1432  
1433   for (Int_t i=lrow; i<=urow; i++)
1434   {
1435    for (Int_t j=lcol; j<=ucol; j++)
1436    {
1437     // add module(i,j) to cluster if the signal <= signal(row,col)
1438     if (GetSignal(i,j,1) <= signal)
1439     {
1440      AliCalmodule* m=(AliCalmodule*)fMatrix->GetObject(i,j);
1441      if (m) ((AliCalcluster*)fClusters->At(GetNclusters()-1))->Add(*m);
1442     }
1443     AddRing(i,j,n-1); // Go for ring of modules around this (i,j) one
1444    }
1445   }
1446  }
1447 }
1448 ///////////////////////////////////////////////////////////////////////////
1449 Int_t AliCalorimeter::GetNclusters()
1450 {
1451 // Provide the number of clusters
1452  Int_t nclu=0;
1453  if (fClusters) nclu=fClusters->GetEntries();
1454  return nclu;
1455 }
1456 ///////////////////////////////////////////////////////////////////////////
1457 AliCalcluster* AliCalorimeter::GetCluster(Int_t j)
1458 {
1459 // Provide cluster number j
1460 // Note : j=1 denotes the first cluster
1461
1462  if (!fClusters) return 0;
1463
1464  if ((j >= 1) && (j <= GetNclusters()))
1465  {
1466   return (AliCalcluster*)fClusters->At(j-1);
1467  }
1468  else
1469  {
1470   cout << " *AliCalorimeter::GetCluster* cluster number : " << j
1471        << " out of range ==> 0 returned." << endl;
1472   return 0;
1473  }
1474 }
1475 ///////////////////////////////////////////////////////////////////////////
1476 AliCalmodule* AliCalorimeter::GetModule(Int_t j)
1477 {
1478 // Provide 'fired' module number j
1479 // Note : j=1 denotes the first 'fired' module
1480
1481  if (!fMatrix) return 0;
1482
1483  if ((j >= 1) && (j <= GetNsignals()))
1484  {
1485   return (AliCalmodule*)fMatrix->GetObject(j);
1486  }
1487  else
1488  {
1489   cout << " *AliCalorimeter::GetModule* module number : " << j
1490        << " out of range ==> 0 returned." << endl;
1491   return 0;
1492  }
1493 }
1494 ///////////////////////////////////////////////////////////////////////////
1495 AliCalmodule* AliCalorimeter::GetModule(Int_t row,Int_t col)
1496 {
1497 // Provide access to module (row,col).
1498 // Note : first module is at (1,1).
1499
1500  AliCalmodule* m=0;
1501  if (fMatrix) m=(AliCalmodule*)fMatrix->GetObject(row,col);
1502  return m;
1503 }
1504 ///////////////////////////////////////////////////////////////////////////
1505 TH2F* AliCalorimeter::DrawModules(Float_t thresh,Int_t mode)
1506 {
1507 // Provide a lego plot of the module signals.
1508 // The input parameter mode (default mode=0) has the same meaning as
1509 // specified in the memberfunction GetSignal(row,col,mode).
1510 // Only modules with a (corrected) signal value above the threshold
1511 // (default thresh=0) will be displayed.
1512
1513  Int_t nrows=fNrows;
1514  Int_t ncols=fNcolumns;
1515
1516  if (fMatrix && !nrows && !ncols)
1517  {
1518   nrows=fMatrix->GetMaxRow();
1519   ncols=fMatrix->GetMaxColumn();
1520  }
1521  
1522  if (fHmodules)
1523  {
1524   fHmodules->Reset();
1525  }
1526  else
1527  {
1528   fHmodules=new TH2F("fHmodules","Module signals",
1529             ncols,0.5,float(ncols)+0.5,nrows,0.5,float(nrows)+0.5);
1530  
1531   fHmodules->SetDirectory(0); // Suppress global character of histo pointer
1532  }
1533  
1534  Int_t nmods=GetNsignals();
1535
1536  Int_t row,col;
1537  Float_t signal;
1538  Int_t dead;
1539  for (Int_t i=1; i<=nmods; i++)
1540  {
1541   AliCalmodule* m=(AliCalmodule*)fMatrix->GetObject(i);
1542   if (m)
1543   {
1544    row=m->GetRow();
1545    col=m->GetColumn();
1546    dead=m->GetDeadValue();
1547    signal=0;
1548    if (!dead) signal=GetSignal(row,col,mode);
1549    if (signal>thresh) fHmodules->Fill(float(col),float(row),signal);
1550   }
1551  }
1552  
1553  fHmodules->Draw("lego");
1554  return fHmodules;
1555 }
1556 ///////////////////////////////////////////////////////////////////////////
1557 TH2F* AliCalorimeter::DrawClusters(Float_t thresh)
1558 {
1559 // Provide a lego plot of the cluster signals.
1560 // Only clusters with a signal value above the threshold (default thresh=0)
1561 // will be displayed.
1562
1563  Int_t nrows=fNrows;
1564  Int_t ncols=fNcolumns;
1565
1566  if (fMatrix && !nrows && !ncols)
1567  {
1568   nrows=fMatrix->GetMaxRow();
1569   ncols=fMatrix->GetMaxColumn();
1570  }
1571  
1572  if (fHclusters)
1573  {
1574   fHclusters->Reset();
1575  }
1576  else
1577  {
1578   fHclusters=new TH2F("fHclusters","Cluster signals",
1579             ncols,0.5,float(ncols)+0.5,nrows,0.5,float(nrows)+0.5);
1580  
1581   fHclusters->SetDirectory(0); // Suppress global character of histo pointer
1582  }
1583  
1584  AliCalcluster* c;
1585  Int_t row,col;
1586  Float_t signal;
1587  for (Int_t i=0; i<GetNclusters(); i++)
1588  {
1589   c=(AliCalcluster*)fClusters->At(i);
1590   if (c)
1591   {
1592    row=c->GetRow();
1593    col=c->GetColumn();
1594    signal=c->GetSignal();
1595    if (signal>thresh) fHclusters->Fill(float(col),float(row),signal);
1596   }
1597  }
1598  
1599  fHclusters->Draw("lego");
1600  return fHclusters;
1601 }
1602 ///////////////////////////////////////////////////////////////////////////
1603 void AliCalorimeter::Ungroup()
1604 {
1605 // Set the module signals back to the non-clustered situation
1606
1607  if (!fMatrix) return;
1608  
1609  Int_t nsig=GetNsignals();
1610
1611  Float_t signal=0;
1612  for (Int_t j=1; j<=nsig; j++)
1613  {
1614   AliCalmodule* m=(AliCalmodule*)fMatrix->GetObject(j);
1615   if (m)
1616   {
1617    signal=m->GetSignal();
1618    m->SetClusteredSignal(signal);
1619   }
1620  }
1621 }
1622 ///////////////////////////////////////////////////////////////////////////
1623 void AliCalorimeter::AddVetoSignal(AliSignal& s)
1624 {
1625 // Associate an (extrapolated) AliSignal as veto to the calorimeter.
1626  if (!fVetos)
1627  {
1628   fVetos=new TObjArray();
1629   fVetos->SetOwner();
1630  } 
1631
1632  AliSignal* sx=new AliSignal(s);
1633
1634  fVetos->Add(sx);
1635 }
1636 ///////////////////////////////////////////////////////////////////////////
1637 Int_t AliCalorimeter::GetNvetos()
1638 {
1639 // Provide the number of veto signals associated to the calorimeter.
1640  Int_t nvetos=0;
1641  if (fVetos) nvetos=fVetos->GetEntries();
1642  return nvetos;
1643 }
1644 ///////////////////////////////////////////////////////////////////////////
1645 AliSignal* AliCalorimeter::GetVetoSignal(Int_t i)
1646 {
1647 // Provide access to the i-th veto signal of this calorimeter
1648 // Note : The first hit corresponds to i=1
1649
1650  if (i>0 && i<=GetNvetos())
1651  {
1652   return (AliSignal*)fVetos->At(i-1);
1653  }
1654  else
1655  {
1656   cout << " *AliCalorimeter::GetVetoSignal* Signal number " << i
1657        << " out of range ==> 0 returned." << endl;
1658   return 0;
1659  }
1660 }
1661 ///////////////////////////////////////////////////////////////////////////
1662 void AliCalorimeter::SetSwapMode(Int_t swap)
1663 {
1664 // Set the swap mode for the module and position matrices.
1665 // At invokation of this memberfunction the default argument is swap=1.
1666 // For further details see the documentation of AliObjMatrix.
1667  if (swap==0 || swap==1)
1668  {
1669   fSwap=swap;
1670  }
1671  else
1672  {
1673   cout << " *AliCalorimeter::SetSwapMode* Invalid argument : swap = " << swap << endl; 
1674  }
1675 }
1676 ///////////////////////////////////////////////////////////////////////////
1677 Int_t AliCalorimeter::GetSwapMode()
1678 {
1679 // Provide the swap mode for the module and position matrices.
1680 // For further details see the documentation of AliObjMatrix.
1681  return fSwap;
1682 }
1683 ///////////////////////////////////////////////////////////////////////////
1684 TObject* AliCalorimeter::Clone(const char* name)
1685 {
1686 // Make a deep copy of the current object and provide the pointer to the copy.
1687 // This memberfunction enables automatic creation of new objects of the
1688 // correct type depending on the object type, a feature which may be very useful
1689 // for containers like AliEvent when adding objects in case the
1690 // container owns the objects.
1691
1692  AliCalorimeter* cal=new AliCalorimeter(*this);
1693  if (name)
1694  {
1695   if (strlen(name)) cal->SetName(name);
1696  } 
1697  return cal;
1698 }
1699 ///////////////////////////////////////////////////////////////////////////