AliPhysics  vAN-20150630 (513c479)
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Macros
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 "AliEMCALTriggerTypes.h"
23 #include "AliLog.h"
24 #include "AliVCaloCells.h"
25 #include "AliVCaloTrigger.h"
26 #include "AliVVZERO.h"
27 #include "AliEmcalTriggerMaker.h"
28 
29 #include "THistManager.h"
30 #include "TString.h"
31 
32 #include <bitset>
33 
36 ClassImp(AliEmcalTriggerMaker::AliEmcalTriggerChannelPosition)
37 ClassImp(AliEmcalTriggerMaker::AliEmcalTriggerChannelContainer)
39 
40 using namespace std;
41 
42 const TString AliEmcalTriggerMaker::fgkTriggerTypeNames[5] = {"EJE", "EGA", "EL0", "REJE", "REGA"};
43 
48  AliAnalysisTaskEmcal("AliEmcalTriggerMaker",kFALSE),
49  fCaloTriggersOutName("EmcalTriggers"),
50  fCaloTriggerSetupOutName("EmcalTriggersSetup"),
51  fV0InName("AliAODVZERO"),
52  fUseTriggerBitConfig(kNewConfig),
53  fTriggerBitConfig(NULL),
54  fCaloTriggersOut(0),
55  fCaloTriggerSetupOut(0),
56  fSimpleOfflineTriggers(0),
57  fV0(0),
58  fITrigger(0),
59  fRejectOffAcceptancePatches(kFALSE),
60  fDoQA(kFALSE),
61  fQAHistos(NULL)
62 {
68  memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
69  memset(fPatchADCSimple, 0, sizeof(Double_t) * kPatchCols * kPatchRows);
70  memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
71  memset(fPatchAmplitudes, 0, sizeof(Float_t) * kPatchCols * kPatchRows);
72  memset(fLevel0TimeMap, 0, sizeof(Char_t) * kPatchCols * kPatchRows);
73 }
74 
80 AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name, Bool_t doQA) :
81  AliAnalysisTaskEmcal(name,doQA),
82  fCaloTriggersOutName("EmcalTriggers"),
83  fCaloTriggerSetupOutName("EmcalTriggersSetup"),
84  fV0InName("AliAODVZERO"),
85  fUseTriggerBitConfig(kNewConfig),
86  fTriggerBitConfig(NULL),
87  fCaloTriggersOut(0),
88  fCaloTriggerSetupOut(0),
89  fSimpleOfflineTriggers(0),
90  fV0(0),
91  fITrigger(0),
92  fRejectOffAcceptancePatches(kFALSE),
93  fDoQA(doQA),
94  fQAHistos(NULL)
95 {
96  // Constructor.
102  memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
103  memset(fPatchAmplitudes, 0, sizeof(Float_t) * kPatchCols * kPatchRows);
104  memset(fPatchADCSimple, 0, sizeof(Double_t) * kPatchCols * kPatchRows);
105  memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
106  memset(fLevel0TimeMap, 0, sizeof(Char_t) * kPatchCols * kPatchRows);
107 }
108 
113 {
115 }
116 
121 {
123 
124  if (!fInitialized)
125  return;
126 
127  if(!fTriggerBitConfig){
128  switch(fUseTriggerBitConfig){
129  case kNewConfig:
131  break;
132  case kOldConfig:
134  break;
135  }
136  }
137 
138  if (!fCaloTriggersOutName.IsNull()) {
139  fCaloTriggersOut = new TClonesArray("AliEmcalTriggerPatchInfo");
141 
142  if (!(InputEvent()->FindListObject(fCaloTriggersOutName))) {
143  InputEvent()->AddObject(fCaloTriggersOut);
144  }
145  else {
146  fInitialized = kFALSE;
147  AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggersOutName.Data()));
148  return;
149  }
150  }
151 
152  if (!fCaloTriggerSetupOutName.IsNull()) {
155 
156  if (!(InputEvent()->FindListObject(fCaloTriggerSetupOutName))) {
157  InputEvent()->AddObject(fCaloTriggerSetupOut);
158  }
159  else {
160  fInitialized = kFALSE;
161  AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggerSetupOutName.Data()));
162  return;
163  }
164  }
165 
166  if ( ! fV0InName.IsNull()) {
167  fV0 = (AliVVZERO*)InputEvent()->FindListObject(fV0InName);
168  }
169 
170  // container for simple offline trigger processing
171  fSimpleOfflineTriggers = new AliAODCaloTrigger();
172  fSimpleOfflineTriggers->Allocate(0);
173 }
174 
179 {
181 
182  if(fDoQA && fOutput){
183  fQAHistos = new THistManager("TriggerQA");
184  const char *patchtypes[2] = {"Online", "Offline"};
185 
186  for(int itype = 0; itype < 5; itype++){
187  for(const char **patchtype = patchtypes; patchtype < patchtypes + 2; ++patchtype){
188  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, 64, -0.5, 63.5);
189  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, 100, 1., 4.);
190  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);
191  }
192  }
193  fQAHistos->CreateTH1("triggerBitsAll", "Trigger bits for all incoming patches;bit nr", 64, -0.5, 63.5);
194  fQAHistos->CreateTH1("triggerBitsSel", "Trigger bits for reconstructed patches;bit nr", 64, -0.5, 63.5);
195  fOutput->Add(fQAHistos->GetListOfHistograms());
196  PostData(1, fOutput);
197  }
198 }
199 
205 {
206  AliEmcalTriggerPatchInfo *trigger, *triggerMainJet, *triggerMainGamma, *triggerMainLevel0;
207  AliEmcalTriggerPatchInfo *triggerMainJetSimple, *triggerMainGammaSimple;
208 
209  // delete patch array, clear setup object
210  fCaloTriggersOut->Delete();
212 
213  if (!fCaloTriggers) {
214  AliError(Form("Calo triggers container %s not available.", fCaloTriggersName.Data()));
215  return kTRUE;
216  }
217  if (!fCaloCells) {
218  AliError(Form("Calo cells container %s not available.", fCaloCellsName.Data()));
219  return kTRUE;
220  }
221  if (!fCaloCells) {
222  AliError(Form("V0 container %s not available.", fV0InName.Data()));
223  return kTRUE;
224  }
225 
226  // do not process, if sooner than 11h period
227  // 160683 ??
228  if( InputEvent()->GetRunNumber() < 167693 )
229  return kTRUE;
230 
231 // // do not process any MC, since no MC was generated with correct
232 // // EMCal trigger L1 jet trigger simulation, yet
233 // // productions will be enabled, once some correct once are produced
234 // if( MCEvent() != 0 )
235 // return kTRUE;
236 
237  // must reset before usage, or the class will fail
238  fCaloTriggers->Reset();
239 
240  // zero the arrays
241  memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
242  memset(fPatchAmplitudes, 0, sizeof(Float_t) * kPatchCols * kPatchRows);
243  memset(fLevel0TimeMap, 0, sizeof(Char_t) * kPatchCols * kPatchRows);
244 
245  // first run over the patch array to compose a map of 2x2 patch energies
246  // which is then needed to construct the full patch ADC energy
247  // class is not empty
248  if (fCaloTriggers->GetEntries() > 0) {
249 
250  // go throuth the trigger channels
251  while (fCaloTriggers->Next()) {
252  // get position in global 2x2 tower coordinates
253  // A0 left bottom (0,0)
254  Int_t globCol=-1, globRow=-1;
255  fCaloTriggers->GetPosition(globCol, globRow);
256  // exclude channel completely if it is masked as hot channel
257  if(fBadChannels.HasChannel(globCol, globRow)) continue;
258  // for some strange reason some ADC amps are initialized in reconstruction
259  // as -1, neglect those
260  Int_t adcAmp=-1;
261  fCaloTriggers->GetL1TimeSum(adcAmp);
262  if (adcAmp>-1)
263  fPatchADC[globCol][globRow] = adcAmp;
264 
265  // Handling for L0 triggers
266  // For the ADC value we use fCaloTriggers->GetAmplitude()
267  // In data, all patches which have 4 TRUs with proper level0 times are
268  // valid trigger patches. Therefore we need to check all neighbors for
269  // the level0 times, not only the bottom left. In order to obtain this
270  // information, a lookup table with the L0 times for each TRU is created
271  Float_t amplitude(0);
272  fCaloTriggers->GetAmplitude(amplitude);
273  if(amplitude < 0) amplitude = 0;
274  fPatchAmplitudes[globCol][globRow] = amplitude;
275  Int_t nl0times(0);
276  fCaloTriggers->GetNL0Times(nl0times);
277  if(nl0times){
278  TArrayI l0times(nl0times);
279  fCaloTriggers->GetL0Times(l0times.GetArray());
280  for(int itime = 0; itime < nl0times; itime++){
281  if(l0times[itime] >7 && l0times[itime] < 10){
282  fLevel0TimeMap[globCol][globRow] = static_cast<Char_t>(l0times[itime]);
283  break;
284  }
285  }
286  }
287  } // patches
288  } // array not empty
289 
290  // fill the array for offline trigger processing
291  // using calibrated cell energies
292  memset(fPatchADCSimple, 0, sizeof(Double_t) * kPatchRows * kPatchCols); // This works, but in principle cannot assume that the representation for 0 in a double really consists of only zeros...
293 
294  // fill the patch ADCs from cells
295  Int_t nCell = fCaloCells->GetNumberOfCells();
296  for(Int_t iCell = 0; iCell < nCell; ++iCell) {
297  // get the cell info, based in index in array
298  Short_t cellId = fCaloCells->GetCellNumber(iCell);
299  Double_t amp = fCaloCells->GetAmplitude(iCell);
300  // get position
301  Int_t absId=-1;
302  fGeom->GetFastORIndexFromCellIndex(cellId, absId);
303  Int_t globCol=-1, globRow=-1;
304  fGeom->GetPositionInEMCALFromAbsFastORIndex(absId, globCol, globRow);
305  // add
306  fPatchADCSimple[globCol][globRow] += amp/kEMCL1ADCtoGeV;
307  }
308 
309  // dig out common data (thresholds)
310  // 0 - jet high, 1 - gamma high, 2 - jet low, 3 - gamma low
312  fCaloTriggers->GetL1Threshold(1),
313  fCaloTriggers->GetL1Threshold(2),
314  fCaloTriggers->GetL1Threshold(3));
315 
316  // get the V0 value and compute and set the offline thresholds
317  // get V0, compute thresholds and save them as global parameters
318  Int_t v0[2];
319  v0[0] = fV0->GetTriggerChargeA();
320  v0[1] = fV0->GetTriggerChargeC();
321  ULong64_t v0S = v0[0] + v0[1];
322  fSimpleOfflineTriggers->SetL1V0(v0);
323 
324  for (Int_t i = 0; i < 4; ++i) {
325  // A*V0^2/2^32+B*V0/2^16+C
326  ULong64_t thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
327  thresh += ( ((ULong64_t)fThresholdConstants[i][1]) * v0S ) >> 16;
328  thresh += ((ULong64_t)fThresholdConstants[i][2]);
329  fSimpleOfflineTriggers->SetL1Threshold(i,thresh);
330  }
331 
332  // save the thresholds in output object
334  fSimpleOfflineTriggers->GetL1Threshold(1),
335  fSimpleOfflineTriggers->GetL1Threshold(2),
336  fSimpleOfflineTriggers->GetL1Threshold(3));
337 
338  // run the trigger
340 
341  // reset for re-run
342  fCaloTriggers->Reset();
343  fSimpleOfflineTriggers->Reset();
344 
345  // class is not empty
346  if (fCaloTriggers->GetEntries() > 0 || fSimpleOfflineTriggers->GetEntries() > 0) {
347  fITrigger = 0;
348  triggerMainGamma = 0;
349  triggerMainJet = 0;
350  triggerMainGammaSimple = 0;
351  triggerMainJetSimple = 0;
352  triggerMainLevel0 = 0;
353 
354  // go throuth the trigger channels, real first, then offline
355  Bool_t isOfflineSimple=0;
356  while (NextTrigger(isOfflineSimple)) {
357  // process jet
359  trigger = ProcessPatch(kTMEMCalJet, isOfflineSimple);
360  // save main jet triggers in event
361  if (trigger != 0) {
362  // check if more energetic than others for main patch marking
363  if (!isOfflineSimple) {
364  if (triggerMainJet == 0 || (triggerMainJet->GetPatchE() < trigger->GetPatchE()))
365  triggerMainJet = trigger;
366  } else {
367  if (triggerMainJetSimple == 0 || (triggerMainJetSimple->GetPatchE() < trigger->GetPatchE()))
368  triggerMainJetSimple = trigger;
369  }
370  }
371  }
372 
373  // process gamma
375  trigger = ProcessPatch(kTMEMCalGamma, isOfflineSimple);
376  // save main gamma triggers in event
377  if (trigger != 0) {
378  // check if more energetic than others for main patch marking
379  if (!isOfflineSimple) {
380  if (triggerMainGamma == 0 || (triggerMainGamma->GetPatchE() < trigger->GetPatchE()))
381  triggerMainGamma = trigger;
382  } else {
383  if (triggerMainGammaSimple == 0 || (triggerMainGammaSimple->GetPatchE() < trigger->GetPatchE()))
384  triggerMainGammaSimple = trigger;
385  }
386  }
387  }
388 
389  // level 0 triggers (only in case of online patches)
390  if(!isOfflineSimple){
392  trigger = ProcessPatch(kTMEMCalLevel0, kFALSE);
393  // save main level0 trigger in the event
394  if (trigger) {
395  if (!triggerMainLevel0 || (triggerMainLevel0->GetPatchE() < trigger->GetPatchE()))
396  triggerMainLevel0 = trigger;
397  }
398  }
399  }
400 
401  // Recalculated triggers (max patches without threshold)
403  ProcessPatch(kTMEMCalRecalcJet, isOfflineSimple);
405  ProcessPatch(kTMEMCalRecalcGamma, isOfflineSimple);
406  } // triggers
407 
408  // mark the most energetic patch as main
409  // for real and also simple offline
410  if (triggerMainJet != 0) {
411  Int_t tBits = triggerMainJet->GetTriggerBits();
412  // main trigger flag
413  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kMainTriggerBitNum );
414  triggerMainJet->SetTriggerBits( tBits );
415  }
416  if (triggerMainJetSimple != 0) {
417  Int_t tBits = triggerMainJetSimple->GetTriggerBits();
418  // main trigger flag
419  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kMainTriggerBitNum );
420  triggerMainJetSimple->SetTriggerBits(tBits);
421  }
422  if (triggerMainGamma != 0) {
423  Int_t tBits = triggerMainGamma->GetTriggerBits();
424  // main trigger flag
425  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kMainTriggerBitNum );
426  triggerMainGamma->SetTriggerBits( tBits );
427  }
428  if (triggerMainGammaSimple != 0) {
429  Int_t tBits = triggerMainGammaSimple->GetTriggerBits();
430  // main trigger flag
431  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kMainTriggerBitNum );
432  triggerMainGammaSimple->SetTriggerBits( tBits );
433  }
434  if(triggerMainLevel0){
435  Int_t tBits = triggerMainLevel0->GetTriggerBits();
436  // main trigger flag
438  triggerMainLevel0->SetTriggerBits(tBits);
439  }
440  } // there are some triggers
441 
442  // Diagnostics
443  int npatchOnline = 0;
444  for(TIter patchIter = TIter(fCaloTriggersOut).Begin(); patchIter != TIter::End(); ++patchIter){
445  AliEmcalTriggerPatchInfo *mypatch = static_cast<AliEmcalTriggerPatchInfo *>(*patchIter);
446  if(mypatch->IsOfflineSimple()) continue;
447  AliDebug(1,Form("Patch with bits: %s, types: JH[%s], JL[%s], GH[%s], GL[%s], L0[%s]",
448  std::bitset<sizeof(int)*4>(mypatch->GetTriggerBits()).to_string().c_str(),
449  (mypatch->IsJetHigh() ? "y" : "n"), (mypatch->IsJetLow() ? "y" : "n"),
450  (mypatch->IsGammaHigh() ? "y" : "n"), (mypatch->IsGammaLow() ? "y" : "n"),(mypatch->IsLevel0() ? "y" : "n")));
451  npatchOnline++;
452  }
453  AliDebug(1, Form("Number of online patches: %d", npatchOnline));
454 
455  return kTRUE;
456 }
457 
466 {
467  Int_t tBits=-1;
468  if (!isOfflineSimple)
469  fCaloTriggers->GetTriggerBits(tBits);
470  else
471  fSimpleOfflineTriggers->GetTriggerBits(tBits);
472 
473  if(fDoQA){
474  for(unsigned int ibit = 0; ibit < sizeof(tBits)*8; ibit++) {
475  if(tBits & (1 << ibit)){
476  fQAHistos->FillTH1("triggerBitsAll", ibit);
477  }
478  }
479  }
480 
481  if ((type == kTMEMCalJet && !IsEJE( tBits )) ||
482  (type == kTMEMCalGamma && !IsEGA( tBits )) ||
483  (type == kTMEMCalLevel0 && !(CheckForL0(*fCaloTriggers))) ||
484  (type == kTMEMCalRecalcJet && (tBits & (1 << AliEmcalTriggerPatchInfo::kRecalcJetBitNum))==0) ||
485  (type == kTMEMCalRecalcGamma && (tBits & (1 << AliEmcalTriggerPatchInfo::kRecalcGammaBitNum))==0) )
486  return 0;
487 
488  // save primary vertex in vector
489  TVector3 vertex;
490  vertex.SetXYZ(fVertex[0], fVertex[1], fVertex[2]);
491 
492  // get position in global 2x2 tower coordinates
493  // A0 left bottom (0,0)
494  Int_t globCol=-1, globRow=-1;
495  if (!isOfflineSimple)
496  fCaloTriggers->GetPosition(globCol,globRow);
497  else
498  fSimpleOfflineTriggers->GetPosition(globCol, globRow);
499 
500  // Markus: For the moment reject jet patches with a row larger than 44 to overcome
501  // an issue with patches containing inactive TRUs
502  if((type == kTMEMCalJet && IsEJE( tBits )) && (globRow > fGeom->GetNTotalTRU() - 16)) {
503  AliDebug(1, Form("Jet patch in inactive area: row[%d]", globRow));
504  return NULL;
505  }
506 
508  int patchsize = 2;
509  if(type == kTMEMCalJet || type == kTMEMCalRecalcJet) patchsize = 16;
510  if((globCol + patchsize >= kPatchCols) || (globCol + patchsize >= kPatchRows)){
511  AliError(Form("Invalid patch position for patch type %s: Col[%d], Row[%d] - patch rejected", fgkTriggerTypeNames[type].Data(), globCol, globRow));
512  return NULL;
513  }
514  }
515 
516  // get the absolute trigger ID
517  Int_t absId=-1;
518  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol, globRow, absId);
519  // convert to the 4 absId of the cells composing the trigger channel
520  Int_t cellAbsId[4]={-1,-1,-1,-1};
521  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
522 
523  // get low left edge (eta max, phi min)
524  TVector3 edge1;
525  fGeom->GetGlobal(cellAbsId[0], edge1);
526  Int_t colEdge1 = globCol, rowEdge1 = globRow, absIdEdge1 = absId, cellIdEdge1 = cellAbsId[0]; // Used in warning for invalid patch position
527 
528  // sum the available energy in the 32/32 window of cells
529  // step over trigger channels and get all the corresponding cells
530  // make CM
531  Float_t amp = 0;
532  Float_t cmiCol = 0;
533  Float_t cmiRow = 0;
534  Int_t adcAmp = 0;
535  Double_t adcOfflineAmp = 0;
536  int nfastor = (type == kTMEMCalJet || type == kTMEMCalRecalcJet) ? 16 : 2; // 32x32 cell window for L1 Jet trigger, 4x4 for L1 Gamma or L0 trigger
537  for (Int_t i = 0; i < nfastor; ++i) {
538  for (Int_t j = 0; j < nfastor; ++j) {
539  // get the 4 cells composing the trigger channel
540  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+i, globRow+j, absId);
541  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
542  // add amplitudes and find patch edges
543  for (Int_t k = 0; k < 4; ++k) {
544  Float_t ca = fCaloCells->GetCellAmplitude(cellAbsId[k]);
545  //fGeom->GetGlobal(cellAbsId[k], cellCoor);
546  amp += ca;
547  cmiCol += ca*(Float_t)i;
548  cmiRow += ca*(Float_t)j;
549  }
550  // add the STU ADCs in the patch (in case of L1) or the TRU Amplitude (in case of L0)
551  if(type == kTMEMCalLevel0){
552  adcAmp += static_cast<Int_t>(fPatchAmplitudes[globCol+i][globRow+j] * 4); // precision loss in case of global integer field
553  } else {
554  adcAmp += fPatchADC[globCol+i][globRow+j];
555  }
556 
557  adcOfflineAmp += fPatchADCSimple[globCol+i][globRow+j];
558  }
559  }
560 
561  if (amp == 0) {
562  AliDebug(2,"EMCal trigger patch with 0 energy.");
563  return 0;
564  }
565 
566  // get the CM and patch index
567  cmiCol /= amp;
568  cmiRow /= amp;
569  Int_t cmCol = globCol + (Int_t)cmiCol;
570  Int_t cmRow = globRow + (Int_t)cmiRow;
571 
572  // get the patch and corresponding cells
573  fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
574  fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
575 
576  // find which out of the 4 cells is closest to CM and get it's position
577  Int_t cmiCellCol = TMath::Nint(cmiCol * 2.);
578  Int_t cmiCellRow = TMath::Nint(cmiRow * 2.);
579  TVector3 centerMass;
580  fGeom->GetGlobal(cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass);
581 
582  // get up right edge (eta min, phi max)
583  // get the absolute trigger ID
584  Int_t posOffset=-1;
585  switch(type){
586  case kTMEMCalJet:
587  case kTMEMCalRecalcJet:
588  posOffset = 15;
589  break;
590  case kTMEMCalGamma:
591  case kTMEMCalRecalcGamma:
592  posOffset = 1;
593  break;
594  case kTMEMCalLevel0:
595  posOffset = 1;
596  break;
597  default:
598  posOffset = 0;
599  break;
600  };
601  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
602  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
603  TVector3 edge2;
604  fGeom->GetGlobal(cellAbsId[3], edge2);
605  Int_t colEdge2 = globCol+posOffset, rowEdge2 = globRow+posOffset, absIdEdge2 = absId, cellIdEdge2 = cellAbsId[3]; // Used in warning for invalid patch position
606 
607  // get the geometrical center as an average of two diagonally
608  // adjacent patches in the center
609  // picking two diagonally closest cells from the patches
610  switch(type){
611  case kTMEMCalJet:
612  case kTMEMCalRecalcJet:
613  posOffset = 7;
614  break;
615  case kTMEMCalGamma:
616  case kTMEMCalRecalcGamma:
617  posOffset = 0;
618  break;
619  case kTMEMCalLevel0:
620  posOffset = 0;
621  break;
622  default:
623  posOffset = 0;
624  break;
625  };
626  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
627  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
628  TVector3 center1;
629  fGeom->GetGlobal(cellAbsId[3], center1);
630 
631  switch(type){
632  case kTMEMCalJet:
633  case kTMEMCalRecalcJet:
634  posOffset = 8;
635  break;
636  case kTMEMCalGamma:
637  case kTMEMCalRecalcGamma:
638  posOffset = 1;
639  break;
640  case kTMEMCalLevel0:
641  posOffset = 1;
642  break;
643  };
644  fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
645  fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
646  TVector3 center2;
647  fGeom->GetGlobal(cellAbsId[0], center2);
648 
649  TVector3 centerGeo(center1);
650  centerGeo += center2;
651  centerGeo *= 0.5;
652 
653  // relate all to primary vertex
654  TVector3 edge1tmp = edge1, edge2tmp = edge2; // Used in warning for invalid patch position
655  centerGeo -= vertex;
656  centerMass -= vertex;
657  edge1 -= vertex;
658  edge2 -= vertex;
659  // Check for invalid patch positions
660  if(!(edge1[0] || edge1[1] || edge1[2])){
661  AliWarning(Form("Inconsistency in patch position for edge1: [%f|%f|%f]", edge1[0], edge1[1], edge1[2]));
662  AliWarning("Original vectors:");
663  AliWarning(Form("edge1: [%f|%f|%f]", edge1tmp[0], edge1tmp[1], edge1tmp[2]));
664  AliWarning(Form("vertex: [%f|%f|%f]", vertex[0], vertex[1], vertex[2]));
665  AliWarning(Form("Col: %d, Row: %d, FABSID: %d, Cell: %d", colEdge1, rowEdge1, absIdEdge1, cellIdEdge1));
666  AliWarning(Form("Offline: %s", isOfflineSimple ? "yes" : "no"));
667  }
668  if(!(edge2[0] || edge2[1] || edge2[2])){
669  AliWarning(Form("Inconsistency in patch position for edge2: [%f|%f|%f]", edge2[0], edge2[1], edge2[2]));
670  AliWarning("Original vectors:");
671  AliWarning(Form("edge2: [%f|%f|%f]", edge2tmp[0], edge2tmp[1], edge2tmp[2]));
672  AliWarning(Form("vertex: [%f|%f|%f]", vertex[0], vertex[1], vertex[2]));
673  AliWarning(Form("Col: %d, Row: %d, FABSID: %d, Cell: %d", colEdge2, rowEdge2, absIdEdge2, cellIdEdge2));
674  AliWarning(Form("Offline: %s", isOfflineSimple ? "yes" : "no"));
675  }
676 
677  Int_t isMC = MCEvent() ? 1 : 0;
678  Int_t offSet = (1 - isMC) * fTriggerBitConfig->GetTriggerTypesEnd();
679 
680  // fix tbits .. remove the unwanted type triggers
681  // for Jet and Gamma triggers we remove also the level 0 bit since it will be stored in the level 0 patch
682  // for level 0 we remove all gamma and jet trigger bits
683  switch(type){
684  case kTMEMCalJet:
688  break;
689  case kTMEMCalGamma:
693  break;
694  case kTMEMCalLevel0:
695  // Explicitly set the level 0 bit to overcome the masking out
696  tBits |= 1 << (offSet + fTriggerBitConfig->GetLevel0Bit());
700  break;
701  default: // recalculated patches don't need any action
702  break;
703  };
704 
705  // save the trigger object
706  AliEmcalTriggerPatchInfo *trigger =
707  new ((*fCaloTriggersOut)[fITrigger]) AliEmcalTriggerPatchInfo();
708  fITrigger++;
710  trigger->SetCenterGeo(centerGeo, amp);
711  trigger->SetCenterMass(centerMass, amp);
712  trigger->SetEdge1(edge1, amp);
713  trigger->SetEdge2(edge2, amp);
714  trigger->SetADCAmp(adcAmp);
715  trigger->SetADCOfflineAmp(Int_t(adcOfflineAmp));
716  trigger->SetTriggerBits(tBits);
717  trigger->SetOffSet(offSet);
718  trigger->SetEdgeCell(globCol*2, globRow*2); // from triggers to cells
719  //if(isOfflineSimple)trigger->SetOfflineSimple();
720  if(fDoQA){
721  TString patchtype = isOfflineSimple ? "Offline" : "Online";
722  fQAHistos->FillTH2(Form("RCPos%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), globCol, globRow);
723  fQAHistos->FillTH2(Form("EPCentPos%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), centerGeo.Eta(), centerGeo.Phi());
724  fQAHistos->FillTH2(Form("PatchADCvsE%s%s", fgkTriggerTypeNames[type].Data(), patchtype.Data()), isOfflineSimple ? adcOfflineAmp : adcAmp, trigger->GetPatchE());
725  // Redo checking of found trigger bits after masking of unwanted triggers
726  for(unsigned int ibit = 0; ibit < sizeof(tBits)*8; ibit++) {
727  if(tBits & (1 << ibit)){
728  fQAHistos->FillTH1("triggerBitsSel", ibit);
729  }
730  }
731  }
732  return trigger;
733 }
734 
744 {
745 
746  TArrayI tBitsArray(4), rowArray(4), colArray(4);
747 
748  // First entries are for recalculated patches
749 
750  tBitsArray[0] = 1 << AliEmcalTriggerPatchInfo::kRecalcJetBitNum;
751  colArray[0] = -1;
752  rowArray[0] = -1;
753 
755  colArray[1] = -1;
756  rowArray[1] = -1;
757 
759  colArray[2] = -1;
760  rowArray[2] = -1;
761 
763  colArray[3] = -1;
764  rowArray[3] = -1;
765 
766  Double_t maxPatchADCoffline = -1;
767  Int_t maxPatchADC = -1;
768  // run the trigger algo, stepping by 8 towers (= 4 trigger channels)
769  Int_t maxCol = 48;
770  Int_t maxRow = fGeom->GetNTotalTRU()*2;
771  // Markus:
772  // temp fix for the number of TRUs in the 2011 PbPb data to 30
773  // @TODO: Fix in the geometry in the OCDB
774  int runnumber = InputEvent()->GetRunNumber();
775  if(runnumber > 139517 && runnumber <= 170593) maxRow = 60;
776  Int_t isMC = MCEvent() ? 1 : 0;
777  Int_t bitOffSet = (1 - isMC) * fTriggerBitConfig->GetTriggerTypesEnd();
778  for (Int_t i = 0; i <= (maxCol-16); i += 4) {
779  for (Int_t j = 0; j <= (maxRow-16); j += 4) {
780  Double_t tSumOffline = 0;
781  Int_t tSum = 0;
782  Int_t tBits = 0;
783  // window
784  for (Int_t k = 0; k < 16; ++k) {
785  for (Int_t l = 0; l < 16; ++l) {
786  tSumOffline += fPatchADCSimple[i+k][j+l];
787  tSum += (ULong64_t)fPatchADC[i+k][j+l];
788  }
789  }
790 
791  if (tSum > maxPatchADC) { // Mark highest Jet patch
792  maxPatchADC = tSum;
793  colArray[0] = i;
794  rowArray[0] = j;
795  }
796 
797  if (tSumOffline > maxPatchADCoffline) { // Mark highest Jet patch
798  maxPatchADCoffline = tSumOffline;
799  colArray[1] = i;
800  rowArray[1] = j;
801  }
802 
803  // check thresholds
804  if (tSumOffline > fCaloTriggerSetupOut->GetThresholdJetLowSimple())
805  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetJetLowBit() ));
806  if (tSumOffline > fCaloTriggerSetupOut->GetThresholdJetHighSimple())
807  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetJetHighBit() ));
808 
809  // add trigger values
810  if (tBits != 0) {
811  // add offline bit
812  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kSimpleOfflineBitNum );
813  tBitsArray.Set( tBitsArray.GetSize() + 1 );
814  colArray.Set( colArray.GetSize() + 1 );
815  rowArray.Set( rowArray.GetSize() + 1 );
816  tBitsArray[tBitsArray.GetSize()-1] = tBits;
817  colArray[colArray.GetSize()-1] = i;
818  rowArray[rowArray.GetSize()-1] = j;
819  }
820  }
821  } // trigger algo
822 
823  // 4x4 trigger algo, stepping by 2 towers (= 1 trigger channel)
824  maxPatchADC = -1;
825  maxPatchADCoffline = -1;
826 
827  for (Int_t i = 0; i <= (maxCol-2); ++i) {
828  for (Int_t j = 0; j <= (maxRow-2); ++j) {
829  Int_t tSum = 0;
830  Double_t tSumOffline = 0;
831  Int_t tBits = 0;
832 
833  // window
834  for (Int_t k = 0; k < 2; ++k) {
835  for (Int_t l = 0; l < 2; ++l) {
836  tSumOffline += fPatchADCSimple[i+k][j+l];
837  tSum += (ULong64_t)fPatchADC[i+k][j+l];
838  }
839  }
840 
841  if (tSum > maxPatchADC) { // Mark highest Gamma patch
842  maxPatchADC = tSum;
843  colArray[2] = i;
844  rowArray[2] = j;
845  }
846  if (tSumOffline > maxPatchADCoffline) { // Mark highest Gamma patch
847  maxPatchADCoffline = tSumOffline;
848  colArray[3] = i;
849  rowArray[3] = j;
850  }
851 
852  // check thresholds
854  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetGammaLowBit() ));
856  tBits = tBits | ( 1 << ( bitOffSet + fTriggerBitConfig->GetGammaHighBit() ));
857 
858  // add trigger values
859  if (tBits != 0) {
860  // add offline bit
861  tBits = tBits | ( 1 << AliEmcalTriggerPatchInfo::kSimpleOfflineBitNum );
862  tBitsArray.Set( tBitsArray.GetSize() + 1 );
863  colArray.Set( colArray.GetSize() + 1 );
864  rowArray.Set( rowArray.GetSize() + 1 );
865  tBitsArray[tBitsArray.GetSize()-1] = tBits;
866  colArray[colArray.GetSize()-1] = i;
867  rowArray[rowArray.GetSize()-1] = j;
868  }
869  }
870  } // trigger algo
871 
872  // save in object
873  fSimpleOfflineTriggers->DeAllocate();
874  fSimpleOfflineTriggers->Allocate(tBitsArray.GetSize());
875  for (Int_t i = 0; i < tBitsArray.GetSize(); ++i){
876  fSimpleOfflineTriggers->Add(colArray[i],rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i]);
877  }
878 }
879 
885 Bool_t AliEmcalTriggerMaker::NextTrigger(Bool_t &isOfflineSimple)
886 {
887 
888  isOfflineSimple = kFALSE;
889  Bool_t loopContinue = fCaloTriggers->Next();
890  if (!loopContinue) {
891  loopContinue = fSimpleOfflineTriggers->Next();
892  isOfflineSimple = kTRUE;
893  }
894  return loopContinue;
895 }
896 
903 Bool_t AliEmcalTriggerMaker::CheckForL0(const AliVCaloTrigger& trg) const {
904  Int_t row(-1), col(-1); trg.GetPosition(col, row);
905  if(col < 0 || row < 0){
906  AliError(Form("Patch outside range [col %d, row %d]", col, row));
907  return kFALSE;
908  }
909  Int_t truref(-1), trumod(-1), absFastor(-1), adc(-1);
910  fGeom->GetAbsFastORIndexFromPositionInEMCAL(col, row, absFastor);
911  fGeom->GetTRUFromAbsFastORIndex(absFastor, truref, adc);
912  int nvalid(0);
913  for(int ipos = 0; ipos < 2; ipos++){
914  if(row + ipos >= kPatchRows) continue; // boundary check
915  for(int jpos = 0; jpos < 2; jpos++){
916  if(col + jpos >= kPatchCols) continue; // boundary check
917  // Check whether we are in the same TRU
918  trumod = -1;
919  fGeom->GetAbsFastORIndexFromPositionInEMCAL(col+jpos, row+ipos, absFastor);
920  fGeom->GetTRUFromAbsFastORIndex(absFastor, trumod, adc);
921  if(trumod != truref) continue;
922  if(col + jpos >= kPatchCols) AliError(Form("Boundary error in col [%d, %d + %d]", col + jpos, col, jpos));
923  if(row + ipos >= kPatchRows) AliError(Form("Boundary error in row [%d, %d + %d]", row + ipos, row, ipos));
924  Char_t l0times = fLevel0TimeMap[col + jpos][row + ipos];
925  if(l0times > 7 && l0times < 10) nvalid++;
926  }
927  }
928  if (nvalid != 4) return false;
929  return true;
930 }
931 
939  if(HasChannel(col, row)) return;
940  fChannels.Add(new AliEmcalTriggerChannelPosition(col, row));
941 }
942 
951  if(fChannels.FindObject(&refChannel)) return true;
952  return false;
953 }
ClassImp(AliAnalysisTaskTriggerRates) AliAnalysisTaskTriggerRates
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.
void SetEdge2(TLorentzVector &v)
TriggerMakerBitConfig_t fUseTriggerBitConfig
type of trigger config
TriggerMakerTriggerType_t
Definition of different trigger patch types.
Bool_t fDoQA
Fill QA histograms.
void SetEdge1(TLorentzVector &v)
const AliEmcalTriggerBitConfig * fTriggerBitConfig
Int_t fITrigger
trigger counter
TList * fOutput
x-section from pythia header
Float_t fPatchAmplitudes[kPatchCols][kPatchRows]
TRU Amplitudes (for L0)
AliEmcalTriggerChannelContainer fBadChannels
Container of bad channels.
New configuration, distiction between high and low threshold.
static const TString fgkTriggerTypeNames[5]
Histogram name tags.
2D position of a trigger channel on the EMCAL surface
Bool_t IsEGA(Int_t tBits) const
AliEMCALGeometry * fGeom
whether it's an ESD analysis
Int_t fPatchADC[kPatchCols][kPatchRows]
ADC values map.
Int_t fThresholdConstants[4][3]
simple offline trigger thresholds constants
Bool_t IsEJE(Int_t tBits) const
void SetEdgeCell(Int_t x, Int_t y)
TString fV0InName
name of output track array
EMCAL Jet patches, recalculated.
AliEmcalTriggerSetupInfo * fCaloTriggerSetupOut
trigger setup
Double_t fPatchADCSimple[kPatchCols][kPatchRows]
patch map for simple offline trigger
AliVCaloCells * fCaloCells
clusters
AliVVZERO * fV0
V0 object.
AliAODCaloTrigger * fSimpleOfflineTriggers
simple offline trigger
EMCAL trigger patch maker.
TClonesArray * fCaloTriggersOut
trigger array out
void SetCenterMass(TLorentzVector &v)
THistManager * fQAHistos
Histograms for QA.
Double_t fVertex[3]
event plane V0C
static const Double_t kEMCL1ADCtoGeV
void SetTriggerBitConfig(const AliEmcalTriggerBitConfig *ref)
EMCAL Gamma patches, recalculated.
Int_t GetRunNumber(TString)
Definition: PlotMuonQA.C:2237
Char_t fLevel0TimeMap[kPatchCols][kPatchRows]
Map needed to store the level0 times.
AliVCaloTrigger * fCaloTriggers
cells
Bool_t fRunTriggerType[5]
Run patch maker for a given trigger type.
TString fCaloTriggerSetupOutName
name of output track array
void SetThresholdsSimple(Int_t i0, Int_t i1, Int_t i2, Int_t i3)
AliEmcalTriggerPatchInfo * ProcessPatch(TriggerMakerTriggerType_t type, Bool_t isOfflineSimple)
Bool_t NextTrigger(Bool_t &isOfflineSimple)
void SetCenterGeo(TVector3 &v, Double_t e)
TSortedList fChannels
Container for listed channels.
void SetThresholds(Int_t i0, Int_t i1, Int_t i2, Int_t i3)
Bool_t CheckForL0(const AliVCaloTrigger &trg) const