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