Belle II Software  release-08-01-10
TOPAlignmentAlgorithm.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <top/calibration/TOPAlignmentAlgorithm.h>
10 #include <top/dbobjects/TOPCalModuleAlignment.h>
11 
12 #include <TFile.h>
13 #include <TTree.h>
14 #include <TH1F.h>
15 #include <TH2F.h>
16 
17 #include <string>
18 #include <algorithm>
19 #include <set>
20 
21 using namespace std;
22 
23 namespace Belle2 {
28  namespace TOP {
29 
30  TOPAlignmentAlgorithm::TOPAlignmentAlgorithm():
31  CalibrationAlgorithm("TOPAlignmentCollector")
32  {
33  setDescription("Calibration algorithm for geometrcal alignment of TOP module");
34  }
35 
37  {
38 
39  // get basic histogram
40 
41  auto h1 = getObjectPtr<TH2F>("tracks_per_slot");
42  if (not h1) {
43  B2ERROR("histogram 'tracks_per_slot' not found");
44  return c_Failure;
45  }
46  unsigned numModules = h1->GetNbinsX();
47  unsigned numSets = h1->GetNbinsY();
48 
49  // clear multimap which will hold alignment data from last iterations
50 
51  m_inputData.clear();
52 
53  // get alignment data of last iterations
54 
55  for (unsigned set = 0; set < numSets; set++) {
56 
57  // get ntuple of a given subsample
58 
59  std::string name = "alignTree" + to_string(set);
60  auto alignTree = getObjectPtr<TTree>(name);
61  if (not alignTree) {
62  B2ERROR("TOPAlignmentAlgorithm: 'alignTree' not found");
63  return c_Failure;
64  }
65 
66  alignTree->SetBranchAddress("ModuleId", &m_moduleID);
67  alignTree->SetBranchAddress("iter", &m_iter);
68  alignTree->SetBranchAddress("ntrk", &m_ntrk);
69  alignTree->SetBranchAddress("errorCode", &m_errorCode);
70  alignTree->SetBranchAddress("iterPars", &m_vAlignPars, &m_bAlignPars);
71  alignTree->SetBranchAddress("iterParsErr", &m_vAlignParsErr, &m_bAlignParsErr);
72  alignTree->SetBranchAddress("valid", &m_valid);
73 
74  // get last iteration for each module
75 
76  std::map<int, int> lastIterations;
77  std::map<int, int> lastIterationEntries;
78  for (int i = 0; i < alignTree->GetEntries(); i++) {
79  alignTree->GetEntry(i);
80  if (m_iter > lastIterations[m_moduleID]) {
81  lastIterations[m_moduleID] = m_iter;
82  lastIterationEntries[m_moduleID] = i;
83  }
84  }
85 
86  // store last iteration in a multimap
87 
88  for (const auto& lastIterationEntry : lastIterationEntries) {
89  alignTree->GetEntry(lastIterationEntry.second);
90  if (m_vAlignPars->size() != m_vAlignParsErr->size()) {
91  B2ERROR("slot " << m_moduleID << ", set=" << set <<
92  ": sizes of vectors of alignment parameters and errors differ. "
93  "Entry ignored.");
94  continue;
95  }
96  AlignData data;
97  data.iter = m_iter;
98  data.ntrk = m_ntrk;
99  data.alignPars = *m_vAlignPars;
100  data.alignErrs = *m_vAlignParsErr;
101  data.valid = m_valid;
102  m_inputData.emplace(m_moduleID, data);
103  }
104 
105  }
106 
107  // construct file name, open output root file
108 
109  const auto& expRun = getRunList();
110  string expNo = to_string(expRun[0].first);
111  while (expNo.length() < 4) expNo.insert(0, "0");
112  string runNo = to_string(expRun[0].second);
113  while (runNo.length() < 5) runNo.insert(0, "0");
114  string outputFileName = "alignment-e" + expNo + "-r" + runNo + ".root";
115  auto* file = TFile::Open(outputFileName.c_str(), "recreate");
116 
117  // write control histograms
118 
119  h1->Write();
120  TDirectory* oldDir = gDirectory;
121  for (unsigned slot = 1; slot <= numModules; slot++) {
122  std::string slotName = "_s" + to_string(slot);
123  auto h2 = getObjectPtr<TH1F>("local_z" + slotName);
124  auto h3 = getObjectPtr<TH2F>("cth_vs_p" + slotName);
125  auto h4 = getObjectPtr<TH2F>("poca_xy" + slotName);
126  auto h5 = getObjectPtr<TH1F>("poca_z" + slotName);
127  auto h6 = getObjectPtr<TH1F>("Ecms" + slotName);
128  auto h7 = getObjectPtr<TH1F>("charge" + slotName);
129  auto h8 = getObjectPtr<TH2F>("timeHits" + slotName);
130  auto h9 = getObjectPtr<TH1F>("numPhot" + slotName);
131 
132  std::string name = "slot_" + to_string(slot);
133  oldDir->mkdir(name.c_str())->cd();
134  if (h2) h2->Write();
135  if (h3) h3->Write();
136  if (h4) h4->Write();
137  if (h5) h5->Write();
138  if (h6) h6->Write();
139  if (h7) h7->Write();
140  if (h8) h8->Write();
141  if (h9) h9->Write();
142  oldDir->cd();
143  }
144 
145  // book output histograms
146 
147  auto h_valid = new TH1F("valid", "Valid results",
148  numModules, 0.5, numModules + 0.5);
149  h_valid->SetXTitle("slot number");
150  h_valid->SetYTitle("valid flag");
151 
152  auto h_iter = new TH1F("iterations", "Number of iterations",
153  numModules, 0.5, numModules + 0.5);
154  h_iter->SetXTitle("slot number");
155  h_iter->SetYTitle("iterations");
156 
157  auto h_ntrk = new TH1F("ntrk", "Number of tracks",
158  numModules, 0.5, numModules + 0.5);
159  h_ntrk->SetXTitle("slot number");
160  h_ntrk->SetYTitle("tracks");
161 
162  std::vector<TH1F*> h_params;
163 
164  auto h_x = new TH1F("delta_x", "Displacement in x",
165  numModules, 0.5, numModules + 0.5);
166  h_x->SetXTitle("slot number");
167  h_x->SetYTitle("#Deltax [cm]");
168  h_params.push_back(h_x);
169 
170  auto h_y = new TH1F("delta_y", "Displacement in y",
171  numModules, 0.5, numModules + 0.5);
172  h_y->SetXTitle("slot number");
173  h_y->SetYTitle("#Deltay [cm]");
174  h_params.push_back(h_y);
175 
176  auto h_z = new TH1F("delta_z", "Displacement in z",
177  numModules, 0.5, numModules + 0.5);
178  h_z->SetXTitle("slot number");
179  h_z->SetYTitle("#Deltaz [cm]");
180  h_params.push_back(h_z);
181 
182  auto h_alpha = new TH1F("alpha", "Rotation angle around x",
183  numModules, 0.5, numModules + 0.5);
184  h_alpha->SetXTitle("slot number");
185  h_alpha->SetYTitle("#alpha [rad]");
186  h_params.push_back(h_alpha);
187 
188  auto h_beta = new TH1F("beta", "Rotation angle around y",
189  numModules, 0.5, numModules + 0.5);
190  h_beta->SetXTitle("slot number");
191  h_beta->SetYTitle("#beta [rad]");
192  h_params.push_back(h_beta);
193 
194  auto h_gamma = new TH1F("gamma", "Rotation angle around z",
195  numModules, 0.5, numModules + 0.5);
196  h_gamma->SetXTitle("slot number");
197  h_gamma->SetYTitle("#gamma [rad]");
198  h_params.push_back(h_gamma);
199 
200  auto h_t0 = new TH1F("t0", "Module T0",
201  numModules, 0.5, numModules + 0.5);
202  h_t0->SetXTitle("slot number");
203  h_t0->SetYTitle("t_{0} [ns]");
204  h_params.push_back(h_t0);
205 
206  auto h_refind = new TH1F("dn_n", "Refractive index scale factor",
207  numModules, 0.5, numModules + 0.5);
208  h_refind->SetXTitle("slot number");
209  h_refind->SetYTitle("#Deltan/n");
210  h_params.push_back(h_refind);
211 
212  // create DB object
213 
214  auto* alignment = new TOPCalModuleAlignment();
215 
216  // merge subsamples
217 
218  mergeData();
219 
220  // store merged data in histograms and in DB object
221 
222  for (const auto& element : m_mergedData) {
223  int moduleID = element.first;
224  const auto& data = element.second;
225  h_valid->SetBinContent(moduleID, data.valid);
226  h_iter->SetBinContent(moduleID, data.iter);
227  h_ntrk->SetBinContent(moduleID, data.ntrk);
228  auto vsize = std::min(data.alignPars.size(), data.alignErrs.size());
229  for (unsigned i = 0; i < std::min(h_params.size(), vsize); i++) {
230  h_params[i]->SetBinContent(moduleID, data.alignPars[i]);
231  h_params[i]->SetBinError(moduleID, data.alignErrs[i]);
232  }
233  if (vsize < 6) {
234  B2ERROR("slot " << moduleID <<
235  ": too few alignment parameters found in ntuple, npar = " << vsize);
236  continue;
237  }
238  alignment->setX(moduleID, data.alignPars[0], data.alignErrs[0]);
239  alignment->setY(moduleID, data.alignPars[1], data.alignErrs[1]);
240  alignment->setZ(moduleID, data.alignPars[2], data.alignErrs[2]);
241  alignment->setAlpha(moduleID, data.alignPars[3], data.alignErrs[3]);
242  alignment->setBeta(moduleID, data.alignPars[4], data.alignErrs[4]);
243  alignment->setGamma(moduleID, data.alignPars[5], data.alignErrs[5]);
244  if (data.valid) {
245  alignment->setCalibrated(moduleID);
246  } else {
247  alignment->setUnusable(moduleID);
248  }
249  }
250 
251  // write the results and close the file
252 
253  file->Write();
254  file->Close();
255 
256  // check the results and return if alignment precision is not satisfied
257 
258  if (not alignment->areAllCalibrated()) {
259  B2INFO("Alignment not successful for all slots");
260  delete alignment;
261  return c_NotEnoughData;
262  }
263  if (not alignment->areAllPrecise(m_spatialPrecision, m_angularPrecision)) {
264  B2INFO("Alignment successful but precision worse than required");
265  delete alignment;
266  return c_NotEnoughData;
267  }
268 
269  // otherwise import calibration to DB
270 
271  saveCalibration(alignment);
272 
273  return c_OK;
274  }
275 
276 
278  {
279  // clear the map
280 
281  m_mergedData.clear();
282 
283  // make a list of module ID's
284 
285  std::set<int> slotIDs;
286  for (const auto& element : m_inputData) {
287  slotIDs.insert(element.first);
288  }
289 
290  // book a histogram of pulls
291 
292  auto h_pulls = new TH1F("pulls", "Pulls of statistically independent results",
293  200, -20.0, 20.0);
294  h_pulls->SetXTitle("pulls");
295 
296  // fill pulls
297 
298  for (auto slot : slotIDs) {
299  const auto range = m_inputData.equal_range(slot);
300  std::vector<AlignData> data;
301  for (auto it = range.first; it != range.second; ++it) {
302  data.push_back(it->second);
303  }
304  for (size_t i = 0; i < data.size(); i++) {
305  const auto& pars1 = data[i].alignPars;
306  const auto& errs1 = data[i].alignErrs;
307  for (size_t j = i + 1; j < data.size(); j++) {
308  const auto& pars2 = data[j].alignPars;
309  const auto& errs2 = data[j].alignErrs;
310  for (size_t k = 0; k < std::min(pars1.size(), pars2.size()); k++) {
311  double e1 = errs1[k];
312  double e2 = errs2[k];
313  if (e1 == 0 or e2 == 0) continue;
314  double pull = (pars1[k] - pars2[k]) / sqrt(e1 * e1 + e2 * e2);
315  h_pulls->Fill(pull);
316  }
317  }
318  }
319  }
320 
321  // determine scale factor for errors
322 
323  double scaleFact = 1;
324  if (h_pulls->GetEntries() > 1) scaleFact = h_pulls->GetRMS();
325 
326  // merge data
327 
328  for (auto slot : slotIDs) {
329  const auto range = m_inputData.equal_range(slot);
330  if (range.first == range.second) continue;
331  AlignData mergedData;
332  for (auto it = range.first; it != range.second; ++it) {
333  mergedData.add(it->second);
334  }
335  mergedData.finalize(scaleFact);
336  m_mergedData[slot] = mergedData;
337  }
338 
339  }
340 
341 
343  {
344  iter = std::max(iter, data.iter);
345  ntrk += data.ntrk;
346  if (not data.valid) return;
347 
348  for (size_t i = alignPars.size(); i < data.alignPars.size(); i++) {
349  alignPars.push_back(0);
350  alignErrs.push_back(0);
351  }
352 
353  for (size_t i = 0; i < data.alignPars.size(); i++) {
354  auto e = data.alignErrs[i];
355  if (e == 0) continue;
356  auto wt = 1 / (e * e);
357  alignPars[i] += data.alignPars[i] * wt ;
358  alignErrs[i] += wt ;
359  }
360  valid = true;
361  }
362 
363 
365  {
366  for (size_t i = 0; i < alignPars.size(); i++) {
367  auto wt = alignErrs[i];
368  if (wt == 0) continue;
369  alignPars[i] /= wt;
370  alignErrs[i] = 1 / sqrt(wt) * scaleFact;
371  }
372  }
373 
374 
375  } // end namespace TOP
377 } // end namespace Belle2
Base class for calibration algorithms.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
EResult
The result of calibration.
@ c_OK
Finished successfuly =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
@ c_Failure
Failed =3 in Python.
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
Alignment constants for all 16 modules.
std::vector< float > * m_vAlignPars
alignment parameters
double m_spatialPrecision
required precision of displacements
TBranch * m_bAlignParsErr
branch of error on alignment parameters
std::multimap< int, AlignData > m_inputData
input from ntuples
virtual EResult calibrate() final
algorithm implementation
double m_angularPrecision
required precision of rotation angles
std::vector< float > * m_vAlignParsErr
error on alignment parameters
TBranch * m_bAlignPars
branch of alignment parameters
bool m_valid
true if alignment parameters are valid
int m_errorCode
error code of the alignment procedure
void mergeData()
merge subsamples and rescale errors
std::map< int, AlignData > m_mergedData
merged subsamples
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
void add(const AlignData &data)
Merge another data structure to this one.
bool valid
true if alignment parameters are valid
void finalize(double scaleFact)
Calculate weighted averages and rescale errors.
std::vector< float > alignPars
alignment parameters
std::vector< float > alignErrs
uncertainties on alignment parameters