403fddc0df692af566e6f25dcdc005810d8403b2
[u/mrichter/AliRoot.git] / STEER / ESD / AliESDHeader.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 //-------------------------------------------------------------------------
17 //                      Implementation of   Class AliESDHeader
18 //   Header data
19 //   for the ESD   
20 //   Origin: Christian Klein-Boesing, CERN, Christian.Klein-Boesing@cern.ch 
21 //-------------------------------------------------------------------------
22
23 #include "AliESDHeader.h"
24 #include "AliTriggerScalersESD.h"
25 #include "AliTriggerScalersRecordESD.h"
26 #include "AliTriggerIR.h"
27 #include "AliTriggerConfiguration.h"
28 #include "AliLog.h" 
29
30 ClassImp(AliESDHeader)
31
32 //______________________________________________________________________________
33 AliESDHeader::AliESDHeader() :
34   AliVHeader(),
35   fTriggerMask(0),
36   fTriggerMaskNext50(0),
37   fOrbitNumber(0),
38   fTimeStamp(0),
39   fEventType(0),
40   fEventSpecie(0),
41   fPeriodNumber(0),
42   fEventNumberInFile(0),
43   fBunchCrossNumber(0),
44   fTriggerCluster(0),
45   fL0TriggerInputs(0),
46   fL1TriggerInputs(0),
47   fL2TriggerInputs(0),
48   fTriggerScalers(),
49   fTriggerScalersDeltaEvent(),
50   fTriggerScalersDeltaRun(),
51   fTriggerInputsNames(kNTriggerInputs),
52   fCTPConfig(NULL),
53   fIRBufferArray(),
54   fIRInt2InteractionsMap(0),
55   fIRInt1InteractionsMap(0)
56 {
57   // default constructor
58
59   SetName("AliESDHeader");
60   for(Int_t i = 0; i<kNMaxIR ; i++) fIRArray[i] = 0;
61   fTriggerInputsNames.SetOwner(kTRUE);
62 }
63
64 AliESDHeader::~AliESDHeader() 
65 {
66   // destructor
67   for(Int_t i=0;i<kNMaxIR;i++)if(fIRArray[i])delete fIRArray[i];
68   delete fCTPConfig;
69
70   fIRBufferArray.Delete();
71 }
72
73
74 AliESDHeader::AliESDHeader(const AliESDHeader &header) :
75   AliVHeader(header),
76   fTriggerMask(header.fTriggerMask),
77   fTriggerMaskNext50(header.fTriggerMaskNext50),
78   fOrbitNumber(header.fOrbitNumber),
79   fTimeStamp(header.fTimeStamp),
80   fEventType(header.fEventType),
81   fEventSpecie(header.fEventSpecie),
82   fPeriodNumber(header.fPeriodNumber),
83   fEventNumberInFile(header.fEventNumberInFile),
84   fBunchCrossNumber(header.fBunchCrossNumber),
85   fTriggerCluster(header.fTriggerCluster),
86   fL0TriggerInputs(header.fL0TriggerInputs),
87   fL1TriggerInputs(header.fL1TriggerInputs),
88   fL2TriggerInputs(header.fL2TriggerInputs),
89   fTriggerScalers(header.fTriggerScalers),
90   fTriggerScalersDeltaEvent(header.fTriggerScalersDeltaEvent),
91   fTriggerScalersDeltaRun(header.fTriggerScalersDeltaRun),
92   fTriggerInputsNames(TObjArray(kNTriggerInputs)),
93   fCTPConfig(header.fCTPConfig),
94   fIRBufferArray(),
95   fIRInt2InteractionsMap(header.fIRInt2InteractionsMap),
96   fIRInt1InteractionsMap(header.fIRInt1InteractionsMap)
97 {
98   // copy constructor
99   for(Int_t i = 0; i<kNMaxIR ; i++) {
100     if(header.fIRArray[i])fIRArray[i] = new AliTriggerIR(*header.fIRArray[i]);
101     else fIRArray[i]=0;
102   }
103   for(Int_t i = 0; i < kNTriggerInputs; i++) {
104     TNamed *str = (TNamed *)((header.fTriggerInputsNames).At(i));
105     if (str) fTriggerInputsNames.AddAt(new TNamed(*str),i);
106   }
107
108   for(Int_t i = 0; i < (header.fIRBufferArray).GetEntries(); ++i) {
109     AliTriggerIR *ir = (AliTriggerIR*)((header.fIRBufferArray).At(i));
110     if (ir) fIRBufferArray.Add(new AliTriggerIR(*ir));
111   }
112 }
113
114 AliESDHeader& AliESDHeader::operator=(const AliESDHeader &header)
115
116   // assigment operator
117   if(this!=&header) {
118     AliVHeader::operator=(header);
119     fTriggerMask = header.fTriggerMask;
120     fTriggerMaskNext50 = header.fTriggerMaskNext50;
121     fOrbitNumber = header.fOrbitNumber;
122     fTimeStamp = header.fTimeStamp;
123     fEventType = header.fEventType;
124     fEventSpecie = header.fEventSpecie;
125     fPeriodNumber = header.fPeriodNumber;
126     fEventNumberInFile = header.fEventNumberInFile;
127     fBunchCrossNumber = header.fBunchCrossNumber;
128     fTriggerCluster = header.fTriggerCluster;
129     fL0TriggerInputs = header.fL0TriggerInputs;
130     fL1TriggerInputs = header.fL1TriggerInputs;
131     fL2TriggerInputs = header.fL2TriggerInputs;
132     fTriggerScalers = header.fTriggerScalers;
133     fTriggerScalersDeltaEvent = header.fTriggerScalersDeltaEvent;
134     fTriggerScalersDeltaRun = header.fTriggerScalersDeltaRun;
135     fIRInt2InteractionsMap = header.fIRInt2InteractionsMap;
136     fIRInt1InteractionsMap = header.fIRInt1InteractionsMap;
137
138     delete fCTPConfig;
139     fCTPConfig = header.fCTPConfig;
140
141     fTriggerInputsNames.Clear();
142     for(Int_t i = 0; i < kNTriggerInputs; i++) {
143       TNamed *str = (TNamed *)((header.fTriggerInputsNames).At(i));
144       if (str) fTriggerInputsNames.AddAt(new TNamed(*str),i);
145     }
146     for(Int_t i = 0; i<kNMaxIR ; i++) {
147       delete fIRArray[i];
148        if(header.fIRArray[i])fIRArray[i] = new AliTriggerIR(*header.fIRArray[i]);
149        else fIRArray[i]=0;
150     }
151
152     fIRBufferArray.Delete();
153     for(Int_t i = 0; i < (header.fIRBufferArray).GetEntries(); ++i) {
154       AliTriggerIR *ir = (AliTriggerIR*)((header.fIRBufferArray).At(i));
155       if (ir) fIRBufferArray.Add(new AliTriggerIR(*ir));
156     }
157   }
158   return *this;
159 }
160
161 void AliESDHeader::Copy(TObject &obj) const 
162 {  
163   // this overwrites the virtual TOBject::Copy()
164   // to allow run time copying without casting
165   // in AliESDEvent
166
167   if(this==&obj)return;
168   AliESDHeader *robj = dynamic_cast<AliESDHeader*>(&obj);
169   if(!robj)return; // not an AliESDHeader
170   *robj = *this;
171
172 }
173 //______________________________________________________________________________
174 void AliESDHeader::Reset()
175 {
176   // reset all data members
177   fTriggerMask       = 0;
178   fTriggerMaskNext50 = 0;
179   fOrbitNumber       = 0;
180   fTimeStamp         = 0;
181   fEventType         = 0;
182   fEventSpecie       = 0;
183   fPeriodNumber      = 0;
184   fEventNumberInFile = 0;
185   fBunchCrossNumber  = 0;
186   fTriggerCluster    = 0;
187   fL0TriggerInputs   = 0;
188   fL1TriggerInputs   = 0;
189   fL2TriggerInputs   = 0;
190   fTriggerScalers.Reset();
191   fTriggerScalersDeltaEvent.Reset();
192   fTriggerScalersDeltaRun.Reset();
193   fTriggerInputsNames.Clear();
194
195   fIRInt2InteractionsMap.ResetAllBits();
196   fIRInt1InteractionsMap.ResetAllBits();
197
198   delete fCTPConfig;
199   fCTPConfig = 0;
200   for(Int_t i=0;i<kNMaxIR;i++)if(fIRArray[i]){
201    delete fIRArray[i];
202    fIRArray[i]=0;
203   }
204
205   fIRBufferArray.Delete();
206 }
207 //______________________________________________________________________________
208 Bool_t AliESDHeader::AddTriggerIR(const AliTriggerIR* ir)
209 {
210   // Add an IR object into the array
211   // of IRs in the ESD header
212
213  fIRBufferArray.Add(new AliTriggerIR(*ir));
214
215  return kTRUE;
216 }
217 //______________________________________________________________________________
218 void AliESDHeader::Print(const Option_t *) const
219 {
220   // Print some data members
221   printf("Event # %d in file Bunch crossing # %d Orbit # %d Trigger %lld \n",
222          GetEventNumberInFile(),
223          GetBunchCrossNumber(),
224          GetOrbitNumber(),
225          GetTriggerMask());
226          printf("List of the active trigger inputs: ");
227          for(Int_t i = 0; i < kNTriggerInputs; i++) {
228            TNamed *str = (TNamed *)((fTriggerInputsNames).At(i));
229            if (str) printf("%i %s ",i,str->GetName());
230          }
231          printf("\n");
232 }
233
234 //______________________________________________________________________________
235 void AliESDHeader::SetActiveTriggerInputs(const char*name, Int_t index)
236 {
237   // Fill the active trigger inputs names
238   // into the corresponding fTriggerInputsNames (TObjArray of TNamed)
239   if (index >= kNTriggerInputs || index < 0) {
240     AliError(Form("Index (%d) is outside the allowed range (0,59)!",index));
241     return;
242   }
243
244   fTriggerInputsNames.AddAt(new TNamed(name,NULL),index);
245 }
246 //______________________________________________________________________________
247 const char* AliESDHeader::GetTriggerInputName(Int_t index, Int_t trglevel) const
248 {
249   // Get the trigger input name
250   // at the specified position in the trigger mask and trigger level (0,1,2)
251   TNamed *trginput = 0;
252   if (trglevel == 0) trginput = (TNamed *)fTriggerInputsNames.At(index);
253   if (trglevel == 1) trginput = (TNamed *)fTriggerInputsNames.At(index+24);  
254   if (trglevel == 2) trginput = (TNamed *)fTriggerInputsNames.At(index+48); 
255   if (trginput) return trginput->GetName();
256   else return "";
257 }
258 //______________________________________________________________________________
259 TString AliESDHeader::GetActiveTriggerInputs() const
260 {
261   // Returns the list with the names of the active trigger inputs
262   TString trginputs;
263   for(Int_t i = 0; i < kNTriggerInputs; i++) {
264     TNamed *str = (TNamed *)((fTriggerInputsNames).At(i));
265     if (str) {
266       trginputs += " ";
267       trginputs += str->GetName();
268       trginputs += " ";
269     }
270   }
271
272   return trginputs;
273 }
274 //______________________________________________________________________________
275 TString AliESDHeader::GetFiredTriggerInputs() const
276 {
277   // Returns the list with the names of the fired trigger inputs
278   TString trginputs;
279   for(Int_t i = 0; i < kNTriggerInputs; i++) {
280       TNamed *str = (TNamed *)((fTriggerInputsNames.At(i)));
281       if (i < 24 && (fL0TriggerInputs & (1ul << i))) {
282         if (str) {
283           trginputs += " ";
284           trginputs += str->GetName();
285           trginputs += " ";
286         }
287       }
288       if (i >= 24 && i < 48 && (fL1TriggerInputs & (1ul << (i-24)))) {
289         if (str) {
290           trginputs += " ";
291           trginputs += str->GetName();
292           trginputs += " ";
293         }
294       }
295       if (i >= 48 && (fL2TriggerInputs & (1u << (i-48)))) {
296         if (str) {
297           trginputs += " ";
298           trginputs += str->GetName();
299           trginputs += " ";
300         }
301       }
302
303   }
304   return trginputs;
305 }
306 //______________________________________________________________________________
307 Bool_t AliESDHeader::IsTriggerInputFired(const char *name) const
308 {
309   // Checks if the trigger input is fired 
310  
311   TNamed *trginput = (TNamed *)fTriggerInputsNames.FindObject(name);
312   if (!trginput) return kFALSE;
313
314   Int_t inputIndex = fTriggerInputsNames.IndexOf(trginput);
315   if (inputIndex < 0) return kFALSE;
316   
317   if (fL0TriggerInputs & (1lu << inputIndex)) return kTRUE;
318   else if (fL1TriggerInputs & (1lu << (inputIndex-24))) return kTRUE;
319   else if (fL2TriggerInputs & (1u << (inputIndex-48))) return kTRUE;
320   else return kFALSE;
321 }
322 //________________________________________________________________________________
323 Int_t  AliESDHeader::GetTriggerIREntries(Int_t int1, Int_t int2, Float_t deltaTime) const
324 {
325   // returns number of IR-s within time window deltaTime
326   // all possible combinations of int1 and int2 int1 - zdc bit, int2 v0 bit
327   //
328   const AliTriggerIR *IR;
329   // triggered event 
330   Int_t nIR = GetTriggerIREntries();
331   UInt_t orbit1 = GetOrbitNumber();
332   const Double_t ot=0.0889218; //orbit time msec
333   Float_t timediff; // time difference between orbits (msec)
334   //
335   Int_t nofIR;
336   nofIR=0;
337   // loop over IR-s
338     for(Int_t i=0;i<nIR;i++){//1
339       IR=GetTriggerIR(i);
340       //
341       UInt_t orbit2 = IR->GetOrbit();
342       timediff = (orbit2<=orbit1) ? (Float_t)((orbit1-orbit2))*ot : 
343         (Float_t)((16777215-orbit1+orbit2))*ot;
344       if (timediff>deltaTime) continue; //timediff outside time window
345       if((int1&int2) == -1){ //ignore both bits, just count IR-s within time window
346         nofIR++;
347         continue;
348       }
349       // now check if int1, int2 bits are set
350       UInt_t nw = IR->GetNWord();
351       Bool_t *bint1 = IR->GetInt1s();
352       Bool_t *bint2 = IR->GetInt2s();
353       //
354       Int_t flag1,flag2;
355       flag1=0;
356       flag2=0;
357       for(UInt_t j=0;j<nw;j++){//2
358         if(bint1[j]) flag1=1; // at least one int1 set
359         if(bint2[j]) flag2=1; //  at least one int2 set
360         //printf("IR %d, bint1 %d, bint2 %d\n",i,bint1[j],bint2[j]);
361       }//2
362       // checking combinations
363       //
364       
365       if((flag1*int1*flag2*int2)==1){// int1=1 & int2=1  
366           nofIR++;
367           continue;       
368       }
369       if(int1 == -1){// ignore int1
370         if(flag2&int2){// int2=1
371           nofIR++;
372           continue;
373         }
374         else if (!flag2&!int2){ //int2=0 
375           nofIR++;
376           continue;          
377         }
378       }
379       
380       if(int2 ==-1){//ignore int2
381         if(flag1&int1){//int1=1
382           nofIR++;
383           continue;  
384         }
385         else if(!flag1&!int1){ //int1=0
386           nofIR++;
387           continue;  
388         }
389       }
390       
391       if((flag1*int1)&!flag2&!int2){// int1=1, int2=0
392           nofIR++;
393           continue;  
394       }
395       
396       if((int2*flag2)&!int1&!flag1){// int1=0, int2=1
397           nofIR++;
398           continue;  
399       } 
400          
401       
402
403     }//1
404   
405     return nofIR;
406 }
407 //__________________________________________________________________________
408 TObjArray AliESDHeader::GetIRArray(Int_t int1, Int_t int2, Float_t deltaTime) const
409 {
410   //
411   // returns an array of IR-s within time window deltaTime
412   // all possible combinations of int1 and int2 int1 - zdc bit, int2 v0 bit
413   //
414   const AliTriggerIR *IR;
415   TObjArray arr;
416   // triggered event 
417   Int_t nIR = GetTriggerIREntries();
418   UInt_t orbit1 = GetOrbitNumber();
419   const Double_t ot=0.0889218; //orbit time msec
420   Float_t timediff; // time difference between orbits (msec)
421   //
422   // loop over IR-s
423     for(Int_t i=0;i<nIR;i++){//1
424       IR=GetTriggerIR(i);
425       //
426       UInt_t orbit2 = IR->GetOrbit();
427       timediff = (orbit2<=orbit1) ? (Float_t)((orbit1-orbit2))*ot : 
428         (Float_t)((16777215-orbit1+orbit2))*ot;
429       if (timediff>deltaTime) continue; //timediff outside time window
430       if((int1&int2) == -1){ //ignore both bits, just count IR-s within time window
431         arr.Add((AliTriggerIR*)IR); //add this IR
432         continue;
433       }
434       // now check if int1, int2 bits are set
435       UInt_t nw = IR->GetNWord();
436       Bool_t *bint1 = IR->GetInt1s();
437       Bool_t *bint2 = IR->GetInt2s();
438       //
439       Int_t flag1,flag2;
440       flag1=0;
441       flag2=0;
442       for(UInt_t j=0;j<nw;j++){//2
443         if(bint1[j]) flag1=1; // at least one int1 set
444         if(bint2[j]) flag2=1; //  at least one int2 set
445       }//2
446       // checking combinations
447       //
448       if((flag1*int1*flag2*int2)==1){// int1=1 & int2=1
449           arr.Add((AliTriggerIR*)IR); //add this IR
450           continue;       
451       }
452       if(int1 == -1){// ignore int1
453         if(flag2&int2){// int2=1
454           arr.Add((AliTriggerIR*)IR); //add this IR
455           continue;
456         }
457         else if (!flag2&!int2){ //int2=0 
458           arr.Add((AliTriggerIR*)IR); //add this IR
459           continue;          
460         }
461       }
462       if(int2 ==-1){//ignore int2
463         if(flag1&int1){//int1=1
464           arr.Add((AliTriggerIR*)IR); //add this IR
465           continue;  
466         }
467         else if(!flag1&!int1){ //int1=0
468           arr.Add((AliTriggerIR*)IR); //add this IR
469           continue;  
470         }
471       }
472       if ((flag1*int1)&!flag2&!int2){// int1=1, int2=0
473           arr.Add((AliTriggerIR*)IR); //add this IR
474           continue;  
475       }
476       if ((int2*flag2)&!int1&!flag1){// int1=0, int2=1
477           arr.Add((AliTriggerIR*)IR); //add this IR
478           continue;  
479       }      
480
481     }//1
482   
483   return arr;
484 }
485
486 //__________________________________________________________________________
487 void AliESDHeader::SetIRInteractionMap() const
488 {
489   //
490   // Function to compute the map of interations 
491   // within 0TVX (int2) or V0A&V0C (int1) and the Event Id 
492   // Note, the zero value is excluded
493   //
494   const AliTriggerIR *ir[5] = {GetTriggerIR(0),GetTriggerIR(1),GetTriggerIR(2),GetTriggerIR(3),GetTriggerIR(4)};
495
496   Long64_t orb = (Long64_t)GetOrbitNumber();
497   Long64_t bc = (Long64_t)GetBunchCrossNumber();
498   
499   Long64_t evId = orb*3564 + bc;
500
501   for(Int_t i = 0; i < 5; ++i) {
502     if (ir[i] == NULL || ir[i]->GetNWord() == 0) continue;
503     Long64_t irOrb = (Long64_t)ir[i]->GetOrbit();
504     Bool_t* int2 = ir[i]->GetInt2s();
505     Bool_t* int1 = ir[i]->GetInt1s();
506     UShort_t* bcs = ir[i]->GetBCs();
507     for(UInt_t nW = 0; nW < ir[i]->GetNWord(); ++nW) {
508       Long64_t intId = irOrb*3564 + (Long64_t)bcs[nW];
509       if (int2[nW] == kTRUE) {
510           Int_t item = (intId-evId);
511           Int_t bin = FindIRIntInteractionsBXMap(item);
512           if(bin>=0) {
513             fIRInt2InteractionsMap.SetBitNumber(bin,kTRUE);
514           }
515       }
516       if (int1[nW] == kTRUE) {
517           Int_t item = (intId-evId);
518           Int_t bin = FindIRIntInteractionsBXMap(item);
519           if(bin>=0) {
520             fIRInt1InteractionsMap.SetBitNumber(bin,kTRUE);
521           }
522       }
523     }
524   }
525
526   fIRInt2InteractionsMap.Compact();
527   fIRInt1InteractionsMap.Compact();
528 }
529
530 //__________________________________________________________________________
531 Int_t AliESDHeader::FindIRIntInteractionsBXMap(Int_t difference) const
532 {
533   //
534   // The mapping is of 181 bits, from -90 to +90
535   //
536   Int_t bin=-1;
537
538   if(difference<-90 || difference>90) return bin;
539   else { bin = 90 + difference; }
540   
541   return bin;
542 }
543
544 //__________________________________________________________________________
545 Int_t AliESDHeader::GetIRInt2ClosestInteractionMap() const
546 {
547   //
548   // Calculation of the closest interaction
549   //
550   SetIRInteractionMap();
551
552   Int_t firstNegative=100;
553   for(Int_t item=-1; item>=-90; item--) {
554     Int_t bin = FindIRIntInteractionsBXMap(item);
555     Bool_t isFired = fIRInt2InteractionsMap.TestBitNumber(bin);
556     if(isFired) {
557       firstNegative = item;
558       break;
559     }
560   }
561   Int_t firstPositive=100;
562   for(Int_t item=1; item<=90; item++) {
563     Int_t bin = FindIRIntInteractionsBXMap(item);
564     Bool_t isFired = fIRInt2InteractionsMap.TestBitNumber(bin);
565     if(isFired) {
566       firstPositive = item;
567       break;
568     }
569   }
570
571   Int_t closest = firstPositive < TMath::Abs(firstNegative) ? firstPositive : TMath::Abs(firstNegative);
572   if(firstPositive==100 && firstNegative==100) closest=0;
573   return closest;
574 }
575
576 //__________________________________________________________________________
577 Int_t AliESDHeader::GetIRInt1ClosestInteractionMap(Int_t gap) const
578 {
579   //
580   // Calculation of the closest interaction
581   // In case of VZERO (Int1) one has to introduce a gap
582   // in order to avoid false positivies from after-pulses
583
584   SetIRInteractionMap();
585
586   Int_t firstNegative=100;
587   for(Int_t item=-1; item>=-90; item--) {
588     Int_t bin = FindIRIntInteractionsBXMap(item);
589     Bool_t isFired = fIRInt1InteractionsMap.TestBitNumber(bin);
590     if(isFired) {
591       firstNegative = item;
592       break;
593     }
594   }
595   Int_t firstPositive=100;
596   for(Int_t item=1+gap; item<=90; item++) {
597     Int_t bin = FindIRIntInteractionsBXMap(item);
598     Bool_t isFired = fIRInt1InteractionsMap.TestBitNumber(bin);
599     if(isFired) {
600       firstPositive = item;
601       break;
602     }
603   }
604
605   Int_t closest = firstPositive < TMath::Abs(firstNegative) ? firstPositive : TMath::Abs(firstNegative);
606   if(firstPositive==100 && firstNegative==100) closest=0;
607   return closest;
608 }
609
610 //__________________________________________________________________________
611 Int_t  AliESDHeader::GetIRInt2LastInteractionMap() const
612 {
613   //
614   // Calculation of the last interaction
615   //
616   SetIRInteractionMap();
617
618   Int_t lastNegative=0;
619   for(Int_t item=-90; item<=-1; item++) {
620     Int_t bin = FindIRIntInteractionsBXMap(item);
621     Bool_t isFired = fIRInt2InteractionsMap.TestBitNumber(bin);
622     if(isFired) {
623       lastNegative = item;
624       break;
625     }
626   }
627   Int_t lastPositive=0;
628   for(Int_t item=90; item>=1; item--) {
629     Int_t bin = FindIRIntInteractionsBXMap(item);
630     Bool_t isFired = fIRInt2InteractionsMap.TestBitNumber(bin);
631     if(isFired) {
632       lastPositive = item;
633       break;
634     }
635   }
636
637   Int_t last = lastPositive > TMath::Abs(lastNegative) ? lastPositive : TMath::Abs(lastNegative);
638   return last;
639 }