ATLAS Offline Software
postProcessIDPVMHistos.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
17 
18 #include "TFile.h"
19 #include "TSystem.h"
20 #include "TH1.h"
21 #include "TH2.h"
22 #include "TObject.h"
23 
24 #include <iostream>
25 #include <memory>
26 #include <string>
27 
28 using namespace std;
29 
30 
31 bool file_exists(const string & p_name) {
32  return !gSystem->AccessPathName(p_name.c_str(), kFileExists);
33 }
34 
35 // check if the name of an object matches what we expect from a resolution helper
36 bool isResolutionHelper(TObject* entry){
37  const std::string objName{entry->GetName()};
38  return ((objName.find("resHelper") == 0 || objName.find("pullHelper") == 0) && dynamic_cast<TH1*>(entry));
39 }
40 
41 // get the x axis observable and resolution (y axis) from the name of a 2D histo.
42 // Relies on the conventions within IDPVM
43 std::vector<std::string> getObservableAndResoAndSuffix(const TObject* resHelper){
44  const std::string name{resHelper->GetName()};
45  const std::string keyWord {"Helper_"};
46  const size_t offset = keyWord.size();
47  auto start = name.find(keyWord)+offset;
48  auto sep = name.find('_',start);
49  auto sep2 = name.find('_',sep+1);
50 
51  std::string first = name.substr(start, sep - start);
52  std::string second;
53  std::string third;
54  if (sep2 == std::string::npos) {
55  // Only one underscore after Helper_
56  second = name.substr(sep + 1);
57  } else {
58  second = name.substr(sep + 1, sep2 - sep - 1);
59  third = name.substr(sep2 + 1);
60  }
61 
62  return {first, second, third};
63 }
64 
65 // get the resolution type (pull or res) - taken from the prefix of the 2D histo name
66 std::string getResoType(const TObject* resHelper){
67  std::string aux{resHelper->GetName()};
68  return aux.substr(0, aux.find("Helper"));
69 }
70 
71 // clone an existing histogram of a known name
72 TH1* cloneExisting(const std::string & name){
73  auto *h = gDirectory->Get(name.c_str());
74  if (!h){
75  std::cerr << "Could not find existing histogram "<<name<<" - will not postprocess "<<std::endl;
76  return nullptr;
77  }
78  auto *ret = dynamic_cast<TH1*>(h->Clone(name.c_str()));
79  if (!ret){
80  std::cerr << "Found an existing object "<<name<<", but it is not a histogram ("<<h->IsA()->GetName()<<") - will not postprocess "<<std::endl;
81  }
82  return ret; // will also catch ret == nullptr
83 }
84 
85 // get the names of the 1D histograms following IDPVM conventions.
86 std::pair<std::string, std::string> getPullAndResoNames(const std::string & type){
87  if (type == "res"){
88  return {"resolution","resmean"};
89  }
90  else if (type == "pull"){
91  return {"pullwidth","pullmean"};
92  }
93  else {
94  std::cerr << " Not able to identify the histogram names for a resolution type "<<type<<" - supported are 'res' and 'pull'. "<<std::endl;
95  }
96  return {"",""};
97 }
98 
99 int postProcessHistos(TObject* resHelper, IDPVM::ResolutionHelper & theHelper){
100  // here we have to rely on the naming conventions of IDPVM to identify what we are looking at
101  auto vars = getObservableAndResoAndSuffix(resHelper);
102  auto type = getResoType(resHelper);
103  // cast to TH2
104  TH2* resHelper2D = dynamic_cast<TH2*>(resHelper);
105  if (!resHelper2D){
106  std::cerr <<"Unable to reduce the histogram "<<resHelper->GetName()<<" to a TH2 - this histo can not yet be postprocessed! " <<std::endl;
107  return 1;
108  }
109  const auto & oneDimNames = getPullAndResoNames(type);
110  // get the corresponding 1D histos by cloning the existing ones in the same folder
111  std::string suffix = "_vs_"+vars[0]+"_"+vars[1];
112  if(!vars[2].empty()) suffix += "_" + vars[2];
113  TH1* h_width = cloneExisting(oneDimNames.first+suffix);
114  TH1* h_mean = cloneExisting(oneDimNames.second+suffix);
115  // then call the resolution helper as done in "online" IDPVM
116  theHelper.makeResolutions(resHelper2D, h_width, h_mean);
117  // update our 1D histos
118  h_width->Write();
119  h_mean->Write();
120  // and we are done
121  return 0;
122 }
123 
124 // recursively parse a directory tree, post-processing any histos seen along the way
125 int postProcessDir(TDirectory* dir, IDPVM::ResolutionHelper & theHelper){
126 
127  int outcome = 0;
128  auto theCWD = gDirectory;
129  // walk through all keys in this directory
130  dir->cd();
131  auto *keys = dir->GetListOfKeys();
132  for (auto *const key : *keys){
133  // Check if it's a directory and handle separately
134  TDirectory* theDir = dynamic_cast<TDirectory*>(dir->Get(key->GetName()));
135  if (theDir){
136  outcome |= postProcessDir(theDir, theHelper);
137  continue; // Do NOT delete directories, ROOT manages them
138  }
139 
140  // If it's a histogram, wrap it in a unique_ptr
141  std::unique_ptr<TObject> gotIt(dir->Get(key->GetName()));
142  if (isResolutionHelper(gotIt.get())){
143  outcome |= postProcessHistos(gotIt.get(), theHelper);
144  }
145  }
146  theCWD->cd();
147  return outcome;
148 }
149 
150 // function driving the postprocessing for this file
151 int pproc_file(const std::string & p_infile) {
152 
153  IDPVM::ResolutionHelper theHelper;
154 
155  std::unique_ptr<TFile> infile(TFile::Open(p_infile.c_str(),"UPDATE"));
156  if (!infile || infile->IsZombie()) {
157  std::cerr << "could not open input file "<<p_infile<<" for updating "<< std::endl;
158  return 1;
159  }
160 
161  int res = postProcessDir(infile.get(), theHelper); // recursively post-process the directory tree, starting from the root.
162  return res;
163 }
164 
165 
166 int main(int argc, char* argv[]) {
167 
168  std::string infile{""};
170  if (argc == 2){
171  infile = argv[1];
172  }
177  else if (argc == 4 && std::string(argv[1]) == std::string{"-f"}){
179  gSystem->CopyFile(argv[3],argv[2],true);
181  infile = argv[2];
182  }
183  else {
184  std::cerr<<" Usage: postProcessIDPVMHistos <File to post-process>"<<std::endl;
185  std::cerr<< " where the file is typically obtained by hadding" << std::endl;
186  std::cerr<< " outputs of several independent IDPVM runs." << std::endl;
187  std::cerr<<" Alternative usage: postProcessIDPVMHistos -f <desired output file name> <File to post-process>"<<std::endl;
188  std::cerr<< " imitates a hadd-like signature for PhysVal merging." << std::endl;
189  return 1;
190  }
192  if (!file_exists(infile)) {
193  std::cerr << "Error: invalid input file: " << infile << std::endl;
194  return 1;
195  }
197  std::cout << " Post-processing file " << infile << "\n" << std::endl;
198  return pproc_file(infile);
199 }
isResolutionHelper
bool isResolutionHelper(TObject *entry)
Definition: postProcessIDPVMHistos.cxx:36
hotSpotInTAG.suffix
string suffix
Definition: hotSpotInTAG.py:185
run.infile
string infile
Definition: run.py:13
IDPVM::ResolutionHelper::makeResolutions
void makeResolutions(const TH2 *h_input2D, TH1 *hwidth, TH1 *hmean, TH1 *hproj[], bool saveProjections, IDPVM::ResolutionHelper::methods theMethod=IDPVM::ResolutionHelper::iterRMS_convergence)
extract 1D resolution plots from a 2D "residual vs observable" histogram.
Definition: InnerDetector/InDetValidation/InDetPhysValMonitoring/src/ResolutionHelper.cxx:382
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:13
python.SystemOfUnits.second
float second
Definition: SystemOfUnits.py:135
postProcessHistos
int postProcessHistos(TObject *resHelper, IDPVM::ResolutionHelper &theHelper)
Definition: postProcessIDPVMHistos.cxx:99
cloneExisting
TH1 * cloneExisting(const std::string &name)
Definition: postProcessIDPVMHistos.cxx:72
pproc_file
int pproc_file(const std::string &p_infile)
Definition: postProcessIDPVMHistos.cxx:151
IDPVM::ResolutionHelper
Definition: InnerDetector/InDetValidation/InDetPhysValMonitoring/InDetPhysValMonitoring/ResolutionHelper.h:28
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
ResolutionHelper.h
getObservableAndResoAndSuffix
std::vector< std::string > getObservableAndResoAndSuffix(const TObject *resHelper)
Definition: postProcessIDPVMHistos.cxx:43
getPullAndResoNames
std::pair< std::string, std::string > getPullAndResoNames(const std::string &type)
Definition: postProcessIDPVMHistos.cxx:86
ParseInputs.gDirectory
gDirectory
Definition: Final2012/ParseInputs.py:133
h
LArCellNtuple.argv
argv
Definition: LArCellNtuple.py:152
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
file_exists
bool file_exists(const string &p_name)
Definition: postProcessIDPVMHistos.cxx:31
DQHistogramMergeRegExp.argc
argc
Definition: DQHistogramMergeRegExp.py:19
main
int main(int argc, char *argv[])
Definition: postProcessIDPVMHistos.cxx:166
beamspotman.dir
string dir
Definition: beamspotman.py:621
GetAllXsec.entry
list entry
Definition: GetAllXsec.py:132
grepfile.sep
sep
Definition: grepfile.py:38
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
DeMoScan.first
bool first
Definition: DeMoScan.py:534
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:801
getResoType
std::string getResoType(const TObject *resHelper)
Definition: postProcessIDPVMHistos.cxx:66
postProcessDir
int postProcessDir(TDirectory *dir, IDPVM::ResolutionHelper &theHelper)
Definition: postProcessIDPVMHistos.cxx:125
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37