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