1 // $Id: AliEmcalTriggerMaker.cxx 64593 2013-10-18 10:23:58Z loizides $
3 // Class to make emcal particles in AOD/ESD events.
7 #include <TClonesArray.h>
11 #include "AliEmcalTriggerPatchInfo.h"
12 #include "AliEmcalTriggerSetupInfo.h"
14 #include "AliEmcalTriggerMaker.h"
15 #include "AliEMCALTriggerTypes.h"
16 #include "AliEMCALGeometry.h"
18 #include "AliVCaloTrigger.h"
19 #include "AliAODCaloTrigger.h"
20 #include "AliVCaloCells.h"
21 #include "AliVVZERO.h"
23 ClassImp(AliEmcalTriggerMaker)
27 //________________________________________________________________________
28 AliEmcalTriggerMaker::AliEmcalTriggerMaker() :
29 AliAnalysisTaskEmcal("AliEmcalTriggerMaker",kFALSE),
30 fCaloTriggersOutName("EmcalTriggers"),
31 fCaloTriggerSetupOutName("EmcalTriggersSetup"),
32 fV0InName("AliAODVZERO"),
34 fCaloTriggerSetupOut(0),
35 fSimpleOfflineTriggers(0),
40 for( int i = 0; i < 4; i++ )
41 for( int j = 0; j < 3; j++ )
42 fThresholdConstants[i][j] = 0;
45 //________________________________________________________________________
46 AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name) :
47 AliAnalysisTaskEmcal(name,kFALSE),
48 fCaloTriggersOutName("EmcalTriggers"),
49 fCaloTriggerSetupOutName("EmcalTriggersSetup"),
50 fV0InName("AliAODVZERO"),
52 fCaloTriggerSetupOut(0),
53 fSimpleOfflineTriggers(0),
58 for( int i = 0; i < 4; i++ )
59 for( int j = 0; j < 3; j++ )
60 fThresholdConstants[i][j] = 0;
63 //________________________________________________________________________
64 AliEmcalTriggerMaker::~AliEmcalTriggerMaker()
69 //________________________________________________________________________
70 void AliEmcalTriggerMaker::ExecOnce()
74 AliAnalysisTaskEmcal::ExecOnce();
79 if (!fCaloTriggersOutName.IsNull()) {
80 fCaloTriggersOut = new TClonesArray("AliEmcalTriggerPatchInfo");
81 fCaloTriggersOut->SetName(fCaloTriggersOutName);
83 if (!(InputEvent()->FindListObject(fCaloTriggersOutName))) {
84 InputEvent()->AddObject(fCaloTriggersOut);
87 fInitialized = kFALSE;
88 AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggersOutName.Data()));
93 if (!fCaloTriggerSetupOutName.IsNull()) {
94 fCaloTriggerSetupOut = new AliEmcalTriggerSetupInfo();
95 fCaloTriggerSetupOut->SetName(fCaloTriggerSetupOutName);
97 if (!(InputEvent()->FindListObject(fCaloTriggerSetupOutName))) {
98 InputEvent()->AddObject(fCaloTriggerSetupOut);
101 fInitialized = kFALSE;
102 AliFatal(Form("%s: Container with same name %s already present. Aborting", GetName(), fCaloTriggerSetupOutName.Data()));
107 if ( ! fV0InName.IsNull()) {
108 fV0 = (AliVVZERO*)InputEvent()->FindListObject( fV0InName );
111 // container for simple offline trigger processing
112 fSimpleOfflineTriggers = new AliAODCaloTrigger();
113 fSimpleOfflineTriggers->Allocate( 0 );
116 //________________________________________________________________________
117 Bool_t AliEmcalTriggerMaker::Run()
119 // Create the emcal particles
122 Int_t globCol, globRow, v0[2];
123 Int_t absId, adcAmp, tBits;
124 Int_t i, j, nCell, iCell;
126 ULong64_t v0S, thresh;
127 Bool_t isOfflineSimple;
129 AliEmcalTriggerPatchInfo *trigger, *triggerMainJet, *triggerMainGamma;
130 AliEmcalTriggerPatchInfo *triggerMainJetSimple, *triggerMainGammaSimple;
132 // delete patch array, clear setup object
133 fCaloTriggersOut->Delete();
134 fCaloTriggerSetupOut->Clean();
136 if( !fCaloTriggers ){
137 AliError(Form("Calo triggers container %s not available.", fCaloTriggersName.Data()));
141 AliError(Form("Calo cells container %s not available.", fCaloCellsName.Data()));
145 AliError(Form("V0 container %s not available.", fV0InName.Data()));
149 // do not process, if sooner than 11h period
151 if( InputEvent()->GetRunNumber() < 167693 )
154 // // do not process any MC, since no MC was generated with correct
155 // // EMCal trigger L1 jet trigger simulation, yet
156 // // productions will be enabled, once some correct once are produced
157 // if( MCEvent() != 0 )
160 // must reset before usage, or the class will fail
161 fCaloTriggers->Reset();
163 // first run over the patch array to compose a map of 2x2 patch energies
164 // which is then needed to construct the full patch ADC energy
165 // class is not empty
166 if( fCaloTriggers->GetEntries() > 0 ){
169 for( i = 0; i < 48; i++ )
170 for( j = 0; j < 64; j++ )
173 // go throuth the trigger channels
174 while( fCaloTriggers->Next() ){
175 // get position in global 2x2 tower coordinates
176 // A0 left bottom (0,0)
177 fCaloTriggers->GetPosition( globCol, globRow );
179 // for some strange reason some ADC amps are initialized in reconstruction
180 // as -1, neglect those :\\ wth
181 fCaloTriggers->GetL1TimeSum( adcAmp );
183 fPatchADC[globCol][globRow] = adcAmp;
188 // fill the array for offline trigger processing
189 // using calibrated cell energies
190 for( i = 0; i < 48; i++ )
191 for( j = 0; j < 64; j++ )
192 fPatchADCSimple[i][j] = 0;
194 // fill the patch ADCs from cells
195 nCell = fCaloCells->GetNumberOfCells();
197 for( iCell = 0; iCell < nCell; iCell++ ){
198 // get the cell info, based in index in array
199 cellId = fCaloCells->GetCellNumber( iCell );
200 amp = fCaloCells->GetAmplitude( iCell );
203 fGeom->GetFastORIndexFromCellIndex( cellId, absId );
204 fGeom->GetPositionInEMCALFromAbsFastORIndex( absId, globCol, globRow );
207 fPatchADCSimple[globCol][globRow] += amp/kEMCL1ADCtoGeV;
210 // dig out common data (thresholds)
211 // 0 - jet high, 1 - gamma high, 2 - jet low, 3 - gamma low
212 fCaloTriggerSetupOut->SetThresholds( fCaloTriggers->GetL1Threshold( 0 ),
213 fCaloTriggers->GetL1Threshold( 1 ),
214 fCaloTriggers->GetL1Threshold( 2 ),
215 fCaloTriggers->GetL1Threshold( 3 ));
217 // get the V0 value and compute and set the offline thresholds
218 // get V0, compute thresholds and save them as global parameters
219 v0[0] = fV0->GetTriggerChargeA();
220 v0[1] = fV0->GetTriggerChargeC();
223 fSimpleOfflineTriggers->SetL1V0( v0 );
225 for( i = 0; i < 4; i++ ){
226 // A*V0^2/2^32+B*V0/2^16+C
227 thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
228 thresh += ( ((ULong64_t)fThresholdConstants[i][1]) * v0S ) >> 16;
229 thresh += ((ULong64_t)fThresholdConstants[i][2]);
230 fSimpleOfflineTriggers->SetL1Threshold( i, thresh );
233 // save the thresholds in output object
234 fCaloTriggerSetupOut->SetThresholdsSimple( fSimpleOfflineTriggers->GetL1Threshold( 0 ),
235 fSimpleOfflineTriggers->GetL1Threshold( 1 ),
236 fSimpleOfflineTriggers->GetL1Threshold( 2 ),
237 fSimpleOfflineTriggers->GetL1Threshold( 3 ));
240 RunSimpleOfflineTrigger();
243 fCaloTriggers->Reset();
244 fSimpleOfflineTriggers->Reset();
246 // class is not empty
247 if( fCaloTriggers->GetEntries() > 0 || fSimpleOfflineTriggers->GetEntries() > 0 ){
250 triggerMainGamma = 0;
252 triggerMainGammaSimple = 0;
253 triggerMainJetSimple = 0;
255 // go throuth the trigger channels, real first, then offline
256 while( NextTrigger( isOfflineSimple ) ){
259 trigger = ProcessPatch( 0, isOfflineSimple );
261 // save main jet triggers in event
263 // check if more energetic than others for main patch marking
264 if( ! isOfflineSimple ){
265 if( triggerMainJet == 0 )
266 triggerMainJet = trigger;
267 else if( triggerMainJet->GetPatchE() < trigger->GetPatchE() )
268 triggerMainJet = trigger;
271 if( triggerMainJetSimple == 0 )
272 triggerMainJetSimple = trigger;
273 else if( triggerMainJetSimple->GetPatchE() < trigger->GetPatchE() )
274 triggerMainJetSimple = trigger;
279 trigger = ProcessPatch( 1, isOfflineSimple );
281 // save main gamma triggers in event
283 // check if more energetic than others for main patch marking
284 if( ! isOfflineSimple ){
285 if( triggerMainGamma == 0 )
286 triggerMainGamma = trigger;
287 else if( triggerMainGamma->GetPatchE() < trigger->GetPatchE() )
288 triggerMainGamma = trigger;
291 if( triggerMainGammaSimple == 0 )
292 triggerMainGammaSimple = trigger;
293 else if( triggerMainGammaSimple->GetPatchE() < trigger->GetPatchE() )
294 triggerMainGammaSimple = trigger;
298 // cout << " pi:" << trigger->GetPhiMin() << " px:" << trigger->GetPhiMax();
299 // cout << " pg:" << trigger->GetPhiGeo() << " " << (trigger->GetPhiMin()+trigger->GetPhiMax()) / 2.;
300 // cout << " pc:" << trigger->GetPhiCM();
301 // cout << " ei:" << trigger->GetEtaMin() << " ex:" << trigger->GetEtaMax();
302 // cout << " eg:" << trigger->GetEtaGeo() << " " << (trigger->GetEtaMin()+trigger->GetEtaMax()) / 2.;
303 // cout << " ec:" << trigger->GetEtaCM();
304 // cout << " e:" << trigger->GetPatchE();
305 // cout << " jl:" << trigger->IsJetLow() << " jh:" << trigger->IsJetHigh() << endl;
309 // mark the most energetic patch as main
310 // for real and also simple offline
311 if( triggerMainJet != 0 ){
312 tBits = triggerMainJet->GetTriggerBits();
314 tBits = tBits | ( 1 << 24 );
315 triggerMainJet->SetTriggerBits( tBits );
317 if( triggerMainJetSimple != 0 ){
318 tBits = triggerMainJetSimple->GetTriggerBits();
320 tBits = tBits | ( 1 << 24 );
321 triggerMainJetSimple->SetTriggerBits( tBits );
323 if( triggerMainGamma != 0 ){
324 tBits = triggerMainGamma->GetTriggerBits();
326 tBits = tBits | ( 1 << 24 );
327 triggerMainGamma->SetTriggerBits( tBits );
329 if( triggerMainGammaSimple != 0 ){
330 tBits = triggerMainGammaSimple->GetTriggerBits();
332 tBits = tBits | ( 1 << 24 );
333 triggerMainGammaSimple->SetTriggerBits( tBits );
336 } // there are some triggers
341 //________________________________________________________________________
342 AliEmcalTriggerPatchInfo* AliEmcalTriggerMaker::ProcessPatch( Int_t type, Bool_t isOfflineSimple ){
345 Int_t globCol, globRow, tBits, cellAbsId[4];
347 Int_t i, j, k, cmCol, cmRow, cmiCellCol, cmiCellRow;
348 Double_t amp, ca, cmiCol, cmiRow;
350 TVector3 centerGeo, center1, center2, centerMass, edge1, edge2, vertex, cellCoor;
352 AliEmcalTriggerPatchInfo *trigger;
354 // check if jet trigger low or high
355 if( ! isOfflineSimple )
356 fCaloTriggers->GetTriggerBits( tBits );
358 fSimpleOfflineTriggers->GetTriggerBits( tBits );
360 if(( type == 0 && ! IsEJE( tBits )) || ( type == 1 && ! IsEGA( tBits )))
363 // save primary vertex in vector
364 vertex.SetXYZ( fVertex[0], fVertex[1], fVertex[2] );
366 // get position in global 2x2 tower coordinates
367 // A0 left bottom (0,0)
368 if( ! isOfflineSimple )
369 fCaloTriggers->GetPosition( globCol, globRow );
371 fSimpleOfflineTriggers->GetPosition( globCol, globRow );
373 // get the absolute trigger ID
374 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol, globRow, absId );
375 // convert to the 4 absId of the cells composing the trigger channel
376 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
378 // get low left edge (eta max, phi min)
379 fGeom->GetGlobal( cellAbsId[0], edge1 );
381 // sum the available energy in the 32/32 window of cells
382 // step over trigger channels and get all the corresponding cells
388 if( IsEJE( tBits ) && type == 0 ){
389 for( i = 0; i < 16; i++ ){
390 for( j = 0; j < 16; j++ ){
391 // get the 4 cells composing the trigger channel
392 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+i, globRow+j, absId );
393 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
394 // add amplitudes and find patch edges
395 for( k = 0; k < 4; k++ ){
396 ca = fCaloCells->GetCellAmplitude( cellAbsId[k] );
397 fGeom->GetGlobal( cellAbsId[k], cellCoor );
399 cmiCol += ca*(Double_t)i;
400 cmiRow += ca*(Double_t)j;
402 // add the STU ADCs in the patch
403 if( ! isOfflineSimple )
404 adcAmp += fPatchADC[globCol+i][globRow+j];
406 adcAmp += fPatchADCSimple[globCol+i][globRow+j];
408 } // 32x32 cell window
411 if( IsEGA( tBits ) && type == 1 ){
412 for( i = 0; i < 2; i++ ){
413 for( j = 0; j < 2; j++ ){
414 // get the 4 cells composing the trigger channel
415 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+i, globRow+j, absId );
416 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
417 // add amplitudes and find patch edges
418 for( k = 0; k < 4; k++ ){
419 ca = fCaloCells->GetCellAmplitude( cellAbsId[k] );
420 fGeom->GetGlobal( cellAbsId[k], cellCoor );
422 cmiCol += ca*(Double_t)i;
423 cmiRow += ca*(Double_t)j;
425 // add the STU ADCs in the patch
426 if( ! isOfflineSimple )
427 adcAmp += fPatchADC[globCol+i][globRow+j];
429 adcAmp += fPatchADCSimple[globCol+i][globRow+j];
434 AliDebug(2,"EMCal trigger patch with 0 energy.");
438 // get the CM and patch index
441 cmCol = globCol + (Int_t)cmiCol;
442 cmRow = globRow + (Int_t)cmiRow;
444 // get the patch and corresponding cells
445 fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
446 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
448 // find which out of the 4 cells is closest to CM and get it's position
449 cmiCellCol = TMath::Nint( cmiCol * 2. );
450 cmiCellRow = TMath::Nint( cmiRow * 2. );
451 fGeom->GetGlobal( cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass );
453 // get up right edge (eta min, phi max)
454 // get the absolute trigger ID
456 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+15, globRow+15, absId );
458 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+1, globRow+1, absId );
459 // convert to the 4 absId of the cells composing the trigger channel
460 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
462 fGeom->GetGlobal( cellAbsId[3], edge2 );
464 // get the geometrical center as an average of two diagonally
465 // adjacent patches in the center
466 // picking two diagonally closest cells from the patches
468 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+7, globRow+7, absId );
470 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol, globRow, absId );
472 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
473 fGeom->GetGlobal( cellAbsId[3], center1 );
476 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+8, globRow+8, absId );
478 fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+1, globRow+1, absId );
480 fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
481 fGeom->GetGlobal( cellAbsId[0], center2 );
484 centerGeo += center2;
487 // relate all to primary vertex
489 centerMass -= vertex;
493 // fix tbits .. remove the unwanted type triggers
495 tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1GammaLow) | 1 << (kTriggerTypeEnd + kL1GammaHigh) | 1 << (kL1GammaLow) | 1 << (kL1GammaHigh));
497 tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1JetLow) | 1 << (kTriggerTypeEnd + kL1JetHigh) | 1 << (kL1JetLow) | 1 << (kL1JetHigh));
499 // save the trigger object
500 new ((*fCaloTriggersOut)[fITrigger])AliEmcalTriggerPatchInfo();
501 trigger = (AliEmcalTriggerPatchInfo*)fCaloTriggersOut->At( fITrigger );
504 Int_t isMC = MCEvent() ? 1 : 0;
505 Int_t offSet = (1 - isMC) * kTriggerTypeEnd;
507 trigger->SetCenterGeo( centerGeo, amp );
508 trigger->SetCenterMass( centerMass, amp );
509 trigger->SetEdge1( edge1, amp );
510 trigger->SetEdge2( edge2, amp );
511 trigger->SetADCAmp( adcAmp );
512 trigger->SetTriggerBits( tBits );
513 trigger->SetOffSet(offSet);
514 trigger->SetEdgeCell( globCol*2, globRow*2 ); // from triggers to cells
521 //________________________________________________________________________
522 void AliEmcalTriggerMaker::RunSimpleOfflineTrigger()
524 // runs simple offline trigger algorithm
526 // it creates separate patches for jet and gamma triggers
527 // on the same positions (different from STU reconstruction behavior)
528 // TODO:: change to merge
530 Int_t i, j, k, l, tBits, tSum;
531 TArrayI tBitsArray, rowArray, colArray;
533 // 0 thresholds = no processing
534 if( fCaloTriggerSetupOut->GetThresholdJetLowSimple() == 0 &&
535 fCaloTriggerSetupOut->GetThresholdJetHighSimple() == 0 )
538 // run the trigger algo, stepping by 8 towers (= 4 trigger channels)
539 for( i = 0; i < 32; i += 4 ){
540 for( j = 0; j < 48; j += 4 ){
546 for( k = 0; k < 16; k++ )
547 for( l = 0; l < 16; l++ )
548 tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
551 if( tSum > fCaloTriggerSetupOut->GetThresholdJetLowSimple() )
552 tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetLow ));
553 if( tSum > fCaloTriggerSetupOut->GetThresholdJetHighSimple() )
554 tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetHigh ));
556 // add trigger values
559 tBits = tBits | ( 1 << 25 );
561 tBitsArray.Set( tBitsArray.GetSize() + 1 );
562 colArray.Set( colArray.GetSize() + 1 );
563 rowArray.Set( rowArray.GetSize() + 1 );
565 tBitsArray[tBitsArray.GetSize()-1] = tBits;
566 colArray[colArray.GetSize()-1] = i;
567 rowArray[rowArray.GetSize()-1] = j;
572 // 4x4 trigger algo, stepping by 2 towers (= 1 trigger channel)
573 for( i = 0; i < 46; i ++ ){
574 for( j = 0; j < 62; j ++ ){
580 for( k = 0; k < 2; k++ )
581 for( l = 0; l < 2; l++ )
582 tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
585 if( tSum > fCaloTriggerSetupOut->GetThresholdGammaLowSimple() )
586 tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaLow ));
587 if( tSum > fCaloTriggerSetupOut->GetThresholdGammaHighSimple() )
588 tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaHigh ));
590 // add trigger values
593 tBits = tBits | ( 1 << 25 );
595 tBitsArray.Set( tBitsArray.GetSize() + 1 );
596 colArray.Set( colArray.GetSize() + 1 );
597 rowArray.Set( rowArray.GetSize() + 1 );
599 tBitsArray[tBitsArray.GetSize()-1] = tBits;
600 colArray[colArray.GetSize()-1] = i;
601 rowArray[rowArray.GetSize()-1] = j;
608 fSimpleOfflineTriggers->DeAllocate();
609 fSimpleOfflineTriggers->Allocate( tBitsArray.GetSize() );
611 for( i = 0; i < tBitsArray.GetSize(); i++ ){
612 fSimpleOfflineTriggers->Add( colArray[i], rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i] );
617 //________________________________________________________________________
618 Bool_t AliEmcalTriggerMaker::NextTrigger( Bool_t &isOfflineSimple )
624 loopContinue = fCaloTriggers->Next();
625 isOfflineSimple = kFALSE;
627 if( ! loopContinue ){
628 loopContinue = fSimpleOfflineTriggers->Next();
629 isOfflineSimple = kTRUE;