Skip to content

Commit 8ff247a

Browse files
committed
AOD: Prepare Thinner for TPC-only V0s
This patch carefully checks which tracks are associated with a V0 and flags to not be discarded. This is written such that the thinner is unaware of the track-type. Additionally, this patch further generalizes the thinner by making it check manually for the table_name with regex. E.g., previously the v0-name was specifically ‘O2v0_001’, now this has been changed to ’O2v0_00?’. That way, we no longer care about the actual version contained in the table. Hence, new AO2Ds can also be thinned. Signed-off-by: Felix Schlepper <felix.schlepper@cern.ch>
1 parent 9288e81 commit 8ff247a

File tree

1 file changed

+145
-49
lines changed

1 file changed

+145
-49
lines changed

Framework/AODMerger/src/aodThinner.cxx

Lines changed: 145 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,29 @@
99
// granted to it by virtue of its status as an Intergovernmental Organization
1010
// or submit itself to any jurisdiction.
1111

12-
#include <map>
13-
#include <list>
14-
#include <fstream>
12+
#include <unordered_map>
1513
#include <getopt.h>
1614

1715
#include "TSystem.h"
16+
#include "TStopwatch.h"
17+
#include "TString.h"
18+
#include "TRegexp.h"
1819
#include "TFile.h"
1920
#include "TTree.h"
21+
#include "TBranch.h"
2022
#include "TList.h"
2123
#include "TKey.h"
2224
#include "TDirectory.h"
2325
#include "TObjString.h"
24-
#include <TGrid.h>
25-
#include <TMap.h>
26-
#include <TLeaf.h>
26+
#include "TGrid.h"
27+
#include "TMap.h"
28+
#include "TLeaf.h"
2729

2830
#include "aodMerger.h"
2931

3032
// AOD reduction tool
3133
// Designed for the 2022 pp data with specific selections:
32-
// - Remove all TPC only tracks
34+
// - Remove all TPC only tracks, optionally keep TPC-only V0 tracks
3335
// - Remove all V0s which refer to any removed track
3436
// - Remove all cascade which refer to any removed V0
3537
// - Remove all ambiguous track entries which point to a track with collision
@@ -38,38 +40,66 @@ int main(int argc, char* argv[])
3840
{
3941
std::string inputFileName("AO2D.root");
4042
std::string outputFileName("AO2D_thinned.root");
41-
int exitCode = 0; // 0: success, >0: failure
43+
int exitCode = 0; // 0: success, !=0: failure
44+
bool bV0TPC = false, bOverwrite = false;
4245

4346
int option_index = 1;
47+
48+
const char* const short_opts = "i:o:KOh";
4449
static struct option long_options[] = {
45-
{"input", required_argument, nullptr, 0},
46-
{"output", required_argument, nullptr, 1},
47-
{"help", no_argument, nullptr, 2},
50+
{"input", required_argument, nullptr, 'i'},
51+
{"output", required_argument, nullptr, 'o'},
52+
{"keep-v0-tpc-only-tracks", no_argument, nullptr, 'K'},
53+
{"overwrite", no_argument, nullptr, 'O'},
54+
{"help", no_argument, nullptr, 'h'},
4855
{nullptr, 0, nullptr, 0}};
4956

5057
while (true) {
51-
int c = getopt_long(argc, argv, "", long_options, &option_index);
52-
if (c == -1) {
53-
break;
54-
} else if (c == 0) {
55-
inputFileName = optarg;
56-
} else if (c == 1) {
57-
outputFileName = optarg;
58-
} else if (c == 2) {
59-
printf("AO2D thinning tool. Options: \n");
60-
printf(" --input <inputfile.root> Contains input file path to the file to be thinned. Default: %s\n", inputFileName.c_str());
61-
printf(" --output <outputfile.root> Target output ROOT file. Default: %s\n", outputFileName.c_str());
62-
return -1;
63-
} else {
64-
return -2;
58+
const auto opt = getopt_long(argc, argv, short_opts, long_options, &option_index);
59+
if (opt == -1) {
60+
break; // use defaults
61+
}
62+
switch (opt) {
63+
case 'i':
64+
inputFileName = optarg;
65+
break;
66+
case 'o':
67+
outputFileName = optarg;
68+
break;
69+
case 'K':
70+
bV0TPC = true;
71+
printf("Keeping TPC-only tracks associated with V0s\n");
72+
break;
73+
case 'O':
74+
bOverwrite = true;
75+
printf("Overwriting existing output file if existing\n");
76+
break;
77+
case 'h':
78+
case '?':
79+
default:
80+
printf("AO2D thinning tool. Options: \n");
81+
printf(" --input/-i <inputfile.root> Contains input file path to the file to be thinned. Default: %s\n", inputFileName.c_str());
82+
printf(" --output/-o <outputfile.root> Target output ROOT file. Default: %s\n", outputFileName.c_str());
83+
printf("\n");
84+
printf(" Optional Arguments:\n");
85+
printf(" --overwrite/-O Overwrite existing output file\n");
86+
printf(" --keep-v0-tpc-only-tracks/-K Keep tracks associated to TPC-only V0s\n");
87+
return -1;
6588
}
6689
}
6790

6891
printf("AOD reduction started with:\n");
6992
printf(" Input file: %s\n", inputFileName.c_str());
7093
printf(" Ouput file name: %s\n", outputFileName.c_str());
7194

72-
auto outputFile = TFile::Open(outputFileName.c_str(), "RECREATE", "", 501);
95+
TStopwatch clock;
96+
clock.Start(kTRUE);
97+
98+
auto outputFile = TFile::Open(Form("%s", outputFileName.c_str()), (bOverwrite) ? "RECREATE" : "CREATE", "", 501);
99+
if (outputFile == nullptr) {
100+
printf("Error: File %s exists or cannot be created!\n", outputFileName.c_str());
101+
return 1;
102+
}
73103
TDirectory* outputDir = nullptr;
74104

75105
if (inputFileName.find("alien:") == 0) {
@@ -87,18 +117,21 @@ int main(int argc, char* argv[])
87117
keyList->Sort();
88118

89119
for (auto key1 : *keyList) {
120+
// Keep metaData
90121
if (((TObjString*)key1)->GetString().EqualTo("metaData")) {
91122
auto metaData = (TMap*)inputFile->Get("metaData");
92123
outputFile->cd();
93124
metaData->Write("metaData", TObject::kSingleKey);
94125
}
95126

127+
// Keep parentFiles
96128
if (((TObjString*)key1)->GetString().EqualTo("parentFiles")) {
97129
auto parentFiles = (TMap*)inputFile->Get("parentFiles");
98130
outputFile->cd();
99131
parentFiles->Write("parentFiles", TObject::kSingleKey);
100132
}
101133

134+
// Skip everything else, except 'DF_*'
102135
if (!((TObjString*)key1)->GetString().BeginsWith("DF_")) {
103136
continue;
104137
}
@@ -131,15 +164,27 @@ int main(int argc, char* argv[])
131164
}
132165
}
133166

167+
// Scan versions e.g. 001 or 002 ...
168+
TString v0Name{"O2v0_???"}, trkExtraName{"O2trackextra*"};
169+
TRegexp v0Re(v0Name, kTRUE), trkExtraRe(trkExtraName, kTRUE);
170+
for (TObject* obj : *treeList) {
171+
TString st = obj->GetName();
172+
if (st.Index(v0Re) != kNPOS) {
173+
v0Name = st;
174+
} else if (st.Index(trkExtraRe) != kNPOS) {
175+
trkExtraName = st;
176+
}
177+
}
178+
134179
// Certain order needed in order to populate vectors of skipped entries
135-
auto v0Entry = (TObject*)treeList->FindObject("O2v0_001");
180+
auto v0Entry = (TObject*)treeList->FindObject(v0Name);
136181
treeList->Remove(v0Entry);
137182
treeList->AddFirst(v0Entry);
138183

139184
// Prepare maps for track skimming
140-
auto trackExtraTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, "O2trackextra")); // for example we can use this line to access the track table
185+
auto trackExtraTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, trkExtraName.Data()));
141186
if (trackExtraTree == nullptr) {
142-
printf("O2trackextra table not found\n");
187+
printf("%s table not found\n", trkExtraName.Data());
143188
exitCode = 6;
144189
break;
145190
}
@@ -149,27 +194,60 @@ int main(int argc, char* argv[])
149194
exitCode = 7;
150195
break;
151196
}
152-
auto v0s = (TTree*)inputFile->Get(Form("%s/%s", dfName, "O2v0_001"));
197+
auto v0s = (TTree*)inputFile->Get(Form("%s/%s", dfName, v0Name.Data()));
153198
if (v0s == nullptr) {
154-
printf("O2v0_001 table not found\n");
199+
printf("%s table not found\n", v0Name.Data());
155200
exitCode = 8;
156201
break;
157202
}
158203

204+
std::unordered_map<int, bool> keepV0TPCs;
205+
if (bV0TPC) {
206+
// We need to loop over the V0s once and flag the prong indices
207+
// technically we need to flag only V0s with TPC-only prongs but
208+
// this requires in-depth knowledge of the data-model which we don't need.
209+
int trackIdxPos = 0, trackIdxNeg = 0;
210+
v0s->SetBranchAddress("fIndexTracks_Pos", &trackIdxPos);
211+
v0s->SetBranchAddress("fIndexTracks_Neg", &trackIdxNeg);
212+
for (int i{0}; v0s->LoadTree(i) >= 0; ++i) {
213+
v0s->GetEntry(i);
214+
keepV0TPCs[trackIdxPos] = true;
215+
keepV0TPCs[trackIdxNeg] = true;
216+
}
217+
}
218+
159219
std::vector<int> acceptedTracks(trackExtraTree->GetEntries(), -1);
160220
std::vector<bool> hasCollision(trackExtraTree->GetEntries(), false);
161221
std::vector<int> keepV0s(v0s->GetEntries(), -1);
162222

163223
uint8_t tpcNClsFindable = 0;
224+
bool bTPClsFindable = false;
164225
uint8_t ITSClusterMap = 0;
226+
bool bITSClusterMap = false;
165227
uint8_t TRDPattern = 0;
228+
bool bTRDPattern = false;
166229
float_t TOFChi2 = 0;
167-
// char16_t fTPCNClsFindableMinusFound = 0;
168-
trackExtraTree->SetBranchAddress("fTPCNClsFindable", &tpcNClsFindable);
169-
trackExtraTree->SetBranchAddress("fITSClusterMap", &ITSClusterMap);
170-
trackExtraTree->SetBranchAddress("fTRDPattern", &TRDPattern);
171-
trackExtraTree->SetBranchAddress("fTOFChi2", &TOFChi2);
172-
// trackExtraTree->SetBranchAddress("fTPCNClsFindableMinusFound", &fTPCNClsFindableMinusFound);
230+
bool bTOFChi2 = false;
231+
232+
// Test if track properties exist
233+
TBranch* br = nullptr;
234+
TIter next(trackExtraTree->GetListOfBranches());
235+
while ((br = (TBranch*)next())) {
236+
TString brName = br->GetName();
237+
if (brName == "fTPCNClsFindable") {
238+
trackExtraTree->SetBranchAddress("fTPCNClsFindable", &tpcNClsFindable);
239+
bTPClsFindable = true;
240+
} else if (brName == "fITSClusterMap") {
241+
trackExtraTree->SetBranchAddress("fITSClusterMap", &ITSClusterMap);
242+
bITSClusterMap = true;
243+
} else if (brName == "fTRDPattern") {
244+
trackExtraTree->SetBranchAddress("fTRDPattern", &TRDPattern);
245+
bTRDPattern = true;
246+
} else if (brName == "fTOFChi2") {
247+
trackExtraTree->SetBranchAddress("fTOFChi2", &TOFChi2);
248+
bTOFChi2 = true;
249+
}
250+
}
173251

174252
int fIndexCollisions = 0;
175253
track_iu->SetBranchAddress("fIndexCollisions", &fIndexCollisions);
@@ -181,20 +259,23 @@ int main(int argc, char* argv[])
181259
trackExtraTree->GetEntry(i);
182260
track_iu->GetEntry(i);
183261

184-
// Remove TPC only tracks
185-
if (tpcNClsFindable > 0. && ITSClusterMap == 0 && TRDPattern == 0 && TOFChi2 < -1.) {
262+
// Flag collisions
263+
hasCollision[i] = (fIndexCollisions >= 0);
264+
265+
// Remove TPC only tracks, if (opt.) they are not assoc. to a V0
266+
if ((!bTPClsFindable || tpcNClsFindable > 0.) &&
267+
(!bITSClusterMap || ITSClusterMap == 0) &&
268+
(!bTRDPattern || TRDPattern == 0) &&
269+
(!bTOFChi2 || TOFChi2 < -1.) &&
270+
(!bV0TPC || keepV0TPCs.find(i) == keepV0TPCs.end())) {
186271
counter++;
187272
} else {
188273
acceptedTracks[i] = i - counter;
189274
}
190-
hasCollision[i] = (fIndexCollisions >= 0);
191275
}
192276

193277
for (auto key2 : *treeList) {
194-
auto treeName = ((TObjString*)key2)->GetString().Data();
195-
196-
auto inputTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, treeName));
197-
printf(" Processing tree %s with %lld entries with total size %lld\n", treeName, inputTree->GetEntries(), inputTree->GetTotBytes());
278+
TString treeName = ((TObjString*)key2)->GetString().Data();
198279

199280
// Connect trees but do not copy entries (using the clone function)
200281
// NOTE Basket size etc. are copied in CloneTree()
@@ -203,6 +284,9 @@ int main(int argc, char* argv[])
203284
printf("Writing to output folder %s\n", dfName);
204285
}
205286
outputDir->cd();
287+
288+
auto inputTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, treeName.Data()));
289+
printf(" Processing tree %s with %lld entries with total size %lld\n", treeName.Data(), inputTree->GetEntries(), inputTree->GetTotBytes());
206290
auto outputTree = inputTree->CloneTree(0);
207291
outputTree->SetAutoFlush(0);
208292

@@ -213,7 +297,7 @@ int main(int argc, char* argv[])
213297
for (int i = 0; i < branches->GetEntriesFast(); ++i) {
214298
TBranch* br = (TBranch*)branches->UncheckedAt(i);
215299
TString branchName(br->GetName());
216-
TString tableName(getTableName(branchName, treeName));
300+
TString tableName(getTableName(branchName, treeName.Data()));
217301
// register index of track index ONLY
218302
if (!tableName.EqualTo("O2track")) {
219303
continue;
@@ -243,10 +327,10 @@ int main(int argc, char* argv[])
243327
}
244328
}
245329

246-
bool processingTracks = memcmp(treeName, "O2track", 7) == 0; // matches any of the track tables
247-
bool processingCascades = memcmp(treeName, "O2cascade", 9) == 0;
248-
bool processingV0s = memcmp(treeName, "O2v0", 4) == 0;
249-
bool processingAmbiguousTracks = memcmp(treeName, "O2ambiguoustrack", 16) == 0;
330+
bool processingTracks = treeName.BeginsWith("O2track"); // matches any of the track tables
331+
bool processingCascades = treeName.BeginsWith("O2cascade");
332+
bool processingV0s = treeName.BeginsWith("O2v0");
333+
bool processingAmbiguousTracks = treeName.BeginsWith("O2ambiguoustrack");
250334

251335
auto indexV0s = -1;
252336
if (processingCascades) {
@@ -337,6 +421,18 @@ int main(int argc, char* argv[])
337421
gSystem->Unlink(outputFile->GetName());
338422
}
339423

424+
clock.Stop();
425+
426+
// Report savings
427+
auto sBefore = inputFile->GetSize();
428+
auto sAfter = outputFile->GetSize();
429+
if (sBefore <= 0 || sAfter <= 0) {
430+
printf("Warning: Empty input or output file after thinning!\n");
431+
exitCode = 9;
432+
}
433+
auto spaceSaving = (1 - ((double)sAfter) / ((double)sBefore)) * 100;
434+
printf("Stats: After=%lld / Before=%lld Bytes ---> Saving %.1f%% diskspace!\n", sAfter, sBefore, spaceSaving);
435+
printf("Timing: CPU=%.2f (s); Real=%.2f (s)\n", clock.CpuTime(), clock.RealTime());
340436
printf("End of AOD thinning.\n");
341437

342438
return exitCode;

0 commit comments

Comments
 (0)