]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG/EMCAL/AliEmcalTriggerMaker.cxx
Correct handling of main trigger for multiple trigger classes
[u/mrichter/AliRoot.git] / PWG / EMCAL / AliEmcalTriggerMaker.cxx
1 // $Id: AliEmcalTriggerMaker.cxx 64593 2013-10-18 10:23:58Z loizides $
2 //
3 // Class to make array of trigger patch objects in AOD/ESD events.
4 //
5 // Author: J.Kral
6 #include <TClonesArray.h>
7 #include <TArrayI.h>
8 #include <THashList.h>
9 #include "AliAODCaloTrigger.h"
10 #include "AliEMCALGeometry.h"
11 #include "AliEMCALTriggerTypes.h"
12 #include "AliEmcalTriggerPatchInfo.h"
13 #include "AliEmcalTriggerSetupInfo.h"
14 #include "AliLog.h"
15 #include "AliVCaloCells.h"
16 #include "AliVCaloTrigger.h"
17 #include "AliVVZERO.h"
18 #include "AliEmcalTriggerMaker.h"
19
20 #include "THistManager.h"
21 #include "TString.h"
22
23 ClassImp(AliEmcalTriggerMaker)
24
25 using namespace std;
26
27 //________________________________________________________________________
28 AliEmcalTriggerMaker::AliEmcalTriggerMaker() : 
29   AliAnalysisTaskEmcal("AliEmcalTriggerMaker",kFALSE),
30   fCaloTriggersOutName("EmcalTriggers"),
31   fCaloTriggerSetupOutName("EmcalTriggersSetup"),
32   fV0InName("AliAODVZERO"),
33   fCaloTriggersOut(0),
34   fCaloTriggerSetupOut(0),
35   fSimpleOfflineTriggers(0),
36   fV0(0),
37   fITrigger(0),
38   fDoQA(kFALSE),
39   fQAHistos(NULL)
40 {
41   // Constructor.
42   fRunTriggerType[kTMEMCalJet] = kTRUE;
43   fRunTriggerType[kTMEMCalGamma] = kTRUE;
44   fRunTriggerType[kTMEMCalLevel0] = kTRUE;
45   memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
46   memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
47   memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
48 }
49
50 //________________________________________________________________________
51 AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name, Bool_t doQA) :
52   AliAnalysisTaskEmcal(name,doQA),
53   fCaloTriggersOutName("EmcalTriggers"),
54   fCaloTriggerSetupOutName("EmcalTriggersSetup"),
55   fV0InName("AliAODVZERO"),
56   fCaloTriggersOut(0),
57   fCaloTriggerSetupOut(0),
58   fSimpleOfflineTriggers(0),
59   fV0(0),
60   fITrigger(0),
61   fDoQA(doQA),
62   fQAHistos(NULL)
63 {
64   // Constructor.
65   memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
66   memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
67   memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
68 }
69
70 //________________________________________________________________________
71 AliEmcalTriggerMaker::~AliEmcalTriggerMaker()
72 {
73   // Destructor.
74 }
75
76 //________________________________________________________________________
77 void AliEmcalTriggerMaker::ExecOnce()
78 {
79   // Init the analysis.
80
81   AliAnalysisTaskEmcal::ExecOnce();
82
83   if (!fInitialized)
84     return;
85
86   if (!fCaloTriggersOutName.IsNull()) {
87     fCaloTriggersOut = new TClonesArray("AliEmcalTriggerPatchInfo");
88     fCaloTriggersOut->SetName(fCaloTriggersOutName);
89
90     if (!(InputEvent()->FindListObject(fCaloTriggersOutName))) {
91       InputEvent()->AddObject(fCaloTriggersOut);
92     }
93     else {
94       fInitialized = kFALSE;
95       AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggersOutName.Data()));
96       return;
97     }
98   }
99
100   if (!fCaloTriggerSetupOutName.IsNull()) {
101     fCaloTriggerSetupOut = new AliEmcalTriggerSetupInfo();
102     fCaloTriggerSetupOut->SetName(fCaloTriggerSetupOutName);
103
104     if (!(InputEvent()->FindListObject(fCaloTriggerSetupOutName))) {
105       InputEvent()->AddObject(fCaloTriggerSetupOut);
106     }
107     else {
108       fInitialized = kFALSE;
109       AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggerSetupOutName.Data()));
110       return;
111     }
112   }
113
114   if ( ! fV0InName.IsNull()) {
115     fV0 = (AliVVZERO*)InputEvent()->FindListObject(fV0InName);
116   }
117
118   // container for simple offline trigger processing
119   fSimpleOfflineTriggers = new AliAODCaloTrigger();
120   fSimpleOfflineTriggers->Allocate(0);
121 }
122
123 //________________________________________________________________________
124 void AliEmcalTriggerMaker::UserCreateOutputObjects()
125 {
126   // Do basic QA monitoring (if requested)
127   AliAnalysisTaskEmcal::UserCreateOutputObjects();
128
129   if(fDoQA){
130     fQAHistos = new THistManager("TriggerQA");
131
132     TString trtypenames[3] = {"EJE", "EGA", "EL0"};
133     for(int itype = 0; itype < 3; itype++){
134       fQAHistos->CreateTH2(Form("RCPos%s", trtypenames[itype].Data()), Form("Lower edge position of %s patches (col-row)", trtypenames[itype].Data()), 48, -0.5, 47.5, 64, -0.5, 63.5);
135       fQAHistos->CreateTH2(Form("EPCentPos%s", trtypenames[itype].Data()), Form("Center position of the %s trigger patches", trtypenames[itype].Data()), 20, -0.8, 0.8, 100., 1., 4.);
136       fQAHistos->CreateTH2(Form("PatchADCvsE%s", trtypenames[itype].Data()), Form("Patch ADC value for trigger type %s", trtypenames[itype].Data()), 200, 0., 200, 200, 0., 200);
137     }
138     fQAHistos->CreateTH1("triggerBitsAll", "Trigger bits for all incoming patches", 64, -0.5, 63.5);
139     fQAHistos->CreateTH1("triggerBitsSel", "Trigger bits for reconstructed patches", 64, -0.5, 63.5);
140     fOutput->Add(fQAHistos->GetListOfHistograms());
141     PostData(1, fOutput);
142   }
143 }
144
145 //________________________________________________________________________
146 Bool_t AliEmcalTriggerMaker::Run() 
147 {
148   // Create and fill the patch array.
149
150   AliEmcalTriggerPatchInfo *trigger, *triggerMainJet, *triggerMainGamma, *triggerMainLevel0;
151   AliEmcalTriggerPatchInfo *triggerMainJetSimple, *triggerMainGammaSimple;
152
153   // delete patch array, clear setup object
154   fCaloTriggersOut->Delete();
155   fCaloTriggerSetupOut->Clean();
156
157   if (!fCaloTriggers) {
158     AliError(Form("Calo triggers container %s not available.", fCaloTriggersName.Data()));
159     return kTRUE;
160   }
161   if (!fCaloCells) {
162     AliError(Form("Calo cells container %s not available.", fCaloCellsName.Data()));
163     return kTRUE;
164   }
165   if (!fCaloCells) {
166     AliError(Form("V0 container %s not available.", fV0InName.Data()));
167     return kTRUE;
168   }
169   
170   // do not process, if sooner than 11h period
171   // 160683 ??
172   if( InputEvent()->GetRunNumber() < 167693 )
173     return kTRUE;
174  
175 //   // do not process any MC, since no MC was generated with correct
176 //   // EMCal trigger L1 jet trigger simulation, yet
177 //   // productions will be enabled, once some correct once are produced
178 //   if( MCEvent() != 0 )
179 //     return kTRUE;
180   
181   // must reset before usage, or the class will fail 
182   fCaloTriggers->Reset();
183
184   // first run over the patch array to compose a map of 2x2 patch energies
185   // which is then needed to construct the full patch ADC energy
186   // class is not empty
187   if (fCaloTriggers->GetEntries() > 0) {
188     // zero the arrays
189     memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
190
191     // go throuth the trigger channels
192     while (fCaloTriggers->Next()) {
193       // get position in global 2x2 tower coordinates
194       // A0 left bottom (0,0)
195       Int_t globCol=-1, globRow=-1;
196       fCaloTriggers->GetPosition(globCol, globRow);
197       // for some strange reason some ADC amps are initialized in reconstruction
198       // as -1, neglect those 
199       Int_t adcAmp=-1;
200       fCaloTriggers->GetL1TimeSum(adcAmp);
201       if (adcAmp>-1)
202             fPatchADC[globCol][globRow] = adcAmp;
203     } // patches
204   } // array not empty
205   
206   // fill the array for offline trigger processing
207   // using calibrated cell energies
208   memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchRows * kPatchCols);
209
210   // fill the patch ADCs from cells
211   Int_t nCell = fCaloCells->GetNumberOfCells();
212   for(Int_t iCell = 0; iCell < nCell; ++iCell) {
213     // get the cell info, based in index in array
214     Short_t cellId = fCaloCells->GetCellNumber(iCell);
215     Double_t amp = fCaloCells->GetAmplitude(iCell);
216     // get position
217     Int_t absId=-1;
218     fGeom->GetFastORIndexFromCellIndex(cellId, absId);
219     Int_t globCol=-1, globRow=-1;
220     fGeom->GetPositionInEMCALFromAbsFastORIndex(absId, globCol, globRow);
221     // add
222     fPatchADCSimple[globCol][globRow] += amp/kEMCL1ADCtoGeV;
223   }
224
225   // dig out common data (thresholds)
226   // 0 - jet high, 1 - gamma high, 2 - jet low, 3 - gamma low
227   fCaloTriggerSetupOut->SetThresholds(fCaloTriggers->GetL1Threshold(0),
228                                       fCaloTriggers->GetL1Threshold(1),
229                                       fCaloTriggers->GetL1Threshold(2),
230                                       fCaloTriggers->GetL1Threshold(3));
231
232   // get the V0 value and compute and set the offline thresholds
233   // get V0, compute thresholds and save them as global parameters
234   Int_t v0[2];
235   v0[0] = fV0->GetTriggerChargeA();
236   v0[1] = fV0->GetTriggerChargeC();
237   ULong64_t v0S = v0[0] + v0[1];
238   fSimpleOfflineTriggers->SetL1V0(v0);
239   
240   for (Int_t i = 0; i < 4; ++i) {
241     // A*V0^2/2^32+B*V0/2^16+C
242     ULong64_t thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
243     thresh += ( ((ULong64_t)fThresholdConstants[i][1]) * v0S ) >> 16;
244     thresh += ((ULong64_t)fThresholdConstants[i][2]);
245     fSimpleOfflineTriggers->SetL1Threshold(i,thresh);
246   }
247   
248   // save the thresholds in output object
249   fCaloTriggerSetupOut->SetThresholdsSimple(fSimpleOfflineTriggers->GetL1Threshold(0),
250                                             fSimpleOfflineTriggers->GetL1Threshold(1),
251                                             fSimpleOfflineTriggers->GetL1Threshold(2),
252                                             fSimpleOfflineTriggers->GetL1Threshold(3));
253
254   // run the trigger
255   RunSimpleOfflineTrigger();
256
257   // reset for re-run
258   fCaloTriggers->Reset();
259   fSimpleOfflineTriggers->Reset();
260
261   // class is not empty
262   if (fCaloTriggers->GetEntries() > 0 ||  fSimpleOfflineTriggers->GetEntries() > 0) {
263     fITrigger = 0;
264     triggerMainGamma = 0;
265     triggerMainJet = 0;
266     triggerMainGammaSimple = 0;
267     triggerMainJetSimple = 0;
268     triggerMainLevel0 = 0;
269
270     // go throuth the trigger channels, real first, then offline
271     Bool_t isOfflineSimple=0;
272     while (NextTrigger(isOfflineSimple)) {
273       // process jet
274       if(fRunTriggerType[kTMEMCalJet]){
275         trigger = ProcessPatch(kTMEMCalJet, isOfflineSimple);
276         // save main jet triggers in event
277         if (trigger != 0) {
278           // check if more energetic than others for main patch marking
279           if (!isOfflineSimple) {
280             if (triggerMainJet == 0 || (triggerMainJet->GetPatchE() < trigger->GetPatchE()))
281               triggerMainJet = trigger;
282           } else {
283             if (triggerMainJetSimple == 0 || (triggerMainJetSimple->GetPatchE() < trigger->GetPatchE()))
284               triggerMainJetSimple = trigger;
285           }
286         }
287       }
288       
289       // process gamma
290       if(fRunTriggerType[kTMEMCalGamma]){
291         trigger = ProcessPatch(kTMEMCalGamma, isOfflineSimple);
292         // save main gamma triggers in event
293         if (trigger != 0) {
294           // check if more energetic than others for main patch marking
295           if (!isOfflineSimple) {
296             if (triggerMainGamma == 0 || (triggerMainGamma->GetPatchE() < trigger->GetPatchE()))
297               triggerMainGamma = trigger;
298           } else {
299             if (triggerMainGammaSimple == 0 || (triggerMainGammaSimple->GetPatchE() < trigger->GetPatchE()))
300               triggerMainGammaSimple = trigger;
301           }
302         }
303       }
304
305       // level 0 triggers
306       if(fRunTriggerType[kTMEMCalLevel0]){
307         trigger = ProcessPatch(kTMEMCalLevel0, isOfflineSimple);
308         // save main level0 trigger in the event
309         if (trigger) {
310           if (!triggerMainLevel0 || (triggerMainLevel0->GetPatchE() < trigger->GetPatchE()))
311             triggerMainLevel0 = trigger;
312         }
313       }
314     } // triggers
315     
316     // mark the most energetic patch as main
317     // for real and also simple offline
318     if (triggerMainJet != 0) {
319       Int_t tBits = triggerMainJet->GetTriggerBits();
320       // main trigger flag
321       tBits = tBits | ( 1 << 24 );
322       triggerMainJet->SetTriggerBits( tBits );
323     }
324     if (triggerMainJetSimple != 0) {
325       Int_t tBits = triggerMainJetSimple->GetTriggerBits();
326       // main trigger flag
327       tBits = tBits | ( 1 << 24 );
328       triggerMainJetSimple->SetTriggerBits(tBits);
329     }
330     if (triggerMainGamma != 0) {
331       Int_t tBits = triggerMainGamma->GetTriggerBits();
332       // main trigger flag
333       tBits = tBits | ( 1 << 24 );
334       triggerMainGamma->SetTriggerBits( tBits );
335     }
336     if (triggerMainGammaSimple != 0) {
337       Int_t tBits = triggerMainGammaSimple->GetTriggerBits();
338       // main trigger flag
339       tBits = tBits | ( 1 << 24 );
340       triggerMainGammaSimple->SetTriggerBits( tBits );
341     }
342     if(triggerMainLevel0){
343       Int_t tBits = triggerMainLevel0->GetTriggerBits();
344       // main trigger flag
345       tBits |= (1 << 24);
346       triggerMainLevel0->SetTriggerBits(tBits);
347     }
348   } // there are some triggers
349
350   return kTRUE;
351 }
352
353 //________________________________________________________________________
354 AliEmcalTriggerPatchInfo* AliEmcalTriggerMaker::ProcessPatch(TriggerMakerTriggerType_t type, Bool_t isOfflineSimple)
355 {
356   // Process and fill trigger patch.
357   // check if jet trigger low or high
358   Int_t tBits=-1;
359   if (!isOfflineSimple)
360     fCaloTriggers->GetTriggerBits(tBits);
361   else
362     fSimpleOfflineTriggers->GetTriggerBits(tBits);
363
364   Int_t nBitsFound = 0;
365   Int_t bitsFound[64];
366   if(fDoQA){
367     for(unsigned int ibit = 0; ibit < sizeof(tBits)*8; ibit++) {
368       if(tBits & (1 << ibit)){
369         bitsFound[nBitsFound++] = ibit;
370         fQAHistos->FillTH1("triggerBitsAll", ibit);
371       }
372     }
373   }
374         
375   if ((type == kTMEMCalJet    && !IsEJE( tBits )) || 
376       (type == kTMEMCalGamma  && !IsEGA( tBits )) || 
377       (type == kTMEMCalLevel0 && !(CheckForL0(*fCaloTriggers))))
378     return 0;
379   TString trtypenames[3] = {"EJE", "EGA", "EL0"}; // For QA
380
381   // save primary vertex in vector
382   TVector3 vertex;
383   vertex.SetXYZ(fVertex[0], fVertex[1], fVertex[2]);
384
385   // get position in global 2x2 tower coordinates
386   // A0 left bottom (0,0)
387   Int_t globCol=-1, globRow=-1;
388   if (!isOfflineSimple)
389     fCaloTriggers->GetPosition(globCol,globRow);
390   else
391     fSimpleOfflineTriggers->GetPosition(globCol, globRow);
392
393   // get the absolute trigger ID
394   Int_t absId=-1;
395   fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol, globRow, absId);
396   // convert to the 4 absId of the cells composing the trigger channel
397   Int_t cellAbsId[4]={-1,-1,-1,-1};
398   fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
399         
400   // get low left edge (eta max, phi min)
401   TVector3 edge1;
402   fGeom->GetGlobal(cellAbsId[0], edge1);
403         
404   // sum the available energy in the 32/32 window of cells
405   // step over trigger channels and get all the corresponding cells
406   // make CM
407   Double_t amp = 0;
408   Int_t cmiCol = 0;
409   Int_t cmiRow = 0;
410   Int_t adcAmp = 0;
411   int nfastor = (type == kTMEMCalJet) ? 16 : 2; // 32x32 cell window for L1 Jet trigger, 4x4 for L1 Gamma or L0 trigger
412   for (Int_t i = 0; i < nfastor; ++i) {
413     for (Int_t j = 0; j < nfastor; ++j) {
414           // get the 4 cells composing the trigger channel
415           fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+i, globRow+j, absId);
416           fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
417           // add amplitudes and find patch edges
418           for (Int_t k = 0; k < 4; ++k) {
419             Double_t ca = fCaloCells->GetCellAmplitude(cellAbsId[k]);
420             //fGeom->GetGlobal(cellAbsId[k], cellCoor);
421             amp += ca;
422             cmiCol += ca*(Double_t)i;
423             cmiRow += ca*(Double_t)j;
424           }
425           // add the STU ADCs in the patch (in case of L1) or the TRU Amplitude (in case of L0)
426           if (!isOfflineSimple )
427               if(type == kTMEMCalLevel0){
428                 adcAmp += fPatchADC[globCol+i][globRow+j] * 4; // precision loss in case of global integer field
429               } else
430                 adcAmp += fPatchADC[globCol+i][globRow+j];
431           else
432             adcAmp += fPatchADCSimple[globCol+i][globRow+j];
433     }
434   }
435
436   if (amp == 0) {
437     AliDebug(2,"EMCal trigger patch with 0 energy.");
438     return 0;
439   }
440   
441   // get the CM and patch index
442   cmiCol /= amp;
443   cmiRow /= amp;
444   Int_t cmCol = globCol + (Int_t)cmiCol;
445   Int_t cmRow = globRow + (Int_t)cmiRow;
446
447   // get the patch and corresponding cells
448   fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
449   fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
450
451   // find which out of the 4 cells is closest to CM and get it's position
452   Int_t cmiCellCol = TMath::Nint(cmiCol * 2.);
453   Int_t cmiCellRow = TMath::Nint(cmiRow * 2.);
454   TVector3 centerMass;
455   fGeom->GetGlobal(cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass);
456         
457   // get up right edge (eta min, phi max)
458   // get the absolute trigger ID
459   Int_t posOffset=-1;
460   switch(type){
461   case kTMEMCalJet:
462     posOffset = 15;
463     break;
464   case kTMEMCalGamma:
465     posOffset = 1;
466     break;
467   case kTMEMCalLevel0:
468     posOffset = 1;
469     break;
470   default:
471     posOffset = 0;
472     break;
473   };
474   fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
475   fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
476   TVector3 edge2;
477   fGeom->GetGlobal(cellAbsId[3], edge2);
478         
479   // get the geometrical center as an average of two diagonally
480   // adjacent patches in the center
481   // picking two diagonally closest cells from the patches
482   switch(type){
483   case kTMEMCalJet:
484     posOffset = 7;
485     break;
486   case kTMEMCalGamma:
487     posOffset = 0;
488     break;
489   case kTMEMCalLevel0:
490     posOffset = 0;
491     break;
492   default:
493     posOffset = 0;
494     break;
495   };
496   fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
497   fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
498   TVector3 center1;
499   fGeom->GetGlobal(cellAbsId[3], center1);
500         
501   switch(type){
502   case kTMEMCalJet:
503     posOffset = 8;
504     break;
505   case kTMEMCalGamma:
506     posOffset = 1;
507     break;
508   case kTMEMCalLevel0:
509     posOffset = 1;
510     break;
511   };
512   fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
513   fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
514   TVector3 center2;
515   fGeom->GetGlobal(cellAbsId[0], center2);
516         
517   TVector3 centerGeo(center1);
518   centerGeo += center2;
519   centerGeo *= 0.5;
520         
521   // relate all to primary vertex
522   centerGeo -= vertex;
523   centerMass -= vertex;
524   edge1 -= vertex;
525   edge2 -= vertex;
526
527   Int_t isMC = MCEvent() ? 1 : 0;
528   Int_t offSet = (1 - isMC) * kTriggerTypeEnd;
529         
530   // fix tbits .. remove the unwanted type triggers
531   // for Jet and Gamma triggers we remove also the level 0 bit since it will be stored in the level 0 patch
532   // for level 0 we remove all gamma and jet trigger bits
533   switch(type){
534   case kTMEMCalJet:
535     tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1GammaLow) | 1 << (kTriggerTypeEnd + kL1GammaHigh) | 1 << (kL1GammaLow) | 1 << (kL1GammaHigh) |
536                        1 << (kTriggerTypeEnd + kL0) | 1 << (kL0));
537     break;
538   case kTMEMCalGamma:
539     tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1JetLow) | 1 << (kTriggerTypeEnd + kL1JetHigh) | 1 << (kL1JetLow) | 1 << (kL1JetHigh) |
540                        1 << (kTriggerTypeEnd + kL0) | 1 << (kL0));
541     break;
542   case kTMEMCalLevel0:
543     // Explicitly set the level 0 bit to overcome the masking out
544     tBits |= 1 << (offSet + kL0);
545     tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1JetLow) | 1 << (kTriggerTypeEnd + kL1JetHigh) | 1 << (kL1JetLow) | 1 << (kL1JetHigh) |
546                        1 << (kTriggerTypeEnd + kL1GammaLow) | 1 << (kTriggerTypeEnd + kL1GammaHigh) | 1 << (kL1GammaLow) | 1 << (kL1GammaHigh));
547     break;
548   };
549
550   // save the trigger object
551   AliEmcalTriggerPatchInfo *trigger = 
552     new ((*fCaloTriggersOut)[fITrigger]) AliEmcalTriggerPatchInfo();
553   fITrigger++;
554   trigger->SetCenterGeo(centerGeo, amp);
555   trigger->SetCenterMass(centerMass, amp);
556   trigger->SetEdge1(edge1, amp);
557   trigger->SetEdge2(edge2, amp);
558   trigger->SetADCAmp(adcAmp);
559   trigger->SetTriggerBits(tBits);
560   trigger->SetOffSet(offSet);
561   trigger->SetEdgeCell(globCol*2, globRow*2); // from triggers to cells
562   if(fDoQA){
563     fQAHistos->FillTH2(Form("RCPos%s", trtypenames[type].Data()), globCol, globRow);
564     fQAHistos->FillTH2(Form("EPCentPos%s", trtypenames[type].Data()), centerGeo.Eta(), centerGeo.Phi());
565     fQAHistos->FillTH2(Form("PatchADCvsE%s", trtypenames[type].Data()), adcAmp, trigger->GetPatchE());
566     if(nBitsFound){
567       for(int ibit = 0; ibit < nBitsFound; ibit++)
568         fQAHistos->FillTH1("triggerBitsSel", bitsFound[ibit]);
569     }
570   }
571   return trigger;
572 }
573
574 //________________________________________________________________________
575 void AliEmcalTriggerMaker::RunSimpleOfflineTrigger() 
576 {
577   // Runs a simple offline trigger algorithm.
578   // It creates separate patches for jet and gamma triggers
579   // on the same positions (different from STU reconstruction behavior)
580   // TODO:: change to merge
581
582   TArrayI tBitsArray, rowArray, colArray;
583   
584   // 0 thresholds = no processing
585   if (fCaloTriggerSetupOut->GetThresholdJetLowSimple() == 0 &&
586       fCaloTriggerSetupOut->GetThresholdJetHighSimple() == 0 )
587     return;
588   
589   // run the trigger algo, stepping by 8 towers (= 4 trigger channels)
590   for (Int_t i = 0; i < 32; i += 4) {
591     for (Int_t j = 0; j < 48; j += 4) {
592       Int_t tSum  = 0;
593       Int_t tBits = 0;
594       // window
595       for (Int_t k = 0; k < 16; ++k)
596         for (Int_t l = 0; l < 16; ++l)
597           tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
598       
599       // check thresholds
600       if (tSum > fCaloTriggerSetupOut->GetThresholdJetLowSimple())
601         tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetLow ));
602       if (tSum > fCaloTriggerSetupOut->GetThresholdJetHighSimple())
603         tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetHigh ));
604       
605       // add trigger values
606       if (tBits != 0) {
607         // add offline bit
608         tBits = tBits | ( 1 << 25 );
609         tBitsArray.Set( tBitsArray.GetSize() + 1 );
610         colArray.Set( colArray.GetSize() + 1 );
611         rowArray.Set( rowArray.GetSize() + 1 );
612         tBitsArray[tBitsArray.GetSize()-1] = tBits;
613         colArray[colArray.GetSize()-1] = i;
614         rowArray[rowArray.GetSize()-1] = j;
615       }
616     }
617   } // trigger algo
618   
619   // 4x4 trigger algo, stepping by 2 towers (= 1 trigger channel)
620   for (Int_t i = 0; i < 46; ++i) {
621     for (Int_t j = 0; j < 62; ++j) {
622       Int_t tSum = 0;
623       Int_t tBits = 0;
624       
625       // window
626       for (Int_t k = 0; k < 2; ++k)
627         for (Int_t l = 0; l < 2; ++l)
628           tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
629       
630       // check thresholds
631       if (tSum > fCaloTriggerSetupOut->GetThresholdGammaLowSimple())
632         tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaLow ));
633       if (tSum > fCaloTriggerSetupOut->GetThresholdGammaHighSimple())
634         tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaHigh ));
635       
636       // add trigger values
637       if (tBits != 0) {
638         // add offline bit
639         tBits = tBits | ( 1 << 25 );
640         tBitsArray.Set( tBitsArray.GetSize() + 1 );
641         colArray.Set( colArray.GetSize() + 1 );
642         rowArray.Set( rowArray.GetSize() + 1 );
643         tBitsArray[tBitsArray.GetSize()-1] = tBits;
644         colArray[colArray.GetSize()-1] = i;
645         rowArray[rowArray.GetSize()-1] = j;
646       }
647     }
648   } // trigger algo
649   
650   // save in object
651   fSimpleOfflineTriggers->DeAllocate();
652   fSimpleOfflineTriggers->Allocate(tBitsArray.GetSize());
653   for (Int_t i = 0; i < tBitsArray.GetSize(); ++i){
654     fSimpleOfflineTriggers->Add(colArray[i],rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i]);
655   }
656 }
657
658 //________________________________________________________________________
659 Bool_t AliEmcalTriggerMaker::NextTrigger(Bool_t &isOfflineSimple) 
660 {
661   // Get next trigger
662   
663   isOfflineSimple = kFALSE;
664   Bool_t loopContinue = fCaloTriggers->Next();
665   if (!loopContinue) {
666     loopContinue = fSimpleOfflineTriggers->Next();
667     isOfflineSimple = kTRUE;
668   }
669   return loopContinue;
670 }
671
672 //________________________________________________________________________
673 Bool_t AliEmcalTriggerMaker::CheckForL0(const AliVCaloTrigger& trg) const {
674   // Check whether the patch is a level0 patch
675   if(MCEvent()){
676     // For Monte-Carlo select
677     Int_t tbits(-1);
678     trg.GetTriggerBits(tbits);
679     return tbits & (1 << kL0);
680   } else {
681     // For Data check from the level0 times if the trigger has fired at level0
682     Int_t nl0times(0);
683     Bool_t l0fired(kFALSE);
684     trg.GetNL0Times(nl0times);
685     if(nl0times){
686       TArrayI l0times(nl0times);
687       trg.GetL0Times(l0times.GetArray());
688       // Apply timing cut to see if a L0 has fired
689       for(Int_t *l0timeIter = l0times.GetArray(); l0timeIter < l0times.GetArray() + l0times.GetSize(); l0timeIter++){
690         if(*l0timeIter > 7 && *l0timeIter < 10){
691           l0fired = kTRUE;
692           break;
693         }
694       }
695     }
696     return l0fired;
697   }
698 }