Skip to content

Commit 239ae7c

Browse files
committed
PWGEM/PhotonMeson: Add Background calculation to pi0QC task
- Add mixed events and rotation background calculation - Fix loop over collisions instead of whole timeframes - Added opening angle cut
1 parent 70940c3 commit 239ae7c

1 file changed

Lines changed: 151 additions & 24 deletions

File tree

PWGEM/PhotonMeson/Tasks/emcalPi0QC.cxx

Lines changed: 151 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
using namespace o2::framework;
5353
using namespace o2::framework::expressions;
54-
using collisionEvSelIt = o2::soa::Join<o2::aod::Collisions, o2::aod::EvSels>::iterator;
54+
using collisionEvSelIt = o2::aod::Collision;
5555
using selectedClusters = o2::soa::Filtered<o2::aod::EMCALClusters>;
5656
using selectedCluster = o2::soa::Filtered<o2::aod::EMCALCluster>;
5757
using selectedAmbiguousClusters = o2::soa::Filtered<o2::aod::EMCALAmbiguousClusters>;
@@ -99,6 +99,30 @@ struct Meson {
9999
float getOpeningAngle() const { return pgamma1.photon.Angle(pgamma2.photon.Vect()); };
100100
};
101101

102+
struct EventMixVec {
103+
104+
void AddEvent(std::vector<Photon> vecGamma)
105+
{
106+
if (vecEvtMix.size() < nEVtMixSize) {
107+
vecEvtMix.push_back(vecGamma);
108+
} else {
109+
vecEvtMix.erase(vecEvtMix.begin() + nEVtMixSize - 1);
110+
vecEvtMix.push_back(vecGamma);
111+
}
112+
}
113+
Photon* getPhoton(int iEvt, int iGamma)
114+
{
115+
if (vecEvtMix.size() >= iEvt)
116+
return nullptr;
117+
if (vecEvtMix[iEvt].size() >= iGamma)
118+
return nullptr;
119+
return &vecEvtMix[iEvt][iGamma];
120+
}
121+
122+
std::vector<std::vector<Photon>> vecEvtMix;
123+
unsigned int nEVtMixSize = 20;
124+
};
125+
102126
struct Pi0QCTask {
103127
HistogramRegistry mHistManager{"NeutralMesonHistograms"};
104128
o2::emcal::Geometry* mGeometry = nullptr;
@@ -115,6 +139,7 @@ struct Pi0QCTask {
115139
Configurable<float> mClusterMaxM02Cut{"MaxM02Cut", 0.7, "apply max M02 cut"};
116140
Configurable<float> mMinEnergyCut{"MinEnergyCut", 0.7, "apply min cluster energy cut"};
117141
Configurable<int> mMinNCellsCut{"MinNCellsCut", 1, "apply min cluster number of cell cut"};
142+
Configurable<float> mMinOpenAngleCut{"OpeningAngleCut", 0.0202, "apply min opening angle cut"};
118143
Configurable<std::string> mClusterDefinition{"clusterDefinition", "kV3Default", "cluster definition to be selected, e.g. V3Default"};
119144
std::vector<int> mVetoBCIDs;
120145
std::vector<int> mSelectBCIDs;
@@ -127,6 +152,11 @@ struct Pi0QCTask {
127152

128153
// define container for photons
129154
std::vector<Photon> mPhotons;
155+
// define container for photons for each collision
156+
std::map<int, std::vector<Photon>> mapPhotons;
157+
158+
// event mixing class
159+
EventMixVec evtMix;
130160

131161
/// \brief Create output histograms and initialize geometry
132162
void init(InitContext const&)
@@ -145,6 +175,7 @@ struct Pi0QCTask {
145175

146176
// event properties
147177
mHistManager.add("eventsAll", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}});
178+
mHistManager.add("eventsEMCTrigg", "Number of EMC triggered events", o2HistType::kTH1F, {{1, 0.5, 1.5}});
148179
mHistManager.add("eventsSelected", "Number of events", o2HistType::kTH1F, {{1, 0.5, 1.5}});
149180
mHistManager.add("eventBCAll", "Bunch crossing ID of event (all events)", o2HistType::kTH1F, {bcAxis});
150181
mHistManager.add("eventBCSelected", "Bunch crossing ID of event (selected events)", o2HistType::kTH1F, {bcAxis});
@@ -154,6 +185,7 @@ struct Pi0QCTask {
154185
// cluster properties
155186
mHistManager.add("clusterE", "Energy of cluster", o2HistType::kTH1F, {energyAxis});
156187
mHistManager.add("clusterE_SimpleBinning", "Energy of cluster", o2HistType::kTH1F, {{400, 0, 100}});
188+
mHistManager.add("clusterTime", "Time of cluster", o2HistType::kTH1F, {{500, -250, 250}});
157189
mHistManager.add("clusterEtaPhi", "Eta and phi of cluster", o2HistType::kTH2F, {{100, -1, 1}, {100, 0, 2 * TMath::Pi()}});
158190
mHistManager.add("clusterM02", "M02 of cluster", o2HistType::kTH1F, {{400, 0, 5}});
159191
mHistManager.add("clusterM20", "M20 of cluster", o2HistType::kTH1F, {{400, 0, 2.5}});
@@ -164,6 +196,7 @@ struct Pi0QCTask {
164196
// meson related histograms
165197
mHistManager.add("invMassVsPt", "invariant mass and pT of meson candidates", o2HistType::kTH2F, {{400, 0, 0.8}, {energyAxis}});
166198
mHistManager.add("invMassVsPtBackground", "invariant mass and pT of background meson candidates", o2HistType::kTH2F, {{400, 0, 0.8}, {energyAxis}});
199+
mHistManager.add("invMassVsPtMixedBackground", "invariant mass and pT of mixed background meson candidates", o2HistType::kTH2F, {{400, 0, 0.8}, {energyAxis}});
167200

168201
if (mVetoBCID->length()) {
169202
std::stringstream parser(mVetoBCID.value);
@@ -187,36 +220,38 @@ struct Pi0QCTask {
187220
}
188221
}
189222
/// \brief Process EMCAL clusters that are matched to a collisions
190-
void processCollisions(collisionEvSelIt const& theCollision, selectedClusters const& clusters, o2::aod::BCs const& bcs)
223+
224+
// void processCollisions(collisionEvSelIt const& collision, selectedClusters const& clusters)
225+
void processCollisions(o2::soa::Join<o2::aod::Collisions, o2::aod::EvSels>::iterator const& collision, selectedClusters const& clusters)
191226
{
227+
// for(const auto & collision : theCollisions){
192228
mHistManager.fill(HIST("eventsAll"), 1);
193-
229+
LOG(debug) << "processCollisions";
194230
// do event selection if mDoEventSel is specified
195231
// currently the event selection is hard coded to kINT7
196232
// but other selections are possible that are defined in TriggerAliases.h
197-
if (mDoEventSel && (!theCollision.alias()[kINT7])) {
233+
if (mDoEventSel && (!collision.alias()[kINT7])) {
198234
LOG(debug) << "Event not selected becaus it is not kINT7, skipping";
199235
return;
200236
}
201-
mHistManager.fill(HIST("eventVertexZAll"), theCollision.posZ());
202-
if (mVertexCut > 0 && TMath::Abs(theCollision.posZ()) > mVertexCut) {
203-
LOG(debug) << "Event not selected because of z-vertex cut z= " << theCollision.posZ() << " > " << mVertexCut << " cm, skipping";
237+
mHistManager.fill(HIST("eventVertexZAll"), collision.posZ());
238+
if (mVertexCut > 0 && TMath::Abs(collision.posZ()) > mVertexCut) {
239+
LOG(debug) << "Event not selected because of z-vertex cut z= " << collision.posZ() << " > " << mVertexCut << " cm, skipping";
204240
return;
205241
}
206242
mHistManager.fill(HIST("eventsSelected"), 1);
207-
mHistManager.fill(HIST("eventVertexZSelected"), theCollision.posZ());
243+
mHistManager.fill(HIST("eventVertexZSelected"), collision.posZ());
208244

209-
ProcessClusters(theCollision, clusters, bcs);
210-
ProcessMesons(theCollision, clusters, bcs);
245+
ProcessClusters(clusters);
246+
ProcessMesons(clusters);
211247
}
212248
PROCESS_SWITCH(Pi0QCTask, processCollisions, "Process clusters from collision", false);
213249

214250
/// \brief Process EMCAL clusters that are not matched to a collision
215251
/// This is not needed for most users
216-
void processAmbiguous(o2::aod::BC const& bc, selectedAmbiguousClusters const& clusters)
252+
void processAmbiguous(o2::aod::BCs::iterator const& bc, selectedAmbiguousClusters const& clusters)
217253
{
218-
// loop over bc , if requested (mVetoBCID >= 0), reject everything from a certain BC
219-
// this can be used as alternative to event selection (e.g. for pilot beam data)
254+
LOG(debug) << "processAmbiguous";
220255
// TODO: remove this loop and put it in separate process function that only takes care of ambiguous clusters
221256
o2::InteractionRecord eventIR;
222257
eventIR.setFromLong(bc.globalBC());
@@ -230,22 +265,90 @@ struct Pi0QCTask {
230265
}
231266
mHistManager.fill(HIST("eventBCSelected"), eventIR.bc);
232267

233-
// ToDo: Add mode if collision is not found
234-
// ProcessClusters(theCollision, clusters, bcs);
235-
// ProcessMesons(theCollision, clusters, bcs);
268+
ProcessAmbigousClusters(clusters);
269+
ProcessMesons(clusters);
236270
}
237271
PROCESS_SWITCH(Pi0QCTask, processAmbiguous, "Process Ambiguous clusters", false);
238272

239273
/// \brief Process EMCAL clusters that are matched to a collisions
240274
template <typename Clusters>
241-
void ProcessClusters(collisionEvSelIt const& theCollision, Clusters const& clusters, o2::aod::BCs const& bcs)
275+
void ProcessClusters(Clusters const& clusters)
242276
{
277+
LOG(debug) << "ProcessClusters";
243278
// clear photon vector
244279
mPhotons.clear();
280+
mapPhotons.clear();
281+
282+
int globalCollID = -1000;
245283

246284
// loop over all clusters from accepted collision
247285
// auto eventClusters = clusters.select(o2::aod::emcalcluster::bcId == theCollision.bc().globalBC());
248286
for (const auto& cluster : clusters) {
287+
288+
// o2::InteractionRecord eventIR;
289+
auto collID = cluster.collisionId();
290+
if (globalCollID == -1000)
291+
globalCollID = collID;
292+
293+
if (globalCollID != collID) {
294+
LOG(info) << "Something went wrong with the collision ID";
295+
}
296+
297+
// fill histograms of cluster properties
298+
// in this implementation the cluster properties are directly
299+
// loaded from the flat table, in the future one should
300+
// consider using the AnalysisCluster object to work with
301+
// after loading.
302+
LOG(debug) << "Cluster energy: " << cluster.energy();
303+
LOG(debug) << "Cluster time: " << cluster.time();
304+
LOG(debug) << "Cluster M02: " << cluster.m02();
305+
mHistManager.fill(HIST("clusterE"), cluster.energy());
306+
mHistManager.fill(HIST("clusterTime"), cluster.time());
307+
mHistManager.fill(HIST("clusterE_SimpleBinning"), cluster.energy());
308+
mHistManager.fill(HIST("clusterEtaPhi"), cluster.eta(), cluster.phi());
309+
mHistManager.fill(HIST("clusterM02"), cluster.m02());
310+
mHistManager.fill(HIST("clusterM20"), cluster.m20());
311+
mHistManager.fill(HIST("clusterNLM"), cluster.nlm());
312+
mHistManager.fill(HIST("clusterNCells"), cluster.nCells());
313+
mHistManager.fill(HIST("clusterDistanceToBadChannel"), cluster.distanceToBadChannel());
314+
315+
// apply basic cluster cuts
316+
if (cluster.energy() < mMinEnergyCut) {
317+
LOG(debug) << "Cluster rejected because of energy cut";
318+
continue;
319+
}
320+
if (cluster.nCells() <= mMinNCellsCut) {
321+
LOG(debug) << "Cluster rejected because of nCells cut";
322+
continue;
323+
}
324+
if (cluster.m02() < mClusterMinM02Cut || cluster.m02() > mClusterMaxM02Cut) {
325+
LOG(debug) << "Cluster rejected because of m02 cut";
326+
continue;
327+
}
328+
if (cluster.time() < mTimeMin || cluster.time() > mTimeMax) {
329+
LOG(debug) << "Cluster rejected because of time cut";
330+
continue;
331+
}
332+
333+
// put clusters in photon vector
334+
mPhotons.push_back(Photon(cluster.eta(), cluster.phi(), cluster.energy(), cluster.id()));
335+
}
336+
}
337+
338+
/// \brief Process EMCAL clusters that are matched to a collisions
339+
template <typename Clusters>
340+
void ProcessAmbigousClusters(Clusters const& clusters)
341+
{
342+
LOG(debug) << "ProcessClusters";
343+
// clear photon vector
344+
mPhotons.clear();
345+
346+
// loop over all clusters from accepted collision
347+
for (const auto& cluster : clusters) {
348+
349+
o2::InteractionRecord eventIR;
350+
auto collID = cluster.bcId();
351+
249352
// fill histograms of cluster properties
250353
// in this implementation the cluster properties are directly
251354
// loaded from the flat table, in the future one should
@@ -255,6 +358,7 @@ struct Pi0QCTask {
255358
LOG(debug) << "Cluster time: " << cluster.time();
256359
LOG(debug) << "Cluster M02: " << cluster.m02();
257360
mHistManager.fill(HIST("clusterE"), cluster.energy());
361+
mHistManager.fill(HIST("clusterTime"), cluster.time());
258362
mHistManager.fill(HIST("clusterE_SimpleBinning"), cluster.energy());
259363
mHistManager.fill(HIST("clusterEtaPhi"), cluster.eta(), cluster.phi());
260364
mHistManager.fill(HIST("clusterM02"), cluster.m02());
@@ -282,32 +386,39 @@ struct Pi0QCTask {
282386
}
283387

284388
// put clusters in photon vector
285-
// ToDo: At the moment, the eta and phi values are not corrected for a shift of the primary vertex! Should only be a small effect but has to be corrected
286389
mPhotons.push_back(Photon(cluster.eta(), cluster.phi(), cluster.energy(), cluster.id()));
287390
}
288391
}
289392

290393
/// \brief Process meson candidates, calculate invariant mass and pT and fill histograms
291394
template <typename Clusters>
292-
void ProcessMesons(collisionEvSelIt const& theCollision, Clusters const& clusters, o2::aod::BCs const& bcs)
395+
void ProcessMesons(Clusters const& clusters)
293396
{
397+
LOG(debug) << "ProcessMesons " << mPhotons.size();
398+
399+
mHistManager.fill(HIST("eventsEMCTrigg"), 1);
400+
294401
// if less then 2 clusters are found, skip event
295-
if (mPhotons.size() < 2) {
402+
if (mPhotons.size() < 2)
296403
return;
297-
}
298404

299405
// loop over all photon combinations and build meson candidates
300406
for (unsigned int ig1 = 0; ig1 < mPhotons.size(); ++ig1) {
301407
for (unsigned int ig2 = ig1 + 1; ig2 < mPhotons.size(); ++ig2) {
302408

303409
// build meson from photons
304410
Meson meson(mPhotons[ig1], mPhotons[ig2]);
305-
mHistManager.fill(HIST("invMassVsPt"), meson.getMass(), meson.getPt());
411+
if (meson.getOpeningAngle() > mMinOpenAngleCut) {
412+
mHistManager.fill(HIST("invMassVsPt"), meson.getMass(), meson.getPt());
413+
}
306414

307415
// calculate background candidates (rotation background)
308416
CalculateBackground(meson, ig1, ig2);
309417
}
418+
CalculateMixedBack(mPhotons[ig1]);
310419
}
420+
421+
evtMix.AddEvent(mPhotons);
311422
}
312423

313424
/// \brief Calculate background (using rotation background method)
@@ -347,8 +458,24 @@ struct Pi0QCTask {
347458
Meson mesonRotated2(rotPhoton2, mPhotons[ig3]);
348459

349460
// Fill histograms
350-
mHistManager.fill(HIST("invMassVsPtBackground"), mesonRotated1.getMass(), mesonRotated1.getPt());
351-
mHistManager.fill(HIST("invMassVsPtBackground"), mesonRotated2.getMass(), mesonRotated2.getPt());
461+
if (mesonRotated1.getOpeningAngle() > mMinOpenAngleCut) {
462+
mHistManager.fill(HIST("invMassVsPtBackground"), mesonRotated1.getMass(), mesonRotated1.getPt());
463+
}
464+
if (mesonRotated2.getOpeningAngle() > mMinOpenAngleCut) {
465+
mHistManager.fill(HIST("invMassVsPtBackground"), mesonRotated2.getMass(), mesonRotated2.getPt());
466+
}
467+
}
468+
}
469+
470+
void CalculateMixedBack(Photon gamma)
471+
{
472+
for (unsigned int i = 0; i < evtMix.vecEvtMix.size(); ++i) {
473+
for (unsigned int ig1 = 0; ig1 < evtMix.vecEvtMix[i].size(); ++ig1) {
474+
Meson meson(gamma, evtMix.vecEvtMix[i][ig1]);
475+
if (meson.getOpeningAngle() > mMinOpenAngleCut) {
476+
mHistManager.fill(HIST("invMassVsPtMixedBackground"), meson.getMass(), meson.getPt());
477+
}
478+
}
352479
}
353480
}
354481

0 commit comments

Comments
 (0)