ATLAS Offline Software
Functions
makeHIResponse.cxx File Reference
#include "TChain.h"
#include "TChainElement.h"
#include "TFile.h"
#include "TH1I.h"
#include "TH2F.h"
#include "TH3F.h"
#include "TObjArray.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
#include <string>

Go to the source code of this file.

Functions

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. More...
 
std::string getFileNamePattern (std::string name, int runNr)
 Gets a string with "%d" and replaces them with the same run number. More...
 
int main (int argc, char **argv)
 This macro reads outputs from "HIClusterGeoFiller.py" and performs a linear regression with prepared values. More...
 

Function Documentation

◆ getFileNamePattern()

std::string getFileNamePattern ( std::string  name,
int  runNr 
)

Gets a string with "%d" and replaces them with the same run number.

It's effectively "Form(...)" that works for an unknown number of placeholders

Definition at line 67 of file makeHIResponse.cxx.

67  {
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 }

◆ 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.

Parameters
grlPath to the GRL .xml file
Returns
unordered map of run numbers (as keys) and vectors of LB ranges (as values)

Definition at line 25 of file makeHIResponse.cxx.

25  {
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 }

◆ main()

int main ( int  argc,
char **  argv 
)

This macro reads outputs from "HIClusterGeoFiller.py" and performs a linear regression with prepared values.

The input file names shall contain the run number. There has to be one file per run; ideally, every run mentioned in the GRL has its corresponding file and every LB mentioned in the GRL has its corresponding histogram in that file. The slope and intercept of the linear regression are written to an output files as response and offset. Response values are normalized to unity along the phi angle, i.e. in each eta slice. In the final root weight file, there are also histograms "h3_w", "h3_eta", "h3_phi", and "h3_R". These are produced by "HICaloGeoExtract.py".

Parameters
argv[1]Path to the GRL .xml file
argv[2],argv[3],...Parts of the path to the input files; blanks are filled with the run number
Returns
Technically integer, practically "cluster.geo.RESPONSE_OFFSET_RUNINDEX.root" file with response, offset, and run index

Definition at line 88 of file makeHIResponse.cxx.

88  {
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
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
std::sort
void sort(typename std::reverse_iterator< DataModel_detail::iterator< DVL > > beg, typename std::reverse_iterator< DataModel_detail::iterator< DVL > > end, const Compare &comp)
Specialization of sort for DataVector/List.
Definition: DVL_algorithms.h:623
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