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+ // / \file zdc-task-intercalib.cxx
13+ // / \brief Task for ZDC tower inter-calibration
14+ // / \author chiara.oppedisano@cern.ch
15+
16+ // o2-linter: disable=name/workflow-file
17+ // o2-linter: disable=name/file-cpp
18+ #include " Framework/AnalysisTask.h"
19+ #include " Framework/AnalysisDataModel.h"
20+ #include " Framework/HistogramRegistry.h"
21+ #include " Framework/runDataProcessing.h"
22+ #include " Common/DataModel/EventSelection.h"
23+ #include " Common/CCDB/EventSelectionParams.h"
24+ #include " Common/CCDB/TriggerAliases.h"
25+ #include " Common/DataModel/Centrality.h"
26+ #include " Common/DataModel/Multiplicity.h"
27+ #include " Common/DataModel/InterCalibrationZDC.h"
28+
29+ #include " TH1F.h"
30+ #include " TH2F.h"
31+
32+ using namespace o2 ;
33+ using namespace o2 ::framework;
34+ using namespace o2 ::framework::expressions;
35+ using namespace o2 ::aod::evsel;
36+
37+ using BCsRun3 = soa::Join<aod::BCs, aod::Timestamps, aod::BcSels, aod::Run3MatchedToBCSparse>;
38+ using ColEvSels = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Cs>;
39+
40+ struct InterCalibrationZDC {
41+
42+ Produces<aod::InterCalibrationZDC> zTab;
43+
44+ // Configurable parameters
45+ //
46+ Configurable<int > nBins{" nBins" , 400 , " n bins" };
47+ Configurable<float > maxZN{" maxZN" , 399.5 , " Max ZN signal" };
48+ Configurable<bool > tdcCut{" tdcCut" , false , " Flag for TDC cut" };
49+ Configurable<float > tdcZNmincut{" tdcZNmincut" , -2.5 , " Min ZN TDC cut" };
50+ Configurable<float > tdcZNmaxcut{" tdcZNmaxcut" , -2.5 , " Max ZN TDC cut" };
51+ // Event selections
52+ Configurable<bool > cfgEvSelSel8{" cfgEvSelSel8" , true , " Event selection: sel8" };
53+ Configurable<float > cfgEvSelVtxZ{" cfgEvSelVtxZ" , 10 , " Event selection: zVtx" };
54+ Configurable<bool > cfgEvSelsDoOccupancySel{" cfgEvSelsDoOccupancySel" , true , " Event selection: do occupancy selection" };
55+ Configurable<float > cfgEvSelsMaxOccupancy{" cfgEvSelsMaxOccupancy" , 10000 , " Event selection: set max occupancy" };
56+ Configurable<bool > cfgEvSelsNoSameBunchPileupCut{" cfgEvSelsNoSameBunchPileupCut" , true , " Event selection: no same bunch pileup cut" };
57+ Configurable<bool > cfgEvSelsIsGoodZvtxFT0vsPV{" cfgEvSelsIsGoodZvtxFT0vsPV" , true , " Event selection: is good ZVTX FT0 vs PV" };
58+ Configurable<bool > cfgEvSelsNoCollInTimeRangeStandard{" cfgEvSelsNoCollInTimeRangeStandard" , true , " Event selection: no collision in time range standard" };
59+ Configurable<bool > cfgEvSelsIsVertexITSTPC{" cfgEvSelsIsVertexITSTPC" , true , " Event selection: is vertex ITSTPC" };
60+ Configurable<bool > cfgEvSelsIsGoodITSLayersAll{" cfgEvSelsIsGoodITSLayersAll" , true , " Event selection: is good ITS layers all" };
61+ //
62+ HistogramRegistry registry{" Histos" , {}, OutputObjHandlingPolicy::AnalysisObject};
63+
64+ enum SelectionCriteria {
65+ evSel_zvtx,
66+ evSel_sel8,
67+ evSel_occupancy,
68+ evSel_kNoSameBunchPileup,
69+ evSel_kIsGoodZvtxFT0vsPV,
70+ evSel_kNoCollInTimeRangeStandard,
71+ evSel_kIsVertexITSTPC,
72+ evSel_kIsGoodITSLayersAll,
73+ evSel_allEvents,
74+ nEventSelections
75+ };
76+
77+ void init (InitContext const &)
78+ {
79+ registry.add (" ZNApmc" , " ZNApmc; ZNA PMC; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
80+ registry.add (" ZNCpmc" , " ZNCpmc; ZNC PMC; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
81+ registry.add (" ZNApm1" , " ZNApm1; ZNA PM1; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
82+ registry.add (" ZNApm2" , " ZNApm2; ZNA PM2; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
83+ registry.add (" ZNApm3" , " ZNApm3; ZNA PM3; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
84+ registry.add (" ZNApm4" , " ZNApm4; ZNA PM4; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
85+ registry.add (" ZNCpm1" , " ZNCpm1; ZNC PM1; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
86+ registry.add (" ZNCpm2" , " ZNCpm2; ZNC PM2; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
87+ registry.add (" ZNCpm3" , " ZNCpm3; ZNC PM3; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
88+ registry.add (" ZNCpm4" , " ZNCpm4; ZNC PM4; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
89+ registry.add (" ZNAsumq" , " ZNAsumq; ZNA uncalib. sum PMQ; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
90+ registry.add (" ZNCsumq" , " ZNCsumq; ZNC uncalib. sum PMQ; Entries" , {HistType::kTH1F , {{nBins, -0.5 , maxZN}}});
91+
92+ registry.add (" hEventCount" , " Number of Event; Cut; #Events Passed Cut" , {HistType::kTH1D , {{nEventSelections, 0 , nEventSelections}}});
93+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_allEvents + 1 , " All events" );
94+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_zvtx + 1 , " vtxZ" );
95+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_sel8 + 1 , " Sel8" );
96+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_occupancy + 1 , " kOccupancy" );
97+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_kNoSameBunchPileup + 1 , " kNoSameBunchPileup" );
98+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_kIsGoodZvtxFT0vsPV + 1 , " kIsGoodZvtxFT0vsPV" );
99+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_kNoCollInTimeRangeStandard + 1 , " kNoCollInTimeRangeStandard" );
100+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_kIsVertexITSTPC + 1 , " kIsVertexITSTPC" );
101+ registry.get <TH1 >(HIST (" hEventCount" ))->GetXaxis ()->SetBinLabel (evSel_kIsGoodITSLayersAll + 1 , " kkIsGoodITSLayersAll" );
102+ }
103+
104+
105+ template <typename TCollision>
106+ uint8_t eventSelected (TCollision collision)
107+ {
108+ uint8_t selectionBits = 0 ;
109+ bool selected;
110+
111+ registry.fill (HIST (" hEventCount" ), evSel_allEvents);
112+
113+ selected = std::fabs (collision.posZ ()) < cfgEvSelVtxZ;
114+ if (selected){
115+ selectionBits |= (uint8_t )(0x1u << evSel_zvtx);
116+ registry.fill (HIST (" hEventCount" ), evSel_zvtx);
117+ }
118+
119+ selected = collision.sel8 ();
120+ if (selected) {
121+ selectionBits |= (uint8_t )(0x1u << evSel_sel8);
122+ registry.fill (HIST (" hEventCount" ), evSel_sel8);
123+ }
124+
125+ auto occupancy = collision.trackOccupancyInTimeRange ();
126+ selected = occupancy <= cfgEvSelsMaxOccupancy;
127+ if (selected) {
128+ selectionBits |= (uint8_t )(0x1u << evSel_occupancy);
129+ registry.fill (HIST (" hEventCount" ), evSel_occupancy);
130+ }
131+
132+ selected = collision.selection_bit (o2::aod::evsel::kNoSameBunchPileup );
133+ if (selected) {
134+ selectionBits |= (uint8_t )(0x1u << evSel_kNoSameBunchPileup);
135+ registry.fill (HIST (" hEventCount" ), evSel_kNoSameBunchPileup);
136+ }
137+
138+ selected = collision.selection_bit (o2::aod::evsel::kIsGoodZvtxFT0vsPV );
139+ if (selected) {
140+ selectionBits |= (uint8_t )(0x1u << evSel_kIsGoodZvtxFT0vsPV);
141+ registry.fill (HIST (" hEventCount" ), evSel_kIsGoodZvtxFT0vsPV);
142+ }
143+
144+ selected = collision.selection_bit (o2::aod::evsel::kNoCollInTimeRangeStandard );
145+ if (selected) {
146+ selectionBits |= (uint8_t )(0x1u << evSel_kNoCollInTimeRangeStandard);
147+ registry.fill (HIST (" hEventCount" ), evSel_kNoCollInTimeRangeStandard);
148+ }
149+
150+ selected = collision.selection_bit (o2::aod::evsel::kIsVertexITSTPC );
151+ if (selected) {
152+ selectionBits |= (uint8_t )(0x1u << evSel_kIsVertexITSTPC);
153+ registry.fill (HIST (" hEventCount" ), evSel_kIsVertexITSTPC);
154+ }
155+
156+ selected = collision.selection_bit (o2::aod::evsel::kIsGoodITSLayersAll );
157+ if (selected) {
158+ selectionBits |= (uint8_t )(0x1u << evSel_kIsGoodITSLayersAll);
159+ registry.fill (HIST (" hEventCount" ), evSel_kIsGoodITSLayersAll);
160+ }
161+
162+ return selectionBits;
163+ }
164+
165+ void process (ColEvSels const & cols, BCsRun3 const & /* bcs*/ , aod::Zdcs const & /* zdcs*/ )
166+ {
167+ // collision-based event selection
168+ int nTowers = 4 ; // number of ZDC towers
169+
170+ for (auto const & collision : cols) {
171+ const auto & foundBC = collision.foundBC_as <BCsRun3>();
172+ if (foundBC.has_zdc ()) {
173+ const auto & zdc = foundBC.zdc ();
174+
175+ uint8_t evSelection = eventSelected (collision);
176+
177+ float centrality = collision.centFT0C ();
178+
179+ // To assure that ZN have a genuine signal (tagged by the relative TDC)
180+ // we can check that the amplitude is >0 or that ADC is NOT very negative (-inf)
181+
182+ double pmcZNC = zdc.energyCommonZNC ();
183+ double pmcZNA = zdc.energyCommonZNA ();
184+ bool isZNChit = false , isZNAhit = false ;
185+ //
186+ double tdcZNC = zdc.timeZNC ();
187+ double tdcZNA = zdc.timeZNA ();
188+ // OR we can select a narrow window in both ZN TDCs using the configurable parameters
189+ if (tdcCut) { // a narrow TDC window is set
190+ if ((tdcZNC >= tdcZNmincut) && (tdcZNC <= tdcZNmaxcut)) {
191+ isZNChit = true ;
192+ }
193+ if ((tdcZNA >= tdcZNmincut) && (tdcZNA <= tdcZNmaxcut)) {
194+ isZNAhit = true ;
195+ }
196+ } else { // if no window on TDC is set
197+ if (pmcZNC > -1 .) {
198+ isZNChit = true ;
199+ }
200+ if (pmcZNA > -1 .) {
201+ isZNAhit = true ;
202+ }
203+ }
204+ //
205+ double sumZNC = 0 ;
206+ double sumZNA = 0 ;
207+ double pmqZNC[4 ] = {
208+ 0 ,
209+ 0 ,
210+ 0 ,
211+ 0 ,
212+ };
213+ double pmqZNA[4 ] = {
214+ 0 ,
215+ 0 ,
216+ 0 ,
217+ 0 ,
218+ };
219+ //
220+ if (isZNChit) {
221+ for (int it = 0 ; it < nTowers; it++) {
222+ pmqZNC[it] = (zdc.energySectorZNC ())[it];
223+ sumZNC += pmqZNC[it];
224+ }
225+ registry.get <TH1 >(HIST (" ZNCpmc" ))->Fill (pmcZNC);
226+ registry.get <TH1 >(HIST (" ZNCpm1" ))->Fill (pmqZNC[0 ]);
227+ registry.get <TH1 >(HIST (" ZNCpm2" ))->Fill (pmqZNC[1 ]);
228+ registry.get <TH1 >(HIST (" ZNCpm3" ))->Fill (pmqZNC[2 ]);
229+ registry.get <TH1 >(HIST (" ZNCpm4" ))->Fill (pmqZNC[3 ]);
230+ registry.get <TH1 >(HIST (" ZNCsumq" ))->Fill (sumZNC);
231+ }
232+ if (isZNAhit) {
233+ for (int it = 0 ; it < nTowers; it++) {
234+ pmqZNA[it] = (zdc.energySectorZNA ())[it];
235+ sumZNA += pmqZNA[it];
236+ }
237+ //
238+ registry.get <TH1 >(HIST (" ZNApmc" ))->Fill (pmcZNA);
239+ registry.get <TH1 >(HIST (" ZNApm1" ))->Fill (pmqZNA[0 ]);
240+ registry.get <TH1 >(HIST (" ZNApm2" ))->Fill (pmqZNA[1 ]);
241+ registry.get <TH1 >(HIST (" ZNApm3" ))->Fill (pmqZNA[2 ]);
242+ registry.get <TH1 >(HIST (" ZNApm4" ))->Fill (pmqZNA[3 ]);
243+ registry.get <TH1 >(HIST (" ZNAsumq" ))->Fill (sumZNA);
244+ }
245+ if (isZNAhit || isZNChit)
246+ zTab (pmcZNA, pmqZNA[0 ], pmqZNA[1 ], pmqZNA[2 ], pmqZNA[3 ], tdcZNC, pmcZNC, pmqZNC[0 ], pmqZNC[1 ], pmqZNC[2 ], pmqZNC[3 ], tdcZNA, centrality, foundBC.timestamp (), evSelection);
247+ }
248+ }
249+ }
250+ };
251+
252+ WorkflowSpec defineDataProcessing (ConfigContext const & cfgc) // o2-linter: disable=name/file-cpp
253+ {
254+ return WorkflowSpec{
255+ adaptAnalysisTask<InterCalibrationZDC>(cfgc)};
256+ }
0 commit comments