34int main(
int argc,
char* argv[])
36 std::string inputAO2D(
"AO2D.root");
37 std::string outputFileName{
"AO2D_strained.root"};
38 std::string tables{
"O2bc,O2calotrigger,O2collision,O2fdd,O2ft0,O2fv0a"};
39 double downsampling = 1.0;
42 int compression = 505;
44 std::random_device
rd;
45 std::mt19937
gen(
rd());
46 std::uniform_real_distribution<> dis(0.0, 1.0);
49 static struct option long_options[] = {
50 {
"input", required_argument,
nullptr, 0},
51 {
"output", required_argument,
nullptr, 1},
52 {
"verbosity", required_argument,
nullptr, 2},
53 {
"tables", required_argument,
nullptr, 3},
54 {
"downsampling", required_argument,
nullptr, 4},
55 {
"compression", required_argument,
nullptr, 5},
56 {
"help", no_argument,
nullptr,
'h'},
57 {
nullptr, 0,
nullptr, 0}};
60 int c = getopt_long(argc, argv,
"", long_options, &option_index);
66 outputFileName = optarg;
72 downsampling = atof(optarg);
74 compression = atoi(optarg);
75 }
else if (
c ==
'h') {
76 printf(
"AO2D strainer tool. Options: \n");
77 printf(
" --input <%s> Contains path to files to be merged. Default: %s\n", inputAO2D.c_str(), inputAO2D.c_str());
78 printf(
" --output <%s> Target output ROOT file. Default: %s\n", outputFileName.c_str(), outputFileName.c_str());
79 printf(
" --verbosity <flag> Verbosity of output (default: %d).\n",
verbosity);
80 printf(
" --tables <list of tables> Comma separated list of tables (default: %s).\n", tables.c_str());
81 printf(
" --downsampling <downsample> Fraction of DF to be kept (default: %f)\n", downsampling);
82 printf(
" --compression <root compression id> Compression algorithm / level to use (default: %d)\n", compression);
89 printf(
"AOD strainer started with:\n");
90 printf(
" Input file: %s\n", inputAO2D.c_str());
91 printf(
" Output file name: %s\n", outputFileName.c_str());
92 printf(
" Tables to be kept: %s\n", tables.c_str());
93 printf(
" Downsampling: %f\n", downsampling);
95 std::vector<std::string> listOfTables;
96 std::stringstream ss(tables);
99 while (std::getline(ss, token,
',')) {
100 listOfTables.push_back(token);
103 auto outputFile = TFile::Open(outputFileName.c_str(),
"RECREATE",
"", compression);
104 TDirectory* outputDir =
nullptr;
105 TString line(inputAO2D.c_str());
106 if (line.BeginsWith(
"alien://") && !gGrid && !TGrid::Connect(
"alien:")) {
107 printf(
"Error: Could not connect to AliEn.\n");
110 printf(
"Processing input file: %s\n", line.Data());
111 auto inputFile = TFile::Open(line);
113 printf(
"Error: Could not open input file %s.\n", line.Data());
117 TList* keyList = inputFile->GetListOfKeys();
120 for (
auto key1 : *keyList) {
121 if (((TObjString*)key1)->GetString().EqualTo(
"metaData")) {
122 auto metaDataCurrentFile = (TMap*)inputFile->Get(
"metaData");
124 metaDataCurrentFile->Write(
"metaData", TObject::kSingleKey);
127 if (((TObjString*)key1)->GetString().EqualTo(
"parentFiles")) {
128 auto parentFilesCurrentFile = (TMap*)inputFile->Get(
"parentFiles");
130 parentFilesCurrentFile->Write(
"parentFiles", TObject::kSingleKey);
133 if (!((TObjString*)key1)->GetString().BeginsWith(
"DF_") || dis(
gen) > downsampling) {
137 auto dfName = ((TObjString*)key1)->GetString().Data();
139 printf(
" Processing folder %s\n", dfName);
141 outputDir = outputFile->mkdir(dfName);
142 auto folder = (TDirectoryFile*)inputFile->Get(dfName);
143 auto treeList = folder->GetListOfKeys();
148 for (
auto i = 0;
i < treeList->GetEntries(); ++
i) {
149 TKey* ki = (TKey*)treeList->At(
i);
150 for (
int j =
i + 1;
j < treeList->GetEntries(); ++
j) {
151 TKey* kj = (TKey*)treeList->At(
j);
152 if (std::strcmp(ki->GetName(), kj->GetName()) == 0 && std::strcmp(ki->GetTitle(), kj->GetTitle()) == 0) {
153 if (ki->GetCycle() < kj->GetCycle()) {
154 printf(
" *** FATAL *** we had ordered the keys, first cycle should be higher, please check");
158 treeList->Remove(kj);
168 std::list<std::string> foundTrees;
170 for (
auto key2 : *treeList) {
171 auto treeName = ((TObjString*)key2)->GetString().Data();
172 bool found = (std::find(foundTrees.begin(), foundTrees.end(), treeName) != foundTrees.end());
174 printf(
" ***WARNING*** Tree %s was already merged (even if we purged duplicated trees before, so this should not happen), skipping\n", treeName);
177 bool foundTable =
false;
178 for (
auto const& table : listOfTables) {
180 foundTrees.push_back(treeName);
187 printf(
" Skipping tree %s\n", treeName);
192 auto inputTree = (TTree*)inputFile->Get(Form(
"%s/%s", dfName, treeName));
194 printf(
" Processing tree %s with %lld entries with total size %lld\n", treeName, inputTree->GetEntries(), inputTree->GetTotBytes());
198 auto outputTree = inputTree->CloneTree(-1,
"fast");
204 printf(
"Removing incomplete output file %s.\n", outputFile->GetName());
205 gSystem->Unlink(outputFile->GetName());