Belle II Software  release-05-02-19
TOPAlignerModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2016 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Marko Staric *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Own include
12 #include <top/modules/TOPAligner/TOPAlignerModule.h>
13 #include <top/geometry/TOPGeometryPar.h>
14 #include <top/reconstruction/TOPalign.h>
15 #include <top/reconstruction/TOPtrack.h>
16 #include <top/reconstruction/TOPconfigure.h>
17 
18 // framework - DataStore
19 #include <framework/datastore/StoreArray.h>
20 #include <framework/datastore/StoreObjPtr.h>
21 
22 // framework aux
23 #include <framework/gearbox/Const.h>
24 #include <framework/logging/Logger.h>
25 
26 // analysis
27 #include <analysis/utility/PCmsLabTransform.h>
28 
29 // root
30 #include <TH1F.h>
31 #include <TH2F.h>
32 
33 
34 using namespace std;
35 
36 namespace Belle2 {
41  using namespace TOP;
42 
43  //-----------------------------------------------------------------
44  // Register module
45  //-----------------------------------------------------------------
46 
47  REG_MODULE(TOPAligner)
48 
49 
50  //-----------------------------------------------------------------
51  // Implementation
52  //-----------------------------------------------------------------
53 
55 
56  {
57  // set module description
58  setDescription("Alignment of TOP");
59  // setPropertyFlags(c_ParallelProcessingCertified);
60 
61  // Add parameters
62  addParam("minBkgPerBar", m_minBkgPerBar,
63  "Minimal number of background photons per module", 0.0);
64  addParam("scaleN0", m_scaleN0,
65  "Scale factor for figure-of-merit N0", 1.0);
66  addParam("targetModule", m_targetMid,
67  "Module to be aligned. Must be 1 <= Mid <= 16.", 1);
68  addParam("maxFails", m_maxFails,
69  "Maximum number of consecutive failed iterations before resetting the procedure", 100);
70  addParam("sample", m_sample,
71  "sample type: one of dimuon, bhabha or cosmics", std::string("dimuon"));
72  addParam("minMomentum", m_minMomentum,
73  "minimal track momentum if sample is cosmics", 1.0);
74  addParam("deltaEcms", m_deltaEcms,
75  "c.m.s energy window (half size) if sample is dimuon or bhabha", 0.1);
76  addParam("dr", m_dr, "cut on POCA in r", 2.0);
77  addParam("dz", m_dz, "cut on POCA in abs(z)", 4.0);
78  addParam("minZ", m_minZ,
79  "minimal local z of extrapolated hit", -130.0);
80  addParam("maxZ", m_maxZ,
81  "maximal local z of extrapolated hit", 130.0);
82  addParam("outFileName", m_outFileName,
83  "Root output file name containing alignment results",
84  std::string("TopAlignPars.root"));
85  addParam("stepPosition", m_stepPosition, "step size for translations", 1.0);
86  addParam("stepAngle", m_stepAngle, "step size for rotations", 0.01);
87  addParam("stepTime", m_stepTime, "step size for t0", 0.05);
88  addParam("stepRefind", m_stepRefind,
89  "step size for scaling of refractive index (dn/n)", 0.005);
90  addParam("gridSize", m_gridSize,
91  "size of a 2D grid for time-of-propagation averaging in analytic PDF: "
92  "[number of emission points along track, number of Cerenkov angles]. "
93  "No grid used if list is empty.", m_gridSize);
94  std::string names;
95  for (const auto& parName : m_align.getParameterNames()) names += parName + ", ";
96  names.pop_back();
97  names.pop_back();
98  addParam("parInit", m_parInit,
99  "initial parameter values in the order [" + names + "]. "
100  "If list is too short, the missing ones are set to 0.", m_parInit);
101  auto parFixed = m_parFixed;
102  addParam("parFixed", m_parFixed, "list of names of parameters to be fixed. "
103  "Valid names are: " + names, parFixed);
104 
105  }
106 
107  TOPAlignerModule::~TOPAlignerModule()
108  {
109  }
110 
111  void TOPAlignerModule::initialize()
112  {
113 
114  // check if target module ID is valid
115 
116  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
117  if (!geo->isModuleIDValid(m_targetMid))
118  B2FATAL("Target module ID = " << m_targetMid << " is invalid. Exiting...");
119 
120  // check if sample type is valid
121 
122  if (!(m_sample == "dimuon" or m_sample == "bhabha" or m_sample == "cosmics")) {
123  B2FATAL("Invalid sample type " << m_sample << ". Exiting...");
124  }
125  if (m_sample == "bhabha") m_chargedStable = Const::electron;
126 
127  // set alignment object
128 
129  m_align.setModuleID(m_targetMid);
130  m_align.setSteps(m_stepPosition, m_stepAngle, m_stepTime, m_stepRefind);
131  if (m_gridSize.size() == 2) {
132  m_align.setGrid(m_gridSize[0], m_gridSize[1]);
133  B2INFO("TOPAligner: grid for time-of-propagation averaging is set");
134  }
135  m_align.setParameters(m_parInit);
136  for (const auto& parName : m_parFixed) {
137  m_align.fixParameter(parName);
138  }
139 
140  // configure detector in reconstruction code
141 
142  TOPconfigure config;
143 
144  // input
145 
146  m_digits.isRequired();
147  m_tracks.isRequired();
148  m_extHits.isRequired();
149  m_recBunch.isOptional();
150 
151  // set counter for failed iterations:
152 
153  m_countFails = 0;
154 
155  // open output file
156 
157  m_file = new TFile(m_outFileName.c_str(), "RECREATE");
158  if (m_file->IsZombie()) {
159  B2FATAL("Couldn't open file '" << m_outFileName << "' for writing!");
160  return;
161  }
162 
163  // create output tree
164 
165  m_alignTree = new TTree("alignTree", "TOP alignment results");
166  m_alignTree->Branch("ModuleId", &m_targetMid);
167  m_alignTree->Branch("iter", &m_iter);
168  m_alignTree->Branch("ntrk", &m_ntrk);
169  m_alignTree->Branch("errorCode", &m_errorCode);
170  m_alignTree->Branch("iterPars", &m_vAlignPars);
171  m_alignTree->Branch("iterParsErr", &m_vAlignParsErr);
172  m_alignTree->Branch("valid", &m_valid);
173  m_alignTree->Branch("x", &m_x);
174  m_alignTree->Branch("y", &m_y);
175  m_alignTree->Branch("z", &m_z);
176  m_alignTree->Branch("p", &m_p);
177  m_alignTree->Branch("theta", &m_theta);
178  m_alignTree->Branch("phi", &m_phi);
179  m_alignTree->Branch("r_poca", &m_pocaR);
180  m_alignTree->Branch("z_poca", &m_pocaZ);
181  m_alignTree->Branch("x_poca", &m_pocaX);
182  m_alignTree->Branch("y_poca", &m_pocaY);
183  m_alignTree->Branch("Ecms", &m_cmsE);
184  m_alignTree->Branch("charge", &m_charge);
185  m_alignTree->Branch("PDG", &m_PDG);
186 
187  }
188 
189  void TOPAlignerModule::beginRun()
190  {
191  }
192 
193  void TOPAlignerModule::event()
194  {
195 
196  // check bunch reconstruction status and run alignment:
197  // - if object exists and bunch is found (collision data w/ bunch finder in the path)
198  // - if object doesn't exist (cosmic data and other cases w/o bunch finder)
199 
200  if (m_recBunch.isValid()) {
201  if (!m_recBunch->isReconstructed()) return;
202  }
203 
204  // add photons
205 
206  TOPalign::clearData();
207 
208  for (const auto& digit : m_digits) {
209  if (digit.getHitQuality() == TOPDigit::EHitQuality::c_Good)
210  TOPalign::addData(digit.getModuleID(), digit.getPixelID(), digit.getTime(),
211  digit.getTimeError());
212  }
213 
214  TOPalign::setPhotonYields(m_minBkgPerBar, m_scaleN0);
215 
216  // track-by-track iterations
217 
218  for (const auto& track : m_tracks) {
219 
220  // construct TOPtrack from mdst track
221  TOPtrack trk(&track);
222  if (!trk.isValid()) continue;
223 
224  // skip if track not hitting target module
225  if (trk.getModuleID() != m_targetMid) continue;
226 
227  // track selection
228  if (!selectTrack(trk)) continue;
229 
230  // do an iteration
231  int err = m_align.iterate(trk, m_chargedStable);
232  m_iter++;
233 
234  // check number of consecutive failures, and in case reset
235  if (err == 0) {
236  m_countFails = 0;
237  } else if (m_countFails <= m_maxFails) {
238  m_countFails++;
239  } else {
240  B2INFO("Reached maximum allowed number of failed iterations. "
241  "Resetting TOPalign object");
242  m_align.reset();
243  m_countFails = 0;
244  }
245 
246  // get new parameter values and estimated errors
247  m_vAlignPars = m_align.getParameters();
248  m_vAlignParsErr = m_align.getErrors();
249  m_ntrk = m_align.getNumUsedTracks();
250  m_errorCode = err;
251  m_valid = m_align.isValid();
252 
253  // fill output tree
254  m_alignTree->Fill();
255 
256  // print info
257  TString resMsg = "M= ";
258  resMsg += m_align.getModuleID();
259  resMsg += " ntr=";
260  resMsg += m_ntrk;
261  resMsg += " err=";
262  resMsg += m_errorCode;
263  resMsg += " v=";
264  resMsg += m_align.isValid();
265  for (auto par : m_vAlignPars) {
266  resMsg += " ";
267  resMsg += par;
268  }
269  B2DEBUG(100, resMsg);
270 
271  }
272 
273  }
274 
275 
276  void TOPAlignerModule::endRun()
277  {
278  }
279 
280  void TOPAlignerModule::terminate()
281  {
282 
283  m_file->cd();
284  m_alignTree->Write();
285 
286  TH1F valid("valid", "status valid", 16, 0.5, 16.5);
287  valid.SetXTitle("slot ID");
288  valid.SetBinContent(m_targetMid, m_valid);
289  valid.Write();
290 
291  TH1F ntrk("ntrk", "number of tracks", 16, 0.5, 16.5);
292  ntrk.SetXTitle("slot ID");
293  ntrk.SetBinContent(m_targetMid, m_ntrk);
294  ntrk.Write();
295 
296  std::string name, title;
297  name = "results_slot" + to_string(m_targetMid);
298  title = "alignment parameters, slot " + to_string(m_targetMid);
299  int npar = m_align.getParameters().size();
300  TH1F h0(name.c_str(), title.c_str(), npar, 0, npar);
301  const auto& par = m_align.getParameters();
302  const auto& err = m_align.getErrors();
303  for (int i = 0; i < npar; i++) {
304  h0.SetBinContent(i + 1, par[i]);
305  h0.SetBinError(i + 1, err[i]);
306  }
307  h0.Write();
308 
309  name = "errMatrix_slot" + to_string(m_targetMid);
310  title = "error matrix, slot " + to_string(m_targetMid);
311  TH2F h1(name.c_str(), title.c_str(), npar, 0, npar, npar, 0, npar);
312  const auto& errMatrix = m_align.getErrorMatrix();
313  for (int i = 0; i < npar; i++) {
314  for (int k = 0; k < npar; k++) {
315  h1.SetBinContent(i + 1, k + 1, errMatrix[i + npar * k]);
316  }
317  }
318  h1.Write();
319 
320  name = "corMatrix_slot" + to_string(m_targetMid);
321  title = "correlation matrix, slot " + to_string(m_targetMid);
322  TH2F h2(name.c_str(), title.c_str(), npar, 0, npar, npar, 0, npar);
323  std::vector<double> diag;
324  for (int i = 0; i < npar; i++) {
325  double d = errMatrix[i * (1 + npar)];
326  if (d != 0) d = 1.0 / sqrt(d);
327  diag.push_back(d);
328  }
329  for (int i = 0; i < npar; i++) {
330  for (int k = 0; k < npar; k++) {
331  h2.SetBinContent(i + 1, k + 1, diag[i] * diag[k] * errMatrix[i + npar * k]);
332  }
333  }
334  h2.Write();
335 
336  m_file->Close();
337 
338  if (m_valid) {
339  B2RESULT("TOPAligner: slot = " << m_targetMid << ", status = successful, "
340  << "iterations = " << m_iter << ", tracks used = " << m_ntrk);
341  } else {
342  B2RESULT("TOPAligner: slot = " << m_targetMid << ", status = failed, "
343  << "error code = " << m_errorCode
344  << ", iterations = " << m_iter << ", tracks used = " << m_ntrk);
345  }
346  }
347 
348  bool TOPAlignerModule::selectTrack(const TOP::TOPtrack& trk)
349  {
350 
351  const auto* fit = trk.getTrack()->getTrackFitResultWithClosestMass(m_chargedStable);
352  auto pocaPosition = fit->getPosition();
353  m_pocaR = pocaPosition.Perp();
354  m_pocaZ = pocaPosition.Z();
355  m_pocaX = pocaPosition.X();
356  m_pocaY = pocaPosition.Y();
357  if (m_pocaR > m_dr) return false;
358  if (fabs(m_pocaZ) > m_dz) return false;
359 
360  auto pocaMomentum = fit->getMomentum();
361 
362  if (m_sample == "cosmics") {
363  if (pocaMomentum.Mag() < m_minMomentum) return false;
364  } else {
365  TLorentzVector lorentzLab;
366  lorentzLab.SetXYZM(pocaMomentum.X(), pocaMomentum.Y(), pocaMomentum.Z(),
367  m_chargedStable.getMass());
369  auto lorentzCms = T.labToCms(lorentzLab);
370  m_cmsE = lorentzCms.Energy();
371  double dE = m_cmsE - T.getCMSEnergy() / 2;
372  if (fabs(dE) > m_deltaEcms) return false;
373  }
374 
375  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
376  const auto& module = geo->getModule(m_targetMid);
377  auto position = module.pointToLocal(trk.getPosition());
378  auto momentum = module.momentumToLocal(trk.getMomentum());
379  m_x = position.X();
380  m_y = position.Y();
381  m_z = position.Z();
382  m_p = momentum.Mag();
383  m_theta = momentum.Theta();
384  m_phi = momentum.Phi();
385  m_charge = trk.getCharge();
386  m_PDG = trk.getPDGcode();
387 
388  if (m_z < m_minZ or m_z > m_maxZ) return false;
389 
390  return true;
391  }
392 
394 } // end Belle2 namespace
395 
Belle2::TOP::TOPtrack::getPDGcode
int getPDGcode() const
Return PDG code.
Definition: TOPtrack.h:199
Belle2::PCmsLabTransform::labToCms
static TLorentzVector labToCms(const TLorentzVector &vec)
Transforms Lorentz vector into CM System.
Definition: PCmsLabTransform.cc:15
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::TOP::TOPtrack
Class to hold reconstructed track, interface to fortran.
Definition: TOPtrack.h:42
Belle2::TOPAlignerModule
Alignment of TOP.
Definition: TOPAlignerModule.h:45
Belle2::PCmsLabTransform::getCMSEnergy
double getCMSEnergy() const
Returns CMS energy of e+e- (aka.
Definition: PCmsLabTransform.h:57
Belle2::TOP::TOPtrack::isValid
bool isValid() const
Check if track is properly defined.
Definition: TOPtrack.h:87
Belle2::TOP::TOPtrack::getModuleID
int getModuleID() const
Return module ID.
Definition: TOPtrack.h:217
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::Track::getTrackFitResultWithClosestMass
const TrackFitResult * getTrackFitResultWithClosestMass(const Const::ChargedStable &requestedType) const
Return the track fit for a fit hypothesis with the closest mass.
Definition: Track.cc:70
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::TOP::TOPtrack::getPosition
const TVector3 & getPosition() const
Return spatial position.
Definition: TOPtrack.h:93
Belle2::TOP::TOPconfigure
Configure TOP geometry for reconstruction: provides interface to fortran code.
Definition: TOPconfigure.h:36
Belle2::TOP::TOPtrack::getTrack
const Track * getTrack() const
Return mdst track if this track is constructed from it.
Definition: TOPtrack.h:229
Belle2::TOP::TOPtrack::getMomentum
const TVector3 & getMomentum() const
Return momentum vector.
Definition: TOPtrack.h:99
Belle2::PCmsLabTransform
Class to hold Lorentz transformations from/to CMS and boost vector.
Definition: PCmsLabTransform.h:37
Belle2::TOP::TOPtrack::getCharge
int getCharge() const
Return charge.
Definition: TOPtrack.h:205