AliPhysics  9fe175b (9fe175b)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AliEmcalTriggerMaker.cxx
Go to the documentation of this file.
1 /**************************************************************************
2  * Copyright(c) 1998-2013, 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 #include <TClonesArray.h>
16 #include <TArrayI.h>
17 #include <THashList.h>
18 #include "AliAODCaloTrigger.h"
19 #include "AliEMCALGeometry.h"
20 #include "AliEmcalTriggerMaker.h"
22 #include "AliEMCALTriggerConstants.h"
23 #include "AliEMCALTriggerDataGrid.h"
24 #include "AliEMCALTriggerPatchInfo.h"
25 #include "AliLog.h"
26 #include "AliVCaloCells.h"
27 #include "AliVCaloTrigger.h"
28 #include "AliVVZERO.h"
29 #include "THistManager.h"
30 #include "TString.h"
31 
32 #include <bitset>
33 #include <iostream>
34 
37 
38 
40 using namespace std;
41 
42 const int AliEmcalTriggerMaker::kColsEta = 48;
43 
44 const TString AliEmcalTriggerMaker::fgkTriggerTypeNames[5] = {"EJE", "EGA", "EL0", "REJE", "REGA"};
45 
50  AliAnalysisTaskEmcal("AliEmcalTriggerMaker",kFALSE),
51  fCaloTriggersOutName("EmcalTriggers"),
52  fCaloTriggerSetupOutName("EmcalTriggersSetup"),
53  fV0InName("AliAODVZERO"),
54  fUseTriggerBitConfig(kNewConfig),
55  fTriggerBitConfig(NULL),
56  fCaloTriggersOut(0),
57  fCaloTriggerSetupOut(0),
58  fSimpleOfflineTriggers(0),
59  fV0(0),
60  fPatchAmplitudes(NULL),
61  fPatchADCSimple(NULL),
62  fPatchADC(NULL),
63  fLevel0TimeMap(NULL),
64  fITrigger(0),
65  fDoQA(kFALSE),
66  fRejectOffAcceptancePatches(kFALSE),
67  fQAHistos(NULL),
68  fDebugLevel(0)
69 {
75  memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
76 }
77 
83 AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name, Bool_t doQA) :
84  AliAnalysisTaskEmcal(name,doQA),
85  fCaloTriggersOutName("EmcalTriggers"),
86  fCaloTriggerSetupOutName("EmcalTriggersSetup"),
87  fV0InName("AliAODVZERO"),
88  fUseTriggerBitConfig(kNewConfig),
89  fTriggerBitConfig(NULL),
90  fCaloTriggersOut(0),
91  fCaloTriggerSetupOut(0),
92  fSimpleOfflineTriggers(0),
93  fV0(0),
94  fPatchAmplitudes(NULL),
95  fPatchADCSimple(NULL),
96  fPatchADC(NULL),
97  fLevel0TimeMap(NULL),
98  fITrigger(0),
99  fDoQA(doQA),
100  fRejectOffAcceptancePatches(kFALSE),
101  fQAHistos(NULL),
102  fDebugLevel(0)
103 {
104  // Constructor.
105  fRunTriggerType[kTMEMCalJet] = kTRUE;
110  memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
111 }
112 
117 {
119 }
120 
125 {
127 
128  if (!fInitialized)
129  return;
130 
131  if(!fTriggerBitConfig){
132  switch(fUseTriggerBitConfig){
133  case kNewConfig:
134  fTriggerBitConfig = new AliEMCALTriggerBitConfigNew();
135  break;
136  case kOldConfig:
137  fTriggerBitConfig = new AliEMCALTriggerBitConfigOld();
138  break;
139  }
140  }
141 
142  if (!fCaloTriggersOutName.IsNull()) {
143  fCaloTriggersOut = new TClonesArray("AliEMCALTriggerPatchInfo");
145 
146  if (!(InputEvent()->FindListObject(fCaloTriggersOutName))) {
147  InputEvent()->AddObject(fCaloTriggersOut);
148  }
149  else {
150  fInitialized = kFALSE;
151  AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggersOutName.Data()));
152  return;
153  }
154  }
155 
156  if (!fCaloTriggerSetupOutName.IsNull()) {
159 
160  if (!(InputEvent()->FindListObject(fCaloTriggerSetupOutName))) {
161  InputEvent()->AddObject(fCaloTriggerSetupOut);
162  }
163  else {
164  fInitialized = kFALSE;
165  AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggerSetupOutName.Data()));
166  return;
167  }
168  }
169 
170  if ( ! fV0InName.IsNull()) {
171  fV0 = (AliVVZERO*)InputEvent()->FindListObject(fV0InName);
172  }
173 
174 
175  // Allocate containers for the ADC values
176  int nrows = fGeom->GetNTotalTRU() * 2;
177  std::cout << "Allocating channel grid with 48 columns in eta and " << nrows << " rows in phi" << std::endl;
178  fPatchAmplitudes->Allocate(48, nrows);
179  fPatchADC->Allocate(48, nrows);
180  fPatchADCSimple->Allocate(48, nrows);
181  fLevel0TimeMap->Allocate(48, nrows);
182 
183  // container for simple offline trigger processing
184  fSimpleOfflineTriggers = new AliAODCaloTrigger();
185  fSimpleOfflineTriggers->Allocate(0);
186 }
187 
192 {
194 
195  // Create data structure for energy measurements;
200 
201  if(fDoQA && fOutput){
202  fQAHistos = new THistManager("TriggerQA");
203  const char *patchtypes[2] = {"Online", "Offline"};
204 
205  for(int itype = 0; itype < 5; itype++){
206  for(const char **patchtype = patchtypes; patchtype < patchtypes + 2; ++patchtype){
207  fQAHistos->CreateTH2(Form("RCPos%s%s", fgkTriggerTypeNames[itype].Data(), *patchtype), Form("Lower edge position of %s %s patches (col-row);iEta;iPhi", *patchtype, fgkTriggerTypeNames[itype].Data()), 48, -0.5, 47.5, 104, -0.5, 103.5);
208  fQAHistos->CreateTH2(Form("EPCentPos%s%s", fgkTriggerTypeNames[itype].Data(), *patchtype), Form("Center position of the %s %s trigger patches;#eta;#phi", *patchtype, fgkTriggerTypeNames[itype].Data()), 20, -0.8, 0.8, 700, 0., 7.);
209  fQAHistos->CreateTH2(Form("PatchADCvsE%s%s", fgkTriggerTypeNames[itype].Data(), *patchtype), Form("Patch ADC value for trigger type %s %s;Trigger ADC;FEE patch energy (GeV)", *patchtype, fgkTriggerTypeNames[itype].Data()), 2000, 0., 2000, 200, 0., 200);
210  }
211  }
212  fQAHistos->CreateTH1("triggerBitsAll", "Trigger bits for all incoming patches;bit nr", 64, -0.5, 63.5);
213  fQAHistos->CreateTH1("triggerBitsSel", "Trigger bits for reconstructed patches;bit nr", 64, -0.5, 63.5);
215  PostData(1, fOutput);
216  }
217 }
218 
224 {
225  AliEMCALTriggerPatchInfo *trigger, *triggerMainJet, *triggerMainGamma, *triggerMainLevel0;
226  AliEMCALTriggerPatchInfo *triggerMainJetSimple, *triggerMainGammaSimple;
227 
228  // delete patch array, clear setup object
229  fCaloTriggersOut->Delete();
231 
232  if (!fCaloTriggers) {
233  AliError(Form("Calo triggers container %s not available.", fCaloTriggersName.Data()));
234  return kTRUE;
235  }
236  if (!fCaloCells) {
237  AliError(Form("Calo cells container %s not available.", fCaloCellsName.Data()));
238  return kTRUE;
239  }
240  if (!fCaloCells) {
241  AliError(Form("V0 container %s not available.", fV0InName.Data()));
242  return kTRUE;
243  }
244 
245  // do not process, if sooner than 11h period
246  // 160683 ??
247  if( InputEvent()->GetRunNumber() < 167693 )
248  return kTRUE;
249 
250 // // do not process any MC, since no MC was generated with correct
251 // // EMCal trigger L1 jet trigger simulation, yet
252 // // productions will be enabled, once some correct once are produced
253 // if( MCEvent() != 0 )
254 // return kTRUE;
255 
256  // must reset before usage, or the class will fail
257  fCaloTriggers->Reset();
258 
259  // zero the arrays
260  fPatchAmplitudes->Reset();
261  fPatchADC->Reset();
262  fPatchADCSimple->Reset();
263  fLevel0TimeMap->Reset();
264 
265  // first run over the patch array to compose a map of 2x2 patch energies
266  // which is then needed to construct the full patch ADC energy
267  // class is not empty
268  if (fCaloTriggers->GetEntries() > 0) {
269 
270  // go throuth the trigger channels
271  while (fCaloTriggers->Next()) {
272  // get position in global 2x2 tower coordinates
273  // A0 left bottom (0,0)
274  Int_t globCol=-1, globRow=-1;
275  fCaloTriggers->GetPosition(globCol, globRow);
276  // exclude channel completely if it is masked as hot channel
277  if(fBadChannels.HasChannel(globCol, globRow)) continue;
278  // for some strange reason some ADC amps are initialized in reconstruction
279  // as -1, neglect those
280  Int_t adcAmp=-1;
281  fCaloTriggers->GetL1TimeSum(adcAmp);
282  if (adcAmp>-1)
283  (*fPatchADC)(globCol,globRow) = adcAmp;
284 
285  // Handling for L0 triggers
286  // For the ADC value we use fCaloTriggers->GetAmplitude()
287  // In data, all patches which have 4 TRUs with proper level0 times are
288  // valid trigger patches. Therefore we need to check all neighbors for
289  // the level0 times, not only the bottom left. In order to obtain this
290  // information, a lookup table with the L0 times for each TRU is created
291  Float_t amplitude(0);
292  fCaloTriggers->GetAmplitude(amplitude);
293  if(amplitude < 0) amplitude = 0;
294  (*fPatchAmplitudes)(globCol,globRow) = amplitude;
295  Int_t nl0times(0);
296  fCaloTriggers->GetNL0Times(nl0times);
297  if(nl0times){
298  TArrayI l0times(nl0times);
299  fCaloTriggers->GetL0Times(l0times.GetArray());
300  for(int itime = 0; itime < nl0times; itime++){
301  if(l0times[itime] >7 && l0times[itime] < 10){
302  (*fLevel0TimeMap)(globCol,globRow) = static_cast<Char_t>(l0times[itime]);
303  break;
304  }
305  }
306  }
307  } // patches
308  } // array not empty
309 
310  // fill the patch ADCs from cells
311  Int_t nCell = fCaloCells->GetNumberOfCells();
312  for(Int_t iCell = 0; iCell < nCell; ++iCell) {
313  // get the cell info, based in index in array
314  Short_t cellId = fCaloCells->GetCellNumber(iCell);
315  Double_t amp = fCaloCells->GetAmplitude(iCell);
316  // get position
317  Int_t absId=-1;
318  fGeom->GetFastORIndexFromCellIndex(cellId, absId);
319  Int_t globCol=-1, globRow=-1;
320  fGeom->GetPositionInEMCALFromAbsFastORIndex(absId, globCol, globRow);
321  // add
322  (*fPatchADCSimple)(globCol,globRow) += amp/EMCALTrigger::kEMCL1ADCtoGeV;
323  }
324 
325  // dig out common data (thresholds)
326  // 0 - jet high, 1 - gamma high, 2 - jet low, 3 - gamma low
328  fCaloTriggers->GetL1Threshold(1),
329  fCaloTriggers->GetL1Threshold(2),
330  fCaloTriggers->GetL1Threshold(3));
331 
332  // get the V0 value and compute and set the offline thresholds
333  // get V0, compute thresholds and save them as global parameters
334  Int_t v0[2];
335  v0[0] = fV0->GetTriggerChargeA();
336  v0[1] = fV0->GetTriggerChargeC();
337  ULong64_t v0S = v0[0] + v0[1];
338  fSimpleOfflineTriggers->SetL1V0(v0);
339 
340  for (Int_t i = 0; i < 4; ++i) {
341  // A*V0^2/2^32+B*V0/2^16+C
342  ULong64_t thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
343  thresh += ( ((ULong64_t)fThresholdConstants[i][1]) * v0S ) >> 16;
344  thresh += ((ULong64_t)fThresholdConstants[i][2]);
345  fSimpleOfflineTriggers->SetL1Threshold(i,thresh);
346  }
347 
348  // save the thresholds in output object
350  fSimpleOfflineTriggers->GetL1Threshold(1),
351  fSimpleOfflineTriggers->GetL1Threshold(2),
352  fSimpleOfflineTriggers->GetL1Threshold(3));
353 
354  // run the trigger
356 
357  // reset for re-run
358  fCaloTriggers->Reset();
359  fSimpleOfflineTriggers->Reset();
360 
361  // class is not empty
362  if (fCaloTriggers->GetEntries() > 0 || fSimpleOfflineTriggers->GetEntries() > 0) {
363  fITrigger = 0;
364  triggerMainGamma = 0;
365  triggerMainJet = 0;
366  triggerMainGammaSimple = 0;
367  triggerMainJetSimple = 0;
368  triggerMainLevel0 = 0;
369 
370  // go throuth the trigger channels, real first, then offline
371  Bool_t isOfflineSimple=0;
372  while (NextTrigger(isOfflineSimple)) {
373  // process jet
375  trigger = ProcessPatch(kTMEMCalJet, isOfflineSimple);
376  // save main jet triggers in event
377  if (trigger != 0) {
378  // check if more energetic than others for main patch marking
379  if (!isOfflineSimple) {
380  if (triggerMainJet == 0 || (triggerMainJet->GetPatchE() < trigger->GetPatchE()))
381  triggerMainJet = trigger;
382  } else {
383  if (triggerMainJetSimple == 0 || (triggerMainJetSimple->GetPatchE() < trigger->GetPatchE()))
384  triggerMainJetSimple = trigger;
385  }
386  }
387  }
388 
389  // process gamma
391  trigger = ProcessPatch(kTMEMCalGamma, isOfflineSimple);
392  // save main gamma triggers in event
393  if (trigger != 0) {
394  // check if more energetic than others for main patch marking
395  if (!isOfflineSimple) {
396  if (triggerMainGamma == 0 || (triggerMainGamma->GetPatchE() < trigger->GetPatchE()))
397  triggerMainGamma = trigger;
398  } else {
399  if (triggerMainGammaSimple == 0 || (triggerMainGammaSimple->GetPatchE() < trigger->GetPatchE()))
400  triggerMainGammaSimple = trigger;
401  }
402  }
403  }
404 
405  // level 0 triggers (only in case of online patches)
406  if(!isOfflineSimple){
408  trigger = ProcessPatch(kTMEMCalLevel0, kFALSE);
409  // save main level0 trigger in the event
410  if (trigger) {
411  if (!triggerMainLevel0 || (triggerMainLevel0->GetPatchE() < trigger->GetPatchE()))
412  triggerMainLevel0 = trigger;
413  }
414  }
415  }
416 
417  // Recalculated triggers (max patches without threshold)
419  ProcessPatch(kTMEMCalRecalcJet, isOfflineSimple);
421  ProcessPatch(kTMEMCalRecalcGamma, isOfflineSimple);
422  } // triggers
423 
424  // mark the most energetic patch as main
425  // for real and also simple offline
426  if (triggerMainJet != 0) {
427  Int_t tBits = triggerMainJet->GetTriggerBits();
428  // main trigger flag
429  tBits = tBits | ( 1 << kMainTriggerBitNum );
430  triggerMainJet->SetTriggerBits( tBits );
431  }
432  if (triggerMainJetSimple != 0) {
433  Int_t tBits = triggerMainJetSimple->GetTriggerBits();
434  // main trigger flag
435  tBits = tBits | ( 1 << kMainTriggerBitNum );
436  triggerMainJetSimple->SetTriggerBits(tBits);
437  }
438  if (triggerMainGamma != 0) {
439  Int_t tBits = triggerMainGamma->GetTriggerBits();
440  // main trigger flag
441  tBits = tBits | ( 1 << kMainTriggerBitNum );
442  triggerMainGamma->SetTriggerBits( tBits );
443  }
444  if (triggerMainGammaSimple != 0) {
445  Int_t tBits = triggerMainGammaSimple->GetTriggerBits();
446  // main trigger flag
447  tBits = tBits | ( 1 << kMainTriggerBitNum );
448  triggerMainGammaSimple->SetTriggerBits( tBits );
449  }
450  if(triggerMainLevel0){
451  Int_t tBits = triggerMainLevel0->GetTriggerBits();
452  // main trigger flag
453  tBits |= (1 << kMainTriggerBitNum);
454  triggerMainLevel0->SetTriggerBits(tBits);
455  }
456  } // there are some triggers
457 
458  // Diagnostics
459  int npatchOnline = 0;
460  for(TIter patchIter = TIter(fCaloTriggersOut).Begin(); patchIter != TIter::End(); ++patchIter){
461  AliEMCALTriggerPatchInfo *mypatch = static_cast<AliEMCALTriggerPatchInfo *>(*patchIter);
462  if(mypatch->IsOfflineSimple()) continue;
463  AliDebug(1,Form("Patch with bits: %s, types: JH[%s], JL[%s], GH[%s], GL[%s], L0[%s]",
464  std::bitset<sizeof(int)*4>(mypatch->GetTriggerBits()).to_string().c_str(),
465  (mypatch->IsJetHigh() ? "y" : "n"), (mypatch->IsJetLow() ? "y" : "n"),
466  (mypatch->IsGammaHigh() ? "y" : "n"), (mypatch->IsGammaLow() ? "y" : "n"),(mypatch->IsLevel0() ? "y" : "n")));
467  npatchOnline++;
468  }
469  AliDebug(1, Form("Number of online patches: %d", npatchOnline));
470 
471  return kTRUE;
472 }
473 
481 AliEMCALTriggerPatchInfo* AliEmcalTriggerMaker::ProcessPatch(TriggerMakerTriggerType_t type, Bool_t isOfflineSimple)
482 {
483  Int_t tBits=-1;
484  if (!isOfflineSimple)
485  fCaloTriggers->GetTriggerBits(tBits);
486  else
487  fSimpleOfflineTriggers->GetTriggerBits(tBits);
488 
489  if(fDoQA){
490  for(unsigned int ibit = 0; ibit < sizeof(tBits)*8; ibit++) {
491  if(tBits & (1 << ibit)){
492  fQAHistos->FillTH1("triggerBitsAll", ibit);
493  }
494  }
495  }
496 
497  if ((type == kTMEMCalJet && !IsEJE( tBits )) ||
498  (type == kTMEMCalGamma && !IsEGA( tBits )) ||
499  (type == kTMEMCalLevel0 && !(CheckForL0(*fCaloTriggers))) ||
500  (type == kTMEMCalRecalcJet && (tBits & (1 << (kRecalcOffset + fTriggerBitConfig->GetJetLowBit())))==0) ||
501  (type == kTMEMCalRecalcGamma && (tBits & (1 << (kRecalcOffset + fTriggerBitConfig->GetGammaLowBit())))==0) )
502  return 0;
503 
504  // save primary vertex in vector
505  TVector3 vertex;
506  vertex.SetXYZ(fVertex[0], fVertex[1], fVertex[2]);
507 
508  // get position in global 2x2 tower coordinates
509  // A0 left bottom (0,0)
510  Int_t globCol=-1, globRow=-1;
511  if (!isOfflineSimple)
512  fCaloTriggers->GetPosition(globCol,globRow);
513  else
514  fSimpleOfflineTriggers->GetPosition(globCol, globRow);
515 
516  // Markus: For the moment reject jet patches with a row larger than 44 to overcome
517  // an issue with patches containing inactive TRUs
518  // (last 2 supermodules inactive but still included in the reconstruction)
519  Int_t runno = InputEvent()->GetRunNumber();
520  if(runno > 176000 && runno <= 197692){
521  // Valid only for 2012 geometry
522  if((type == kTMEMCalJet && IsEJE( tBits )) && (globRow > 44)) { // Hard coded number in order to be insensitive to changes in the geometry
523  AliDebug(1, Form("Jet patch in inactive area: row[%d]", globRow));
524  return NULL;
525  }
526  }
527 
529  int patchsize = 2;
530  const int kRowsPhi = fGeom->GetNTotalTRU() * 2;
531  if(type == kTMEMCalJet || type == kTMEMCalRecalcJet) patchsize = 16;
532  if((globCol + patchsize >= kColsEta) || (globCol + patchsize >= kRowsPhi)){
533  AliError(Form("Invalid patch position for patch type %s: Col[%d], Row[%d] - patch rejected", fgkTriggerTypeNames[type].Data(), globCol, globRow));
534  return NULL;
535  }
536  }
537 
538  // get the absolute trigger ID
539  Int_t absId=-1;
540  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol, globRow, absId);
541  // convert to the 4 absId of the cells composing the trigger channel
542  Int_t cellAbsId[4]={-1,-1,-1,-1};
543  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
544 
545  // get low left edge (eta max, phi min)
546  TVector3 edge1;
547  fGeom->GetGlobal(cellAbsId[0], edge1);
548  Int_t colEdge1 = globCol, rowEdge1 = globRow, absIdEdge1 = absId, cellIdEdge1 = cellAbsId[0]; // Used in warning for invalid patch position
549 
550  // sum the available energy in the 32/32 window of cells
551  // step over trigger channels and get all the corresponding cells
552  // make CM
553  Float_t amp = 0;
554  Float_t cmiCol = 0;
555  Float_t cmiRow = 0;
556  Int_t adcAmp = 0;
557  Double_t adcOfflineAmp = 0;
558  int nfastor = (type == kTMEMCalJet || type == kTMEMCalRecalcJet) ? 16 : 2; // 32x32 cell window for L1 Jet trigger, 4x4 for L1 Gamma or L0 trigger
559  for (Int_t i = 0; i < nfastor; ++i) {
560  for (Int_t j = 0; j < nfastor; ++j) {
561  // get the 4 cells composing the trigger channel
562  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+i, globRow+j, absId);
563  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
564  // add amplitudes and find patch edges
565  for (Int_t k = 0; k < 4; ++k) {
566  Float_t ca = fCaloCells->GetCellAmplitude(cellAbsId[k]);
567  //fGeom->GetGlobal(cellAbsId[k], cellCoor);
568  amp += ca;
569  cmiCol += ca*(Float_t)i;
570  cmiRow += ca*(Float_t)j;
571  }
572  // add the STU ADCs in the patch (in case of L1) or the TRU Amplitude (in case of L0)
573  if(type == kTMEMCalLevel0){
574  try {
575  adcAmp += static_cast<Int_t>((*fPatchAmplitudes)(globCol+i,globRow+j) * 4); // precision loss in case of global integer field
577  if(fDebugLevel){
578  std::cerr << e.what() << std::endl;
579  }
580  }
581  } else {
582  try {
583  adcAmp += (*fPatchADC)(globCol+i,globRow+j);
585  if(fDebugLevel){
586  std::cerr << e.what() << std::endl;
587  }
588  }
589  }
590 
591  try{
592  adcOfflineAmp += (*fPatchADCSimple)(globCol+i,globRow+j);
594  if(fDebugLevel){
595  std::cerr << e.what() << std::endl;
596  }
597  }
598  }
599  }
600 
601  if (amp == 0) {
602  AliDebug(2,"EMCal trigger patch with 0 energy.");
603  return 0;
604  }
605 
606  // get the CM and patch index
607  cmiCol /= amp;
608  cmiRow /= amp;
609  Int_t cmCol = globCol + (Int_t)cmiCol;
610  Int_t cmRow = globRow + (Int_t)cmiRow;
611 
612  // get the patch and corresponding cells
613  fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
614  fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
615 
616  // find which out of the 4 cells is closest to CM and get it's position
617  Int_t cmiCellCol = TMath::Nint(cmiCol * 2.);
618  Int_t cmiCellRow = TMath::Nint(cmiRow * 2.);
619  TVector3 centerMass;
620  fGeom->GetGlobal(cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass);
621 
622  // get up right edge (eta min, phi max)
623  // get the absolute trigger ID
624  Int_t posOffset=-1;
625  switch(type){
626  case kTMEMCalJet:
627  case kTMEMCalRecalcJet:
628  posOffset = 15;
629  break;
630  case kTMEMCalGamma:
631  case kTMEMCalRecalcGamma:
632  posOffset = 1;
633  break;
634  case kTMEMCalLevel0:
635  posOffset = 1;
636  break;
637  default:
638  posOffset = 0;
639  break;
640  };
641  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
642  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
643  TVector3 edge2;
644  fGeom->GetGlobal(cellAbsId[3], edge2);
645  Int_t colEdge2 = globCol+posOffset, rowEdge2 = globRow+posOffset, absIdEdge2 = absId, cellIdEdge2 = cellAbsId[3]; // Used in warning for invalid patch position
646 
647  // get the geometrical center as an average of two diagonally
648  // adjacent patches in the center
649  // picking two diagonally closest cells from the patches
650  switch(type){
651  case kTMEMCalJet:
652  case kTMEMCalRecalcJet:
653  posOffset = 7;
654  break;
655  case kTMEMCalGamma:
656  case kTMEMCalRecalcGamma:
657  posOffset = 0;
658  break;
659  case kTMEMCalLevel0:
660  posOffset = 0;
661  break;
662  default:
663  posOffset = 0;
664  break;
665  };
666  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
667  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
668  TVector3 center1;
669  fGeom->GetGlobal(cellAbsId[3], center1);
670 
671  switch(type){
672  case kTMEMCalJet:
673  case kTMEMCalRecalcJet:
674  posOffset = 8;
675  break;
676  case kTMEMCalGamma:
677  case kTMEMCalRecalcGamma:
678  posOffset = 1;
679  break;
680  case kTMEMCalLevel0:
681  posOffset = 1;
682  break;
683  };
684  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
685  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
686  TVector3 center2;
687  fGeom->GetGlobal(cellAbsId[0], center2);
688 
689  TVector3 centerGeo(center1);
690  centerGeo += center2;
691  centerGeo *= 0.5;
692 
693  // relate all to primary vertex
694  TVector3 edge1tmp = edge1, edge2tmp = edge2; // Used in warning for invalid patch position
695  centerGeo -= vertex;
696  centerMass -= vertex;
697  edge1 -= vertex;
698  edge2 -= vertex;
699  // Check for invalid patch positions
700  if(!(edge1[0] || edge1[1] || edge1[2])){
701  AliWarning(Form("Inconsistency in patch position for edge1: [%f|%f|%f]", edge1[0], edge1[1], edge1[2]));
702  AliWarning("Original vectors:");
703  AliWarning(Form("edge1: [%f|%f|%f]", edge1tmp[0], edge1tmp[1], edge1tmp[2]));
704  AliWarning(Form("vertex: [%f|%f|%f]", vertex[0], vertex[1], vertex[2]));
705  AliWarning(Form("Col: %d, Row: %d, FABSID: %d, Cell: %d", colEdge1, rowEdge1, absIdEdge1, cellIdEdge1));
706  AliWarning(Form("Offline: %s", isOfflineSimple ? "yes" : "no"));
707  }
708  if(!(edge2[0] || edge2[1] || edge2[2])){
709  AliWarning(Form("Inconsistency in patch position for edge2: [%f|%f|%f]", edge2[0], edge2[1], edge2[2]));
710  AliWarning("Original vectors:");
711  AliWarning(Form("edge2: [%f|%f|%f]", edge2tmp[0], edge2tmp[1], edge2tmp[2]));
712  AliWarning(Form("vertex: [%f|%f|%f]", vertex[0], vertex[1], vertex[2]));
713  AliWarning(Form("Col: %d, Row: %d, FABSID: %d, Cell: %d", colEdge2, rowEdge2, absIdEdge2, cellIdEdge2));
714  AliWarning(Form("Offline: %s", isOfflineSimple ? "yes" : "no"));
715  }
716 
717  Int_t isMC = MCEvent() ? 1 : 0;
718  Int_t offSet = (1 - isMC) * fTriggerBitConfig->GetTriggerTypesEnd();
719 
720  // fix tbits .. remove the unwanted type triggers
721  // for Jet and Gamma triggers we remove also the level 0 bit since it will be stored in the level 0 patch
722  // for level 0 we remove all gamma and jet trigger bits
723  switch(type){
724  case kTMEMCalJet:
725  tBits = tBits & ~( 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetGammaLowBit()) | 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetGammaHighBit()) |
726  1 << (fTriggerBitConfig->GetGammaLowBit()) | 1 << (fTriggerBitConfig->GetGammaHighBit()) |
727  1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetLevel0Bit()) | 1 << (fTriggerBitConfig->GetLevel0Bit()));
728  break;
729  case kTMEMCalGamma:
730  tBits = tBits & ~( 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetJetLowBit()) | 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetJetHighBit()) |
731  1 << (fTriggerBitConfig->GetJetLowBit()) | 1 << (fTriggerBitConfig->GetJetHighBit()) |
732  1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetLevel0Bit()) | 1 << (fTriggerBitConfig->GetLevel0Bit()));
733  break;
734  case kTMEMCalLevel0:
735  // Explicitly set the level 0 bit to overcome the masking out
736  tBits |= 1 << (offSet + fTriggerBitConfig->GetLevel0Bit());
737  tBits = tBits & ~( 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetJetLowBit()) | 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetJetHighBit()) |
738  1 << (fTriggerBitConfig->GetJetLowBit()) | 1 << (fTriggerBitConfig->GetJetHighBit()) | 1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetGammaLowBit()) |
739  1 << (fTriggerBitConfig->GetTriggerTypesEnd() + fTriggerBitConfig->GetGammaHighBit()) | 1 << (fTriggerBitConfig->GetGammaLowBit()) | 1 << (fTriggerBitConfig->GetGammaHighBit()));
740  break;
741  default: // recalculated patches don't need any action
742  break;
743  };
744 
745  // save the trigger object
746  AliEMCALTriggerPatchInfo *trigger =
747  new ((*fCaloTriggersOut)[fITrigger]) AliEMCALTriggerPatchInfo();
748  fITrigger++;
749  trigger->SetTriggerBitConfig(fTriggerBitConfig);
750  trigger->SetCenterGeo(centerGeo, amp);
751  trigger->SetCenterMass(centerMass, amp);
752  trigger->SetEdge1(edge1, amp);
753  trigger->SetEdge2(edge2, amp);
754  trigger->SetADCAmp(adcAmp);
755  trigger->SetADCOfflineAmp(Int_t(adcOfflineAmp));
756  trigger->SetTriggerBits(tBits);
757  trigger->SetOffSet(offSet);
758  trigger->SetCol0(globCol);
759  trigger->SetRowStart(globRow);
760  trigger->SetEdgeCell(globCol*2, globRow*2); // from triggers to cells
761  //if(isOfflineSimple)trigger->SetOfflineSimple();
762  if(fDoQA){
763  TString patchtype = isOfflineSimple ? "Offline" : "Online";
764  fQAHistos->FillTH2(Form("RCPos%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), globCol, globRow);
765  fQAHistos->FillTH2(Form("EPCentPos%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), centerGeo.Eta(), centerGeo.Phi());
766  fQAHistos->FillTH2(Form("PatchADCvsE%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), isOfflineSimple ? adcOfflineAmp : adcAmp, trigger->GetPatchE());
767  // Redo checking of found trigger bits after masking of unwanted triggers
768  for(unsigned int ibit = 0; ibit < sizeof(tBits)*8; ibit++) {
769  if(tBits & (1 << ibit)){
770  fQAHistos->FillTH1("triggerBitsSel", ibit);
771  }
772  }
773  }
774  return trigger;
775 }
776 
786 {
787 
788  TArrayI tBitsArray(4), rowArray(4), colArray(4);
789 
790  // First entries are for recalculated patches
791 
792  tBitsArray[0] = 1 << (kRecalcOffset + fTriggerBitConfig->GetJetLowBit());
793  colArray[0] = -1;
794  rowArray[0] = -1;
795 
796  tBitsArray[1] = 1 << (kRecalcOffset + fTriggerBitConfig->GetJetLowBit()) | 1 << (kOfflineOffset + fTriggerBitConfig->GetJetLowBit());
797  colArray[1] = -1;
798  rowArray[1] = -1;
799 
800  tBitsArray[2] = 1 << (kRecalcOffset + fTriggerBitConfig->GetGammaLowBit());
801  colArray[2] = -1;
802  rowArray[2] = -1;
803 
804  tBitsArray[3] = 1 << (kRecalcOffset + fTriggerBitConfig->GetGammaLowBit()) | 1 << (kOfflineOffset + fTriggerBitConfig->GetGammaLowBit());
805  colArray[3] = -1;
806  rowArray[3] = -1;
807 
808  Double_t maxPatchADCoffline = -1;
809  Int_t maxPatchADC = -1;
810  // run the trigger algo, stepping by 8 towers (= 4 trigger channels)
811  Int_t maxCol = 48;
812  Int_t maxRow = fGeom->GetNTotalTRU()*2;
813  // Markus:
814  // temp fix for the number of TRUs in the 2011 PbPb data to 30
815  // @TODO: Fix in the geometry in the OCDB
816  int runnumber = InputEvent()->GetRunNumber();
817  if(runnumber > 139517 && runnumber <= 170593) maxRow = 60;
818  Int_t isMC = MCEvent() ? 1 : 0;
819  Int_t bitOffSet = (1 - isMC) * fTriggerBitConfig->GetTriggerTypesEnd();
820  for (Int_t i = 0; i <= (maxCol-16); i += 4) {
821  for (Int_t j = 0; j <= (maxRow-16); j += 4) {
822  Double_t tSumOffline = 0;
823  Int_t tSum = 0;
824  Int_t tBits = 0;
825  // window
826  for (Int_t k = 0; k < 16; ++k) {
827  for (Int_t l = 0; l < 16; ++l) {
828  tSumOffline += (*fPatchADCSimple)(i+k,j+l);
829  tSum += static_cast<ULong64_t>((*fPatchADC)(i+k,j+l));
830  }
831  }
832 
833  if (tSum > maxPatchADC) { // Mark highest Jet patch
834  maxPatchADC = tSum;
835  colArray[0] = i;
836  rowArray[0] = j;
837  }
838 
839  if (tSumOffline > maxPatchADCoffline) { // Mark highest Jet patch
840  maxPatchADCoffline = tSumOffline;
841  colArray[1] = i;
842  rowArray[1] = j;
843  }
844 
845  // check thresholds
846  if (tSumOffline > fCaloTriggerSetupOut->GetThresholdJetLowSimple())
847  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetJetLowBit() ));
848  if (tSumOffline > fCaloTriggerSetupOut->GetThresholdJetHighSimple())
849  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetJetHighBit() ));
850 
851  // add trigger values
852  if (tBits != 0) {
853  // add offline bit
854  tBits = tBits | ( 1 << (kOfflineOffset + fTriggerBitConfig->GetJetLowBit()) );
855  tBitsArray.Set( tBitsArray.GetSize() + 1 );
856  colArray.Set( colArray.GetSize() + 1 );
857  rowArray.Set( rowArray.GetSize() + 1 );
858  tBitsArray[tBitsArray.GetSize()-1] = tBits;
859  colArray[colArray.GetSize()-1] = i;
860  rowArray[rowArray.GetSize()-1] = j;
861  }
862  }
863  } // trigger algo
864 
865  // 4x4 trigger algo, stepping by 2 towers (= 1 trigger channel)
866  maxPatchADC = -1;
867  maxPatchADCoffline = -1;
868 
869  for (Int_t i = 0; i <= (maxCol-2); ++i) {
870  for (Int_t j = 0; j <= (maxRow-2); ++j) {
871  Int_t tSum = 0;
872  Double_t tSumOffline = 0;
873  Int_t tBits = 0;
874 
875  // window
876  for (Int_t k = 0; k < 2; ++k) {
877  for (Int_t l = 0; l < 2; ++l) {
878  tSumOffline += (*fPatchADCSimple)(i+k,j+l);
879  tSum += static_cast<ULong64_t>((*fPatchADC)(i+k,j+l));
880  }
881  }
882 
883  if (tSum > maxPatchADC) { // Mark highest Gamma patch
884  maxPatchADC = tSum;
885  colArray[2] = i;
886  rowArray[2] = j;
887  }
888  if (tSumOffline > maxPatchADCoffline) { // Mark highest Gamma patch
889  maxPatchADCoffline = tSumOffline;
890  colArray[3] = i;
891  rowArray[3] = j;
892  }
893 
894  // check thresholds
896  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetGammaLowBit() ));
898  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetGammaHighBit() ));
899 
900  // add trigger values
901  if (tBits != 0) {
902  // add offline bit
903  tBits = tBits | ( 1 << (kOfflineOffset + fTriggerBitConfig->GetGammaLowBit()) );
904  tBitsArray.Set( tBitsArray.GetSize() + 1 );
905  colArray.Set( colArray.GetSize() + 1 );
906  rowArray.Set( rowArray.GetSize() + 1 );
907  tBitsArray[tBitsArray.GetSize()-1] = tBits;
908  colArray[colArray.GetSize()-1] = i;
909  rowArray[rowArray.GetSize()-1] = j;
910  }
911  }
912  } // trigger algo
913 
914  // save in object
915  fSimpleOfflineTriggers->DeAllocate();
916  fSimpleOfflineTriggers->Allocate(tBitsArray.GetSize());
917  for (Int_t i = 0; i < tBitsArray.GetSize(); ++i){
918  fSimpleOfflineTriggers->Add(colArray[i],rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i]);
919  }
920 }
921 
927 Bool_t AliEmcalTriggerMaker::NextTrigger(Bool_t &isOfflineSimple)
928 {
929 
930  isOfflineSimple = kFALSE;
931  Bool_t loopContinue = fCaloTriggers->Next();
932  if (!loopContinue) {
933  loopContinue = fSimpleOfflineTriggers->Next();
934  isOfflineSimple = kTRUE;
935  }
936  return loopContinue;
937 }
938 
945 Bool_t AliEmcalTriggerMaker::CheckForL0(const AliVCaloTrigger& trg) const {
946  Int_t row(-1), col(-1); trg.GetPosition(col, row);
947  if(col < 0 || row < 0){
948  AliError(Form("Patch outside range [col %d, row %d]", col, row));
949  return kFALSE;
950  }
951  Int_t truref(-1), trumod(-1), absFastor(-1), adc(-1);
952  fGeom->GetAbsFastORIndexFromPositionInEMCAL(col, row, absFastor);
953  fGeom->GetTRUFromAbsFastORIndex(absFastor, truref, adc);
954  int nvalid(0);
955  const int kNRowsPhi = fGeom->GetNTotalTRU() * 2;
956  for(int ipos = 0; ipos < 2; ipos++){
957  if(row + ipos >= kNRowsPhi) continue; // boundary check
958  for(int jpos = 0; jpos < 2; jpos++){
959  if(col + jpos >= kColsEta) continue; // boundary check
960  // Check whether we are in the same TRU
961  trumod = -1;
962  fGeom->GetAbsFastORIndexFromPositionInEMCAL(col+jpos, row+ipos, absFastor);
963  fGeom->GetTRUFromAbsFastORIndex(absFastor, trumod, adc);
964  if(trumod != truref) continue;
965  if(col + jpos >= kColsEta) AliError(Form("Boundary error in col [%d, %d + %d]", col + jpos, col, jpos));
966  if(row + ipos >= kNRowsPhi) AliError(Form("Boundary error in row [%d, %d + %d]", row + ipos, row, ipos));
967  Char_t l0times = (*fLevel0TimeMap)(col + jpos,row + ipos);
968  if(l0times > 7 && l0times < 10) nvalid++;
969  }
970  }
971  if (nvalid != 4) return false;
972  return true;
973 }
Bool_t fRejectOffAcceptancePatches
Switch for rejection of patches outside the acceptance.
TString fCaloTriggersOutName
name of output track array
Class to make array of trigger patch objects in AOD/ESD events.
Old configuration, no distinction between high and low threshold.
AliEMCALTriggerDataGrid< double > * fPatchADCSimple
! patch map for simple offline trigger
TriggerMakerBitConfig_t fUseTriggerBitConfig
type of trigger config
Base task in the EMCAL framework.
TriggerMakerTriggerType_t
Definition of different trigger patch types.
Bool_t fDoQA
Fill QA histograms.
void FillTH2(const char *hname, double x, double y, double weight=1., Option_t *opt="")
Int_t fITrigger
! trigger counter
static const int kColsEta
Number of columns in eta direction.
New configuration, distiction between high and low threshold.
static const TString fgkTriggerTypeNames[5]
Histogram name tags.
const AliEMCALTriggerBitConfig * fTriggerBitConfig
Trigger bit configuration, aliroot-dependent.
TH2 * CreateTH2(const char *name, const char *title, int nbinsx, double xmin, double xmax, int nbinsy, double ymin, double ymax, Option_t *opt="")
Trigger bit indicating the main (highest energy) trigger patch of a given type per event...
AliEMCALTriggerDataGrid< float > * fPatchAmplitudes
! TRU Amplitudes (for L0)
THashList * GetListOfHistograms() const
Definition: THistManager.h:504
Bool_t IsEGA(Int_t tBits) const
AliEMCALGeometry * fGeom
!emcal geometry
TString fCaloTriggersName
name of calo triggers collection
TH1 * CreateTH1(const char *name, const char *title, int nbins, double xmin, double xmax, Option_t *opt="")
Int_t fThresholdConstants[4][3]
simple offline trigger thresholds constants
Bool_t IsEJE(Int_t tBits) const
AliEMCALTriggerChannelContainer fBadChannels
Container of bad channels.
TString fCaloCellsName
name of calo cell collection
TString fV0InName
name of output track array
EMCAL Jet patches, recalculated.
Int_t fDebugLevel
void FillTH1(const char *hname, double x, double weight=1., Option_t *opt="")
Manager for constants used in the trigger maker.
AliEmcalTriggerSetupInfo * fCaloTriggerSetupOut
! trigger setup
Bool_t Data(TH1F *h, Double_t *rangefit, Bool_t writefit, Double_t &sgn, Double_t &errsgn, Double_t &bkg, Double_t &errbkg, Double_t &sgnf, Double_t &errsgnf, Double_t &sigmafit, Int_t &status)
Int_t fDebugLevel
Debug lebel;.
AliVCaloCells * fCaloCells
!cells
AliVVZERO * fV0
! V0 object
AliAODCaloTrigger * fSimpleOfflineTriggers
! simple offline trigger
Bool_t isMC
EMCAL trigger patch maker.
AliEmcalList * fOutput
!output list
TClonesArray * fCaloTriggersOut
! trigger array out
THistManager * fQAHistos
! Histograms for QA
ClassImp(AliAnalysisTaskCRC) AliAnalysisTaskCRC
Double_t fVertex[3]
!event vertex
Container class for histograms for the high- charged particle analysis.
Definition: THistManager.h:43
EMCAL Gamma patches, recalculated.
Int_t GetRunNumber(TString)
Definition: PlotMuonQA.C:2235
AliVCaloTrigger * fCaloTriggers
!calo triggers
Bool_t fRunTriggerType[5]
Run patch maker for a given trigger type.
AliEMCALTriggerDataGrid< char > * fLevel0TimeMap
! Map needed to store the level0 times
Bool_t fInitialized
whether or not the task has been already initialized
TString fCaloTriggerSetupOutName
name of output track array
Settings manager for the trigger patch algorithmThis class contains the main settings (trigger thresh...
void SetThresholdsSimple(Int_t i0, Int_t i1, Int_t i2, Int_t i3)
Bool_t NextTrigger(Bool_t &isOfflineSimple)
AliEMCALTriggerPatchInfo * ProcessPatch(TriggerMakerTriggerType_t type, Bool_t isOfflineSimple)
void SetThresholds(Int_t i0, Int_t i1, Int_t i2, Int_t i3)
Bool_t CheckForL0(const AliVCaloTrigger &trg) const
AliEMCALTriggerDataGrid< int > * fPatchADC
! ADC values map