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