12 #include <top/modules/TOPCommonT0Calibrator/TOPCommonT0CalibratorModule.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(
"Common T0 calibration with dimuons or bhabhas.");
57 addParam(
"numBins", m_numBins,
"number of bins of the search region", 200);
58 addParam(
"timeRange", m_timeRange,
59 "time range in which to search for the minimum [ns]", 10.0);
60 addParam(
"minBkgPerBar", m_minBkgPerBar,
61 "minimal number of background photons per module", 0.0);
62 addParam(
"scaleN0", m_scaleN0,
63 "Scale factor for figure-of-merit N0", 1.0);
64 addParam(
"sigmaSmear", m_sigmaSmear,
65 "sigma in [ns] for additional smearing of PDF", 0.0);
66 addParam(
"sample", m_sample,
67 "sample type: one of dimuon, bhabha or cosmics", std::string(
"dimuon"));
68 addParam(
"minMomentum", m_minMomentum,
69 "minimal track momentum if sample is cosmics", 1.0);
70 addParam(
"deltaEcms", m_deltaEcms,
71 "c.m.s energy window (half size) if sample is dimuon or bhabha", 0.1);
72 addParam(
"dr", m_dr,
"cut on POCA in r", 2.0);
73 addParam(
"dz", m_dz,
"cut on POCA in abs(z)", 4.0);
74 addParam(
"minZ", m_minZ,
75 "minimal local z of extrapolated hit", -130.0);
76 addParam(
"maxZ", m_maxZ,
77 "maximal local z of extrapolated hit", 130.0);
78 addParam(
"outputFileName", m_outFileName,
79 "Root output file name containing calibration results. "
80 "File name can include *'s; "
81 "they will be replaced with a run number from the first input file",
82 std::string(
"commonT0_r*.root"));
83 addParam(
"pdfOption", m_pdfOption,
84 "PDF option, one of 'rough', 'fine', 'optimal'", std::string(
"rough"));
88 TOPCommonT0CalibratorModule::~TOPCommonT0CalibratorModule()
92 void TOPCommonT0CalibratorModule::initialize()
95 m_digits.isRequired();
96 m_tracks.isRequired();
97 m_extHits.isRequired();
98 m_recBunch.isOptional();
105 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
106 m_bunchTimeSep = geo->getNominalTDC().getSyncTimeBase() / 24;
109 if (m_pdfOption ==
"rough") {
110 m_PDFOption = TOPreco::c_Rough;
111 }
else if (m_pdfOption ==
"fine") {
112 m_PDFOption = TOPreco::c_Fine;
113 }
else if (m_pdfOption ==
"optimal") {
114 m_PDFOption = TOPreco::c_Optimal;
116 B2ERROR(
"TOPPDFDebuggerModule: unknown PDF option '" << m_pdfOption <<
"'");
121 m_selector.setMinMomentum(m_minMomentum);
122 m_selector.setDeltaEcms(m_deltaEcms);
123 m_selector.setCutOnPOCA(m_dr, m_dz);
124 m_selector.setCutOnLocalZ(m_minZ, m_maxZ);
127 double tmin = -m_timeRange / 2;
128 double tmax = m_timeRange / 2;
129 for (
unsigned i = 0; i < c_numSets; i++) {
134 auto pos = m_outFileName.find(
"*");
135 if (pos != std::string::npos) {
137 auto run = std::to_string(evtMetaData->getRun());
138 while (run.size() < 5) run =
"0" + run;
139 while (pos != std::string::npos) {
140 m_outFileName.replace(pos, 1, run);
141 pos = m_outFileName.find(
"*");
146 m_file = TFile::Open(m_outFileName.c_str(),
"RECREATE");
148 B2ERROR(
"Cannot open output file '" << m_outFileName <<
"'");
153 m_hits1D = TH1F(
"numHits",
"Number of photons per slot",
154 c_numModules, 0.5, c_numModules + 0.5);
155 m_hits1D.SetXTitle(
"slot number");
156 m_hits1D.SetYTitle(
"hits per slot");
158 m_hits2D = TH2F(
"timeHits",
"Photon times vs. boardstacks",
159 c_numModules * 4, 0.5, c_numModules + 0.5, 200, 0.0, 20.0);
160 m_hits2D.SetXTitle(
"slot number");
161 m_hits2D.SetYTitle(
"time [ns]");
164 m_tree =
new TTree(
"tree",
"Channel T0 calibration results");
165 m_tree->Branch(
"slot", &m_moduleID);
166 m_tree->Branch(
"numPhotons", &m_numPhotons);
167 m_tree->Branch(
"x", &m_x);
168 m_tree->Branch(
"y", &m_y);
169 m_tree->Branch(
"z", &m_z);
170 m_tree->Branch(
"p", &m_p);
171 m_tree->Branch(
"theta", &m_theta);
172 m_tree->Branch(
"phi", &m_phi);
173 m_tree->Branch(
"r_poca", &m_pocaR);
174 m_tree->Branch(
"z_poca", &m_pocaZ);
175 m_tree->Branch(
"x_poca", &m_pocaX);
176 m_tree->Branch(
"y_poca", &m_pocaY);
177 m_tree->Branch(
"Ecms", &m_cmsE);
178 m_tree->Branch(
"charge", &m_charge);
179 m_tree->Branch(
"PDG", &m_PDG);
183 void TOPCommonT0CalibratorModule::beginRun()
187 void TOPCommonT0CalibratorModule::event()
194 if (m_recBunch.isValid()) {
195 if (!m_recBunch->isReconstructed())
return;
201 double mass = m_selector.getChargedStable().getMass();
202 int pdg = m_selector.getChargedStable().getPDGCode();
203 TOPreco reco(Nhyp, &mass, &pdg, m_minBkgPerBar, m_scaleN0);
205 const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
206 double timeMin = tdc.getTimeMin();
207 double timeMax = tdc.getTimeMax();
211 for (
const auto& digit : m_digits) {
212 if (digit.getHitQuality() == TOPDigit::c_Good)
213 reco.
addData(digit.getModuleID(), digit.getPixelID(), digit.getTime(),
214 digit.getTimeError());
219 if (isRunningOffsetSubtracted()) {
220 B2ERROR(
"Running offset subtracted in TOPDigits: common T0 will not be correct");
225 for (
const auto& track : m_tracks) {
231 if (!m_selector.isSelected(trk))
continue;
235 if (reco.
getFlag() != 1)
continue;
238 int sub = gRandom->Integer(c_numSets);
239 auto& finder = m_finders[sub];
240 const auto& binCenters = finder.getBinCenters();
241 for (
unsigned ibin = 0; ibin < binCenters.size(); ibin++) {
242 double t0 = binCenters[ibin];
243 finder.add(ibin, -2 * reco.
getLogL(t0, timeMin, timeMax, m_sigmaSmear));
247 for (
const auto& digit : m_digits) {
248 if (digit.getHitQuality() != TOPDigit::c_Good)
continue;
249 if (digit.getModuleID() != trk.
getModuleID())
continue;
250 if (digit.getTime() < timeMin)
continue;
251 if (digit.getTime() > timeMax)
continue;
252 m_hits1D.Fill(digit.getModuleID());
253 int bs = digit.getBoardstackNumber();
254 m_hits2D.Fill((digit.getModuleID() * 4 + bs - 1.5) / 4.0 , digit.getTime());
260 const auto& localPosition = m_selector.getLocalPosition();
261 m_x = localPosition.X();
262 m_y = localPosition.Y();
263 m_z = localPosition.Z();
264 const auto& localMomentum = m_selector.getLocalMomentum();
265 m_p = localMomentum.Mag();
266 m_theta = localMomentum.Theta();
267 m_phi = localMomentum.Phi();
268 const auto& pocaPosition = m_selector.getPOCAPosition();
269 m_pocaR = pocaPosition.Perp();
270 m_pocaZ = pocaPosition.Z();
271 m_pocaX = pocaPosition.X();
272 m_pocaY = pocaPosition.Y();
273 m_cmsE = m_selector.getCMSEnergy();
282 void TOPCommonT0CalibratorModule::endRun()
286 void TOPCommonT0CalibratorModule::terminate()
291 TH1F h_pulls(
"pulls",
"Pulls of statistically independent results",
293 h_pulls.SetXTitle(
"pulls");
294 std::vector<double> pos, err;
295 for (
int i = 0; i < c_numSets; i++) {
296 const auto& minimum = m_finders[i].getMinimum();
297 if (not minimum.valid)
continue;
298 pos.push_back(minimum.position);
299 err.push_back(minimum.error);
301 for (
unsigned i = 0; i < pos.size(); i++) {
302 for (
unsigned j = i + 1; j < pos.size(); j++) {
303 double pull = (pos[i] - pos[j]) / sqrt(err[i] * err[i] + err[j] * err[j]);
308 double scaleError = 1;
309 if (h_pulls.GetEntries() > 1) scaleError = h_pulls.GetRMS();
313 auto finder = m_finders[0];
314 for (
int i = 1; i < c_numSets; i++) {
315 finder.add(m_finders[i]);
318 TH1F h_relCommonT0(
"relCommonT0",
"relative common T0", 1, 0, 1);
319 h_relCommonT0.SetYTitle(
"common T0 residual [ns]");
320 TH1F h_commonT0(
"commonT0",
"Common T0", 1, 0, 1);
321 h_commonT0.SetYTitle(
"common T0 [ns]");
323 const auto& minimum = finder.getMinimum();
324 auto h = finder.getHistogram(
"chi2",
"chi2");
327 h_relCommonT0.SetBinContent(1, minimum.position);
328 h_relCommonT0.SetBinError(1, minimum.error * scaleError);
329 double T0 = minimum.position;
330 if (m_commonT0->isCalibrated()) T0 += m_commonT0->getT0();
331 T0 -= round(T0 / m_bunchTimeSep) * m_bunchTimeSep;
332 h_commonT0.SetBinContent(1, T0);
333 h_commonT0.SetBinError(1, minimum.error * scaleError);
335 h_relCommonT0.Write();
345 B2RESULT(
"Results available in " << m_outFileName);
348 bool TOPCommonT0CalibratorModule::isRunningOffsetSubtracted()
350 for (
const auto& digit : m_digits) {
351 if (digit.hasStatus(TOPDigit::c_BunchOffsetSubtracted))
return true;