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>
19 #include <framework/datastore/StoreArray.h>
20 #include <framework/datastore/StoreObjPtr.h>
21 #include <framework/dataobjects/EventMetaData.h>
24 #include <framework/gearbox/Const.h>
25 #include <framework/logging/Logger.h>
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.");
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"));
92 TOPChannelT0CalibratorModule::~TOPChannelT0CalibratorModule()
96 void TOPChannelT0CalibratorModule::initialize()
99 m_digits.isRequired();
100 m_tracks.isRequired();
101 m_extHits.isRequired();
102 m_recBunch.isOptional();
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;
115 B2ERROR(
"TOPPDFDebuggerModule: unknown PDF option '" << m_pdfOption <<
"'");
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);
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++) {
137 auto pos = m_outFileName.find(
"*");
138 if (pos != std::string::npos) {
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(
"*");
149 m_file = TFile::Open(m_outFileName.c_str(),
"RECREATE");
151 B2ERROR(
"Cannot open output file '" << m_outFileName <<
"'");
156 for (
unsigned module = 0; module < c_numModules; module++) {
157 int moduleID = module + 1;
159 std::string slotNum = std::to_string(moduleID);
160 if (moduleID < 10) slotNum =
"0" + slotNum;
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);
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,
173 h2.SetXTitle(
"channel number");
174 h2.SetYTitle(
"time [ns]");
175 m_hits2D.push_back(h2);
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);
199 void TOPChannelT0CalibratorModule::beginRun()
203 void TOPChannelT0CalibratorModule::event()
210 if (m_recBunch.isValid()) {
211 if (!m_recBunch->isReconstructed())
return;
217 double mass = m_selector.getChargedStable().getMass();
218 int pdg = m_selector.getChargedStable().getPDGCode();
219 TOPreco reco(Nhyp, &mass, &pdg, m_minBkgPerBar, m_scaleN0);
221 const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
222 double timeMin = tdc.getTimeMin();
223 double timeMax = tdc.getTimeMax();
225 const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
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());
237 for (
const auto& track : m_tracks) {
243 if (!m_selector.isSelected(trk))
continue;
247 if (reco.
getFlag() != 1)
continue;
251 if (module >= c_numModules)
continue;
252 int sub = gRandom->Integer(2);
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]);
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());
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();
303 void TOPChannelT0CalibratorModule::endRun()
307 void TOPChannelT0CalibratorModule::terminate()
312 TH1F h_pulls(
"pulls",
"Pulls of the two statistically independent results",
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);
324 if (pos.size() < 2)
continue;
325 double pull = (pos[0] - pos[1]) / sqrt(err[0] * err[0] + err[1] * err[1]);
330 double scaleError = h_pulls.GetRMS();
334 for (
unsigned module = 0; module < c_numModules; module++) {
335 int moduleID = module + 1;
337 std::string slotNum = std::to_string(moduleID);
338 if (moduleID < 10) slotNum =
"0" + slotNum;
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]");
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();
350 h_channelT0.SetBinContent(channel + 1, minimum.position);
351 h_channelT0.SetBinError(channel + 1, minimum.error * scaleError);
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];
370 for (
unsigned channel = 0; channel < c_numChannels; channel++) {
371 finder.add(m_finders[0][module][channel]);
373 finderCommon.add(finder);
374 const auto& minimum = finder.getMinimum();
376 h_moduleT0.SetBinContent(module + 1, minimum.position);
377 h_moduleT0.SetBinError(module + 1, minimum.error * scaleError);
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();
388 h_commonT0.SetBinContent(1, minimum.position);
389 h_commonT0.SetBinError(1, minimum.error * scaleError);
395 for (
auto& h : m_hits1D) h.Write();
396 for (
auto& h : m_hits2D) h.Write();
401 B2RESULT(
"Results available in " << m_outFileName);