Skip to content

Commit 62e3117

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 62e3117

File tree

1 file changed

+136
-50
lines changed

1 file changed

+136
-50
lines changed

Framework/AODMerger/src/aodThinner.cxx

Lines changed: 136 additions & 50 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,60 @@ 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 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+
{"overwrite", no_argument, nullptr, 'O'},
53+
{"help", no_argument, nullptr, 'h'},
4854
{nullptr, 0, nullptr, 0}};
4955

5056
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;
57+
const auto opt = getopt_long(argc, argv, short_opts, long_options, &option_index);
58+
if (opt == -1) {
59+
break; // use defaults
60+
}
61+
switch (opt) {
62+
case 'i':
63+
inputFileName = optarg;
64+
break;
65+
case 'o':
66+
outputFileName = optarg;
67+
break;
68+
case 'O':
69+
bOverwrite = true;
70+
printf("Overwriting existing output file if existing\n");
71+
break;
72+
case 'h':
73+
case '?':
74+
default:
75+
printf("AO2D thinning tool. Options: \n");
76+
printf(" --input/-i <inputfile.root> Contains input file path to the file to be thinned. Default: %s\n", inputFileName.c_str());
77+
printf(" --output/-o <outputfile.root> Target output ROOT file. Default: %s\n", outputFileName.c_str());
78+
printf("\n");
79+
printf(" Optional Arguments:\n");
80+
printf(" --overwrite/-O Overwrite existing output file\n");
81+
return -1;
6582
}
6683
}
6784

6885
printf("AOD reduction started with:\n");
6986
printf(" Input file: %s\n", inputFileName.c_str());
7087
printf(" Ouput file name: %s\n", outputFileName.c_str());
7188

72-
auto outputFile = TFile::Open(outputFileName.c_str(), "RECREATE", "", 501);
89+
TStopwatch clock;
90+
clock.Start(kTRUE);
91+
92+
auto outputFile = TFile::Open(outputFileName.c_str(), (bOverwrite) ? "RECREATE" : "CREATE", "", 501);
93+
if (outputFile == nullptr) {
94+
printf("Error: File %s exists or cannot be created!\n", outputFileName.c_str());
95+
return 1;
96+
}
7397
TDirectory* outputDir = nullptr;
7498

7599
if (inputFileName.find("alien:") == 0) {
@@ -87,18 +111,21 @@ int main(int argc, char* argv[])
87111
keyList->Sort();
88112

89113
for (auto key1 : *keyList) {
114+
// Keep metaData
90115
if (((TObjString*)key1)->GetString().EqualTo("metaData")) {
91116
auto metaData = (TMap*)inputFile->Get("metaData");
92117
outputFile->cd();
93118
metaData->Write("metaData", TObject::kSingleKey);
94119
}
95120

121+
// Keep parentFiles
96122
if (((TObjString*)key1)->GetString().EqualTo("parentFiles")) {
97123
auto parentFiles = (TMap*)inputFile->Get("parentFiles");
98124
outputFile->cd();
99125
parentFiles->Write("parentFiles", TObject::kSingleKey);
100126
}
101127

128+
// Skip everything else, except 'DF_*'
102129
if (!((TObjString*)key1)->GetString().BeginsWith("DF_")) {
103130
continue;
104131
}
@@ -131,15 +158,27 @@ int main(int argc, char* argv[])
131158
}
132159
}
133160

161+
// Scan versions e.g. 001 or 002 ...
162+
TString v0Name{"O2v0_???"}, trkExtraName{"O2trackextra*"};
163+
TRegexp v0Re(v0Name, kTRUE), trkExtraRe(trkExtraName, kTRUE);
164+
for (TObject* obj : *treeList) {
165+
TString st = obj->GetName();
166+
if (st.Index(v0Re) != kNPOS) {
167+
v0Name = st;
168+
} else if (st.Index(trkExtraRe) != kNPOS) {
169+
trkExtraName = st;
170+
}
171+
}
172+
134173
// Certain order needed in order to populate vectors of skipped entries
135-
auto v0Entry = (TObject*)treeList->FindObject("O2v0_001");
174+
auto v0Entry = (TObject*)treeList->FindObject(v0Name);
136175
treeList->Remove(v0Entry);
137176
treeList->AddFirst(v0Entry);
138177

139178
// 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
179+
auto trackExtraTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, trkExtraName.Data()));
141180
if (trackExtraTree == nullptr) {
142-
printf("O2trackextra table not found\n");
181+
printf("%s table not found\n", trkExtraName.Data());
143182
exitCode = 6;
144183
break;
145184
}
@@ -149,27 +188,56 @@ int main(int argc, char* argv[])
149188
exitCode = 7;
150189
break;
151190
}
152-
auto v0s = (TTree*)inputFile->Get(Form("%s/%s", dfName, "O2v0_001"));
191+
auto v0s = (TTree*)inputFile->Get(Form("%s/%s", dfName, v0Name.Data()));
153192
if (v0s == nullptr) {
154-
printf("O2v0_001 table not found\n");
193+
printf("%s table not found\n", v0Name.Data());
155194
exitCode = 8;
156195
break;
157196
}
158197

198+
// We need to loop over the V0s once and flag the prong indices
199+
int trackIdxPos = 0, trackIdxNeg = 0;
200+
std::unordered_map<int, bool> keepV0TPCs;
201+
v0s->SetBranchAddress("fIndexTracks_Pos", &trackIdxPos);
202+
v0s->SetBranchAddress("fIndexTracks_Neg", &trackIdxNeg);
203+
for (int i{0}; v0s->LoadTree(i) >= 0; ++i) {
204+
v0s->GetEntry(i);
205+
keepV0TPCs[trackIdxPos] = true;
206+
keepV0TPCs[trackIdxNeg] = true;
207+
}
208+
159209
std::vector<int> acceptedTracks(trackExtraTree->GetEntries(), -1);
160210
std::vector<bool> hasCollision(trackExtraTree->GetEntries(), false);
161211
std::vector<int> keepV0s(v0s->GetEntries(), -1);
162212

163213
uint8_t tpcNClsFindable = 0;
214+
bool bTPClsFindable = false;
164215
uint8_t ITSClusterMap = 0;
216+
bool bITSClusterMap = false;
165217
uint8_t TRDPattern = 0;
218+
bool bTRDPattern = false;
166219
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);
220+
bool bTOFChi2 = false;
221+
222+
// Test if track properties exist
223+
TBranch* br = nullptr;
224+
TIter next(trackExtraTree->GetListOfBranches());
225+
while ((br = (TBranch*)next())) {
226+
TString brName = br->GetName();
227+
if (brName == "fTPCNClsFindable") {
228+
trackExtraTree->SetBranchAddress("fTPCNClsFindable", &tpcNClsFindable);
229+
bTPClsFindable = true;
230+
} else if (brName == "fITSClusterMap") {
231+
trackExtraTree->SetBranchAddress("fITSClusterMap", &ITSClusterMap);
232+
bITSClusterMap = true;
233+
} else if (brName == "fTRDPattern") {
234+
trackExtraTree->SetBranchAddress("fTRDPattern", &TRDPattern);
235+
bTRDPattern = true;
236+
} else if (brName == "fTOFChi2") {
237+
trackExtraTree->SetBranchAddress("fTOFChi2", &TOFChi2);
238+
bTOFChi2 = true;
239+
}
240+
}
173241

174242
int fIndexCollisions = 0;
175243
track_iu->SetBranchAddress("fIndexCollisions", &fIndexCollisions);
@@ -181,28 +249,34 @@ int main(int argc, char* argv[])
181249
trackExtraTree->GetEntry(i);
182250
track_iu->GetEntry(i);
183251

184-
// Remove TPC only tracks
185-
if (tpcNClsFindable > 0. && ITSClusterMap == 0 && TRDPattern == 0 && TOFChi2 < -1.) {
252+
// Flag collisions
253+
hasCollision[i] = (fIndexCollisions >= 0);
254+
255+
// Remove TPC only tracks, if (opt.) they are not assoc. to a V0
256+
if ((!bTPClsFindable || tpcNClsFindable > 0.) &&
257+
(!bITSClusterMap || ITSClusterMap == 0) &&
258+
(!bTRDPattern || TRDPattern == 0) &&
259+
(!bTOFChi2 || TOFChi2 < -1.) &&
260+
(keepV0TPCs.find(i) == keepV0TPCs.end())) {
186261
counter++;
187262
} else {
188263
acceptedTracks[i] = i - counter;
189264
}
190-
hasCollision[i] = (fIndexCollisions >= 0);
191265
}
192266

193267
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());
268+
TString treeName = ((TObjString*)key2)->GetString().Data();
198269

199270
// Connect trees but do not copy entries (using the clone function)
200271
// NOTE Basket size etc. are copied in CloneTree()
201-
if (!outputDir) {
272+
if (outputDir == nullptr) {
202273
outputDir = outputFile->mkdir(dfName);
203274
printf("Writing to output folder %s\n", dfName);
204275
}
205276
outputDir->cd();
277+
278+
auto inputTree = (TTree*)inputFile->Get(Form("%s/%s", dfName, treeName.Data()));
279+
printf(" Processing tree %s with %lld entries with total size %lld\n", treeName.Data(), inputTree->GetEntries(), inputTree->GetTotBytes());
206280
auto outputTree = inputTree->CloneTree(0);
207281
outputTree->SetAutoFlush(0);
208282

@@ -213,7 +287,7 @@ int main(int argc, char* argv[])
213287
for (int i = 0; i < branches->GetEntriesFast(); ++i) {
214288
TBranch* br = (TBranch*)branches->UncheckedAt(i);
215289
TString branchName(br->GetName());
216-
TString tableName(getTableName(branchName, treeName));
290+
TString tableName(getTableName(branchName, treeName.Data()));
217291
// register index of track index ONLY
218292
if (!tableName.EqualTo("O2track")) {
219293
continue;
@@ -243,10 +317,10 @@ int main(int argc, char* argv[])
243317
}
244318
}
245319

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;
320+
bool processingTracks = treeName.BeginsWith("O2track"); // matches any of the track tables
321+
bool processingCascades = treeName.BeginsWith("O2cascade");
322+
bool processingV0s = treeName.BeginsWith("O2v0");
323+
bool processingAmbiguousTracks = treeName.BeginsWith("O2ambiguoustrack");
250324

251325
auto indexV0s = -1;
252326
if (processingCascades) {
@@ -337,6 +411,18 @@ int main(int argc, char* argv[])
337411
gSystem->Unlink(outputFile->GetName());
338412
}
339413

414+
clock.Stop();
415+
416+
// Report savings
417+
auto sBefore = inputFile->GetSize();
418+
auto sAfter = outputFile->GetSize();
419+
if (sBefore <= 0 || sAfter <= 0) {
420+
printf("Warning: Empty input or output file after thinning!\n");
421+
exitCode = 9;
422+
}
423+
auto spaceSaving = (1 - ((double)sAfter) / ((double)sBefore)) * 100;
424+
printf("Stats: After=%lld / Before=%lld Bytes ---> Saving %.1f%% diskspace!\n", sAfter, sBefore, spaceSaving);
425+
printf("Timing: CPU=%.2f (s); Real=%.2f (s)\n", clock.CpuTime(), clock.RealTime());
340426
printf("End of AOD thinning.\n");
341427

342428
return exitCode;

0 commit comments

Comments
 (0)