9 #include <top/modules/TOPModuleT0Calibrator/TOPModuleT0CalibratorModule.h>
10 #include <top/reconstruction_cpp/TOPTrack.h>
11 #include <top/reconstruction_cpp/PDFConstructor.h>
12 #include <top/reconstruction_cpp/TOPRecoManager.h>
13 #include <framework/dataobjects/EventMetaData.h>
14 #include <framework/logging/Logger.h>
40 setDescription(
"Module T0 calibration with dimuons or bhabhas. "
41 "Useful when the geometrical alignment is fine.");
45 addParam(
"numBins", m_numBins,
"number of bins of the search region", 200);
46 addParam(
"timeRange", m_timeRange,
47 "time range in which to search for the minimum [ns]", 10.0);
48 addParam(
"sigmaSmear", m_sigmaSmear,
49 "sigma in [ns] for additional smearing of PDF", 0.0);
50 addParam(
"sample", m_sample,
51 "sample type: one of dimuon, bhabha or cosmics", std::string(
"dimuon"));
52 addParam(
"minMomentum", m_minMomentum,
53 "minimal track momentum if sample is cosmics", 1.0);
54 addParam(
"deltaEcms", m_deltaEcms,
55 "c.m.s energy window (half size) if sample is dimuon or bhabha", 0.1);
56 addParam(
"dr", m_dr,
"cut on POCA in r", 2.0);
57 addParam(
"dz", m_dz,
"cut on POCA in abs(z)", 4.0);
58 addParam(
"minZ", m_minZ,
59 "minimal local z of extrapolated hit", -130.0);
60 addParam(
"maxZ", m_maxZ,
61 "maximal local z of extrapolated hit", 130.0);
62 addParam(
"outputFileName", m_outFileName,
63 "Root output file name containing calibration results. "
64 "File name can include *'s; "
65 "they will be replaced with a run number from the first input file",
66 std::string(
"moduleT0_r*.root"));
67 addParam(
"pdfOption", m_pdfOption,
68 "PDF option, one of 'rough', 'fine', 'optimal'", std::string(
"rough"));
72 void TOPModuleT0CalibratorModule::initialize()
75 m_digits.isRequired();
76 m_tracks.isRequired();
77 m_extHits.isRequired();
78 m_recBunch.isOptional();
81 m_moduleT0.hasChanged();
84 if (m_pdfOption ==
"rough") {
85 m_PDFOption = PDFConstructor::c_Rough;
86 }
else if (m_pdfOption ==
"fine") {
87 m_PDFOption = PDFConstructor::c_Fine;
88 }
else if (m_pdfOption ==
"optimal") {
89 m_PDFOption = PDFConstructor::c_Optimal;
91 B2ERROR(
"TOPPDFDebuggerModule: unknown PDF option '" << m_pdfOption <<
"'");
96 m_selector.setMinMomentum(m_minMomentum);
97 m_selector.setDeltaEcms(m_deltaEcms);
98 m_selector.setCutOnPOCA(m_dr, m_dz);
99 m_selector.setCutOnLocalZ(m_minZ, m_maxZ);
102 double tmin = -m_timeRange / 2;
103 double tmax = m_timeRange / 2;
104 for (
unsigned i = 0; i < 2; i++) {
105 for (
unsigned m = 0; m < c_numModules; m++) {
111 auto pos = m_outFileName.find(
"*");
112 if (pos != std::string::npos) {
114 auto run = std::to_string(evtMetaData->getRun());
115 while (run.size() < 5) run =
"0" + run;
116 while (pos != std::string::npos) {
117 m_outFileName.replace(pos, 1, run);
118 pos = m_outFileName.find(
"*");
123 m_file = TFile::Open(m_outFileName.c_str(),
"RECREATE");
125 B2ERROR(
"Cannot open output file '" << m_outFileName <<
"'");
130 m_hits1D = TH1F(
"numHits",
"Number of photons per slot",
131 c_numModules, 0.5, c_numModules + 0.5);
132 m_hits1D.SetXTitle(
"slot number");
133 m_hits1D.SetYTitle(
"hits per slot");
135 m_hits2D = TH2F(
"timeHits",
"Photon times vs. boardstacks",
136 c_numModules * 4, 0.5, c_numModules + 0.5, 200, 0.0, 20.0);
137 m_hits2D.SetXTitle(
"slot number");
138 m_hits2D.SetYTitle(
"time [ns]");
141 m_tree =
new TTree(
"tree",
"Channel T0 calibration results");
142 m_tree->Branch(
"slot", &m_moduleID);
143 m_tree->Branch(
"numPhotons", &m_numPhotons);
144 m_tree->Branch(
"x", &m_x);
145 m_tree->Branch(
"y", &m_y);
146 m_tree->Branch(
"z", &m_z);
147 m_tree->Branch(
"p", &m_p);
148 m_tree->Branch(
"theta", &m_theta);
149 m_tree->Branch(
"phi", &m_phi);
150 m_tree->Branch(
"r_poca", &m_pocaR);
151 m_tree->Branch(
"z_poca", &m_pocaZ);
152 m_tree->Branch(
"x_poca", &m_pocaX);
153 m_tree->Branch(
"y_poca", &m_pocaY);
154 m_tree->Branch(
"Ecms", &m_cmsE);
155 m_tree->Branch(
"charge", &m_charge);
156 m_tree->Branch(
"PDG", &m_PDG);
160 void TOPModuleT0CalibratorModule::beginRun()
162 if (m_moduleT0.hasChanged()) {
164 B2WARNING(
"ModuleT0 payload has changed. Calibration results may not be correct."
165 <<
LogVar(
"run", evtMetaData->getRun()));
169 void TOPModuleT0CalibratorModule::event()
176 if (m_recBunch.isValid()) {
177 if (not m_recBunch->isReconstructed())
return;
180 TOPRecoManager::setDefaultTimeWindow();
181 double timeMin = TOPRecoManager::getMinTime();
182 double timeMax = TOPRecoManager::getMaxTime();
186 if (isRunningOffsetSubtracted()) {
187 B2ERROR(
"Running offset subtracted in TOPDigits: module T0 will not be correct");
192 for (
const auto& track : m_tracks) {
196 if (not trk.
isValid())
continue;
198 if (not m_selector.isSelected(trk))
continue;
201 PDFConstructor pdfConstructor(trk, m_selector.getChargedStable(), m_PDFOption);
202 if (not pdfConstructor.
isValid())
continue;
206 if (module >= c_numModules)
continue;
207 int sub = gRandom->Integer(2);
208 auto& finder = m_finders[sub][module];
209 const auto& binCenters = finder.getBinCenters();
210 for (
unsigned ibin = 0; ibin < binCenters.size(); ibin++) {
211 double t0 = binCenters[ibin];
212 finder.add(ibin, -2 * pdfConstructor.
getLogL(t0, m_sigmaSmear).
logL);
217 for (
const auto& digit : m_digits) {
218 if (digit.getHitQuality() != TOPDigit::c_Good)
continue;
219 if (digit.getModuleID() != trk.
getModuleID())
continue;
220 if (digit.getTime() < timeMin)
continue;
221 if (digit.getTime() > timeMax)
continue;
223 m_hits1D.Fill(digit.getModuleID());
224 int bs = digit.getBoardstackNumber();
225 m_hits2D.Fill((digit.getModuleID() * 4 + bs - 1.5) / 4.0 , digit.getTime());
230 const auto& localPosition = m_selector.getLocalPosition();
231 m_x = localPosition.X();
232 m_y = localPosition.Y();
233 m_z = localPosition.Z();
234 const auto& localMomentum = m_selector.getLocalMomentum();
235 m_p = localMomentum.Mag();
236 m_theta = localMomentum.Theta();
237 m_phi = localMomentum.Phi();
238 const auto& pocaPosition = m_selector.getPOCAPosition();
239 m_pocaR = pocaPosition.Perp();
240 m_pocaZ = pocaPosition.Z();
241 m_pocaX = pocaPosition.X();
242 m_pocaY = pocaPosition.Y();
243 m_cmsE = m_selector.getCMSEnergy();
252 void TOPModuleT0CalibratorModule::terminate()
256 TH1F h_pulls(
"pulls",
"Pulls of the two statistically independent results",
258 h_pulls.SetXTitle(
"pulls");
259 for (
unsigned module = 0; module < c_numModules; module++) {
260 std::vector<double> pos, err;
261 for (
int i = 0; i < 2; i++) {
262 const auto& minimum = m_finders[i][module].getMinimum();
263 if (not minimum.valid)
continue;
264 pos.push_back(minimum.position);
265 err.push_back(minimum.error);
267 if (pos.size() < 2)
continue;
268 double pull = (pos[0] - pos[1]) / sqrt(err[0] * err[0] + err[1] * err[1]);
272 double scaleError = h_pulls.GetRMS();
276 TH1F h_relModuleT0(
"relModuleT0",
"Module T0 relative to calibration",
277 c_numModules, 0.5, c_numModules + 0.5);
278 h_relModuleT0.SetXTitle(
"slot number");
279 h_relModuleT0.SetYTitle(
"module T0 residual [ns]");
281 for (
unsigned module = 0; module < c_numModules; module++) {
282 auto& finder = m_finders[0][module].add(m_finders[1][module]);
283 const auto& minimum = finder.getMinimum();
285 h_relModuleT0.SetBinContent(module + 1, minimum.position);
286 h_relModuleT0.SetBinError(module + 1, minimum.error * scaleError);
288 std::string slotNum = to_string(module + 1);
289 auto h = finder.getHistogram(
"chi2_slot_" + slotNum,
"slot " + slotNum);
292 h_relModuleT0.Write();
295 TH1F h_moduleT0(
"moduleT0",
"Module T0",
296 c_numModules, 0.5, c_numModules + 0.5);
297 h_moduleT0.SetXTitle(
"slot number");
298 h_moduleT0.SetYTitle(
"module T0 [ns]");
302 for (
int slot = 1; slot <= c_numModules; slot++) {
303 if (h_relModuleT0.GetBinError(slot) > 0) {
305 if (m_moduleT0->isCalibrated(slot)) T0 = m_moduleT0->getT0(slot);
306 average += h_relModuleT0.GetBinContent(slot) + T0;
310 if (num > 0) average /= num;
312 for (
int slot = 1; slot <= c_numModules; slot++) {
314 if (m_moduleT0->isCalibrated(slot)) T0 = m_moduleT0->getT0(slot);
315 double t0 = h_relModuleT0.GetBinContent(slot) + T0 - average;
316 double err = h_relModuleT0.GetBinError(slot);
317 h_moduleT0.SetBinContent(slot, t0);
318 h_moduleT0.SetBinError(slot, err);
329 B2RESULT(num <<
"/16 calibrated. Results available in " << m_outFileName);
333 bool TOPModuleT0CalibratorModule::isRunningOffsetSubtracted()
335 for (
const auto& digit : m_digits) {
336 if (digit.hasStatus(TOPDigit::c_BunchOffsetSubtracted))
return true;
Type-safe access to single objects in the data store.
A module for module T0 calibration with collision data (dimuons or bhabhas) Useful when the geometric...
Minimum finder using tabulated chi^2 values in one dimension.
PDF construction and log likelihood determination for a given track and particle hypothesis.
LogL getLogL() const
Returns extended log likelihood (using the default time window)
bool isValid() const
Checks the object status.
Reconstructed track at TOP.
int getPDGCode() const
Returns PDG code of associated MCParticle (returns 0 if none)
double getCharge() const
Returns charge.
bool isValid() const
Checks if track is successfully constructed.
int getModuleID() const
Returns slot ID.
Utility for the track selection - used in various calibration modules.
Class to store variables with their name which were sent to the logging service.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.
double logL
extended log likelihood