-// $Id$
+// $Id: AliEmcalTriggerMaker.cxx 64593 2013-10-18 10:23:58Z loizides $
//
-// Class to make emcal particles in AOD/ESD events.
+// Class to make array of trigger patch objects in AOD/ESD events.
//
// Author: J.Kral
-
#include <TClonesArray.h>
-#include <iostream>
-
-#include "AliLog.h"
+#include <TArrayI.h>
+#include <THashList.h>
+#include "AliAODCaloTrigger.h"
+#include "AliEMCALGeometry.h"
+#include "AliEMCALTriggerTypes.h"
#include "AliEmcalTriggerPatchInfo.h"
#include "AliEmcalTriggerSetupInfo.h"
-
-#include "AliEmcalTriggerMaker.h"
-#include "AliEMCALTriggerTypes.h"
-#include "AliEMCALGeometry.h"
-
-#include "AliVCaloTrigger.h"
-#include "AliAODCaloTrigger.h"
+#include "AliLog.h"
#include "AliVCaloCells.h"
+#include "AliVCaloTrigger.h"
#include "AliVVZERO.h"
+#include "AliEmcalTriggerMaker.h"
+
+#include "THistManager.h"
+#include "TString.h"
ClassImp(AliEmcalTriggerMaker)
fCaloTriggersOut(0),
fCaloTriggerSetupOut(0),
fSimpleOfflineTriggers(0),
- fV0(0)
+ fV0(0),
+ fITrigger(0),
+ fDoQA(kFALSE),
+ fQAHistos(NULL)
{
// Constructor.
- for( int i = 0; i < 4; i++ )
- for( int j = 0; j < 3; j++ )
- fThresholdConstants[i][j] = 0;
+ memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
+ memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
+ memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
}
//________________________________________________________________________
-AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name) :
- AliAnalysisTaskEmcal(name,kFALSE),
+AliEmcalTriggerMaker::AliEmcalTriggerMaker(const char *name, Bool_t doQA) :
+ AliAnalysisTaskEmcal(name,doQA),
fCaloTriggersOutName("EmcalTriggers"),
fCaloTriggerSetupOutName("EmcalTriggersSetup"),
fV0InName("AliAODVZERO"),
fCaloTriggersOut(0),
fCaloTriggerSetupOut(0),
fSimpleOfflineTriggers(0),
- fV0(0)
+ fV0(0),
+ fITrigger(0),
+ fDoQA(doQA),
+ fQAHistos(NULL)
{
// Constructor.
- for( int i = 0; i < 4; i++ )
- for( int j = 0; j < 3; j++ )
- fThresholdConstants[i][j] = 0;
+ memset(fThresholdConstants, 0, sizeof(Int_t) * 12);
+ memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
+ memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
}
//________________________________________________________________________
}
if ( ! fV0InName.IsNull()) {
- fV0 = (AliVVZERO*)InputEvent()->FindListObject( fV0InName );
+ fV0 = (AliVVZERO*)InputEvent()->FindListObject(fV0InName);
}
// container for simple offline trigger processing
fSimpleOfflineTriggers = new AliAODCaloTrigger();
- fSimpleOfflineTriggers->Allocate( 0 );
+ fSimpleOfflineTriggers->Allocate(0);
+}
+
+//________________________________________________________________________
+void AliEmcalTriggerMaker::UserCreateOutputObjects()
+{
+ // Do basic QA monitoring (if requested)
+ AliAnalysisTaskEmcal::UserCreateOutputObjects();
+
+ if(fDoQA){
+ fQAHistos = new THistManager("TriggerQA");
+
+ TString trtypenames[3] = {"EJE", "EGA", "EL0"};
+ for(int itype = 0; itype < 3; itype++){
+ 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);
+ 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.);
+ 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);
+ }
+ fQAHistos->CreateTH1("triggerBitsAll", "Trigger bits for all incoming patches", 64, -0.5, 63.5);
+ fQAHistos->CreateTH1("triggerBitsSel", "Trigger bits for reconstructed patches", 64, -0.5, 63.5);
+ fOutput->Add(fQAHistos->GetListOfHistograms());
+ PostData(1, fOutput);
+ }
}
//________________________________________________________________________
Bool_t AliEmcalTriggerMaker::Run()
{
- // Create the emcal particles
-
- Short_t cellId;
- Int_t globCol, globRow, tBits, cellAbsId[4], v0[2];
- Int_t absId, adcAmp;
- Int_t i, j, k, iMain, iMainSimple, cmCol, cmRow, cmiCellCol, cmiCellRow, nCell, iCell;
- Int_t jetTrigger, iTriggers;
- Int_t patchADC[48][64];
- Double_t amp, ca, eMain, eMainSimple, cmiCol, cmiRow;
- ULong64_t v0S, thresh;
- Bool_t isOfflineSimple;
-
- TVector3 centerGeo, center1, center2, centerMass, edge1, edge2, vertex;
-
- AliEmcalTriggerPatchInfo *trigger;
+ // Create and fill the patch array.
+
+ AliEmcalTriggerPatchInfo *trigger, *triggerMainJet, *triggerMainGamma, *triggerMainLevel0;
+ AliEmcalTriggerPatchInfo *triggerMainJetSimple, *triggerMainGammaSimple;
// delete patch array, clear setup object
fCaloTriggersOut->Delete();
fCaloTriggerSetupOut->Clean();
- if( !fCaloTriggers ){
+ if (!fCaloTriggers) {
AliError(Form("Calo triggers container %s not available.", fCaloTriggersName.Data()));
return kTRUE;
}
- if( !fCaloCells ){
+ if (!fCaloCells) {
AliError(Form("Calo cells container %s not available.", fCaloCellsName.Data()));
return kTRUE;
}
- if( !fCaloCells ){
+ if (!fCaloCells) {
AliError(Form("V0 container %s not available.", fV0InName.Data()));
return kTRUE;
}
-// // do not process, if sooner than 11h period
-// if( InputEvent()->GetRunNumber() < 167693 )
-// return kTRUE;
-//
+ // do not process, if sooner than 11h period
+ // 160683 ??
+ if( InputEvent()->GetRunNumber() < 167693 )
+ return kTRUE;
+
// // do not process any MC, since no MC was generated with correct
// // EMCal trigger L1 jet trigger simulation, yet
// // productions will be enabled, once some correct once are produced
// must reset before usage, or the class will fail
fCaloTriggers->Reset();
- for (i=0; i<2; i++) {
- fEGA[i] = 0;
- fEJE[i] = 0;
- }
+
// first run over the patch array to compose a map of 2x2 patch energies
// which is then needed to construct the full patch ADC energy
// class is not empty
- if( fCaloTriggers->GetEntries() > 0 ){
-
- // zero the array
- for( i = 0; i < 48; i++ )
- for( j = 0; j < 64; j++ )
- patchADC[i][j] = 0;
-
+ if (fCaloTriggers->GetEntries() > 0) {
+ // zero the arrays
+ memset(fPatchADC, 0, sizeof(Int_t) * kPatchCols * kPatchRows);
+
// go throuth the trigger channels
- while( fCaloTriggers->Next() ){
+ while (fCaloTriggers->Next()) {
// get position in global 2x2 tower coordinates
// A0 left bottom (0,0)
- fCaloTriggers->GetPosition( globCol, globRow );
-
+ Int_t globCol=-1, globRow=-1;
+ fCaloTriggers->GetPosition(globCol, globRow);
// for some strange reason some ADC amps are initialized in reconstruction
- // as -1, neglect those :\\ wth
- fCaloTriggers->GetL1TimeSum( adcAmp );
- if( adcAmp > -1 )
- patchADC[globCol][globRow] = adcAmp;
-
- fCaloTriggers->GetTriggerBits( tBits );
-
- Int_t isMC = 0;
- if (MCEvent()) isMC = 1;
-
- Int_t offSet = (1 - isMC) * kTriggerTypeEnd;
- if (tBits) {
- if ((tBits >> (offSet + kL1GammaHigh)) & 1 ) fEGA[0] = 1;
- if ((tBits >> (offSet + kL1GammaLow )) & 1 ) fEGA[1] = 1;
- if ((tBits >> (offSet + kL1JetHigh )) & 1 ) fEJE[0] = 1;
- if ((tBits >> (offSet + kL1JetLow )) & 1 ) fEJE[1] = 1;
- }
+ // as -1, neglect those
+ Int_t adcAmp=-1;
+ fCaloTriggers->GetL1TimeSum(adcAmp);
+ if (adcAmp>-1)
+ fPatchADC[globCol][globRow] = adcAmp;
} // patches
} // array not empty
// fill the array for offline trigger processing
// using calibrated cell energies
- for( i = 0; i < 48; i++ )
- for( j = 0; j < 64; j++ )
- fPatchADCSimple[i][j] = 0;
+ memset(fPatchADCSimple, 0, sizeof(Int_t) * kPatchRows * kPatchCols);
// fill the patch ADCs from cells
- nCell = fCaloCells->GetNumberOfCells();
-
- for( iCell = 0; iCell < nCell; iCell++ ){
+ Int_t nCell = fCaloCells->GetNumberOfCells();
+ for(Int_t iCell = 0; iCell < nCell; ++iCell) {
// get the cell info, based in index in array
- cellId = fCaloCells->GetCellNumber( iCell );
- amp = fCaloCells->GetAmplitude( iCell );
-
+ Short_t cellId = fCaloCells->GetCellNumber(iCell);
+ Double_t amp = fCaloCells->GetAmplitude(iCell);
// get position
- fGeom->GetFastORIndexFromCellIndex( cellId, absId );
- fGeom->GetPositionInEMCALFromAbsFastORIndex( absId, globCol, globRow );
-
+ Int_t absId=-1;
+ fGeom->GetFastORIndexFromCellIndex(cellId, absId);
+ Int_t globCol=-1, globRow=-1;
+ fGeom->GetPositionInEMCALFromAbsFastORIndex(absId, globCol, globRow);
// add
fPatchADCSimple[globCol][globRow] += amp/kEMCL1ADCtoGeV;
}
// dig out common data (thresholds)
// 0 - jet high, 1 - gamma high, 2 - jet low, 3 - gamma low
- fCaloTriggerSetupOut->SetThresholds( fCaloTriggers->GetL1Threshold( 0 ),
- fCaloTriggers->GetL1Threshold( 1 ),
- fCaloTriggers->GetL1Threshold( 2 ),
- fCaloTriggers->GetL1Threshold( 3 ));
+ fCaloTriggerSetupOut->SetThresholds(fCaloTriggers->GetL1Threshold(0),
+ fCaloTriggers->GetL1Threshold(1),
+ fCaloTriggers->GetL1Threshold(2),
+ fCaloTriggers->GetL1Threshold(3));
// get the V0 value and compute and set the offline thresholds
// get V0, compute thresholds and save them as global parameters
+ Int_t v0[2];
v0[0] = fV0->GetTriggerChargeA();
v0[1] = fV0->GetTriggerChargeC();
- v0S = v0[0] + v0[1];
-
- fSimpleOfflineTriggers->SetL1V0( v0 );
+ ULong64_t v0S = v0[0] + v0[1];
+ fSimpleOfflineTriggers->SetL1V0(v0);
- for( i = 0; i < 4; i++ ){
+ for (Int_t i = 0; i < 4; ++i) {
// A*V0^2/2^32+B*V0/2^16+C
- thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
+ ULong64_t thresh = ( ((ULong64_t)fThresholdConstants[i][0]) * v0S * v0S ) >> 32;
thresh += ( ((ULong64_t)fThresholdConstants[i][1]) * v0S ) >> 16;
thresh += ((ULong64_t)fThresholdConstants[i][2]);
- fSimpleOfflineTriggers->SetL1Threshold( i, thresh );
+ fSimpleOfflineTriggers->SetL1Threshold(i,thresh);
}
// save the thresholds in output object
- fCaloTriggerSetupOut->SetThresholdsSimple( fSimpleOfflineTriggers->GetL1Threshold( 0 ),
- fSimpleOfflineTriggers->GetL1Threshold( 1 ),
- fSimpleOfflineTriggers->GetL1Threshold( 2 ),
- fSimpleOfflineTriggers->GetL1Threshold( 3 ));
-
+ fCaloTriggerSetupOut->SetThresholdsSimple(fSimpleOfflineTriggers->GetL1Threshold(0),
+ fSimpleOfflineTriggers->GetL1Threshold(1),
+ fSimpleOfflineTriggers->GetL1Threshold(2),
+ fSimpleOfflineTriggers->GetL1Threshold(3));
+
// run the trigger
RunSimpleOfflineTrigger();
fSimpleOfflineTriggers->Reset();
// class is not empty
- if( fCaloTriggers->GetEntries() > 0 || fSimpleOfflineTriggers->GetEntries() > 0 ){
-
- iTriggers = 0;
- iMain = -1;
- eMain = -1;
- iMainSimple = -1;
- eMainSimple = -1;
-
- // save primary vertex in vector
- vertex.SetXYZ( fVertex[0], fVertex[1], fVertex[2] );
+ if (fCaloTriggers->GetEntries() > 0 || fSimpleOfflineTriggers->GetEntries() > 0) {
+ fITrigger = 0;
+ triggerMainGamma = 0;
+ triggerMainJet = 0;
+ triggerMainGammaSimple = 0;
+ triggerMainJetSimple = 0;
+ triggerMainLevel0 = 0;
// go throuth the trigger channels, real first, then offline
- while( NextTrigger( isOfflineSimple ) ){
-
- // check if jet trigger low or high
- if( ! isOfflineSimple )
- fCaloTriggers->GetTriggerBits( tBits );
- else
- fSimpleOfflineTriggers->GetTriggerBits( tBits );
-
- jetTrigger = 0;
- if(( tBits >> ( kTriggerTypeEnd + kL1JetLow )) & 1 )
- jetTrigger = 1;
- if(( tBits >> ( kTriggerTypeEnd + kL1JetHigh )) & 1)
- jetTrigger = jetTrigger | 2;
-
- if( jetTrigger == 0 )
- continue;
-
- // get position in global 2x2 tower coordinates
- // A0 left bottom (0,0)
- if( ! isOfflineSimple )
- fCaloTriggers->GetPosition( globCol, globRow );
- else
- fSimpleOfflineTriggers->GetPosition( globCol, globRow );
-
- // get the absolute trigger ID
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol, globRow, absId );
- // convert to the 4 absId of the cells composing the trigger channel
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
-
- // get low left edge (eta max, phi min)
- fGeom->GetGlobal( cellAbsId[0], edge1 );
-
- // sum the available energy in the 32/32 window of cells
- // step over trigger channels and get all the corresponding cells
- // make CM
- amp = 0;
- cmiCol = 0;
- cmiRow = 0;
- adcAmp = 0;
- for( i = 0; i < 16; i++ ){
- for( j = 0; j < 16; j++ ){
- // get the 4 cells composing the trigger channel
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+i, globRow+j, absId );
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
- // add amplitudes and find patch edges
- for( k = 0; k < 4; k++ ){
- ca = fCaloCells->GetCellAmplitude( cellAbsId[k] );
- amp += ca;
- cmiCol += ca*(Double_t)i;
- cmiRow += ca*(Double_t)j;
- }
- // add the STU ADCs in the patch
- if( ! isOfflineSimple )
- adcAmp += patchADC[globCol+i][globRow+j];
- else
- adcAmp += fPatchADCSimple[globCol+i][globRow+j];
+ Bool_t isOfflineSimple=0;
+ while (NextTrigger(isOfflineSimple)) {
+ // process jet
+ trigger = ProcessPatch(kTMEMCalJet, isOfflineSimple);
+ // save main jet triggers in event
+ if (trigger != 0) {
+ // check if more energetic than others for main patch marking
+ if (!isOfflineSimple) {
+ if (triggerMainJet == 0 || (triggerMainJet->GetPatchE() < trigger->GetPatchE()))
+ triggerMainJet = trigger;
+ } else {
+ if (triggerMainJetSimple == 0 || (triggerMainJetSimple->GetPatchE() < trigger->GetPatchE()))
+ triggerMainJetSimple = trigger;
}
- } // 32x32 cell window
- if( amp == 0 ){
- AliDebug(2,"EMCal trigger patch with 0 energy.");
- continue;
}
- // get the CM and patch index
- cmiCol /= amp;
- cmiRow /= amp;
- cmCol = globCol + (Int_t)cmiCol;
- cmRow = globRow + (Int_t)cmiRow;
-
- // get the patch and corresponding cells
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
-
- // find which out of the 4 cells is closest to CM and get it's position
- cmiCellCol = TMath::Nint( cmiCol * 2. );
- cmiCellRow = TMath::Nint( cmiRow * 2. );
- fGeom->GetGlobal( cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass );
-
- // get up right edge (eta min, phi max)
- // get the absolute trigger ID
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+15, globRow+15, absId );
- // convert to the 4 absId of the cells composing the trigger channel
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
-
- fGeom->GetGlobal( cellAbsId[3], edge2 );
-
- // get the geometrical center as an average of two diagonally
- // adjacent patches in the center
- // picking two diagonally closest cells from the patches
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+7, globRow+7, absId );
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
- fGeom->GetGlobal( cellAbsId[3], center1 );
-
- fGeom->GetAbsFastORIndexFromPositionInEMCAL( globCol+8, globRow+8, absId );
- fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
- fGeom->GetGlobal( cellAbsId[0], center2 );
-
- centerGeo = center1;
- centerGeo += center2;
- centerGeo *= 0.5;
-
- // relate all to primary vertex
- centerGeo -= vertex;
- centerMass -= vertex;
- edge1 -= vertex;
- edge2 -= vertex;
-
- // save the trigger object
- new ((*fCaloTriggersOut)[iTriggers])AliEmcalTriggerPatchInfo();
- trigger = (AliEmcalTriggerPatchInfo*)fCaloTriggersOut->At( iTriggers );
- iTriggers++;
-
- trigger->SetCenterGeo( centerGeo, amp );
- trigger->SetCenterMass( centerMass, amp );
- trigger->SetEdge1( edge1, amp );
- trigger->SetEdge2( edge2, amp );
- trigger->SetADCAmp( adcAmp );
- trigger->SetTriggerBits( tBits );
- trigger->SetEdgeCell( globCol*2, globRow*2 ); // from triggers to cells
-
- // check if more energetic than others for main patch marking
- if( ! isOfflineSimple && eMain < amp ){
- eMain = amp;
- iMain = iTriggers - 1;
+ // process gamma
+ trigger = ProcessPatch(kTMEMCalGamma, isOfflineSimple);
+ // save main gamma triggers in event
+ if (trigger != 0) {
+ // check if more energetic than others for main patch marking
+ if (!isOfflineSimple) {
+ if (triggerMainGamma == 0 || (triggerMainGamma->GetPatchE() < trigger->GetPatchE()))
+ triggerMainGamma = trigger;
+ } else {
+ if (triggerMainGammaSimple == 0 || (triggerMainGammaSimple->GetPatchE() < trigger->GetPatchE()))
+ triggerMainGammaSimple = trigger;
+ }
}
- if( isOfflineSimple && eMainSimple < amp ){
- eMainSimple = amp;
- iMainSimple = iTriggers - 1;
+
+ // level 0 triggers
+ trigger = ProcessPatch(kTMEMCalLevel0, isOfflineSimple);
+ // save main level0 trigger in the event
+ if (trigger) {
+ if (!triggerMainLevel0 || (triggerMainLevel0->GetPatchE() < trigger->GetPatchE()))
+ triggerMainLevel0 = trigger;
}
-
-// cout << " pi:" << trigger->GetPhiMin() << " px:" << trigger->GetPhiMax();
-// cout << " pg:" << trigger->GetPhiGeo() << " " << (trigger->GetPhiMin()+trigger->GetPhiMax()) / 2.;
-// cout << " pc:" << trigger->GetPhiCM();
-// cout << " ei:" << trigger->GetEtaMin() << " ex:" << trigger->GetEtaMax();
-// cout << " eg:" << trigger->GetEtaGeo() << " " << (trigger->GetEtaMin()+trigger->GetEtaMax()) / 2.;
-// cout << " ec:" << trigger->GetEtaCM();
-// cout << " e:" << trigger->GetPatchE();
-// cout << " jl:" << trigger->IsJetLow() << " jh:" << trigger->IsJetHigh() << endl;
-
} // triggers
// mark the most energetic patch as main
// for real and also simple offline
- if( iMain > -1 ){
- trigger = (AliEmcalTriggerPatchInfo*)fCaloTriggersOut->At( iMain );
- tBits = trigger->GetTriggerBits();
+ if (triggerMainJet != 0) {
+ Int_t tBits = triggerMainJet->GetTriggerBits();
// main trigger flag
tBits = tBits | ( 1 << 24 );
- trigger->SetTriggerBits( tBits );
+ triggerMainJet->SetTriggerBits( tBits );
}
- if( iMainSimple > -1 ){
- trigger = (AliEmcalTriggerPatchInfo*)fCaloTriggersOut->At( iMainSimple );
- tBits = trigger->GetTriggerBits();
+ if (triggerMainJetSimple != 0) {
+ Int_t tBits = triggerMainJetSimple->GetTriggerBits();
// main trigger flag
tBits = tBits | ( 1 << 24 );
- trigger->SetTriggerBits( tBits );
+ triggerMainJetSimple->SetTriggerBits(tBits);
+ }
+ if (triggerMainGamma != 0) {
+ Int_t tBits = triggerMainGamma->GetTriggerBits();
+ // main trigger flag
+ tBits = tBits | ( 1 << 24 );
+ triggerMainGamma->SetTriggerBits( tBits );
+ }
+ if (triggerMainGammaSimple != 0) {
+ Int_t tBits = triggerMainGammaSimple->GetTriggerBits();
+ // main trigger flag
+ tBits = tBits | ( 1 << 24 );
+ triggerMainGammaSimple->SetTriggerBits( tBits );
+ }
+ if(triggerMainLevel0){
+ Int_t tBits = triggerMainLevel0->GetTriggerBits();
+ // main trigger flag
+ tBits |= (1 << 24);
+ triggerMainLevel0->SetTriggerBits(tBits);
}
-
} // there are some triggers
return kTRUE;
}
+//________________________________________________________________________
+AliEmcalTriggerPatchInfo* AliEmcalTriggerMaker::ProcessPatch(TriggerMakerTriggerType_t type, Bool_t isOfflineSimple)
+{
+ // Process and fill trigger patch.
+ // check if jet trigger low or high
+ Int_t tBits=-1;
+ if (!isOfflineSimple)
+ fCaloTriggers->GetTriggerBits(tBits);
+ else
+ fSimpleOfflineTriggers->GetTriggerBits(tBits);
+
+ Int_t nBitsFound = 0;
+ Int_t bitsFound[64];
+ if(fDoQA){
+ for(int ibit = 0; ibit < 64; ibit++) {
+ if(tBits & (1 << ibit)){
+ bitsFound[nBitsFound++] = ibit;
+ fQAHistos->FillTH1("triggerBitsAll", ibit);
+ }
+ }
+ }
+
+ if ((type == kTMEMCalJet && !IsEJE( tBits )) ||
+ (type == kTMEMCalGamma && !IsEGA( tBits )) ||
+ (type == kTMEMCalLevel0 && !(CheckForL0(*fCaloTriggers))))
+ return 0;
+ TString trtypenames[3] = {"EJE", "EGA", "EL0"}; // For QA
+
+ // save primary vertex in vector
+ TVector3 vertex;
+ vertex.SetXYZ(fVertex[0], fVertex[1], fVertex[2]);
+
+ // get position in global 2x2 tower coordinates
+ // A0 left bottom (0,0)
+ Int_t globCol=-1, globRow=-1;
+ if (!isOfflineSimple)
+ fCaloTriggers->GetPosition(globCol,globRow);
+ else
+ fSimpleOfflineTriggers->GetPosition(globCol, globRow);
+
+ // get the absolute trigger ID
+ Int_t absId=-1;
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol, globRow, absId);
+ // convert to the 4 absId of the cells composing the trigger channel
+ Int_t cellAbsId[4]={-1,-1,-1,-1};
+ fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
+
+ // get low left edge (eta max, phi min)
+ TVector3 edge1;
+ fGeom->GetGlobal(cellAbsId[0], edge1);
+
+ // sum the available energy in the 32/32 window of cells
+ // step over trigger channels and get all the corresponding cells
+ // make CM
+ Double_t amp = 0;
+ Int_t cmiCol = 0;
+ Int_t cmiRow = 0;
+ Int_t adcAmp = 0;
+ int nfastor = (type == kTMEMCalJet) ? 16 : 2; // 32x32 cell window for L1 Jet trigger, 4x4 for L1 Gamma or L0 trigger
+ for (Int_t i = 0; i < nfastor; ++i) {
+ for (Int_t j = 0; j < nfastor; ++j) {
+ // get the 4 cells composing the trigger channel
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+i, globRow+j, absId);
+ fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
+ // add amplitudes and find patch edges
+ for (Int_t k = 0; k < 4; ++k) {
+ Double_t ca = fCaloCells->GetCellAmplitude(cellAbsId[k]);
+ //fGeom->GetGlobal(cellAbsId[k], cellCoor);
+ amp += ca;
+ cmiCol += ca*(Double_t)i;
+ cmiRow += ca*(Double_t)j;
+ }
+ // add the STU ADCs in the patch (in case of L1) or the TRU Amplitude (in case of L0)
+ if (!isOfflineSimple )
+ if(type == kTMEMCalLevel0){
+ adcAmp += fPatchADC[globCol+i][globRow+j] * 4; // precision loss in case of global integer field
+ } else
+ adcAmp += fPatchADC[globCol+i][globRow+j];
+ else
+ adcAmp += fPatchADCSimple[globCol+i][globRow+j];
+ }
+ }
+
+ if (amp == 0) {
+ AliDebug(2,"EMCal trigger patch with 0 energy.");
+ return 0;
+ }
+
+ // get the CM and patch index
+ cmiCol /= amp;
+ cmiRow /= amp;
+ Int_t cmCol = globCol + (Int_t)cmiCol;
+ Int_t cmRow = globRow + (Int_t)cmiRow;
+
+ // get the patch and corresponding cells
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL( cmCol, cmRow, absId );
+ fGeom->GetCellIndexFromFastORIndex( absId, cellAbsId );
+
+ // find which out of the 4 cells is closest to CM and get it's position
+ Int_t cmiCellCol = TMath::Nint(cmiCol * 2.);
+ Int_t cmiCellRow = TMath::Nint(cmiRow * 2.);
+ TVector3 centerMass;
+ fGeom->GetGlobal(cellAbsId[(cmiCellRow%2)*2 + cmiCellCol%2], centerMass);
+
+ // get up right edge (eta min, phi max)
+ // get the absolute trigger ID
+ Int_t posOffset=-1;
+ switch(type){
+ case kTMEMCalJet:
+ posOffset = 15;
+ break;
+ case kTMEMCalGamma:
+ posOffset = 1;
+ break;
+ case kTMEMCalLevel0:
+ posOffset = 1;
+ break;
+ default:
+ posOffset = 0;
+ break;
+ };
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
+ fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
+ TVector3 edge2;
+ fGeom->GetGlobal(cellAbsId[3], edge2);
+
+ // get the geometrical center as an average of two diagonally
+ // adjacent patches in the center
+ // picking two diagonally closest cells from the patches
+ switch(type){
+ case kTMEMCalJet:
+ posOffset = 7;
+ break;
+ case kTMEMCalGamma:
+ posOffset = 0;
+ break;
+ case kTMEMCalLevel0:
+ posOffset = 0;
+ break;
+ default:
+ posOffset = 0;
+ break;
+ };
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
+ fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
+ TVector3 center1;
+ fGeom->GetGlobal(cellAbsId[3], center1);
+
+ switch(type){
+ case kTMEMCalJet:
+ posOffset = 8;
+ break;
+ case kTMEMCalGamma:
+ posOffset = 1;
+ break;
+ case kTMEMCalLevel0:
+ posOffset = 1;
+ break;
+ };
+ fGeom->GetAbsFastORIndexFromPositionInEMCAL(globCol+posOffset, globRow+posOffset, absId);
+ fGeom->GetCellIndexFromFastORIndex(absId, cellAbsId);
+ TVector3 center2;
+ fGeom->GetGlobal(cellAbsId[0], center2);
+
+ TVector3 centerGeo(center1);
+ centerGeo += center2;
+ centerGeo *= 0.5;
+
+ // relate all to primary vertex
+ centerGeo -= vertex;
+ centerMass -= vertex;
+ edge1 -= vertex;
+ edge2 -= vertex;
+
+ Int_t isMC = MCEvent() ? 1 : 0;
+ Int_t offSet = (1 - isMC) * kTriggerTypeEnd;
+
+ // fix tbits .. remove the unwanted type triggers
+ // for Jet and Gamma triggers we remove also the level 0 bit since it will be stored in the level 0 patch
+ // for level 0 we remove all gamma and jet trigger bits
+ switch(type){
+ case kTMEMCalJet:
+ tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1GammaLow) | 1 << (kTriggerTypeEnd + kL1GammaHigh) | 1 << (kL1GammaLow) | 1 << (kL1GammaHigh) |
+ 1 << (kTriggerTypeEnd + kL0) | 1 << (kL0));
+ break;
+ case kTMEMCalGamma:
+ tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1JetLow) | 1 << (kTriggerTypeEnd + kL1JetHigh) | 1 << (kL1JetLow) | 1 << (kL1JetHigh) |
+ 1 << (kTriggerTypeEnd + kL0) | 1 << (kL0));
+ break;
+ case kTMEMCalLevel0:
+ // Explicitly set the level 0 bit to overcome the masking out
+ tBits |= 1 << (offSet + kL0);
+ tBits = tBits & ~( 1 << (kTriggerTypeEnd + kL1JetLow) | 1 << (kTriggerTypeEnd + kL1JetHigh) | 1 << (kL1JetLow) | 1 << (kL1JetHigh) |
+ 1 << (kTriggerTypeEnd + kL1GammaLow) | 1 << (kTriggerTypeEnd + kL1GammaHigh) | 1 << (kL1GammaLow) | 1 << (kL1GammaHigh));
+ break;
+ };
+
+ // save the trigger object
+ AliEmcalTriggerPatchInfo *trigger =
+ new ((*fCaloTriggersOut)[fITrigger]) AliEmcalTriggerPatchInfo();
+ fITrigger++;
+ trigger->SetCenterGeo(centerGeo, amp);
+ trigger->SetCenterMass(centerMass, amp);
+ trigger->SetEdge1(edge1, amp);
+ trigger->SetEdge2(edge2, amp);
+ trigger->SetADCAmp(adcAmp);
+ trigger->SetTriggerBits(tBits);
+ trigger->SetOffSet(offSet);
+ trigger->SetEdgeCell(globCol*2, globRow*2); // from triggers to cells
+ if(fDoQA){
+ fQAHistos->FillTH2(Form("RCPos%s", trtypenames[type].Data()), globCol, globRow);
+ fQAHistos->FillTH2(Form("EPCentPos%s", trtypenames[type].Data()), centerGeo.Eta(), centerGeo.Phi());
+ fQAHistos->FillTH2(Form("PatchADCvsE%s", trtypenames[type].Data()), adcAmp, trigger->GetPatchE());
+ if(nBitsFound){
+ for(int ibit = 0; ibit < nBitsFound; ibit++)
+ fQAHistos->FillTH1("triggerBitsSel", ibit);
+ }
+ }
+ return trigger;
+}
+
//________________________________________________________________________
void AliEmcalTriggerMaker::RunSimpleOfflineTrigger()
{
- // runs simple offline trigger algorithm
+ // Runs a simple offline trigger algorithm.
+ // It creates separate patches for jet and gamma triggers
+ // on the same positions (different from STU reconstruction behavior)
+ // TODO:: change to merge
- Int_t i, j, k, l, tBits, tSum;
TArrayI tBitsArray, rowArray, colArray;
// 0 thresholds = no processing
- if( fCaloTriggerSetupOut->GetThresholdJetLowSimple() == 0 &&
- fCaloTriggerSetupOut->GetThresholdJetHighSimple() == 0 )
+ if (fCaloTriggerSetupOut->GetThresholdJetLowSimple() == 0 &&
+ fCaloTriggerSetupOut->GetThresholdJetHighSimple() == 0 )
return;
// run the trigger algo, stepping by 8 towers (= 4 trigger channels)
- for( i = 0; i < 32; i += 4 ){
- for( j = 0; j < 48; j += 4 ){
-
- tSum = 0;
- tBits = 0;
-
+ for (Int_t i = 0; i < 32; i += 4) {
+ for (Int_t j = 0; j < 48; j += 4) {
+ Int_t tSum = 0;
+ Int_t tBits = 0;
// window
- for( k = 0; k < 16; k++ )
- for( l = 0; l < 16; l++ )
+ for (Int_t k = 0; k < 16; ++k)
+ for (Int_t l = 0; l < 16; ++l)
tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
// check thresholds
- if( tSum > fCaloTriggerSetupOut->GetThresholdJetLowSimple() )
+ if (tSum > fCaloTriggerSetupOut->GetThresholdJetLowSimple())
tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetLow ));
- if( tSum > fCaloTriggerSetupOut->GetThresholdJetHighSimple() )
+ if (tSum > fCaloTriggerSetupOut->GetThresholdJetHighSimple())
tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1JetHigh ));
// add trigger values
- if( tBits != 0 ){
+ if (tBits != 0) {
+ // add offline bit
+ tBits = tBits | ( 1 << 25 );
+ tBitsArray.Set( tBitsArray.GetSize() + 1 );
+ colArray.Set( colArray.GetSize() + 1 );
+ rowArray.Set( rowArray.GetSize() + 1 );
+ tBitsArray[tBitsArray.GetSize()-1] = tBits;
+ colArray[colArray.GetSize()-1] = i;
+ rowArray[rowArray.GetSize()-1] = j;
+ }
+ }
+ } // trigger algo
+
+ // 4x4 trigger algo, stepping by 2 towers (= 1 trigger channel)
+ for (Int_t i = 0; i < 46; ++i) {
+ for (Int_t j = 0; j < 62; ++j) {
+ Int_t tSum = 0;
+ Int_t tBits = 0;
+
+ // window
+ for (Int_t k = 0; k < 2; ++k)
+ for (Int_t l = 0; l < 2; ++l)
+ tSum += (ULong64_t)fPatchADCSimple[i+k][j+l];
+
+ // check thresholds
+ if (tSum > fCaloTriggerSetupOut->GetThresholdGammaLowSimple())
+ tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaLow ));
+ if (tSum > fCaloTriggerSetupOut->GetThresholdGammaHighSimple())
+ tBits = tBits | ( 1 << ( kTriggerTypeEnd + kL1GammaHigh ));
+
+ // add trigger values
+ if (tBits != 0) {
// add offline bit
tBits = tBits | ( 1 << 25 );
-
tBitsArray.Set( tBitsArray.GetSize() + 1 );
colArray.Set( colArray.GetSize() + 1 );
rowArray.Set( rowArray.GetSize() + 1 );
-
tBitsArray[tBitsArray.GetSize()-1] = tBits;
colArray[colArray.GetSize()-1] = i;
rowArray[rowArray.GetSize()-1] = j;
// save in object
fSimpleOfflineTriggers->DeAllocate();
- fSimpleOfflineTriggers->Allocate( tBitsArray.GetSize() );
-
- for( i = 0; i < tBitsArray.GetSize(); i++ ){
- fSimpleOfflineTriggers->Add( colArray[i], rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i] );
+ fSimpleOfflineTriggers->Allocate(tBitsArray.GetSize());
+ for (Int_t i = 0; i < tBitsArray.GetSize(); ++i){
+ fSimpleOfflineTriggers->Add(colArray[i],rowArray[i], 0, 0, 0, 0, 0, tBitsArray[i]);
}
-
}
//________________________________________________________________________
-Bool_t AliEmcalTriggerMaker::NextTrigger( Bool_t &isOfflineSimple )
+Bool_t AliEmcalTriggerMaker::NextTrigger(Bool_t &isOfflineSimple)
{
- // get next trigger
-
- Bool_t loopContinue;
+ // Get next trigger
- loopContinue = fCaloTriggers->Next();
isOfflineSimple = kFALSE;
-
- if( ! loopContinue ){
+ Bool_t loopContinue = fCaloTriggers->Next();
+ if (!loopContinue) {
loopContinue = fSimpleOfflineTriggers->Next();
isOfflineSimple = kTRUE;
}
-
return loopContinue;
}
+
+//________________________________________________________________________
+Bool_t AliEmcalTriggerMaker::CheckForL0(const AliVCaloTrigger& trg) const {
+ // Check whether the patch is a level0 patch
+ if(MCEvent()){
+ // For Monte-Carlo select
+ Int_t tbits(-1);
+ trg.GetTriggerBits(tbits);
+ return tbits & (1 << kL0);
+ } else {
+ // For Data check from the level0 times if the trigger has fired at level0
+ Int_t nl0times(0);
+ Bool_t l0fired(kFALSE);
+ trg.GetNL0Times(nl0times);
+ if(nl0times){
+ TArrayI l0times(nl0times);
+ trg.GetL0Times(l0times.GetArray());
+ // Apply timing cut to see if a L0 has fired
+ for(Int_t *l0timeIter = l0times.GetArray(); l0timeIter < l0times.GetArray() + l0times.GetSize(); l0timeIter++){
+ if(*l0timeIter > 7 && *l0timeIter < 10){
+ l0fired = kTRUE;
+ break;
+ }
+ }
+ }
+ return l0fired;
+ }
+}