12 #include <top/modules/TOPBunchFinder/TOPBunchFinderModule.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 #include <top/reconstruction/TOP1Dpdf.h>
18 #include <top/utilities/Chi2MinimumFinder1D.h>
21 #include <mdst/dataobjects/Track.h>
22 #include <mdst/dataobjects/TrackFitResult.h>
23 #include <mdst/dataobjects/HitPatternCDC.h>
24 #include <tracking/dataobjects/ExtHit.h>
25 #include <top/dataobjects/TOPDigit.h>
26 #include <mdst/dataobjects/MCParticle.h>
27 #include <top/dataobjects/TOPBarHit.h>
28 #include <reconstruction/dataobjects/CDCDedxLikelihood.h>
29 #include <reconstruction/dataobjects/VXDDedxLikelihood.h>
30 #include <mdst/dataobjects/PIDLikelihood.h>
31 #include <top/dataobjects/TOPRecBunch.h>
34 #include <framework/datastore/StoreArray.h>
35 #include <framework/datastore/StoreObjPtr.h>
38 #include <framework/gearbox/Const.h>
39 #include <framework/logging/Logger.h>
65 setDescription(
"A precise event T0 determination w.r.t local time reference of TOP counter. Results available in TOPRecBunch.");
66 setPropertyFlags(c_ParallelProcessingCertified);
69 addParam(
"numBins", m_numBins,
"number of bins of fine search region", 200);
70 addParam(
"timeRange", m_timeRange,
71 "time range in which to do fine search [ns]", 10.0);
72 addParam(
"sigmaSmear", m_sigmaSmear,
73 "sigma in [ns] for additional smearing of PDF", 0.0);
74 addParam(
"minSignal", m_minSignal,
75 "minimal number of signal photons to accept track", 10.0);
76 addParam(
"minSBRatio", m_minSBRatio,
77 "minimal signal-to-background ratio to accept track", 0.0);
78 addParam(
"minDERatio", m_minDERatio,
79 "minimal ratio of detected-to-expected photons to accept track", 0.4);
80 addParam(
"maxDERatio", m_maxDERatio,
81 "maximal ratio of detected-to-expected photons to accept track", 2.5);
82 addParam(
"minPt", m_minPt,
"minimal p_T of the track", 0.3);
83 addParam(
"maxPt", m_maxPt,
"maximal p_T of the track", 6.0);
84 addParam(
"maxD0", m_maxD0,
"maximal absolute value of helix perigee distance", 2.0);
85 addParam(
"maxZ0", m_maxZ0,
"maximal absolute value of helix perigee z coordinate", 4.0);
86 addParam(
"minNHitsCDC", m_minNHitsCDC,
"minimal number of hits in CDC", 20);
87 addParam(
"useMCTruth", m_useMCTruth,
88 "if true, use MC truth for particle mass instead of the most probable from dEdx",
90 addParam(
"saveHistograms", m_saveHistograms,
91 "if true, save histograms to TOPRecBunch",
false);
92 addParam(
"tau", m_tau,
93 "first order filter time constant [number of events]", 100.0);
94 addParam(
"fineSearch", m_fineSearch,
95 "if true, do fine search with two-dimensional PDF",
true);
96 addParam(
"correctDigits", m_correctDigits,
97 "if true, subtract bunch time in TOPDigits",
true);
98 addParam(
"subtractRunningOffset", m_subtractRunningOffset,
99 "if true and correctDigits = True, subtract running offset in TOPDigits "
100 "when running in HLT mode. It must be set to false when running calibration.",
102 addParam(
"bunchesPerSSTclk", m_bunchesPerSSTclk,
103 "number of bunches per SST clock period", 24);
104 addParam(
"usePIDLikelihoods", m_usePIDLikelihoods,
105 "use PIDLikelihoods instead of DedxLikelihoods (only if run on cdst files)",
110 void TOPBunchFinderModule::initialize()
114 m_topDigits.isRequired();
115 m_topRawDigits.isOptional();
116 m_tracks.isRequired();
118 extHits.isRequired();
119 m_initialParticles.isOptional();
123 mcParticles.isRequired();
125 barHits.isRequired();
127 if (m_usePIDLikelihoods) {
129 pidLikelihoods.isRequired();
132 cdcDedxLikelihoods.isRequired();
134 vxdDedxLikelihoods.isOptional();
140 m_recBunch.registerInDataStore();
141 m_timeZeros.registerInDataStore();
143 m_eventT0.registerInDataStore();
151 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
152 m_bunchTimeSep = geo->getNominalTDC().getSyncTimeBase() / m_bunchesPerSSTclk;
157 m_priors[11] = 0.062;
158 m_priors[13] = 0.086;
159 m_priors[211] = 0.734;
160 m_priors[321] = 0.106;
161 m_priors[2212] = 0.013;
162 m_priors[1000010020] = 0;
165 for (
const auto& prior : m_priors) s += prior.second;
166 for (
auto& prior : m_priors) prior.second /= s;
168 if (not m_commonT0.isValid()) {
169 B2ERROR(
"Common T0 calibration payload requested but not available");
178 if (m_commonT0->isCalibrated()) {
181 m_runningError = m_commonT0->getT0Error();
182 }
else if (m_commonT0->isRoughlyCalibrated()) {
184 m_runningOffset = m_commonT0->getT0();
185 m_runningError = m_commonT0->getT0Error();
189 m_runningError = m_bunchTimeSep / sqrt(12.0);
193 B2INFO(
"TOPBunchFinder: running in HLT/express reco mode");
195 B2INFO(
"TOPBunchFinder: running in data processing mode");
201 void TOPBunchFinderModule::beginRun()
205 if (not m_commonT0.isValid()) {
206 B2FATAL(
"Common T0 calibration payload requested but not available for run "
207 << evtMetaData->getRun()
208 <<
" of experiment " << evtMetaData->getExperiment());
214 void TOPBunchFinderModule::event()
221 if (!m_recBunch.isValid()) {
224 m_recBunch->clearReconstructed();
228 if (!m_eventT0.isValid()) m_eventT0.create();
232 if (m_initialParticles.isValid()) {
233 double simTime = m_initialParticles->getTime();
234 int simBunchNumber = round(simTime / m_bunchTimeSep);
235 m_recBunch->setSimulated(simBunchNumber, simTime);
240 if (m_topRawDigits.getEntries() > 0) {
241 const auto* rawDigit = m_topRawDigits[0];
242 m_recBunch->setRevo9Counter(rawDigit->getRevo9Counter());
248 double pionMass = Const::pion.getMass();
249 int pionPDG = Const::pion.getPDGCode();
250 TOPreco reco(Nhyp, &pionMass, &pionPDG);
255 for (
const auto& digit : m_topDigits) {
256 if (digit.getHitQuality() == TOPDigit::c_Good)
257 reco.
addData(digit.getModuleID(), digit.getPixelID(), digit.getTime(),
258 digit.getTimeError());
265 std::vector<TOPtrack> topTracks;
266 std::vector<double> masses;
267 std::vector<int> pdgCodes;
268 std::vector<TOP1Dpdf> top1Dpdfs;
269 std::vector<int> numPhotons;
270 std::vector<Chi2MinimumFinder1D> finders;
274 for (
const auto& track : m_tracks) {
279 const auto* fitResult = track.getTrackFitResultWithClosestMass(Const::pion);
281 B2ERROR(
"No TrackFitResult available. Must be a bug somewhere.");
284 if (fitResult->getHitPatternCDC().getNHits() < m_minNHitsCDC)
continue;
285 if (fabs(fitResult->getD0()) > m_maxD0)
continue;
286 if (fabs(fitResult->getZ0()) > m_maxZ0)
continue;
287 auto pt = fitResult->getTransverseMomentum();
288 if (pt < m_minPt or pt > m_maxPt)
continue;
299 auto chargedStable = getMostProbable(track);
300 mass = chargedStable.getMass();
301 pdg = chargedStable.getPDGCode();
307 if (reco.
getFlag() != 1)
continue;
316 double expPhot = expSignal + expBG;
318 if (expSignal < m_minSignal)
continue;
319 if (expSignal < m_minSBRatio * expBG)
continue;
320 if (numPhot < m_minDERatio * expPhot)
continue;
321 if (numPhot > m_maxDERatio * expPhot)
continue;
323 topTracks.push_back(trk);
324 masses.push_back(mass);
325 pdgCodes.push_back(pdg);
326 top1Dpdfs.push_back(pdf1d);
329 m_recBunch->setNumTracks(numTrk, topTracks.size(), m_nodEdxCount);
330 if (topTracks.empty())
return;
334 double minT0 = top1Dpdfs[0].getMinT0();
335 double maxT0 = top1Dpdfs[0].getMaxT0();
336 double binSize = top1Dpdfs[0].getBinSize();
337 for (
const auto& pdf : top1Dpdfs) {
338 minT0 = std::min(minT0, pdf.getMinT0());
339 maxT0 = std::max(maxT0, pdf.getMaxT0());
341 int numBins = (maxT0 - minT0) / binSize;
342 maxT0 = minT0 + binSize * numBins;
346 for (
const auto& pdf : top1Dpdfs) {
348 auto& finder = finders.back();
349 const auto& bins = finder.getBinCenters();
350 for (
unsigned i = 0; i < bins.size(); i++) {
352 finder.add(i, -2 * pdf.getLogL(t0));
355 auto roughFinder = finders[0];
356 for (
size_t i = 1; i < finders.size(); i++) {
357 roughFinder.add(finders[i]);
360 const auto& t0Rough = roughFinder.getMinimum();
361 if (m_saveHistograms) {
362 m_recBunch->addHistogram(roughFinder.getHistogram(
"chi2_rough_",
363 "rough T0; t_{0} [ns]; -2 log L"));
365 if (t0Rough.position < minT0 or t0Rough.position > maxT0 or !t0Rough.valid) {
366 B2DEBUG(100,
"Rough T0 finder: returning invalid or out of range T0");
378 const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
379 double timeMin = tdc.getTimeMin() + t0Rough.position;
380 double timeMax = tdc.getTimeMax() + t0Rough.position;
381 double t0min = t0Rough.position - m_timeRange / 2;
382 double t0max = t0Rough.position + m_timeRange / 2;
384 for (
size_t itrk = 0; itrk < topTracks.size(); itrk++) {
386 auto& trk = topTracks[itrk];
387 auto mass = masses[itrk];
388 auto pdg = pdgCodes[itrk];
393 B2ERROR(
"TOPBunchFinder: track is not in the acceptance -> must be a bug");
396 auto& finder = finders.back();
397 const auto& binCenters = finder.getBinCenters();
398 for (
unsigned i = 0; i < binCenters.size(); i++) {
399 double t0 = binCenters[i];
400 finder.add(i, -2 * reco.
getLogL(t0, timeMin, timeMax, m_sigmaSmear));
404 if (finders.size() == 0)
return;
405 auto finder = finders[0];
406 for (
size_t i = 1; i < finders.size(); i++) {
407 finder.add(finders[i]);
410 const auto& t0Fine = finder.getMinimum();
411 if (m_saveHistograms) {
412 m_recBunch->addHistogram(finder.getHistogram(
"chi2_fine_",
413 "precise T0; t_{0} [ns]; -2 log L"));
415 if (t0Fine.position < t0min or t0Fine.position > t0max or !t0Fine.valid) {
416 B2DEBUG(100,
"Fine T0 finder: returning invalid or out of range T0");
425 int bunchNo = lround(T0.position / m_bunchTimeSep);
426 double offset = T0.position - m_bunchTimeSep * bunchNo;
427 if (not m_commonT0->isCalibrated()) {
428 double deltaOffset = offset - m_runningOffset;
429 if (fabs(deltaOffset + m_bunchTimeSep) < fabs(deltaOffset)) {
430 offset += m_bunchTimeSep;
432 }
else if (fabs(deltaOffset - m_bunchTimeSep) < fabs(deltaOffset)) {
433 offset -= m_bunchTimeSep;
437 double error = T0.error;
441 double tau = 10 + m_success / 2;
442 if (tau > m_tau) tau = m_tau;
443 double a = exp(-1.0 / tau);
444 m_runningOffset = a * m_runningOffset + (1 - a) * offset;
445 double err1 = a * m_runningError;
446 double err2 = (1 - a) * error;
447 m_runningError = sqrt(err1 * err1 + err2 * err2);
451 double bunchTime = bunchNo * m_bunchTimeSep;
452 m_recBunch->setReconstructed(bunchNo, bunchTime, offset, error,
453 m_runningOffset, m_runningError, m_fineSearch);
455 Const::TOP,
"bunchFinder"));
460 if (finders.size() == topTracks.size()) {
461 for (
size_t itrk = 0; itrk < topTracks.size(); itrk++) {
462 const auto& trk = topTracks[itrk];
463 auto& finder = finders[itrk];
464 const auto& t0trk = finder.getMinimum();
465 auto* timeZero = m_timeZeros.appendNew(trk.getModuleID(),
466 t0trk.position - bunchTime,
467 t0trk.error, numPhotons[itrk]);
468 timeZero->setAssumedMass(masses[itrk]);
469 if (not t0trk.valid) timeZero->setInvalid();
470 timeZero->addRelationTo(trk.getExtHit());
472 if (m_saveHistograms) {
473 std::string num = std::to_string(itrk);
474 auto chi2 = finder.getHistogram(
"chi2_" + num,
475 "precise T0 single track; t_{0} [ns]; -2 log L");
476 auto pdf = top1Dpdfs[itrk].getHistogram(
"pdf1D_" + num,
477 "PDF projected to time axis; time [ns]");
478 TH1F hits((
"hits_" + num).c_str(),
479 "time distribution of hits (t0-subtracted); time [ns]",
480 pdf.GetNbinsX(), pdf.GetXaxis()->GetXmin(), pdf.GetXaxis()->GetXmax());
481 for (
const auto& digit : m_topDigits) {
482 if (digit.getModuleID() != trk.getModuleID())
continue;
483 if (digit.getHitQuality() != TOPDigit::c_Good)
continue;
484 hits.Fill(digit.getTime() - t0trk.position);
486 timeZero->setHistograms(chi2, pdf, hits);
493 if (m_correctDigits) {
494 for (
auto& digit : m_topDigits) {
495 digit.subtractT0(bunchTime);
496 digit.addStatus(TOPDigit::c_EventT0Subtracted);
497 if (m_HLTmode and m_subtractRunningOffset) {
498 digit.subtractT0(m_runningOffset);
499 double err = digit.getTimeError();
500 digit.setTimeError(sqrt(err * err + m_runningError * m_runningError));
501 digit.addStatus(TOPDigit::c_BunchOffsetSubtracted);
509 void TOPBunchFinderModule::terminate()
511 B2RESULT(
"TOPBunchFinder: event T0 determined for " << m_success <<
"/"
512 << m_processed <<
" events");
519 std::vector<double> logL;
520 std::vector<double> priors;
522 if (m_usePIDLikelihoods) {
530 for (
const auto& type : Const::chargedStableSet) {
531 logL.push_back(pid->getLogL(type, subset));
532 priors.push_back(m_priors[abs(type.getPDGCode())]);
537 if (!cdcdedx and !vxddedx) {
541 for (
const auto& type : Const::chargedStableSet) {
542 if (cdcdedx and vxddedx) {
543 logL.push_back(cdcdedx->getLogL(type) + vxddedx->getLogL(type));
544 }
else if (cdcdedx) {
545 logL.push_back(cdcdedx->getLogL(type));
547 logL.push_back(vxddedx->getLogL(type));
549 priors.push_back(m_priors[abs(type.getPDGCode())]);
554 auto logL_max = logL[0];
555 for (
auto x : logL) {
556 if (x > logL_max) logL_max = x;
560 std::vector<double> probability(logL.size());
561 for (
unsigned i = 0; i < logL.size(); ++i) {
562 probability[i] = exp(logL[i] - logL_max) * priors[i];
567 for (
unsigned i = 0; i < probability.size(); ++i) {
568 if (probability[i] > probability[i0]) i0 = i;
570 return Const::chargedStableSet.at(i0);