Skip to content

Commit ac385ce

Browse files
committed
EventFiltering/PWGEM: add software trigger for photons
1 parent 2e1b15a commit ac385ce

File tree

9 files changed

+467
-166
lines changed

9 files changed

+467
-166
lines changed

EventFiltering/CMakeLists.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,14 @@ o2physics_add_dpl_workflow(mult-filter
8282
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
8383
COMPONENT_NAME Analysis)
8484

85-
o2physics_add_dpl_workflow(em-filter
86-
SOURCES PWGEM/photonFilter.cxx
87-
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase
85+
o2physics_add_dpl_workflow(em-photon-filter
86+
SOURCES PWGEM/EMPhotonFilter.cxx
87+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGEMPhotonMesonCore
88+
COMPONENT_NAME Analysis)
89+
90+
o2physics_add_dpl_workflow(em-photon-filter-qc
91+
SOURCES PWGEM/EMPhotonFilterQC.cxx
92+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DetectorsBase O2Physics::PWGEMPhotonMesonCore
8893
COMPONENT_NAME Analysis)
8994

9095
o2physics_add_dpl_workflow(lf-f1proton-filter
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
// \brief software trigger for EM photon
13+
// \author daiki.sekihata@cern.ch
14+
15+
#include "Math/Vector4D.h"
16+
#include "Framework/runDataProcessing.h"
17+
#include "Framework/AnalysisTask.h"
18+
#include "Framework/AnalysisDataModel.h"
19+
#include "Framework/ASoAHelpers.h"
20+
#include "Common/DataModel/CaloClusters.h"
21+
#include "DataFormatsPHOS/TriggerRecord.h"
22+
#include "PWGEM/PhotonMeson/DataModel/gammaTables.h"
23+
#include "PWGEM/PhotonMeson/Core/V0PhotonCut.h"
24+
#include "PWGEM/PhotonMeson/Core/CutsLibrary.h"
25+
#include "EventFiltering/filterTables.h"
26+
#include "Framework/HistogramRegistry.h"
27+
28+
using namespace o2;
29+
using namespace o2::soa;
30+
using namespace o2::aod;
31+
using namespace o2::framework;
32+
using namespace o2::framework::expressions;
33+
34+
using MyCollisions = soa::Join<aod::Collisions, aod::EvSels>;
35+
using MyCollision = MyCollisions::iterator;
36+
37+
using MyPrimaryElectrons = soa::Join<aod::EMPrimaryElectrons, aod::EMPrimaryElectronsPrefilterBit>;
38+
using MyPrimaryElectron = MyPrimaryElectrons::iterator;
39+
40+
struct EMPhotonFilter {
41+
42+
enum EM_Filter_PhotonType {
43+
kPCM = 0x1,
44+
kPHOS = 0x2,
45+
kEMC = 0x4,
46+
};
47+
48+
enum trigs {
49+
kPHOS_Photon = 0,
50+
kPHOS_El = 1,
51+
kPHOS_Pair = 2,
52+
kPHOS_Nbar = 3,
53+
kPCM_MatCalib = 4,
54+
kPCM_EtaDalitz = 5,
55+
kNtrg
56+
};
57+
58+
Produces<aod::PhotonFilters> tags;
59+
60+
Configurable<float> ePhot{"ePhot", 2.2, "Minimal photon energy (GeV)"};
61+
Configurable<float> eEl{"eEl", 1., "Minimal electron energy (GeV)"};
62+
Configurable<float> ePair{"ePair", 0.35, "Minimal photon pair mass (GeV)"};
63+
Configurable<int> nNbar{"nNbar", 2, "Minimal number of nbar clusters"};
64+
65+
// for PCM
66+
Configurable<float> min_pt_tagging{"min_pt_tagging", 0.f, "max. pT for tagging"};
67+
Configurable<float> max_mee_pi0_dalitz{"max_mee_pi0_dalitz", 0.12, "max. mee for pi0 dalitz decay"};
68+
Configurable<float> min_meeg_pi0{"min_meeg_pi0", 0.04, "min. meeg for pi0"};
69+
Configurable<float> max_meeg_pi0{"max_meeg_pi0", 0.24, "max. meeg for pi0"};
70+
Configurable<float> max_mee_eta_dalitz{"max_mee_eta_dalitz", 0.5, "max. mee for eta dalitz decay"};
71+
Configurable<float> min_meeg_eta{"min_meeg_eta", 0.35, "min. meeg for eta"};
72+
Configurable<float> max_meeg_eta{"max_meeg_eta", 0.75, "max. meeg for eta"};
73+
Configurable<float> slope{"slope", 0.0185, "slope for m vs. phiv"};
74+
Configurable<float> intercept{"intercept", -0.0280, "intercept for m vs. phiv"};
75+
76+
HistogramRegistry mHistManager{"events", {}, OutputObjHandlingPolicy::AnalysisObject, true, true};
77+
78+
void init(o2::framework::InitContext&)
79+
{
80+
auto scalers{std::get<std::shared_ptr<TH1>>(mHistManager.add("hEventCounter", "Number of filtered events", HistType::kTH1F, {{20, 0.5, 20.5}}))};
81+
scalers->GetXaxis()->SetBinLabel(1, "all events");
82+
scalers->GetXaxis()->SetBinLabel(2, "sel8");
83+
scalers->GetXaxis()->SetBinLabel(3, "|Z_{vtx}| < 10 cm");
84+
scalers->GetXaxis()->SetBinLabel(4, "sel8 && |Z_{vtx}| < 10 cm");
85+
scalers->GetXaxis()->SetBinLabel(5, "PHOS photon");
86+
scalers->GetXaxis()->SetBinLabel(6, "PHOS electron");
87+
scalers->GetXaxis()->SetBinLabel(7, "PHOS pair");
88+
scalers->GetXaxis()->SetBinLabel(8, "PHOS nbar");
89+
scalers->GetXaxis()->SetBinLabel(9, "PHOS photon & electron");
90+
scalers->GetXaxis()->SetBinLabel(10, "PHOS photon & pair");
91+
scalers->GetXaxis()->SetBinLabel(11, "events with PHOS");
92+
scalers->GetXaxis()->SetBinLabel(12, "PCM Material budget calibration");
93+
scalers->GetXaxis()->SetBinLabel(13, "PCM #eta #rightarrow ee#gamma");
94+
}
95+
96+
Preslice<aod::V0PhotonsKF> perCollision_pcm = aod::v0photonkf::collisionId;
97+
Preslice<aod::DalitzEEs> perCollision_ee = aod::dalitzee::collisionId;
98+
Preslice<aod::CaloClusters> perCollision_phos = aod::calocluster::collisionId;
99+
Preslice<aod::SkimEMCClusters> perCollision_emc = aod::skimmedcluster::collisionId;
100+
101+
template <uint8_t system, typename TCollisions, typename TPhotons1, typename TPhotons2, typename TPhotons3, typename TV0Legs, typename TDielectrons, typename TEMPrimaryElectrons>
102+
void runFilter(TCollisions const& collisions, TPhotons1 const& photons1, TPhotons2 const& photons2, TPhotons3 const& photons3, TV0Legs const&, TDielectrons const& dielectrons, TEMPrimaryElectrons const& emprimaryelectrons)
103+
{
104+
for (auto& collision : collisions) {
105+
mHistManager.fill(HIST("hEventCounter"), 1.);
106+
bool keepEvent[kNtrg]{false};
107+
108+
if (collision.sel8()) {
109+
mHistManager.fill(HIST("hEventCounter"), 2.);
110+
}
111+
if (abs(collision.posZ()) < 10.f) {
112+
mHistManager.fill(HIST("hEventCounter"), 3.);
113+
}
114+
if (collision.sel8() && abs(collision.posZ()) < 10.f) {
115+
mHistManager.fill(HIST("hEventCounter"), 4.);
116+
}
117+
118+
if constexpr (static_cast<bool>(system & EM_Filter_PhotonType::kPCM)) {
119+
auto photons1_per_coll = photons1.sliceBy(perCollision_pcm, collision.globalIndex());
120+
auto dielectrons_per_coll = dielectrons.sliceBy(perCollision_ee, collision.globalIndex());
121+
122+
for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_coll, dielectrons_per_coll))) {
123+
if (g2.pt() < min_pt_tagging) { // this is only to increase rejection factor
124+
continue;
125+
}
126+
if (g2.mass() > max_mee_pi0_dalitz) { // select only pi0 candidates
127+
continue;
128+
}
129+
if (g2.mass() < slope * g2.phiv() + intercept) {
130+
continue;
131+
}
132+
ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.);
133+
ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), g2.mass());
134+
ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
135+
136+
if (min_meeg_pi0 < v12.M() && v12.M() < max_meeg_pi0) {
137+
keepEvent[kPCM_MatCalib] = true;
138+
mHistManager.fill(HIST("hEventCounter"), 12);
139+
break;
140+
}
141+
142+
} // end of dielectron-photon pair loop
143+
144+
for (auto& [g1, g2] : combinations(CombinationsFullIndexPolicy(photons1_per_coll, dielectrons_per_coll))) {
145+
if (g2.mass() > max_mee_eta_dalitz) { // select only eta candidates
146+
continue;
147+
}
148+
if (g2.mass() < slope * g2.phiv() + intercept) {
149+
continue;
150+
}
151+
152+
ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.);
153+
ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), g2.mass());
154+
ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
155+
156+
if (min_meeg_eta < v12.M() && v12.M() < max_meeg_eta) { // eta -> eeg
157+
keepEvent[kPCM_EtaDalitz] = true;
158+
mHistManager.fill(HIST("hEventCounter"), 13);
159+
break;
160+
}
161+
} // end of dielectron-photon pair loop
162+
163+
} // end of PCM decision
164+
165+
if constexpr (static_cast<bool>(system & EM_Filter_PhotonType::kPHOS)) {
166+
int nPHOSclu = 0;
167+
int nPHOSnbar = 0;
168+
auto photons2_coll = photons2.sliceBy(perCollision_phos, collision.globalIndex());
169+
for (const auto& clu : photons2_coll) {
170+
nPHOSclu++;
171+
172+
// Scan current cluster
173+
// photons
174+
keepEvent[kPHOS_Photon] |= (clu.e() > ePhot);
175+
// charged clusters above threshold
176+
keepEvent[kPHOS_El] |= (clu.trackdist() < 2. && clu.e() > eEl); // 2: Distance to CPV cluster in sigmas
177+
// antineutrons
178+
if ((clu.ncell() > 2 && clu.m02() > 0.2 && clu.e() > 0.7 && clu.trackdist() > 2.) &&
179+
((clu.e() < 2. && clu.m02() > 4.5 - clu.m20()) ||
180+
(clu.e() > 2. && clu.m02() > 4. - clu.m20()))) {
181+
nPHOSnbar++;
182+
}
183+
184+
// inv mass
185+
if (clu.trackdist() < 1.) {
186+
auto clu2 = clu;
187+
++clu2;
188+
for (; !keepEvent[kPHOS_Pair] && clu2 != photons2.end(); clu2++) {
189+
// cluster selections
190+
if (clu2.trackdist() < 1.) { // select neutral clusters. Disp, Ncell cuts?
191+
continue;
192+
}
193+
double m = pow(clu.e() + clu2.e(), 2) - pow(clu.px() + clu2.px(), 2) -
194+
pow(clu.py() + clu2.py(), 2) - pow(clu.pz() + clu2.pz(), 2);
195+
if (m > ePair * ePair) {
196+
keepEvent[kPHOS_Pair] |= true;
197+
break;
198+
}
199+
}
200+
}
201+
} // end of cluster loop
202+
keepEvent[kPHOS_Nbar] = (nPHOSnbar >= nNbar);
203+
204+
// Collision processed, fill scalers here
205+
if (nPHOSclu) {
206+
mHistManager.fill(HIST("hEventCounter"), 11.);
207+
}
208+
// Can not fill with variable, have to fill manually
209+
if (keepEvent[kPHOS_Photon]) {
210+
mHistManager.fill(HIST("hEventCounter"), 5.);
211+
if (keepEvent[kPHOS_El]) {
212+
mHistManager.fill(HIST("hEventCounter"), 9.);
213+
}
214+
if (keepEvent[kPHOS_Pair]) {
215+
mHistManager.fill(HIST("hEventCounter"), 10.);
216+
}
217+
}
218+
if (keepEvent[kPHOS_El]) {
219+
mHistManager.fill(HIST("hEventCounter"), 6.);
220+
}
221+
if (keepEvent[kPHOS_Pair]) {
222+
mHistManager.fill(HIST("hEventCounter"), 7.);
223+
}
224+
if (keepEvent[kPHOS_Nbar]) {
225+
mHistManager.fill(HIST("hEventCounter"), 8.);
226+
}
227+
}
228+
229+
// EMC decision
230+
if constexpr (static_cast<bool>(system & EM_Filter_PhotonType::kEMC)) {
231+
// so far, do nothing.
232+
}
233+
tags(keepEvent[kPHOS_Photon], keepEvent[kPHOS_El], keepEvent[kPHOS_Pair], keepEvent[kPHOS_Nbar], keepEvent[kPCM_MatCalib], keepEvent[kPCM_EtaDalitz]);
234+
} // end of collision loop
235+
}
236+
237+
void process_PCM(MyCollisions const& collisions, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::DalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons)
238+
{
239+
const uint8_t system = EM_Filter_PhotonType::kPCM;
240+
runFilter<system>(collisions, v0photons, nullptr, nullptr, v0legs, dielectrons, emprimaryelectrons);
241+
}
242+
243+
Filter phosCluFilter = (o2::aod::calocluster::e > 0.3f);
244+
using CluCandidates = o2::soa::Filtered<o2::aod::CaloClusters>;
245+
void process_PHOS(MyCollisions const& collisions, CluCandidates const& clusters)
246+
{
247+
const uint8_t system = EM_Filter_PhotonType::kPHOS;
248+
runFilter<system>(collisions, nullptr, clusters, nullptr, nullptr, nullptr, nullptr);
249+
}
250+
251+
void process_EMC(MyCollisions const& collisions, aod::SkimEMCClusters const& clusters)
252+
{
253+
const uint8_t system = EM_Filter_PhotonType::kEMC;
254+
runFilter<system>(collisions, nullptr, nullptr, clusters, nullptr, nullptr, nullptr);
255+
}
256+
257+
void process_PCM_PHOS(MyCollisions const& collisions, aod::V0PhotonsKF const& v0photons, aod::V0Legs const& v0legs, aod::DalitzEEs const& dielectrons, MyPrimaryElectrons const& emprimaryelectrons, CluCandidates const& clusters)
258+
{
259+
const uint8_t system = EM_Filter_PhotonType::kPCM | EM_Filter_PhotonType::kPHOS;
260+
runFilter<system>(collisions, v0photons, clusters, nullptr, v0legs, dielectrons, emprimaryelectrons);
261+
}
262+
263+
void processDummy(MyCollisions const& collisions)
264+
{
265+
for (int i = 0; i < collisions.size(); i++) {
266+
tags(false, false, false, false, false, false);
267+
}
268+
}
269+
270+
PROCESS_SWITCH(EMPhotonFilter, process_PCM, "Process PCM software trigger decision", false);
271+
PROCESS_SWITCH(EMPhotonFilter, process_PHOS, "Process PHOS software trigger decision", false);
272+
PROCESS_SWITCH(EMPhotonFilter, process_EMC, "Process EMC software trigger decision", false);
273+
PROCESS_SWITCH(EMPhotonFilter, process_PCM_PHOS, "Process PCM and PHOS software trigger decision", false);
274+
PROCESS_SWITCH(EMPhotonFilter, processDummy, "Process dummy", true);
275+
};
276+
277+
WorkflowSpec defineDataProcessing(ConfigContext const& cfg)
278+
{
279+
return WorkflowSpec{
280+
adaptAnalysisTask<EMPhotonFilter>(cfg, TaskName{"em-photon-filter"})};
281+
}

0 commit comments

Comments
 (0)