12 #include <top/modules/TOPModuleT0Calibrator/TOPModuleT0CalibratorModule.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>
53 setDescription(
"Module T0 calibration with dimuons or bhabhas. "
54 "Useful when the geometrical alignment is fine.");
58 addParam(
"numBins", m_numBins,
"number of bins of the search region", 200);
59 addParam(
"timeRange", m_timeRange,
60 "time range in which to search for the minimum [ns]", 10.0);
61 addParam(
"minBkgPerBar", m_minBkgPerBar,
62 "minimal number of background photons per module", 0.0);
63 addParam(
"scaleN0", m_scaleN0,
64 "Scale factor for figure-of-merit N0", 1.0);
65 addParam(
"sigmaSmear", m_sigmaSmear,
66 "sigma in [ns] for additional smearing of PDF", 0.0);
67 addParam(
"sample", m_sample,
68 "sample type: one of dimuon, bhabha or cosmics", std::string(
"dimuon"));
69 addParam(
"minMomentum", m_minMomentum,
70 "minimal track momentum if sample is cosmics", 1.0);
71 addParam(
"deltaEcms", m_deltaEcms,
72 "c.m.s energy window (half size) if sample is dimuon or bhabha", 0.1);
73 addParam(
"dr", m_dr,
"cut on POCA in r", 2.0);
74 addParam(
"dz", m_dz,
"cut on POCA in abs(z)", 4.0);
75 addParam(
"minZ", m_minZ,
76 "minimal local z of extrapolated hit", -130.0);
77 addParam(
"maxZ", m_maxZ,
78 "maximal local z of extrapolated hit", 130.0);
79 addParam(
"outputFileName", m_outFileName,
80 "Root output file name containing calibration results. "
81 "File name can include *'s; "
82 "they will be replaced with a run number from the first input file",
83 std::string(
"moduleT0_r*.root"));
84 addParam(
"pdfOption", m_pdfOption,
85 "PDF option, one of 'rough', 'fine', 'optimal'", std::string(
"rough"));
89 TOPModuleT0CalibratorModule::~TOPModuleT0CalibratorModule()
93 void TOPModuleT0CalibratorModule::initialize()
96 m_digits.isRequired();
97 m_tracks.isRequired();
98 m_extHits.isRequired();
99 m_recBunch.isOptional();
102 m_moduleT0.hasChanged();
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++) {
135 auto pos = m_outFileName.find(
"*");
136 if (pos != std::string::npos) {
138 auto run = std::to_string(evtMetaData->getRun());
139 while (run.size() < 5) run =
"0" + run;
140 while (pos != std::string::npos) {
141 m_outFileName.replace(pos, 1, run);
142 pos = m_outFileName.find(
"*");
147 m_file = TFile::Open(m_outFileName.c_str(),
"RECREATE");
149 B2ERROR(
"Cannot open output file '" << m_outFileName <<
"'");
154 m_hits1D = TH1F(
"numHits",
"Number of photons per slot",
155 c_numModules, 0.5, c_numModules + 0.5);
156 m_hits1D.SetXTitle(
"slot number");
157 m_hits1D.SetYTitle(
"hits per slot");
159 m_hits2D = TH2F(
"timeHits",
"Photon times vs. boardstacks",
160 c_numModules * 4, 0.5, c_numModules + 0.5, 200, 0.0, 20.0);
161 m_hits2D.SetXTitle(
"slot number");
162 m_hits2D.SetYTitle(
"time [ns]");
165 m_tree =
new TTree(
"tree",
"Channel T0 calibration results");
166 m_tree->Branch(
"slot", &m_moduleID);
167 m_tree->Branch(
"numPhotons", &m_numPhotons);
168 m_tree->Branch(
"x", &m_x);
169 m_tree->Branch(
"y", &m_y);
170 m_tree->Branch(
"z", &m_z);
171 m_tree->Branch(
"p", &m_p);
172 m_tree->Branch(
"theta", &m_theta);
173 m_tree->Branch(
"phi", &m_phi);
174 m_tree->Branch(
"r_poca", &m_pocaR);
175 m_tree->Branch(
"z_poca", &m_pocaZ);
176 m_tree->Branch(
"x_poca", &m_pocaX);
177 m_tree->Branch(
"y_poca", &m_pocaY);
178 m_tree->Branch(
"Ecms", &m_cmsE);
179 m_tree->Branch(
"charge", &m_charge);
180 m_tree->Branch(
"PDG", &m_PDG);
184 void TOPModuleT0CalibratorModule::beginRun()
186 if (m_moduleT0.hasChanged()) {
188 B2WARNING(
"ModuleT0 payload has changed. Calibration results may not be correct."
189 <<
LogVar(
"run", evtMetaData->getRun()));
193 void TOPModuleT0CalibratorModule::event()
200 if (m_recBunch.isValid()) {
201 if (!m_recBunch->isReconstructed())
return;
207 double mass = m_selector.getChargedStable().getMass();
208 int pdg = m_selector.getChargedStable().getPDGCode();
209 TOPreco reco(Nhyp, &mass, &pdg, m_minBkgPerBar, m_scaleN0);
211 const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
212 double timeMin = tdc.getTimeMin();
213 double timeMax = tdc.getTimeMax();
217 for (
const auto& digit : m_digits) {
218 if (digit.getHitQuality() == TOPDigit::c_Good)
219 reco.
addData(digit.getModuleID(), digit.getPixelID(), digit.getTime(),
220 digit.getTimeError());
225 if (isRunningOffsetSubtracted()) {
226 B2ERROR(
"Running offset subtracted in TOPDigits: module T0 will not be correct");
231 for (
const auto& track : m_tracks) {
237 if (!m_selector.isSelected(trk))
continue;
241 if (reco.
getFlag() != 1)
continue;
245 if (module >= c_numModules)
continue;
246 int sub = gRandom->Integer(2);
247 auto& finder = m_finders[sub][module];
248 const auto& binCenters = finder.getBinCenters();
249 for (
unsigned ibin = 0; ibin < binCenters.size(); ibin++) {
250 double t0 = binCenters[ibin];
251 finder.add(ibin, -2 * reco.
getLogL(t0, timeMin, timeMax, m_sigmaSmear));
255 for (
const auto& digit : m_digits) {
256 if (digit.getHitQuality() != TOPDigit::c_Good)
continue;
257 if (digit.getModuleID() != trk.
getModuleID())
continue;
258 if (digit.getTime() < timeMin)
continue;
259 if (digit.getTime() > timeMax)
continue;
260 m_hits1D.Fill(digit.getModuleID());
261 int bs = digit.getBoardstackNumber();
262 m_hits2D.Fill((digit.getModuleID() * 4 + bs - 1.5) / 4.0 , digit.getTime());
268 const auto& localPosition = m_selector.getLocalPosition();
269 m_x = localPosition.X();
270 m_y = localPosition.Y();
271 m_z = localPosition.Z();
272 const auto& localMomentum = m_selector.getLocalMomentum();
273 m_p = localMomentum.Mag();
274 m_theta = localMomentum.Theta();
275 m_phi = localMomentum.Phi();
276 const auto& pocaPosition = m_selector.getPOCAPosition();
277 m_pocaR = pocaPosition.Perp();
278 m_pocaZ = pocaPosition.Z();
279 m_pocaX = pocaPosition.X();
280 m_pocaY = pocaPosition.Y();
281 m_cmsE = m_selector.getCMSEnergy();
290 void TOPModuleT0CalibratorModule::endRun()
294 void TOPModuleT0CalibratorModule::terminate()
298 TH1F h_pulls(
"pulls",
"Pulls of the two statistically independent results",
300 h_pulls.SetXTitle(
"pulls");
301 for (
unsigned module = 0; module < c_numModules; module++) {
302 std::vector<double> pos, err;
303 for (
int i = 0; i < 2; i++) {
304 const auto& minimum = m_finders[i][module].getMinimum();
305 if (not minimum.valid)
continue;
306 pos.push_back(minimum.position);
307 err.push_back(minimum.error);
309 if (pos.size() < 2)
continue;
310 double pull = (pos[0] - pos[1]) / sqrt(err[0] * err[0] + err[1] * err[1]);
314 double scaleError = h_pulls.GetRMS();
318 TH1F h_relModuleT0(
"relModuleT0",
"Module T0 relative to calibration",
319 c_numModules, 0.5, c_numModules + 0.5);
320 h_relModuleT0.SetXTitle(
"slot number");
321 h_relModuleT0.SetYTitle(
"module T0 residual [ns]");
323 for (
unsigned module = 0; module < c_numModules; module++) {
324 auto& finder = m_finders[0][module].add(m_finders[1][module]);
325 const auto& minimum = finder.getMinimum();
327 h_relModuleT0.SetBinContent(module + 1, minimum.position);
328 h_relModuleT0.SetBinError(module + 1, minimum.error * scaleError);
330 std::string slotNum = to_string(module + 1);
331 auto h = finder.getHistogram(
"chi2_slot_" + slotNum,
"slot " + slotNum);
334 h_relModuleT0.Write();
337 TH1F h_moduleT0(
"moduleT0",
"Module T0",
338 c_numModules, 0.5, c_numModules + 0.5);
339 h_moduleT0.SetXTitle(
"slot number");
340 h_moduleT0.SetYTitle(
"module T0 [ns]");
344 for (
int slot = 1; slot <= c_numModules; slot++) {
345 if (h_relModuleT0.GetBinError(slot) > 0) {
347 if (m_moduleT0->isCalibrated(slot)) T0 = m_moduleT0->getT0(slot);
348 average += h_relModuleT0.GetBinContent(slot) + T0;
352 if (num > 0) average /= num;
354 for (
int slot = 1; slot <= c_numModules; slot++) {
356 if (m_moduleT0->isCalibrated(slot)) T0 = m_moduleT0->getT0(slot);
357 double t0 = h_relModuleT0.GetBinContent(slot) + T0 - average;
358 double err = h_relModuleT0.GetBinError(slot);
359 h_moduleT0.SetBinContent(slot, t0);
360 h_moduleT0.SetBinError(slot, err);
371 B2RESULT(num <<
"/16 calibrated. Results available in " << m_outFileName);
375 bool TOPModuleT0CalibratorModule::isRunningOffsetSubtracted()
377 for (
const auto& digit : m_digits) {
378 if (digit.hasStatus(TOPDigit::c_BunchOffsetSubtracted))
return true;