ATLAS Offline Software
Loading...
Searching...
No Matches
CDIReader.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6// CDIReader.h, (c) ATLAS Detector software
8
10
11#include <nlohmann/json.hpp>
12
13using json = nlohmann::json;
14
15Analysis::CDIReader::CDIReader(const std::string& cdipath, bool verbose) : m_use_json(false), m_cdipath(cdipath), m_CDIFile(TFile::Open(m_cdipath.c_str(), "READ"))
16{
17 if (!m_CDIFile)[[unlikely]]{
18 std::cout << "Analysis::CDIReader::CDIReader: " << m_cdipath << " could not be opened."<<std::endl;
19 return;
20 }
21 TObjString* s{};
22 m_CDIFile->GetObject("VersionInfo/BuildNumber", s);
23 if (s && verbose){
24 std::cout << " CDI file build number: " << s->GetName() << std::endl;
25 }
26 TList* taggerkeys = m_CDIFile->GetListOfKeys();
27 for (const auto tagger : *taggerkeys){
28 if (!tagger)[[unlikely]] continue;
29 const std::string taggername{tagger->GetName()};
30 if(taggername != "VersionInfo"){
31 // now we have the top-level tagger name, we want to add this to our overall meta data
32 auto* taggerDir = static_cast<TDirectoryFile*>(m_CDIFile->Get(taggername.c_str()));
33 record_metadata(taggername, 0);
34 crawlCDI(taggerDir, 0, taggername);
35 }
36 }
37}
38
39
40void Analysis::CDIReader::crawlCDI(TDirectoryFile* parentDir, int depth, const std::string& metamap){
41
42 TList* keys = parentDir->GetListOfKeys(); // get directories
43 if(isWPdirectory(keys)){
44 // now that we are at the level of the individual label directories
45 // interact with them, and extract the data they store
46
47 TList* labelkeys = parentDir->GetListOfKeys();
48 Data theseData; // labels, systematics, DSIDS, etc.
49 Labels theseLabels;
50 std::set<std::string> DSID_set; // record all DSID names in the flavour configuration
51 std::set<std::string> systematics_set; // record all uncertainties met in flavour configuration
52
53 Labels path = split(metamap);
54 std::string taggername = path.at(0);
55 std::string jetcollname = path.at(1);
56 std::string workingpointname = path.at(2);
57
58 // For each "label" stored in the working point directory,
59 // we need to access the contents of the label directory
60 // and construct the metadata map
61 for(const auto label : *labelkeys){
62 std::string labelname = label->GetName();
63 if(labelname == "cutvalue" || labelname.find("fraction") != std::string::npos) continue;
64 m_labels.insert(labelname);
65 theseLabels.push_back(labelname);
66
67 // now enter the directory to access uncertainty info for this flavour
68 TDirectoryFile* flavourDir = (TDirectoryFile*)parentDir->Get(labelname.c_str());
69 if(flavourDir){
70 Labels uncertainties; // flavour specific uncertainties
71 TList* DSIDkeys = flavourDir->GetListOfKeys(); // this is the list of all the items in the flavour (DSID etc)
72 for(const auto CDHistCont : *DSIDkeys){
73 std::string DSIDname = CDHistCont->GetName();
74 DSID_set.insert(DSIDname);
75 m_DSIDs.insert(DSIDname);
76 if(DSIDname == "default_SF"){ // let's access the systematic uncertainties
77 // construct the total path
78 std::string dir = taggername + "/" + jetcollname + "/" + workingpointname + "/" + labelname + "/default_SF";
80 m_CDIFile->GetObject(dir.c_str(), cont);
81 if(!cont){
82 std::cout << "No default_SF CalibrationDataHistogramContainer?" << std::endl;
83 } else {
84 uncertainties = cont->listUncertainties();
85 for(const std::string &s : uncertainties){
86 systematics_set.insert(s);
87 }
88 cont->DeleteAll(); // TMap does not own its values: free the histograms it holds
89 delete cont; // then the (now empty) map itself
90 }
91 // add the flavour specific uncertainties here
92 std::string flav_spec_unc_name = labelname + "_syst";
93 theseData[flav_spec_unc_name] = uncertainties;
94 }
95 }
96 } else {
97 std::cout << "No flavour directory?" << std::endl;
98 }
99 }
100 // sort and add the labels to the Data object
101 std::sort(theseLabels.begin(), theseLabels.end());
102 theseData["labels"] = std::move(theseLabels);
103 // convert DSID set to vector of strings
104 Labels theseDSIDs(DSID_set.size());
105 std::copy(DSID_set.begin(), DSID_set.end(), theseDSIDs.begin());
106 theseData["DSIDs"] = std::move(theseDSIDs);
107 // convert systematic set to vector of strings
108 Labels theseSystematics(systematics_set.size());
109 std::copy(systematics_set.begin(), systematics_set.end(), theseSystematics.begin());
110 theseData["systematics"] = std::move(theseSystematics);
111 // Construct this branch of the metadata map
112 // and record the Data object
113 record_metadata_map(theseData, metamap);
114 } else {
115 for(const auto coll: *keys){
116 std::string collname = coll->GetName();
117 if ( collname.find("cutvalue") != std::string::npos || collname.find("fraction") != std::string::npos) continue;
118 // track the metadata as you traverse
119 record_metadata(collname, depth+1);
120 TDirectoryFile* collDir = (TDirectoryFile*)parentDir->Get(collname.c_str());
121 if(collDir && collname != "VersionInfo"){
122 std::string nextmap = metamap + ";" + collname;
123 crawlCDI(collDir, depth+1, nextmap); // traverse further
124 } else {
125 std::cout << "No collection directory?" << std::endl;
126 }
127 }
128 }
129}
130
131
132
133
134void Analysis::CDIReader::printMetadata(int tagger, int jetcoll, int wpoint, int label){
135 /*
136 This method prints subsets of the available metadata collected from the CDI file.
137
138 The CDI data is organized in a hierarchical directory structure, where taggers contain jet-collections, and jet-collections
139 contain working points, etc.
140
141 This method prints wildcard data such as:
142 - tagger / *
143 - tagger / jetcoll/ *
144 - tagger / jetcoll/ wpoint / *
145 - tagger / jetcoll / wpoint / label
146
147 The method operates on simple integer inputs, to indicate what to print out:
148 - Positive integer values for tagger, jetcoll, wpoint, and label (up to the number of available items of each)
149 will print out information specific to that particular entry (e.g. tagger == 1 will print tagger #1 specific info)
150 - Negative integer values indicate a wildcard, and will print out all available items of this type.
151 - Zero indicates to print nothing for that category.
152 */
153 int current_tagger = (tagger < 0) ? -1 : 0;
154 int current_jetcoll = (jetcoll < 0) ? -1 : 0;
155 int current_wpoint = (wpoint < 0) ? -1 : 0;
156 int current_label = (label < 0) ? -1 : 0;
157
158 for (const auto& [tag, jets] : m_metadata){
159 if(current_tagger != -1) current_tagger += 1;
160 if(tagger != current_tagger || tagger == 0) continue;
161
162 std::cout << "| " << tag << std::endl; // print only the tagger you're interested in
163
164 for (const auto& [jet, wps] : jets){
165 if(current_jetcoll != -1) current_jetcoll += 1;
166 if(jetcoll != current_jetcoll || jetcoll == 0) continue;
167
168 std::cout << "|\\__ " << jet << std::endl;
169
170 int num_wps = wps.size();
171 int num_wp_seen = 0;
172 for(const auto& [wp, labels] : wps){
173 if(current_wpoint != -1) current_wpoint += 1;
174 if(wpoint != current_wpoint || wpoint == 0) continue;
175 num_wp_seen += 1;
176 if(num_wp_seen != num_wps){
177 std::cout << "| |\\__" << wp << std::endl;
178 } else {
179 std::cout << "| \\__" << wp << std::endl;
180 }
181
182 int label_index = 0;
183 Data d = labels;
184 for(const std::string& l : d["labels"]){
185 if(current_label != -1) current_label += 1;
186 if(label != current_label || label == 0) continue;
187 if(num_wp_seen != num_wps && label_index == 0){
188 std::cout << "| | \\___" << " (" << label_index << ") " << l << std::endl;
189 } else if(label_index != 0 && num_wp_seen != num_wps) {
190 std::cout << "| | \\___" << " (" << label_index << ") " << l << std::endl;
191 } else {
192 std::cout << "| \\___" << " (" << label_index << ") " << l << std::endl;
193 }
194 label_index += 1;
195 }
196 }
197 }
198 }
199}
200
201bool Analysis::CDIReader::checkConfig(const std::string& tagger, const std::string& jetcoll, const std::string& wp, bool verbose){
202 // this method checks if your config is correct or not
203 // returns true if correct, false if not
204 // if not correct, it will also print a helpful message
205 bool configured = false;
206 // get the number that would correspond to the index of the tagger/jetcoll/wp
207 // if these were each stored in a vector of strings, sorted alphanumerically
208 // which happens already by default in the (ordered) map
209 int tagger_ind = 0;
210 int jetcoll_ind = 0;
211 int wp_ind = 0;
212
213 if(m_metadata.count(tagger) > 0){
214 // get the tagger index
215 for(const auto& tag : m_metadata){
216 tagger_ind += 1;
217 if(tag.first == tagger) break;
218 }
219 if(m_metadata[tagger].count(jetcoll) > 0){
220 // get the jet collection index
221 for(const auto& jet : m_metadata[tagger]){
222 jetcoll_ind += 1;
223 if(jet.first == jetcoll) break;
224 }
225 if(m_metadata[tagger][jetcoll].count(wp) > 0){
226 // get the working point index
227 for(const auto& wpoint : m_metadata[tagger][jetcoll]){
228 wp_ind += 1;
229 if(wpoint.first == wp) break;
230 }
231 if (verbose) std::cout << " Your configuration looks good! Available labels are : " << std::endl;
232 if (verbose) printMetadata(tagger_ind, jetcoll_ind, wp_ind, -1);
233 // construct vector of labels
234 for(const std::string& flavour_label : m_metadata[tagger][jetcoll][wp]["labels"]){
235 m_label_vec.push_back(flavour_label);
236 }
237 // sort the vector of labels
238 std::sort(m_label_vec.begin(), m_label_vec.end());
239 configured = true;
240 } else {
241 if (verbose) std::cout << "Couldn't find \"" << wp << "\" for " << tagger << " / " << jetcoll << " in this CDI file!" << std::endl;
242 if (verbose) std::cout << "Here are your options :" << std::endl;
243 if (verbose) printMetadata(tagger_ind, jetcoll_ind, -1, 0);
244 }
245 } else {
246 if (verbose) std::cout << "Couldn't find \"" << jetcoll << "\" under " << tagger << " in this CDI file!" << std::endl;
247 if (verbose) std::cout << "Here are your options :" << std::endl;
248 if (verbose) printMetadata(tagger_ind, -1, 0, 0);
249 }
250 } else {
251 if (verbose) std::cout << "Couldn't find \"" << tagger << "\" in this CDI file" << std::endl;
252 if (verbose) std::cout << "Here are your options :" << std::endl;
253 if (verbose) printMetadata(-1,0,0,0);
254 }
255
256 if(m_use_json){
257 // let's make a json object from the nlohmann package and save it to file
258 json json_metadata(m_metadata);
259 // get cwd to save in
260 std::filesystem::path cwd = std::filesystem::current_path();
261 std::filesystem::path filepath = cwd / "CDI.json";
262 std::ofstream output(filepath);
263 output << std::setw(4) << json_metadata << std::endl;
264 }
265
266 m_initialized = configured;
267 return configured;
268}
269
270
271std::vector<std::string> Analysis::CDIReader::getDSIDs(const std::string& tagger, const std::string& jetcollection, const std::string& workingpoint){
272 if(!m_initialized){
273 std::cout << " CDIReader :: You need to validate your configuration before working with (flavour) labels!" << std::endl;
274 }
275 Labels DSIDs;
276 if (tagger.empty() || jetcollection.empty() || workingpoint.empty()){
277 // unless specified, return the vector of all known DSIDs from this CDI file
278 Labels DSID_vec(m_DSIDs.size());
279 std::copy(m_DSIDs.begin(), m_DSIDs.end(), DSID_vec.begin());
280 DSIDs = std::move(DSID_vec);
281 //} else if(std::find(m_taggers.begin(), m_taggers.end(), tagger) == m_taggers.end()){
282 } else if(m_taggers.find(tagger) == m_taggers.end()){
283 std::cout << " The tagger [" << tagger << "] doesn't exist in this CDI file!" << std::endl;
284 //} else if(std::find(m_jetcollections.begin(), m_jetcollections.end(), jetcollection) == m_jetcollections.end()){
285 } else if(m_jetcollections.find(jetcollection) == m_jetcollections.end()){
286 std::cout << " The jet collection [" << jetcollection << "] doesn't exist in " << tagger << " this CDI file!" << std::endl;
287 //} else if(std::find(m_workingpoints.begin(), m_workingpoints.end(), workingpoint) == m_workingpoints.end()){
288 } else if(m_workingpoints.find(workingpoint) == m_workingpoints.end()){
289 std::cout << " The working point [" << workingpoint << "] doesn't exist in " << tagger << "/" << jetcollection << " this CDI file!" << std::endl;
290 } else {
291 for (const std::string& DSID : m_metadata[tagger][jetcollection][workingpoint]["DSIDs"]){
292 DSIDs.push_back(DSID);
293 }
294 }
295 return DSIDs;
296}
297
298std::vector<std::string> Analysis::CDIReader::getLabels(const std::string& tagger, const std::string& jetcollection, const std::string& workingpoint){
299 if(!m_initialized){
300 std::cout << " CDIReader :: You need to validate your configuration before working with (flavour) labels!" << std::endl;
301 }
302 Labels labels;
303 if (tagger.empty() || jetcollection.empty() || workingpoint.empty()){
304 // unless specified, return the vector of all flavour labels
305 labels = m_label_vec;
306 } else if(m_taggers.find(tagger) == m_taggers.end()){
307 std::cout << " The tagger [" << tagger << "] doesn't exist in this CDI file!" << std::endl;
308 } else if(m_jetcollections.find(jetcollection) == m_jetcollections.end()){
309 std::cout << " The jet collection [" << jetcollection << "] doesn't exist in " << tagger << " this CDI file!" << std::endl;
310 } else if(m_workingpoints.find(workingpoint) == m_workingpoints.end()){
311 std::cout << " The working point [" << workingpoint << "] doesn't exist in " << tagger << "/" << jetcollection << " this CDI file!" << std::endl;
312 } else {
313 for (const std::string& label : m_metadata[tagger][jetcollection][workingpoint]["labels"]){
314 labels.push_back(label);
315 }
316 }
317 return labels;
318}
319
320std::vector<std::string> Analysis::CDIReader::getJetCollections(const std::string& tagger){
321 Labels jetcolls;
322 if (tagger.empty()){
323 // unless specified, return the vector of all jet collections
324 jetcolls.assign(m_jetcollections.begin(), m_jetcollections.end());
325 } else if (m_taggers.find(tagger) == m_taggers.end()) {
326 std::cout << " The tagger [" << tagger << "] doesn't exist in this CDI file!" << std::endl;
327 } else {
328 // return the jetcollections of this tagger
329 for(const auto& jet : m_metadata[tagger]){
330 jetcolls.push_back(jet.first);
331 }
332 }
333 return jetcolls;
334}
335
336
337std::vector<std::string> Analysis::CDIReader::getWorkingPoints(const std::string& tagger, const std::string& jetcollection){
338 Labels wps;
339 if (tagger.empty() || jetcollection.empty()){
340 // unless specified, return the vector of all working points
341 wps.assign(m_workingpoints.begin(), m_workingpoints.end());
342 } else if(m_taggers.find(tagger) == m_taggers.end()){
343 std::cout << " The tagger [" << tagger << "] doesn't exist in this CDI file!" << std::endl;
344 } else if(m_jetcollections.find(jetcollection) == m_jetcollections.end()){
345 std::cout << " The jet collection [" << jetcollection << "] doesn't exist in " << tagger << " this CDI file!" << std::endl;
346 } else {
347 for(const auto& wp : m_metadata[tagger][jetcollection]){
348 wps.push_back(wp.first);
349 }
350 }
351 return wps;
352}
353
354std::vector<std::string> Analysis::CDIReader::getTaggers(){
355 Labels taggers;
356 taggers.assign(m_taggers.begin(), m_taggers.end());
357 return taggers;
358}
nlohmann::json json
void record_metadata(const std::string &datum, int depth=0)
Definition CDIReader.h:113
Labels getDSIDs(const std::string &tagger="", const std::string &jetcollection="", const std::string &workingpoint="")
Labels getLabels(const std::string &tagger="", const std::string &jetcollection="", const std::string &workingpoint="")
std::unique_ptr< TFile > m_CDIFile
Definition CDIReader.h:104
std::set< std::string > m_taggers
Definition CDIReader.h:105
std::set< std::string > m_DSIDs
Definition CDIReader.h:109
void record_metadata_map(const Data &data, const std::string &path)
Definition CDIReader.h:132
Labels getWorkingPoints(const std::string &tagger, const std::string &jetcollection)
bool checkConfig(const std::string &tagger, const std::string &jetcoll, const std::string &wp, bool verbose=false)
bool isWPdirectory(TList *list)
Definition CDIReader.h:143
std::set< std::string > m_workingpoints
Definition CDIReader.h:107
Labels getJetCollections(const std::string &tagger)
std::set< std::string > m_jetcollections
Definition CDIReader.h:106
CDIReader(const std::string &cdipath, bool verbose=false)
normal constructor.
Definition CDIReader.cxx:15
std::string m_cdipath
Definition CDIReader.h:103
std::set< std::string > m_labels
Definition CDIReader.h:108
std::map< std::string, Labels > Data
Definition CDIReader.h:42
void printMetadata(int tagger=-1, int jetcoll=-1, int wpoint=-1, int label=-1)
std::vector< std::string > Labels
Definition CDIReader.h:41
bool m_initialized
flag whether the initialization has been carried out
Definition CDIReader.h:100
void crawlCDI(TDirectoryFile *parentDir, int depth=0, const std::string &metamap="")
Definition CDIReader.cxx:40
std::vector< std::string > listUncertainties() const
retrieve the list of "uncertainties" accessible to this object.
This is the class holding information for histogram-based calibration results.
std::string depth
tag string for intendation
Definition fastadd.cxx:46
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
bool verbose
Definition hcg.cxx:75
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
std::string label(const std::string &format, int i)
Definition label.h:19
std::string cwd
Definition listroot.cxx:38
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
#define unlikely(x)