Skip to content

Commit 5b251ac

Browse files
committed
Add task for the lumi stability studies for high energy pp
1 parent 0391f17 commit 5b251ac

File tree

2 files changed

+335
-1
lines changed

2 files changed

+335
-1
lines changed

PWGMM/Lumi/Tasks/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,9 @@ o2physics_add_dpl_workflow(lumistab
4444
o2physics_add_dpl_workflow(lumi-stability-light-ions
4545
SOURCES lumiStabilityLightIons.cxx
4646
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore
47-
COMPONENT_NAME Analysis)
47+
COMPONENT_NAME Analysis)
48+
49+
o2physics_add_dpl_workflow(lumi-stability-light-p-p
50+
SOURCES lumiStabilityPP.cxx
51+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore
52+
COMPONENT_NAME Analysis)
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
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 lumiStabilityPP.cxx
13+
/// \brief Analysis over BCs to study the luminosity stability along time for pp collisions
14+
///
15+
/// \author Fabrizio Grosa (fabrizio.grosa@cern.ch), CERN
16+
17+
#include "Common/CCDB/ctpRateFetcher.h"
18+
#include "Common/Core/MetadataHelper.h"
19+
#include "Common/DataModel/Centrality.h"
20+
#include "Common/DataModel/EventSelection.h"
21+
22+
#include "CCDB/BasicCCDBManager.h"
23+
#include "DataFormatsParameters/AggregatedRunInfo.h"
24+
#include "DataFormatsParameters/GRPLHCIFData.h"
25+
#include "Framework/ASoA.h"
26+
#include "Framework/AnalysisDataModel.h"
27+
#include "Framework/AnalysisTask.h"
28+
#include "Framework/runDataProcessing.h"
29+
30+
#include <limits>
31+
#include <map>
32+
#include <string>
33+
#include <vector>
34+
35+
o2::common::core::MetadataHelper metadataInfo; // Metadata helper
36+
37+
namespace o2
38+
{
39+
namespace lumi
40+
{
41+
enum TriggerAliases { AllBCs = 0,
42+
FT0Vtx = 1,
43+
FT0CE = 2,
44+
FDD = 3,
45+
NTriggerAliases };
46+
enum BCCategories { BCA = 0, // A side BCs (bunch-crossings that had beam only from A side)
47+
BCB = 1, // B type BCs (bunch-crossings that had beam from both sides)
48+
BCC = 2, // C side BCs (bunch-crossings that had beam only from C side)
49+
BCE = 3, // empty BCs (bunch-crossings that did not have beam from either side)
50+
BCL = 4, // leading BCs (bunch-crossings that did not have interacting bunches for a configurable number of preceding BCs)
51+
BCSL = 5, // super-leading BCs (bunch-crossings that did not have FDD/FT0 activity for a configurable number of preceding BCs)
52+
NBCCategories };
53+
} // namespace lumi
54+
} // namespace o2
55+
56+
using namespace o2;
57+
using namespace o2::framework;
58+
using namespace o2::framework::expressions;
59+
using namespace o2::lumi;
60+
61+
using BCsWithTimeStampsAndSels = soa::Join<aod::BCs, aod::BcSels, aod::Timestamps, aod::Run3MatchedToBCSparse>;
62+
63+
struct LumiStabilityPP {
64+
65+
Configurable<bool> doBCA{"doBCA", false, "Create and fill histograms for the BCs of type A"};
66+
Configurable<bool> doBCB{"doBCB", true, "Create and fill histograms for the BCs of type B"};
67+
Configurable<bool> doBCC{"doBCC", false, "Create and fill histograms for the BCs of type C"};
68+
Configurable<bool> doBCE{"doBCE", false, "Create and fill histograms for the BCs of type E"};
69+
Configurable<bool> doBCL{"doBCL", false, "Create and fill histograms for leading BCs of type B"};
70+
Configurable<bool> doBCSL{"doBCSL", false, "Create and fill histograms for super-leading BCs (no preceding FT0/FDD activity) of type B"};
71+
Configurable<int> numEmptyBCsBeforeLeadingBC{"numEmptyBCsBeforeLeadingBC", 5, "Number of empty BCs before a leading BC"};
72+
Configurable<bool> requireNoT0ForSLBC{"requireNoT0ForSLBC", false, "Require no T0 signal for definition of super leading BC (otherwise only no FDD)"};
73+
74+
std::bitset<o2::constants::lhc::LHCMaxBunches> beamPatternA, beamPatternC;
75+
std::bitset<o2::constants::lhc::LHCMaxBunches> bcPatternA, bcPatternC, bcPatternB, bcPatternE, bcPatternL;
76+
const int nBCsPerOrbit = o2::constants::lhc::LHCMaxBunches;
77+
78+
parameters::GRPLHCIFData* mLHCIFdata = nullptr;
79+
int runNumber{-1};
80+
ctpRateFetcher mRateFetcher;
81+
82+
HistogramRegistry registry{"registry"};
83+
84+
std::array<std::array<std::map<int, std::shared_ptr<TH1>>, NBCCategories>, NTriggerAliases> histBcVsTime;
85+
std::array<std::array<std::map<int, std::shared_ptr<TH1>>, NBCCategories>, NTriggerAliases> histBcVsBcId;
86+
std::map<int, std::shared_ptr<TH1>> histNBcsVsTime;
87+
std::map<int, std::shared_ptr<TH1>> histNBcsVsBcId;
88+
std::map<int, std::shared_ptr<TH1>> histTfPerMin;
89+
std::map<int, std::shared_ptr<TH1>> histBcHasFT0;
90+
std::map<int, std::shared_ptr<TH1>> histBcHasFDD;
91+
92+
static constexpr std::string_view NBCsVsTimeHistNames[NTriggerAliases][NBCCategories] =
93+
{{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime", "AllBCs/BC_SL/nBCsVsTime"},
94+
{"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime", "FT0VTx/BC_SL/nBCsVsTime"},
95+
{"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime", "FT0CE/BC_SL/nBCsVsTime"},
96+
{"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime", "FDD/BC_SL/nBCsVsTime"}};
97+
98+
static constexpr std::string_view NBCsVsBCIDHistNames[NTriggerAliases][NBCCategories] =
99+
{{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID", "AllBCs/BC_SL/nBCsVsBCID"},
100+
{"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID", "FT0VTx/BC_SL/nBCsVsBCID"},
101+
{"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID", "FT0CE/BC_SL/nBCsVsBCID"},
102+
{"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID", "FDD/BC_SL/nBCsVsBCID"}};
103+
104+
const AxisSpec timeAxis{1440, 0., 1440., "#bf{t-t_{SOF} (min)}"}, bcIDAxis{3600, 0., 3600., "#bf{BC ID in orbit}"};
105+
106+
int64_t bcSOR;
107+
int nBCsPerTF;
108+
int64_t currentTFid = -1;
109+
110+
void init(InitContext&) {}
111+
112+
void createHistograms()
113+
{
114+
if (histNBcsVsTime[runNumber]) { // histograms for this run already there
115+
return;
116+
}
117+
118+
histNBcsVsTime[runNumber] = registry.add<TH1>(Form("%d/FT0Vtx_EvSel/nBCsVsTime", runNumber), "Time of TVX triggered BCs since the start of fill;;#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis});
119+
histNBcsVsBcId[runNumber] = registry.add<TH1>(Form("%d/nBCsVsBCID", runNumber), "Time of TVX triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis});
120+
histTfPerMin[runNumber] = registry.add<TH1>(Form("%d/TFsPerMinute", runNumber), "TFs seen in this minute (to account for failed jobs);#bf{t-t_{SOF} (min)};#bf{#it{N}_{TFs}}", HistType::kTH1D, {timeAxis});
121+
122+
histBcHasFT0[runNumber] = registry.add<TH2>(Form("%d/FITQA/BCHasFT0", runNumber), "Does the BC have FT0?;BC has FT0;TVX triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}});
123+
histBcHasFT0[runNumber]->GetYaxis()->SetBinLabel(1, "No CTP trigger");
124+
histBcHasFT0[runNumber]->GetYaxis()->SetBinLabel(2, "CTP triggered");
125+
histBcHasFT0[runNumber]->GetXaxis()->SetBinLabel(1, "No found FT0");
126+
histBcHasFT0[runNumber]->GetXaxis()->SetBinLabel(2, "Found FT0");
127+
histBcHasFDD[runNumber] = registry.add<TH2>(Form("%d/FITQA/BCHasFDD", runNumber), "Does the BC have FDD?;BC has FDD;FDD triggered according to CTP;#bf{#it{N}_{BC}}", HistType::kTH2D, {{2, -0.5, 1.5}, {2, -0.5, 1.5}});
128+
histBcHasFDD[runNumber]->GetYaxis()->SetBinLabel(1, "No CTP trigger");
129+
histBcHasFDD[runNumber]->GetYaxis()->SetBinLabel(2, "CTP triggered");
130+
histBcHasFDD[runNumber]->GetXaxis()->SetBinLabel(1, "No found FDD");
131+
histBcHasFDD[runNumber]->GetXaxis()->SetBinLabel(2, "Found FDD");
132+
133+
for (int iTrigger{0}; iTrigger < NTriggerAliases; ++iTrigger) {
134+
for (int iBCCategory{0}; iBCCategory < NBCCategories; ++iBCCategory) { // Don't do SL BCs here
135+
if ((iBCCategory == BCA && doBCA) || (iBCCategory == BCB && doBCB) || (iBCCategory == BCC && doBCC) || (iBCCategory == BCE && doBCE) || (iBCCategory == BCL && doBCL) || (iBCCategory == BCSL && doBCSL)) {
136+
histBcVsTime[iTrigger][iBCCategory][runNumber] = registry.add<TH1>(Form("%d/%s", runNumber, std::string(NBCsVsTimeHistNames[iTrigger][iBCCategory]).c_str()), "Time of triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1D, {timeAxis});
137+
histBcVsBcId[iTrigger][iBCCategory][runNumber] = registry.add<TH1>(Form("%d/%s", runNumber, std::string(NBCsVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1D, {bcIDAxis});
138+
}
139+
}
140+
}
141+
}
142+
143+
void setLHCIFData(const auto& bc)
144+
{
145+
if (runNumber == bc.runNumber()) {
146+
return;
147+
}
148+
149+
createHistograms();
150+
151+
auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance();
152+
uint64_t timeStamp = bc.timestamp();
153+
154+
std::map<std::string, std::string> metadata;
155+
mLHCIFdata = ccdbMgr.getSpecific<o2::parameters::GRPLHCIFData>("GLO/Config/GRPLHCIF", timeStamp, metadata);
156+
if (mLHCIFdata == nullptr) {
157+
LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp;
158+
}
159+
160+
runNumber = bc.runNumber();
161+
LOG(info) << "LHCIF data fetched for run " << runNumber << " and timestamp " << timeStamp;
162+
163+
beamPatternA = mLHCIFdata->getBunchFilling().getBeamPattern(0);
164+
beamPatternC = mLHCIFdata->getBunchFilling().getBeamPattern(1);
165+
bcPatternA = beamPatternA & ~beamPatternC;
166+
bcPatternC = ~beamPatternA & beamPatternC;
167+
bcPatternB = beamPatternA & beamPatternC;
168+
bcPatternE = ~beamPatternA & ~beamPatternC;
169+
170+
// Create bcPatternL: leading BCs of type B that follow at least "numEmptyBCsBeforeLeadingBC" empty BCs
171+
bcPatternL.reset(); // Initialize all bits to false
172+
LOG(info) << "Starting to create bcPatternL from bcPatternB";
173+
LOG(info) << "Total number of BCs to check: " << o2::constants::lhc::LHCMaxBunches;
174+
175+
int totalLeadingBCs = 0;
176+
for (int iBC = 0; iBC < o2::constants::lhc::LHCMaxBunches; iBC++) {
177+
if (bcPatternB[iBC]) { // Check if current BC is of type B
178+
int emptyBCsBefore = 0; // Count how many consecutive BCs before this one are NOT type B
179+
for (int j = 1; j <= numEmptyBCsBeforeLeadingBC; j++) {
180+
int prevBC = (iBC - j + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // Protection for BCs at small indices to check the end of the orbit
181+
if (!bcPatternB[prevBC]) {
182+
emptyBCsBefore++;
183+
} else {
184+
break; // Stop counting if we hit a type B BC
185+
}
186+
}
187+
if (emptyBCsBefore >= numEmptyBCsBeforeLeadingBC) { // If we found at least numEmptyBCsBeforeLeadingBC empty BCs before this one, mark it as leading
188+
bcPatternL[iBC] = true;
189+
totalLeadingBCs++;
190+
}
191+
}
192+
}
193+
LOG(info) << "bcPatternL creation complete. Total leading BCs found: " << totalLeadingBCs;
194+
195+
auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), runNumber, metadataInfo.get("LPMProductionTag"));
196+
bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // first bc of the first orbit
197+
LOG(info) << "BC SOR: " << bcSOR << " (orbit SOR: " << runInfo.orbitSOR << ") NBCs per orbit: " << nBCsPerOrbit;
198+
nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; // duration of TF in bcs
199+
200+
return;
201+
}
202+
203+
float getTimeSinceSOF(const auto& bc)
204+
{
205+
return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60; // Convert to minutes
206+
}
207+
208+
template <int iTrigger, int iBCCategory>
209+
void fillHistograms(float timeSinceSOF, int64_t localBC)
210+
{
211+
histBcVsTime[iTrigger][iBCCategory][runNumber]->Fill(timeSinceSOF);
212+
histBcVsBcId[iTrigger][iBCCategory][runNumber]->Fill(localBC);
213+
}
214+
215+
void process(BCsWithTimeStampsAndSels const& bcs, aod::FT0s const&)
216+
{
217+
int64_t globalBCIdOfLastBCWithActivity = 0;
218+
for (const auto& bc : bcs) {
219+
220+
if (bc.timestamp() == 0) {
221+
continue;
222+
}
223+
224+
setLHCIFData(bc);
225+
226+
float timeSinceSOF = getTimeSinceSOF(bc);
227+
228+
if (bc.selection_bit(aod::evsel::kIsTriggerTVX)) {
229+
histNBcsVsTime[runNumber]->Fill(timeSinceSOF);
230+
}
231+
232+
int64_t globalBC = bc.globalBC();
233+
int localBC = globalBC % nBCsPerOrbit;
234+
235+
bool isSuperLeadingBc{true};
236+
if (globalBC - globalBCIdOfLastBCWithActivity < numEmptyBCsBeforeLeadingBC) {
237+
isSuperLeadingBc = false; // not a super-leading BC
238+
}
239+
240+
if (bc.has_fdd() || (requireNoT0ForSLBC && bc.has_ft0())) {
241+
globalBCIdOfLastBCWithActivity = globalBC;
242+
}
243+
244+
if (!bcPatternB[localBC]) {
245+
isSuperLeadingBc = false; // not a super-leading BC
246+
}
247+
248+
int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF;
249+
250+
if (thisTFid != currentTFid) {
251+
currentTFid = thisTFid;
252+
histNBcsVsTime[runNumber]->Fill(timeSinceSOF);
253+
}
254+
255+
std::bitset<64> ctpInputMask(bc.inputMask());
256+
257+
histBcHasFT0[runNumber]->Fill(bc.has_ft0(), ctpInputMask.test(2));
258+
histBcHasFDD[runNumber]->Fill(bc.has_fdd(), ctpInputMask.test(15));
259+
260+
for (int iTrigger{0}; iTrigger < NTriggerAliases; ++iTrigger) {
261+
for (int iBCCategory{0}; iBCCategory < NBCCategories; ++iBCCategory) { // Don't do SL BCs here
262+
if ((iBCCategory == BCA && doBCA) || (iBCCategory == BCB && doBCB) || (iBCCategory == BCC && doBCC) || (iBCCategory == BCE && doBCE) || (iBCCategory == BCL && doBCL)) {
263+
if (iTrigger == AllBCs) {
264+
if (iBCCategory == BCA && bcPatternA[localBC])
265+
fillHistograms<AllBCs, BCA>(timeSinceSOF, localBC);
266+
if (iBCCategory == BCB && bcPatternB[localBC])
267+
fillHistograms<AllBCs, BCB>(timeSinceSOF, localBC);
268+
if (iBCCategory == BCC && bcPatternC[localBC])
269+
fillHistograms<AllBCs, BCC>(timeSinceSOF, localBC);
270+
if (iBCCategory == BCE && bcPatternE[localBC])
271+
fillHistograms<AllBCs, BCE>(timeSinceSOF, localBC);
272+
if (iBCCategory == BCL && bcPatternL[localBC])
273+
fillHistograms<AllBCs, BCL>(timeSinceSOF, localBC);
274+
if (iBCCategory == BCSL && isSuperLeadingBc)
275+
fillHistograms<AllBCs, BCSL>(timeSinceSOF, localBC);
276+
}
277+
if (iTrigger == FT0Vtx && ctpInputMask.test(2)) {
278+
if (iBCCategory == BCA && bcPatternA[localBC])
279+
fillHistograms<FT0Vtx, BCA>(timeSinceSOF, localBC);
280+
if (iBCCategory == BCB && bcPatternB[localBC])
281+
fillHistograms<FT0Vtx, BCB>(timeSinceSOF, localBC);
282+
if (iBCCategory == BCC && bcPatternC[localBC])
283+
fillHistograms<FT0Vtx, BCC>(timeSinceSOF, localBC);
284+
if (iBCCategory == BCE && bcPatternE[localBC])
285+
fillHistograms<FT0Vtx, BCE>(timeSinceSOF, localBC);
286+
if (iBCCategory == BCL && bcPatternL[localBC])
287+
fillHistograms<FT0Vtx, BCL>(timeSinceSOF, localBC);
288+
if (iBCCategory == BCSL && isSuperLeadingBc)
289+
fillHistograms<FT0Vtx, BCSL>(timeSinceSOF, localBC);
290+
}
291+
if (iTrigger == FT0CE && ctpInputMask.test(4)) {
292+
if (iBCCategory == BCA && bcPatternA[localBC])
293+
fillHistograms<FT0CE, BCA>(timeSinceSOF, localBC);
294+
if (iBCCategory == BCB && bcPatternB[localBC])
295+
fillHistograms<FT0CE, BCB>(timeSinceSOF, localBC);
296+
if (iBCCategory == BCC && bcPatternC[localBC])
297+
fillHistograms<FT0CE, BCC>(timeSinceSOF, localBC);
298+
if (iBCCategory == BCE && bcPatternE[localBC])
299+
fillHistograms<FT0CE, BCE>(timeSinceSOF, localBC);
300+
if (iBCCategory == BCL && bcPatternL[localBC])
301+
fillHistograms<FT0CE, BCL>(timeSinceSOF, localBC);
302+
}
303+
if (iTrigger == FDD && ctpInputMask.test(15)) {
304+
if (iBCCategory == BCA && bcPatternA[localBC])
305+
fillHistograms<FDD, BCA>(timeSinceSOF, localBC);
306+
if (iBCCategory == BCB && bcPatternB[localBC])
307+
fillHistograms<FDD, BCB>(timeSinceSOF, localBC);
308+
if (iBCCategory == BCC && bcPatternC[localBC])
309+
fillHistograms<FDD, BCC>(timeSinceSOF, localBC);
310+
if (iBCCategory == BCE && bcPatternE[localBC])
311+
fillHistograms<FDD, BCE>(timeSinceSOF, localBC);
312+
if (iBCCategory == BCL && bcPatternL[localBC])
313+
fillHistograms<FDD, BCL>(timeSinceSOF, localBC);
314+
if (iBCCategory == BCSL && isSuperLeadingBc)
315+
fillHistograms<FDD, BCSL>(timeSinceSOF, localBC);
316+
}
317+
}
318+
}
319+
}
320+
histNBcsVsBcId[runNumber]->Fill(localBC);
321+
}
322+
}
323+
};
324+
325+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
326+
{
327+
metadataInfo.initMetadata(cfgc);
328+
return WorkflowSpec{adaptAnalysisTask<LumiStabilityPP>(cfgc)};
329+
}

0 commit comments

Comments
 (0)