ATLAS Offline Software
makeHIResponse.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "TChain.h"
6 #include "TChainElement.h"
7 #include "TFile.h"
8 #include "TH1I.h"
9 #include "TH2F.h"
10 #include "TH3F.h"
11 #include "TObjArray.h"
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <cstdio>
16 #include <iostream>
17 #include <memory>
18 #include <unordered_map>
19 #include <vector>
20 #include <string>
21 
25 std::unordered_map<int, std::vector<std::pair<int, int>>> getGRLMap(char *grl) {
26  // get rid of everything except the run numbers and LB ranges
27  // also removes the line with all the runs, so each run number is mentioned only once
28  FILE *runList = popen(Form("grep \"Run\\|LBRange\" %s | grep -v Metadata | grep -v GoodRunsListWriter"
29  " | sed -e's/[<>A-Za-z=\"/]//g' -e 's/^ //g' -e 's/ $//g' -e 's/ */ /g' ",
30  grl),
31  "r");
32 
33  std::unordered_map<int, std::vector<std::pair<int, int>>> grlMap{};
34  int a, LB1 = 0;
35  int currentRun = -1;
36  while (fscanf(runList, "%d", &a) != EOF) {
37  if (a > 100000) {
38  // new run
39  if(LB1 != 0) {
40  std::cout << "Start of a new run " << a << ", but the previous LB range is not closed, LB1 = "
41  << LB1 << "; check the GRL file " << grl << std::endl;
42  }
43  currentRun = a;
44  continue;
45  } else {
46  // LB
47  if (LB1 == 0) {
48  LB1 = a; // starting LB
49  }
50  else {
51  // ending LB
52  grlMap[currentRun].push_back(std::make_pair(LB1, a));
53  LB1 = 0;
54  continue;
55  }
56  }
57  }
58  int status = pclose(runList);
59  if (status == -1) {
60  std::cout << "Error in pclose" << std::endl;
61  }
62  return grlMap;
63 }
64 
67 std::string getFileNamePattern(std::string name, int runNr) {
68  std::string runStr = Form("%d", runNr);
69  size_t position = 0;
70  while ((position = name.find("%d", position)) != std::string::npos) {
71  name.replace(position, 2, runStr);
72  position += runStr.length();
73  }
74  return name;
75 }
76 
77 
88 int main(int argc, char **argv) {
89  if (argc <= 2) {
90  std::cout << "Syntax: " << argv[0] << " GoodRunList.xml /path/to/input/files/first.part. [.second.part [...]]" << std::endl;
91  return -1;
92  }
93 
94  auto grlMap = getGRLMap(argv[1]);
96  // for(auto& run : grlMap)
97  // {
98  // std::cout<<"Run "<<run.first<<", size: "<<run.second.size()<<std::endl;
99  // for(auto& lb : run.second)
100  // {
101  // std::cout<<" LB "<<lb.first<<" "<<lb.second<<std::endl;
102  // }
103  // }
104  if (grlMap.size() == 0) {
105  std::cout << "No runs found, is the GRL file (" << argv[1] << ") correct?" << std::endl;
106  return -1;
107  }
108 
109  std::vector<int> runs;
110  for (auto &run : grlMap) {
111  runs.push_back(run.first);
112  }
113  std::sort(runs.begin(), runs.end());
114 
115  // create run index, since we have all the runs now
116  auto runIndex=std::make_unique<TH1I>("h1_run_index", "h1_run_index", runs.size(), 0, runs.size());
117  for (unsigned int r = 0; r < runs.size(); r++) {
118  runIndex->SetBinContent(r + 1, runs.at(r));
119  }
120 
121  // connect all the parts of the file name with a placeholder for a run number
122  std::string fileNameTemplate="";
123  for(int a = 2; a < argc; ++a) {
124  fileNameTemplate += std::string(argv[a]);
125  if (a != argc-1) {
126  // this will be replaced by a run number
127  fileNameTemplate += std::string("%d");
128  }
129  }
130 
131  std::unique_ptr<TH3F> response;
132  std::unique_ptr<TH3F> offset;
133  std::unique_ptr<TH3F> entries;
134  std::unique_ptr<TH2F> etaPhiMap;
135 
136  // loop over runs
137  for (unsigned int r = 0; r < runs.size(); r++) {
138  int run = runs.at(r);
139  // replace placeholders with the actual run number;
140  std::string fileNamePattern = getFileNamePattern(fileNameTemplate, run);
141 
142  std::unique_ptr<TChain> filesChain = std::make_unique<TChain>("");
143  // "Add" also resolves wildcards, if present
144  filesChain->Add(fileNamePattern.c_str());
145  TObjArray * files = filesChain->GetListOfFiles();
146 
147  if (files->IsEmpty()) {
148  std::cout << "Could not open any file with pattern " << fileNamePattern << ", skipping the run " << run << std::endl;
149  continue;
150  }
151 
152  int filesNum = files->GetEntries();
153  std::cout << "Opened " << filesNum << " file" << (filesNum > 1 ? "s" : "") << " with pattern " << fileNamePattern
154  << ", processing the run " << run << std::endl;
155 
156  std::unique_ptr<TH2F> sums;
157 
158  // for each file matching the pattern
159  TIter next(files);
160  TChainElement * fileEl = 0;
161  while (( fileEl = (TChainElement*)next() )) {
162  std::unique_ptr<TFile> file = std::make_unique<TFile>(fileEl->GetTitle());
163  std::cout << "Processing file " << file->GetName() << std::endl;
164 
165  if (!etaPhiMap) {
166  // when the first file in opened, get the eta-phi mapping
167  etaPhiMap = std::make_unique<TH2F>(*(TH2F*)file->Get<TH2F>("h_etaPhiMapping"));
168  etaPhiMap->SetDirectory(nullptr);
169 
170  // book response and offset once eta-phi mapping is known
171  response =
172  std::make_unique<TH3F>("h3_eta_phi_response", "h3_eta_phi_response",
173  etaPhiMap->GetNbinsX(), etaPhiMap->GetXaxis()->GetXmin(), etaPhiMap->GetXaxis()->GetXmax(),
174  etaPhiMap->GetNbinsY(), etaPhiMap->GetYaxis()->GetXmin(), etaPhiMap->GetYaxis()->GetXmax(),
175  runs.size(), 0, runs.size());
176  response->SetDirectory(nullptr);
177  offset = std::make_unique<TH3F>(*(TH3F*)response->Clone("h3_eta_phi_offset"));
178  offset->SetTitle("h3_eta_phi_offset");
179  offset->SetDirectory(nullptr);
180  entries = std::make_unique<TH3F>(*(TH3F*)response->Clone("h3_eta_phi_entries"));
181  entries->SetTitle("h3_eta_phi_entries");
182  entries->SetDirectory(nullptr);
183  }
184 
185  // for each range of LBs
186  for (auto &lbs : grlMap[run]) {
187  // for each LB in that range
188  for (int lb = lbs.first; lb <= lbs.second; lb++) {
189  std::unique_ptr<TH2F> tmp(file->Get<TH2F>(Form("h_clusterET_fcalET_%d_%d", run, lb)));
190  if (!tmp) {
191  std::cout << "Could not get h_clusterET_fcalET_" << run << "_" << lb << ", skipping this LB, r = "<<r << std::endl;
192  continue;
193  }
194 
195  // merge into a single histogram
196  if (!sums) {
197  sums = std::make_unique<TH2F>(*(TH2F*)tmp->Clone("h_clusterET_fcalET_sum"));
198  sums->SetDirectory(nullptr);
199  }
200  else {
201  sums->Add(tmp.get());
202  }
203  }
204  }
205  }
206 
207  if(!sums)
208  {
209  std::cout << "Could not get any LB, skipping the run " << run <<std::endl;
210  continue;
211  }
212 
213  // for each bin number
214  for (int binID = 1; binID <= sums->GetNbinsX(); binID++) {
215  float numEntries = sums->GetBinContent(binID, 6);
216  if (numEntries == 0) {
217  // skip empty bins - these are most likely under- and overflow bins
218  continue;
219  }
220 
221  int eta, phi, dummy;
222  etaPhiMap->GetBinXYZ(binID - 1, eta, phi, dummy);
223 
224  float sumFCalET = sums->GetBinContent(binID, 1);
225  float sumClusterET = sums->GetBinContent(binID, 2);
226  float sumFCalET2 = sums->GetBinContent(binID, 3);
227  // sumClusterET2 is not needed
228  float sumFCalET_clusterET = sums->GetBinContent(binID, 5);
229 
230  float avgFCalET = sumFCalET / numEntries;
231  float avgClusterET = sumClusterET / numEntries;
232  float delta = sumFCalET2 - 2 * sumFCalET * avgFCalET + numEntries * avgFCalET * avgFCalET;
233  if (delta == 0) {
234  continue;
235  }
236 
237  // response and offset; response is not normalized yet
238  float resp = (sumFCalET_clusterET - sumClusterET * avgFCalET) / delta;
239  float offs = avgClusterET - avgFCalET * resp;
240 
241  if (resp < 0) {
242  resp = 0;
243  }
244 
245  entries->SetBinContent(eta, phi, r + 1, numEntries);
246  response->SetBinContent(eta, phi, r + 1, resp);
247  offset->SetBinContent(eta, phi, r + 1, offs);
248  }
249  }
250 
251  if (!response || !offset) {
252  std::cout << "Could not create response or offset" << std::endl;
253  return -1;
254  }
255 
256  entries->GetXaxis()->SetRangeUser(-1.99,1.99);
257  std::unique_ptr<TH1F> avgEntries((TH1F *)entries->Project3D("z"));
258  avgEntries->Scale(1.0 / ((entries->GetXaxis()->GetLast() - entries->GetXaxis()->GetFirst()+1) * entries->GetNbinsY()));
259  entries->GetXaxis()->SetRange(0,0);
260 
261  // normalize response in phi
262  for (int r = 1; r <= response->GetNbinsZ(); r++) {
263 
264  // use bins with at least 10% of average entries
265  float limitEntries = 0.1 * avgEntries->GetBinContent(r);
266 
267  for (int eta = 1; eta <= response->GetNbinsX(); eta++) {
268  int entr = 0;
269  float sum = 0;
270 
271  for (int phi = 1; phi <= response->GetNbinsY(); phi++) {
272  if (entries->GetBinContent(eta, phi, r) < limitEntries) {
273  // skip this eta-phi bin
274  continue;
275  }
276  sum += response->GetBinContent(eta, phi, r);
277  ++entr;
278  }
279 
280  if(entr > 0) {
281  sum /= entr;
282  }
283  else {
284  sum = 1.0;
285  }
286 
287  for (int phi = 1; phi <= response->GetNbinsY(); phi++) {
288  if (entries->GetBinContent(eta, phi, r) < limitEntries) {
289  response->SetBinContent(eta, phi, r, 1.0);
290  offset->SetBinContent(eta, phi, r, 0.0);
291  } else {
292  float resp = response->GetBinContent(eta, phi, r) / sum;
293  if(std::isnan(resp) || resp<=0.) {
294  resp = 1.0;
295  }
296 
297  response->SetBinContent(eta, phi, r, resp);
298  }
299  }
300  }
301  }
302 
303 
304  // save everything
305  std::unique_ptr<TFile> outFile(TFile::Open("cluster.geo.RESPONSE_OFFSET_RUNINDEX.root", "RECREATE"));
306  runIndex->Write();
307  response->Write();
308  offset->Write();
309 
310  std::cout << "Created output file cluster.geo.RESPONSE_OFFSET_RUNINDEX.root" << std::endl;
311  return 0;
312 }
beamspotman.r
def r
Definition: beamspotman.py:672
beamspotman.lbs
lbs
Definition: beamspotman.py:1150
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:67
response
MDT_Response response
Definition: MDT_ResponseTest.cxx:28
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:83
getGRLMap
std::unordered_map< int, std::vector< std::pair< int, int > > > getGRLMap(char *grl)
Reads the GRL .xml file and creates an unordered map of run numbers and associated LB ranges.
Definition: makeHIResponse.cxx:25
find_tgc_unfilled_channelids.runs
int runs
Definition: find_tgc_unfilled_channelids.py:10
python.TrigEgammaMonitorHelper.TH2F
def TH2F(name, title, nxbins, bins_par2, bins_par3, bins_par4, bins_par5=None, bins_par6=None, path='', **kwargs)
Definition: TrigEgammaMonitorHelper.py:45
grl
Definition: ZLumiScripts/grid/grl.py:1
python.output.AtlRunQueryRoot.runNr
runNr
Definition: AtlRunQueryRoot.py:989
convertTimingResiduals.sum
sum
Definition: convertTimingResiduals.py:55
python.BunchSpacingUtils.lb
lb
Definition: BunchSpacingUtils.py:86
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
LArCellNtuple.argv
argv
Definition: LArCellNtuple.py:152
generateReferenceFile.files
files
Definition: generateReferenceFile.py:12
CalibDbCompareRT.dummy
dummy
Definition: CalibDbCompareRT.py:59
file
TFile * file
Definition: tile_monitor.h:29
run
Definition: run.py:1
DQHistogramMergeRegExp.argc
argc
Definition: DQHistogramMergeRegExp.py:19
DeMoUpdate.tmp
string tmp
Definition: DeMoUpdate.py:1167
main
int main(int argc, char **argv)
This macro reads outputs from "HIClusterGeoFiller.py" and performs a linear regression with prepared ...
Definition: makeHIResponse.cxx:88
DQPostProcessTest.outFile
outFile
Comment Out Those You do not wish to run.
Definition: DQPostProcessTest.py:36
getFileNamePattern
std::string getFileNamePattern(std::string name, int runNr)
Gets a string with "%d" and replaces them with the same run number.
Definition: makeHIResponse.cxx:67
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
a
TList * a
Definition: liststreamerinfos.cxx:10
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
entries
double entries
Definition: listroot.cxx:49
merge.status
status
Definition: merge.py:16
python.TrigEgammaMonitorHelper.TH1F
def TH1F(name, title, nxbins, bins_par2, bins_par3=None, path='', **kwargs)
Definition: TrigEgammaMonitorHelper.py:24