Belle II Software  release-05-01-25
TOPChannelT0CalibratorModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2018 - 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/TOPChannelT0Calibrator/TOPChannelT0CalibratorModule.h>
13 #include <top/geometry/TOPGeometryPar.h>
14 #include <top/reconstruction/TOPreco.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 #include <framework/dataobjects/EventMetaData.h>
22 
23 // framework aux
24 #include <framework/gearbox/Const.h>
25 #include <framework/logging/Logger.h>
26 
27 // root
28 #include <TRandom.h>
29 
30 
31 using namespace std;
32 
33 namespace Belle2 {
38  using namespace TOP;
39 
40  //-----------------------------------------------------------------
41  // Register module
42  //-----------------------------------------------------------------
43 
44  REG_MODULE(TOPChannelT0Calibrator)
45 
46  //-----------------------------------------------------------------
47  // Implementation
48  //-----------------------------------------------------------------
49 
51 
52  {
53  // set module description
54  setDescription("Alternative channel T0 calibration with dimuons or bhabhas. "
55  "This module can also be used to check the calibration "
56  "(channel, module and common T0).\n"
57  "Note: after this kind of calibration one cannot do the alignment.");
58  // setPropertyFlags(c_ParallelProcessingCertified);
59 
60  // Add parameters
61  addParam("numBins", m_numBins, "number of bins of the search region", 200);
62  addParam("timeRange", m_timeRange,
63  "time range in which to search for the minimum [ns]", 10.0);
64  addParam("minBkgPerBar", m_minBkgPerBar,
65  "minimal number of background photons per module", 0.0);
66  addParam("scaleN0", m_scaleN0,
67  "Scale factor for figure-of-merit N0", 1.0);
68  addParam("sigmaSmear", m_sigmaSmear,
69  "sigma in [ns] for additional smearing of PDF", 0.0);
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("outputFileName", m_outFileName,
83  "Root output file name containing calibration results. "
84  "File name can include *'s; "
85  "they will be replaced with a run number from the first input file",
86  std::string("calibrationT0_r*.root"));
87  addParam("pdfOption", m_pdfOption,
88  "PDF option, one of 'rough', 'fine', 'optimal'", std::string("rough"));
89 
90  }
91 
92  TOPChannelT0CalibratorModule::~TOPChannelT0CalibratorModule()
93  {
94  }
95 
96  void TOPChannelT0CalibratorModule::initialize()
97  {
98  // input collections
99  m_digits.isRequired();
100  m_tracks.isRequired();
101  m_extHits.isRequired();
102  m_recBunch.isOptional();
103 
104  // Configure TOP detector for reconstruction
105  TOPconfigure config;
106 
107  // Parse PDF option
108  if (m_pdfOption == "rough") {
109  m_PDFOption = TOPreco::c_Rough;
110  } else if (m_pdfOption == "fine") {
111  m_PDFOption = TOPreco::c_Fine;
112  } else if (m_pdfOption == "optimal") {
113  m_PDFOption = TOPreco::c_Optimal;
114  } else {
115  B2ERROR("TOPPDFDebuggerModule: unknown PDF option '" << m_pdfOption << "'");
116  }
117 
118  // set track selector
119  m_selector = TrackSelector(m_sample);
120  m_selector.setMinMomentum(m_minMomentum);
121  m_selector.setDeltaEcms(m_deltaEcms);
122  m_selector.setCutOnPOCA(m_dr, m_dz);
123  m_selector.setCutOnLocalZ(m_minZ, m_maxZ);
124 
125  // minimum finders
126  double tmin = -m_timeRange / 2;
127  double tmax = m_timeRange / 2;
128  for (unsigned i = 0; i < 2; i++) {
129  for (unsigned m = 0; m < c_numModules; m++) {
130  for (unsigned c = 0; c < c_numChannels; c++) {
131  m_finders[i][m][c] = Chi2MinimumFinder1D(m_numBins, tmin, tmax);
132  }
133  }
134  }
135 
136  // if file name includes *'s replace them with a run number
137  auto pos = m_outFileName.find("*");
138  if (pos != std::string::npos) {
139  StoreObjPtr<EventMetaData> evtMetaData;
140  auto run = std::to_string(evtMetaData->getRun());
141  while (run.size() < 5) run = "0" + run;
142  while (pos != std::string::npos) {
143  m_outFileName.replace(pos, 1, run);
144  pos = m_outFileName.find("*");
145  }
146  }
147 
148  // open root file for ntuple and histogram output
149  m_file = TFile::Open(m_outFileName.c_str(), "RECREATE");
150  if (not m_file) {
151  B2ERROR("Cannot open output file '" << m_outFileName << "'");
152  return;
153  }
154 
155  // histograms
156  for (unsigned module = 0; module < c_numModules; module++) {
157  int moduleID = module + 1;
158 
159  std::string slotNum = std::to_string(moduleID);
160  if (moduleID < 10) slotNum = "0" + slotNum;
161 
162  std::string name = "numHits_slot" + slotNum;
163  std::string title = "Number of hits per channel for slot " + slotNum;
164  TH1F h1(name.c_str(), title.c_str(), c_numChannels, 0, c_numChannels);
165  h1.SetXTitle("channel number");
166  h1.SetYTitle("hits per channel");
167  m_hits1D.push_back(h1);
168 
169  name = "timeHits_slot" + slotNum;
170  title = "hit time vs. channel for slot " + slotNum;
171  TH2F h2(name.c_str(), title.c_str(), c_numChannels, 0, c_numChannels,
172  200, 0.0, 20.0);
173  h2.SetXTitle("channel number");
174  h2.SetYTitle("time [ns]");
175  m_hits2D.push_back(h2);
176  }
177 
178  // create output tree
179 
180  m_tree = new TTree("tree", "Channel T0 calibration results");
181  m_tree->Branch("slot", &m_moduleID);
182  m_tree->Branch("numPhotons", &m_numPhotons);
183  m_tree->Branch("x", &m_x);
184  m_tree->Branch("y", &m_y);
185  m_tree->Branch("z", &m_z);
186  m_tree->Branch("p", &m_p);
187  m_tree->Branch("theta", &m_theta);
188  m_tree->Branch("phi", &m_phi);
189  m_tree->Branch("r_poca", &m_pocaR);
190  m_tree->Branch("z_poca", &m_pocaZ);
191  m_tree->Branch("x_poca", &m_pocaX);
192  m_tree->Branch("y_poca", &m_pocaY);
193  m_tree->Branch("Ecms", &m_cmsE);
194  m_tree->Branch("charge", &m_charge);
195  m_tree->Branch("PDG", &m_PDG);
196 
197  }
198 
199  void TOPChannelT0CalibratorModule::beginRun()
200  {
201  }
202 
203  void TOPChannelT0CalibratorModule::event()
204  {
205  /* check bunch reconstruction status and run alignment:
206  - if object exists and bunch is found (collision data w/ bunch finder in the path)
207  - if object doesn't exist (cosmic data and other cases w/o bunch finder)
208  */
209 
210  if (m_recBunch.isValid()) {
211  if (!m_recBunch->isReconstructed()) return;
212  }
213 
214  // create reconstruction object and set various options
215 
216  int Nhyp = 1;
217  double mass = m_selector.getChargedStable().getMass();
218  int pdg = m_selector.getChargedStable().getPDGCode();
219  TOPreco reco(Nhyp, &mass, &pdg, m_minBkgPerBar, m_scaleN0);
220  reco.setPDFoption(m_PDFOption);
221  const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
222  double timeMin = tdc.getTimeMin();
223  double timeMax = tdc.getTimeMax();
224 
225  const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
226 
227  // add photon hits to reconstruction object
228 
229  for (const auto& digit : m_digits) {
230  if (digit.getHitQuality() == TOPDigit::c_Good)
231  reco.addData(digit.getModuleID(), digit.getPixelID(), digit.getTime(),
232  digit.getTimeError());
233  }
234 
235  // loop over reconstructed tracks, make a selection and accumulate log likelihoods
236 
237  for (const auto& track : m_tracks) {
238 
239  // track selection
240  TOPtrack trk(&track);
241  if (!trk.isValid()) continue;
242 
243  if (!m_selector.isSelected(trk)) continue;
244 
245  // run reconstruction
246  reco.reconstruct(trk);
247  if (reco.getFlag() != 1) continue; // track is not in the acceptance of TOP
248 
249  // minimization procedure: accumulate
250  const unsigned module = trk.getModuleID() - 1;
251  if (module >= c_numModules) continue;
252  int sub = gRandom->Integer(2); // generate sub-sample number
253  auto& finders = m_finders[sub][module];
254  const auto& binCenters = finders[0].getBinCenters();
255  for (unsigned ibin = 0; ibin < binCenters.size(); ibin++) {
256  double t0 = binCenters[ibin];
257  std::vector<float> logL;
258  logL.resize(c_numChannels, 0);
259  reco.getLogL(t0, timeMin, timeMax, m_sigmaSmear, logL.data());
260  for (unsigned channel = 0; channel < c_numChannels; channel++) {
261  int pix = chMapper.getPixelID(channel) - 1;
262  finders[channel].add(ibin, -2 * logL[pix]);
263  }
264  }
265 
266  // fill histograms of hits
267  for (const auto& digit : m_digits) {
268  if (digit.getHitQuality() != TOPDigit::c_Good) continue;
269  if (digit.getModuleID() != trk.getModuleID()) continue;
270  if (digit.getTime() < timeMin) continue;
271  if (digit.getTime() > timeMax) continue;
272  auto& h1 = m_hits1D[module];
273  h1.Fill(digit.getChannel());
274  auto& h2 = m_hits2D[module];
275  h2.Fill(digit.getChannel(), digit.getTime());
276  }
277 
278  // fill output tree
279  m_moduleID = trk.getModuleID();
280  m_numPhotons = reco.getNumOfPhotons();
281  const auto& localPosition = m_selector.getLocalPosition();
282  m_x = localPosition.X();
283  m_y = localPosition.Y();
284  m_z = localPosition.Z();
285  const auto& localMomentum = m_selector.getLocalMomentum();
286  m_p = localMomentum.Mag();
287  m_theta = localMomentum.Theta();
288  m_phi = localMomentum.Phi();
289  const auto& pocaPosition = m_selector.getPOCAPosition();
290  m_pocaR = pocaPosition.Perp();
291  m_pocaZ = pocaPosition.Z();
292  m_pocaX = pocaPosition.X();
293  m_pocaY = pocaPosition.Y();
294  m_cmsE = m_selector.getCMSEnergy();
295  m_charge = trk.getCharge();
296  m_PDG = trk.getPDGcode();
297  m_tree->Fill();
298  }
299 
300  }
301 
302 
303  void TOPChannelT0CalibratorModule::endRun()
304  {
305  }
306 
307  void TOPChannelT0CalibratorModule::terminate()
308  {
309 
310  // determine scaling factor for errors from two statistically independent results
311 
312  TH1F h_pulls("pulls", "Pulls of the two statistically independent results",
313  200, -15.0, 15.0);
314  h_pulls.SetXTitle("pulls");
315  for (unsigned module = 0; module < c_numModules; module++) {
316  for (unsigned channel = 0; channel < c_numChannels; channel++) {
317  std::vector<double> pos, err;
318  for (int i = 0; i < 2; i++) {
319  const auto& minimum = m_finders[i][module][channel].getMinimum();
320  if (not minimum.valid) continue;
321  pos.push_back(minimum.position);
322  err.push_back(minimum.error);
323  }
324  if (pos.size() < 2) continue;
325  double pull = (pos[0] - pos[1]) / sqrt(err[0] * err[0] + err[1] * err[1]);
326  h_pulls.Fill(pull);
327  }
328  }
329  h_pulls.Write();
330  double scaleError = h_pulls.GetRMS();
331 
332  // merge two statistically independent finders and store results into histograms
333 
334  for (unsigned module = 0; module < c_numModules; module++) {
335  int moduleID = module + 1;
336 
337  std::string slotNum = std::to_string(moduleID);
338  if (moduleID < 10) slotNum = "0" + slotNum;
339 
340  std::string name = "channelT0_slot" + slotNum;
341  std::string title = "Relative channel T0 for slot " + slotNum;
342  TH1F h_channelT0(name.c_str(), title.c_str(), c_numChannels, 0, c_numChannels);
343  h_channelT0.SetXTitle("channel number");
344  h_channelT0.SetYTitle("relative channel T0 [ns]");
345 
346  for (unsigned channel = 0; channel < c_numChannels; channel++) {
347  auto& finder = m_finders[0][module][channel].add(m_finders[1][module][channel]);
348  const auto& minimum = finder.getMinimum();
349  if (minimum.valid) {
350  h_channelT0.SetBinContent(channel + 1, minimum.position);
351  h_channelT0.SetBinError(channel + 1, minimum.error * scaleError);
352  }
353  }
354 
355  h_channelT0.Write();
356 
357  }
358 
359  // merge all finders of a slot to find module T0
360 
361  TH1F h_moduleT0("moduleT0", "Relative module T0",
362  c_numModules, 0.5, c_numModules + 0.5);
363  h_moduleT0.SetXTitle("slot number");
364  h_moduleT0.SetYTitle("relative module T0 [ns]");
365  auto finderCommon = m_finders[0][0][0];
366  finderCommon.clear();
367  for (unsigned module = 0; module < c_numModules; module++) {
368  auto finder = m_finders[0][module][0];
369  finder.clear();
370  for (unsigned channel = 0; channel < c_numChannels; channel++) {
371  finder.add(m_finders[0][module][channel]);
372  }
373  finderCommon.add(finder);
374  const auto& minimum = finder.getMinimum();
375  if (minimum.valid) {
376  h_moduleT0.SetBinContent(module + 1, minimum.position);
377  h_moduleT0.SetBinError(module + 1, minimum.error * scaleError);
378  }
379  }
380  h_moduleT0.Write();
381 
382  // find common T0
383 
384  TH1F h_commonT0("commonT0", "Relative common T0", 1, 0, 1);
385  h_commonT0.SetYTitle("relative common T0 [ns]");
386  const auto& minimum = finderCommon.getMinimum();
387  if (minimum.valid) {
388  h_commonT0.SetBinContent(1, minimum.position);
389  h_commonT0.SetBinError(1, minimum.error * scaleError);
390  }
391  h_commonT0.Write();
392 
393  // write other histograms and ntuple; close the file
394 
395  for (auto& h : m_hits1D) h.Write();
396  for (auto& h : m_hits2D) h.Write();
397 
398  m_tree->Write();
399  m_file->Close();
400 
401  B2RESULT("Results available in " << m_outFileName);
402  }
403 
404 
406 } // end Belle2 namespace
407 
Belle2::TOPChannelT0CalibratorModule
A module for alternative channel T0 calibration with collision data Note: after this kind of calibrat...
Definition: TOPChannelT0CalibratorModule.h:51
Belle2::TOP::TOPtrack::getPDGcode
int getPDGcode() const
Return PDG code.
Definition: TOPtrack.h:199
Belle2::TOP::TOPreco::getFlag
int getFlag()
Return status.
Definition: TOPreco.cc:278
Belle2::TOP::TOPreco::getNumOfPhotons
int getNumOfPhotons()
Return number of measured photons.
Definition: TOPreco.cc:297
Belle2::TOP::TOPreco::reconstruct
void reconstruct(const TOPtrack &trk, int pdg=0)
Run reconstruction for a given track.
Definition: TOPreco.cc:268
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::TOP::TOPtrack::isValid
bool isValid() const
Check if track is properly defined.
Definition: TOPtrack.h:87
Belle2::TOP::Chi2MinimumFinder1D
Minimum finder using tabulated chi^2 values in one dimension.
Definition: Chi2MinimumFinder1D.h:37
Belle2::TOP::TOPreco::addData
int addData(int moduleID, int pixelID, double time, double timeError)
Add data.
Definition: TOPreco.cc:214
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::TOP::TOPreco
TOP reconstruction: this class provides interface to fortran code.
Definition: TOPreco.h:36
Belle2::TOP::TOPreco::getLogL
double getLogL(int i=0)
Return log likelihood for i-th mass hypothesis.
Definition: TOPreco.cc:303
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
Belle2::TOP::TOPconfigure
Configure TOP geometry for reconstruction: provides interface to fortran code.
Definition: TOPconfigure.h:36
Belle2::TOP::TrackSelector
Utility for the track selection - used in various calibration modules.
Definition: TrackSelector.h:37
Belle2::TOP::TOPtrack::getCharge
int getCharge() const
Return charge.
Definition: TOPtrack.h:205
Belle2::TOP::TOPreco::setPDFoption
void setPDFoption(PDFoption opt, int NP=0, int NC=0)
Sets PDF option.
Definition: TOPreco.cc:196