Skip to content

Commit 9961dc3

Browse files
nstrangmNicolas Strangmann
andauthored
[PWGLF] [PWGMM] Add lumi-stability task for light ions (#13461)
Co-authored-by: Nicolas Strangmann <nicolas.strangmann@.cern.ch>
1 parent dbac26b commit 9961dc3

File tree

2 files changed

+315
-0
lines changed

2 files changed

+315
-0
lines changed

PWGMM/Lumi/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ o2physics_add_dpl_workflow(lumistab
3939
SOURCES lumiStability.cxx
4040
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore
4141
O2::ReconstructionDataFormats
42+
COMPONENT_NAME Analysis)
43+
44+
o2physics_add_dpl_workflow(lumi-stability-light-ions
45+
SOURCES lumiStabilityLightIons.cxx
46+
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCCDB O2Physics::AnalysisCore
4247
COMPONENT_NAME Analysis)
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
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 lumiStabilityLightIons.cxx
13+
/// \brief Analysis over BCs to study the luminosity stability along time
14+
///
15+
/// \author Nicolas Strangmann (nicolas.strangmann@cern.ch) - Goethe University Frankfurt, Stefanie Mrozinski (stefanie.mrozinski@cern.ch) - Goethe University Frankfurt
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/AnalysisTask.h"
26+
#include "Framework/runDataProcessing.h"
27+
28+
#include <limits>
29+
#include <map>
30+
#include <string>
31+
#include <vector>
32+
33+
using namespace o2;
34+
using namespace o2::framework;
35+
using namespace o2::framework::expressions;
36+
37+
o2::common::core::MetadataHelper metadataInfo; // Metadata helper
38+
39+
using MyBCs = soa::Join<aod::BCs, aod::BcSels, aod::Timestamps, aod::Run3MatchedToBCSparse>;
40+
41+
struct LumiStabilityLightIons {
42+
Configurable<bool> cfgRequireGoodRCTQuality{"cfgRequireGoodRCTQuality", false, "Only store BCs with good quality of FT0 in RCT"};
43+
Configurable<bool> cfgDoFT0Vtx{"cfgDoFT0Vtx", true, "Create and fill histograms for the FT0 vertex trigger"};
44+
Configurable<bool> cfgDoFT0CE{"cfgDoFT0CE", true, "Create and fill histograms for the FT0 centrality trigger"};
45+
Configurable<bool> cfgDoFDD{"cfgDoFDD", true, "Create and fill histograms for the FDD trigger"};
46+
Configurable<bool> cfgDo1ZNC{"cfgDo1ZNC", true, "Create and fill histograms for the 1ZNC trigger"};
47+
48+
Configurable<bool> cfgDoBCA{"cfgDoBCA", false, "Create and fill histograms for the BCs of type A"};
49+
Configurable<bool> cfgDoBCB{"cfgDoBCB", true, "Create and fill histograms for the BCs of type B"};
50+
Configurable<bool> cfgDoBCC{"cfgDoBCC", false, "Create and fill histograms for the BCs of type C"};
51+
Configurable<bool> cfgDoBCE{"cfgDoBCE", false, "Create and fill histograms for the BCs of type E"};
52+
Configurable<bool> cfgDoBCL{"cfgDoBCL", false, "Create and fill histograms for leading BCs of type B"};
53+
54+
Configurable<int> cfgEmptyBCsBeforeLeadingBC{"cfgEmptyBCsBeforeLeadingBC", 5, "Minimum number of empty BCs before a leading BC to identify it as such"};
55+
56+
std::bitset<o2::constants::lhc::LHCMaxBunches> beamPatternA, beamPatternC;
57+
std::bitset<o2::constants::lhc::LHCMaxBunches> bcPatternA, bcPatternC, bcPatternB, bcPatternE;
58+
59+
std::string strLPMProductionTag = ""; // MC production tag to be retrieved from AO2D metadata
60+
61+
const int nBCsPerOrbit = 3564;
62+
63+
aod::rctsel::RCTFlagsChecker isFT0GoodRCTChecker{aod::rctsel::kFT0Bad};
64+
parameters::GRPLHCIFData* mLHCIFdata = nullptr;
65+
int mRunNumber = -1;
66+
ctpRateFetcher mRateFetcher;
67+
bool isLeadingBC = false;
68+
69+
HistogramRegistry mHistManager{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false};
70+
71+
const int nTriggers = 5;
72+
enum TriggerAliases { kAllBCs = 0,
73+
kFT0Vtx = 1,
74+
kFT0CE = 2,
75+
kFDD = 3,
76+
k1ZNC = 4 };
77+
const int nBCCategories = 5;
78+
enum BCCategories { kBCA = 0,
79+
kBCB = 1,
80+
kBCC = 2,
81+
kBCE = 3,
82+
kBCL = 4 };
83+
84+
static constexpr std::string_view NBCsVsTimeHistNames[5][5] =
85+
{{"AllBCs/BC_A/nBCsVsTime", "AllBCs/BC_B/nBCsVsTime", "AllBCs/BC_C/nBCsVsTime", "AllBCs/BC_E/nBCsVsTime", "AllBCs/BC_L/nBCsVsTime"},
86+
{"FT0VTx/BC_A/nBCsVsTime", "FT0VTx/BC_B/nBCsVsTime", "FT0VTx/BC_C/nBCsVsTime", "FT0VTx/BC_E/nBCsVsTime", "FT0VTx/BC_L/nBCsVsTime"},
87+
{"FT0CE/BC_A/nBCsVsTime", "FT0CE/BC_B/nBCsVsTime", "FT0CE/BC_C/nBCsVsTime", "FT0CE/BC_E/nBCsVsTime", "FT0CE/BC_L/nBCsVsTime"},
88+
{"FDD/BC_A/nBCsVsTime", "FDD/BC_B/nBCsVsTime", "FDD/BC_C/nBCsVsTime", "FDD/BC_E/nBCsVsTime", "FDD/BC_L/nBCsVsTime"},
89+
{"1ZNC/BC_A/nBCsVsTime", "1ZNC/BC_B/nBCsVsTime", "1ZNC/BC_C/nBCsVsTime", "1ZNC/BC_E/nBCsVsTime", "1ZNC/BC_L/nBCsVsTime"}};
90+
91+
static constexpr std::string_view NBCsVsBCIDHistNames[5][5] =
92+
{{"AllBCs/BC_A/nBCsVsBCID", "AllBCs/BC_B/nBCsVsBCID", "AllBCs/BC_C/nBCsVsBCID", "AllBCs/BC_E/nBCsVsBCID", "AllBCs/BC_L/nBCsVsBCID"},
93+
{"FT0VTx/BC_A/nBCsVsBCID", "FT0VTx/BC_B/nBCsVsBCID", "FT0VTx/BC_C/nBCsVsBCID", "FT0VTx/BC_E/nBCsVsBCID", "FT0VTx/BC_L/nBCsVsBCID"},
94+
{"FT0CE/BC_A/nBCsVsBCID", "FT0CE/BC_B/nBCsVsBCID", "FT0CE/BC_C/nBCsVsBCID", "FT0CE/BC_E/nBCsVsBCID", "FT0CE/BC_L/nBCsVsBCID"},
95+
{"FDD/BC_A/nBCsVsBCID", "FDD/BC_B/nBCsVsBCID", "FDD/BC_C/nBCsVsBCID", "FDD/BC_E/nBCsVsBCID", "FDD/BC_L/nBCsVsBCID"},
96+
{"1ZNC/BC_A/nBCsVsBCID", "1ZNC/BC_B/nBCsVsBCID", "1ZNC/BC_C/nBCsVsBCID", "1ZNC/BC_E/nBCsVsBCID", "1ZNC/BC_L/nBCsVsBCID"}};
97+
98+
int64_t bcSOR;
99+
int nBCsPerTF;
100+
int64_t currentTFid = -1;
101+
102+
void init(InitContext&)
103+
{
104+
mHistManager.add("hMu", "hMu", HistType::kTH1F, {{2000, 0., 0.2}});
105+
106+
strLPMProductionTag = metadataInfo.get("LPMProductionTag"); // to extract info from ccdb by the tag
107+
108+
LOG(info) << "strLPMProductionTag: " << strLPMProductionTag;
109+
110+
AxisSpec timeAxis{1200, 0., 1200., "#bf{t-t_{SOF} (min)}"}, bcIDAxis{3600, 0., 3600., "#bf{BC ID in orbit}"};
111+
112+
for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) {
113+
if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) {
114+
for (int iBCCategory = 0; iBCCategory < nBCCategories; iBCCategory++) {
115+
if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) {
116+
mHistManager.add(Form("%s", 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::kTH1F, {timeAxis});
117+
mHistManager.add(Form("%s", std::string(NBCsVsBCIDHistNames[iTrigger][iBCCategory]).c_str()), "BC ID of triggered BCs;#bf{BC ID in orbit};#bf{#it{N}_{BC}}", HistType::kTH1F, {bcIDAxis});
118+
}
119+
}
120+
}
121+
}
122+
123+
mHistManager.add("FT0Vtx_EvSel/nBCsVsTime", "Time of TVX triggered BCs since the start of fill;;#bf{#it{N}_{BC}}", HistType::kTH1F, {timeAxis});
124+
mHistManager.add("nBCsVsBCID", "Time of TVX triggered BCs since the start of fill;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1F, {bcIDAxis});
125+
mHistManager.add("InteractionRateVsTime", "IR from CTP vs time since SOF;#bf{t-t_{SOF} (min)};#bf{#it{N}_{BC}}", HistType::kTH1F, {timeAxis});
126+
mHistManager.add("TFsPerMinute", "TFs seen in this minute (to account for failed jobs);#bf{t-t_{SOF} (min)};#bf{#it{N}_{TFs}}", HistType::kTH1F, {timeAxis});
127+
128+
if (cfgRequireGoodRCTQuality)
129+
isFT0GoodRCTChecker.init({aod::rctsel::kFT0Bad});
130+
}
131+
132+
void setLHCIFData(const auto& bc)
133+
{
134+
if (mRunNumber == bc.runNumber())
135+
return;
136+
137+
auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance();
138+
uint64_t timeStamp = bc.timestamp();
139+
140+
std::map<std::string, std::string> metadata;
141+
mLHCIFdata = ccdbMgr.getSpecific<o2::parameters::GRPLHCIFData>("GLO/Config/GRPLHCIF", timeStamp, metadata);
142+
if (mLHCIFdata == nullptr)
143+
LOG(fatal) << "GRPLHCIFData not in database, timestamp:" << timeStamp;
144+
mRunNumber = bc.runNumber();
145+
LOG(info) << "LHCIF data fetched for run " << mRunNumber << " and timestamp " << timeStamp;
146+
147+
beamPatternA = mLHCIFdata->getBunchFilling().getBeamPattern(0);
148+
beamPatternC = mLHCIFdata->getBunchFilling().getBeamPattern(1);
149+
bcPatternA = beamPatternA & ~beamPatternC;
150+
bcPatternC = ~beamPatternA & beamPatternC;
151+
bcPatternB = beamPatternA & beamPatternC;
152+
bcPatternE = ~beamPatternA & ~beamPatternC;
153+
154+
auto runInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo(o2::ccdb::BasicCCDBManager::instance(), mRunNumber, strLPMProductionTag);
155+
bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // first bc of the first orbit
156+
LOG(info) << "BC SOR: " << bcSOR << " (orbit SOR: " << runInfo.orbitSOR << ") NBCs per orbit: " << nBCsPerOrbit;
157+
nBCsPerTF = runInfo.orbitsPerTF * nBCsPerOrbit; // duration of TF in bcs
158+
159+
return;
160+
}
161+
162+
double getTVXRate(const auto& bc)
163+
{
164+
auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance();
165+
double tvxRate = mRateFetcher.fetch(&ccdbMgr, bc.timestamp(), bc.runNumber(), "T0VTX");
166+
167+
return tvxRate;
168+
}
169+
170+
double calculateMu(const auto& bc)
171+
{
172+
173+
auto bfilling = mLHCIFdata->getBunchFilling();
174+
double nbc = bfilling.getFilledBCs().size();
175+
double nTriggersPerFilledBC = getTVXRate(bc) / nbc / o2::constants::lhc::LHCRevFreq;
176+
double mu = -std::log(1 - nTriggersPerFilledBC);
177+
178+
return mu;
179+
}
180+
181+
float getTimeSinceSOF(const auto& bc)
182+
{
183+
return (bc.timestamp() - mLHCIFdata->getFillNumberTime()) / 1e3 / 60; // Convert to minutes
184+
}
185+
186+
template <int iTrigger, int iBCCategory>
187+
void fillHistograms(float timeSinceSOF, int64_t localBC)
188+
{
189+
mHistManager.fill(HIST(NBCsVsTimeHistNames[iTrigger][iBCCategory]), timeSinceSOF);
190+
mHistManager.fill(HIST(NBCsVsBCIDHistNames[iTrigger][iBCCategory]), localBC);
191+
}
192+
193+
void process(MyBCs const& bcs, aod::FT0s const&)
194+
{
195+
int nEmptyBCs = 0;
196+
for (const auto& bc : bcs) {
197+
198+
if (bc.timestamp() == 0)
199+
continue;
200+
201+
setLHCIFData(bc);
202+
203+
mHistManager.fill(HIST("hMu"), calculateMu(bc));
204+
205+
float timeSinceSOF = getTimeSinceSOF(bc);
206+
207+
auto hRateHist = mHistManager.get<TH1>(HIST("InteractionRateVsTime"));
208+
hRateHist->SetBinContent(hRateHist->FindBin(timeSinceSOF), getTVXRate(bc));
209+
210+
if (bc.selection_bit(aod::evsel::kIsTriggerTVX))
211+
mHistManager.fill(HIST("FT0Vtx_EvSel/nBCsVsTime"), timeSinceSOF);
212+
213+
int64_t globalBC = bc.globalBC();
214+
int localBC = globalBC % nBCsPerOrbit;
215+
216+
int64_t thisTFid = (globalBC - bcSOR) / nBCsPerTF;
217+
218+
if (thisTFid != currentTFid) {
219+
currentTFid = thisTFid;
220+
mHistManager.fill(HIST("TFsPerMinute"), timeSinceSOF);
221+
}
222+
223+
if (bcPatternB[localBC] && nEmptyBCs >= cfgEmptyBCsBeforeLeadingBC) {
224+
isLeadingBC = true;
225+
nEmptyBCs = 0;
226+
} else {
227+
isLeadingBC = false;
228+
nEmptyBCs++;
229+
}
230+
231+
std::bitset<64> ctpInputMask(bc.inputMask());
232+
233+
for (int iTrigger = 0; iTrigger < nTriggers; iTrigger++) {
234+
if ((iTrigger == kAllBCs) || (iTrigger == kFT0Vtx && cfgDoFT0Vtx) || (iTrigger == kFT0CE && cfgDoFT0CE) || (iTrigger == kFDD && cfgDoFDD) || (iTrigger == k1ZNC && cfgDo1ZNC)) {
235+
for (int iBCCategory = 0; iBCCategory < nBCCategories; iBCCategory++) {
236+
if ((iBCCategory == kBCA && cfgDoBCA) || (iBCCategory == kBCB && cfgDoBCB) || (iBCCategory == kBCC && cfgDoBCC) || (iBCCategory == kBCE && cfgDoBCE) || (iBCCategory == kBCL && cfgDoBCL)) {
237+
if (iTrigger == kAllBCs) {
238+
if (iBCCategory == kBCA && bcPatternA[localBC])
239+
fillHistograms<kAllBCs, kBCA>(timeSinceSOF, localBC);
240+
if (iBCCategory == kBCB && bcPatternB[localBC])
241+
fillHistograms<kAllBCs, kBCB>(timeSinceSOF, localBC);
242+
if (iBCCategory == kBCC && bcPatternC[localBC])
243+
fillHistograms<kAllBCs, kBCC>(timeSinceSOF, localBC);
244+
if (iBCCategory == kBCE && bcPatternE[localBC])
245+
fillHistograms<kAllBCs, kBCE>(timeSinceSOF, localBC);
246+
if (iBCCategory == kBCL && isLeadingBC)
247+
fillHistograms<kAllBCs, kBCL>(timeSinceSOF, localBC);
248+
}
249+
if (iTrigger == kFT0Vtx && ctpInputMask.test(2)) {
250+
if (iBCCategory == kBCA && bcPatternA[localBC])
251+
fillHistograms<kFT0Vtx, kBCA>(timeSinceSOF, localBC);
252+
if (iBCCategory == kBCB && bcPatternB[localBC])
253+
fillHistograms<kFT0Vtx, kBCB>(timeSinceSOF, localBC);
254+
if (iBCCategory == kBCC && bcPatternC[localBC])
255+
fillHistograms<kFT0Vtx, kBCC>(timeSinceSOF, localBC);
256+
if (iBCCategory == kBCE && bcPatternE[localBC])
257+
fillHistograms<kFT0Vtx, kBCE>(timeSinceSOF, localBC);
258+
if (iBCCategory == kBCL && isLeadingBC)
259+
fillHistograms<kFT0Vtx, kBCL>(timeSinceSOF, localBC);
260+
}
261+
if (iTrigger == kFT0CE && ctpInputMask.test(4)) {
262+
if (iBCCategory == kBCA && bcPatternA[localBC])
263+
fillHistograms<kFT0CE, kBCA>(timeSinceSOF, localBC);
264+
if (iBCCategory == kBCB && bcPatternB[localBC])
265+
fillHistograms<kFT0CE, kBCB>(timeSinceSOF, localBC);
266+
if (iBCCategory == kBCC && bcPatternC[localBC])
267+
fillHistograms<kFT0CE, kBCC>(timeSinceSOF, localBC);
268+
if (iBCCategory == kBCE && bcPatternE[localBC])
269+
fillHistograms<kFT0CE, kBCE>(timeSinceSOF, localBC);
270+
if (iBCCategory == kBCL && isLeadingBC)
271+
fillHistograms<kFT0CE, kBCL>(timeSinceSOF, localBC);
272+
}
273+
if (iTrigger == kFDD && ctpInputMask.test(15)) {
274+
if (iBCCategory == kBCA && bcPatternA[localBC])
275+
fillHistograms<kFDD, kBCA>(timeSinceSOF, localBC);
276+
if (iBCCategory == kBCB && bcPatternB[localBC])
277+
fillHistograms<kFDD, kBCB>(timeSinceSOF, localBC);
278+
if (iBCCategory == kBCC && bcPatternC[localBC])
279+
fillHistograms<kFDD, kBCC>(timeSinceSOF, localBC);
280+
if (iBCCategory == kBCE && bcPatternE[localBC])
281+
fillHistograms<kFDD, kBCE>(timeSinceSOF, localBC);
282+
if (iBCCategory == kBCL && isLeadingBC)
283+
fillHistograms<kFDD, kBCL>(timeSinceSOF, localBC);
284+
}
285+
if (iTrigger == k1ZNC && ctpInputMask.test(25)) {
286+
if (iBCCategory == kBCA && bcPatternA[localBC])
287+
fillHistograms<k1ZNC, kBCA>(timeSinceSOF, localBC);
288+
if (iBCCategory == kBCB && bcPatternB[localBC])
289+
fillHistograms<k1ZNC, kBCB>(timeSinceSOF, localBC);
290+
if (iBCCategory == kBCC && bcPatternC[localBC])
291+
fillHistograms<k1ZNC, kBCC>(timeSinceSOF, localBC);
292+
if (iBCCategory == kBCE && bcPatternE[localBC])
293+
fillHistograms<k1ZNC, kBCE>(timeSinceSOF, localBC);
294+
if (iBCCategory == kBCL && isLeadingBC)
295+
fillHistograms<k1ZNC, kBCL>(timeSinceSOF, localBC);
296+
}
297+
}
298+
}
299+
}
300+
}
301+
mHistManager.fill(HIST("nBCsVsBCID"), localBC);
302+
}
303+
}
304+
};
305+
306+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
307+
{
308+
metadataInfo.initMetadata(cfgc);
309+
return WorkflowSpec{adaptAnalysisTask<LumiStabilityLightIons>(cfgc)};
310+
}

0 commit comments

Comments
 (0)