10 #include <top/modules/TOPBunchFinder/TOPBunchFinderModule.h>
11 #include <top/geometry/TOPGeometryPar.h>
12 #include <top/reconstruction_cpp/TOPTrack.h>
13 #include <top/reconstruction_cpp/PDFConstructor.h>
14 #include <top/reconstruction_cpp/TOPRecoManager.h>
15 #include <top/reconstruction_cpp/PDF1Dim.h>
16 #include <top/utilities/Chi2MinimumFinder1D.h>
19 #include <mdst/dataobjects/TrackFitResult.h>
20 #include <mdst/dataobjects/HitPatternCDC.h>
21 #include <tracking/dataobjects/ExtHit.h>
22 #include <mdst/dataobjects/MCParticle.h>
23 #include <top/dataobjects/TOPBarHit.h>
24 #include <reconstruction/dataobjects/CDCDedxLikelihood.h>
25 #include <reconstruction/dataobjects/VXDDedxLikelihood.h>
26 #include <mdst/dataobjects/PIDLikelihood.h>
29 #include <framework/gearbox/Const.h>
30 #include <framework/logging/Logger.h>
55 setDescription(
"A precise event T0 determination w.r.t local time reference of TOP counter. "
56 "Results available in TOPRecBunch.");
57 setPropertyFlags(c_ParallelProcessingCertified);
60 addParam(
"numBins", m_numBins,
"number of bins of fine search region", 200);
61 addParam(
"timeRangeFine", m_timeRangeFine,
62 "time range in which to do fine search [ns]", 10.0);
63 addParam(
"timeRangeCoarse", m_timeRangeCoarse,
64 "time range in which to do coarse search, if autoRange turned off [ns]", 100.0);
65 addParam(
"autoRange", m_autoRange,
66 "turn on/off automatic determination of the coarse search region (false means off)",
false);
67 addParam(
"sigmaSmear", m_sigmaSmear,
68 "sigma in [ns] for additional smearing of PDF", 0.0);
69 addParam(
"minSignal", m_minSignal,
70 "minimal number of signal photons to accept track", 10.0);
71 addParam(
"minSBRatio", m_minSBRatio,
72 "minimal signal-to-background ratio to accept track", 0.0);
73 addParam(
"minDERatio", m_minDERatio,
74 "minimal ratio of detected-to-expected photons to accept track", 0.2);
75 addParam(
"maxDERatio", m_maxDERatio,
76 "maximal ratio of detected-to-expected photons to accept track", 2.5);
77 addParam(
"minPt", m_minPt,
"minimal p_T of the track", 0.3);
78 addParam(
"maxPt", m_maxPt,
"maximal p_T of the track", 6.0);
79 addParam(
"maxD0", m_maxD0,
"maximal absolute value of helix perigee distance", 2.0);
80 addParam(
"maxZ0", m_maxZ0,
"maximal absolute value of helix perigee z coordinate", 4.0);
81 addParam(
"minNHitsCDC", m_minNHitsCDC,
"minimal number of hits in CDC", 20);
82 addParam(
"useMCTruth", m_useMCTruth,
83 "if true, use MC truth for particle mass instead of the most probable from dEdx",
85 addParam(
"saveHistograms", m_saveHistograms,
86 "if true, save histograms to TOPRecBunch",
false);
87 addParam(
"tau", m_tau,
88 "first order filter time constant [number of events]", 100.0);
89 addParam(
"fineSearch", m_fineSearch,
90 "if true, do fine search with two-dimensional PDF",
true);
91 addParam(
"correctDigits", m_correctDigits,
92 "if true, subtract bunch time in TOPDigits",
true);
93 addParam(
"subtractRunningOffset", m_subtractRunningOffset,
94 "if true and correctDigits = True, subtract running offset in TOPDigits "
95 "when running in HLT mode. It must be set to false when running calibration.",
97 addParam(
"bunchesPerSSTclk", m_bunchesPerSSTclk,
98 "number of bunches per SST clock period", 24);
99 addParam(
"usePIDLikelihoods", m_usePIDLikelihoods,
100 "use PIDLikelihoods instead of DedxLikelihoods (only if run on cdst files)",
105 void TOPBunchFinderModule::initialize()
109 m_topDigits.isRequired();
110 m_topRawDigits.isOptional();
111 m_tracks.isRequired();
114 m_initialParticles.isOptional();
122 if (m_usePIDLikelihoods) {
135 m_recBunch.registerInDataStore();
136 m_timeZeros.registerInDataStore();
137 m_timeZeros.registerRelationTo(extHits);
138 m_eventT0.registerInDataStore();
142 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
143 m_bunchTimeSep = geo->getNominalTDC().getSyncTimeBase() / m_bunchesPerSSTclk;
148 m_priors[11] = 0.062;
149 m_priors[13] = 0.086;
150 m_priors[211] = 0.734;
151 m_priors[321] = 0.106;
152 m_priors[2212] = 0.013;
153 m_priors[1000010020] = 0;
156 for (
const auto& prior : m_priors) s += prior.second;
157 for (
auto& prior : m_priors) prior.second /= s;
159 if (not m_commonT0.isValid()) {
160 B2ERROR(
"Common T0 calibration payload requested but not available");
172 if (m_commonT0->isCalibrated()) {
175 m_runningError = m_commonT0->getT0Error();
176 }
else if (m_commonT0->isRoughlyCalibrated()) {
178 m_runningOffset = m_commonT0->getT0();
179 m_runningError = m_commonT0->getT0Error();
183 m_runningError = m_bunchTimeSep / sqrt(12.0);
187 B2INFO(
"TOPBunchFinder: running in HLT/express reco mode");
189 B2INFO(
"TOPBunchFinder: running in data processing mode");
195 void TOPBunchFinderModule::beginRun()
199 if (not m_commonT0.isValid()) {
200 B2FATAL(
"Common T0 calibration payload requested but not available for run "
201 << evtMetaData->getRun()
202 <<
" of experiment " << evtMetaData->getExperiment());
208 void TOPBunchFinderModule::event()
212 TOPRecoManager::setDefaultTimeWindow();
216 if (not m_recBunch.isValid()) {
219 m_recBunch->clearReconstructed();
223 if (not m_eventT0.isValid()) m_eventT0.create();
227 if (m_initialParticles.isValid()) {
228 double simTime = m_initialParticles->getTime();
229 int simBunchNumber = round(simTime / m_bunchTimeSep);
230 m_recBunch->setSimulated(simBunchNumber, simTime);
235 if (m_topRawDigits.getEntries() > 0) {
236 const auto* rawDigit = m_topRawDigits[0];
237 m_recBunch->setRevo9Counter(rawDigit->getRevo9Counter());
242 const auto& tdc = TOPGeometryPar::Instance()->getGeometry()->getNominalTDC();
243 double timeWindow = m_feSetting->getReadoutWindows() * tdc.getSyncTimeBase() / TOPNominalTDC::c_syncWindows;
249 std::vector<TOPTrack> topTracks;
250 std::vector<PDFConstructor> pdfConstructors;
251 std::vector<PDF1Dim> top1Dpdfs;
252 std::vector<int> numPhotons;
253 std::vector<Chi2MinimumFinder1D> finders;
257 for (
const auto& track : m_tracks) {
259 if (not trk.
isValid())
continue;
262 const auto* fitResult = track.getTrackFitResultWithClosestMass(Const::pion);
264 B2ERROR(
"No TrackFitResult available. Must be a bug somewhere.");
267 if (fitResult->getHitPatternCDC().getNHits() < m_minNHitsCDC)
continue;
268 if (fabs(fitResult->getD0()) > m_maxD0)
continue;
269 if (fabs(fitResult->getZ0()) > m_maxZ0)
continue;
270 auto pt = fitResult->getTransverseMomentum();
271 if (pt < m_minPt or pt > m_maxPt)
continue;
274 auto chargedStable = Const::pion;
279 if (chargedStable == Const::invalidParticle)
continue;
281 chargedStable = getMostProbable(track);
285 PDFConstructor pdfConstructor(trk, chargedStable, PDFConstructor::c_Rough);
286 if (not pdfConstructor.
isValid())
continue;
290 PDF1Dim pdf1d(pdfConstructor, 0.5, timeWindow);
296 double expPhot = expSignal + expBG;
298 if (expSignal < m_minSignal)
continue;
299 if (expSignal < m_minSBRatio * expBG)
continue;
300 if (numPhot < m_minDERatio * expPhot)
continue;
301 if (numPhot > m_maxDERatio * expPhot)
continue;
303 topTracks.push_back(trk);
304 pdfConstructors.push_back(pdfConstructor);
305 top1Dpdfs.push_back(pdf1d);
306 numPhotons.push_back(numPhot);
308 m_recBunch->setNumTracks(numTrk, topTracks.size(), m_nodEdxCount);
309 if (topTracks.empty())
return;
313 double minT0 = -m_timeRangeCoarse / 2;
314 double maxT0 = m_timeRangeCoarse / 2;
316 minT0 = top1Dpdfs[0].getMinT0();
317 maxT0 = top1Dpdfs[0].getMaxT0();
318 for (
const auto& pdf : top1Dpdfs) {
319 minT0 = std::min(minT0, pdf.getMinT0());
320 maxT0 = std::max(maxT0, pdf.getMaxT0());
323 double binSize = top1Dpdfs[0].getBinSize();
324 int numBins = (maxT0 - minT0) / binSize;
325 maxT0 = minT0 + binSize * numBins;
329 for (
const auto& pdf : top1Dpdfs) {
331 auto& finder = finders.back();
332 const auto& bins = finder.getBinCenters();
333 for (
unsigned i = 0; i < bins.size(); i++) {
335 finder.add(i, -2 * pdf.getLogL(t0));
338 auto coarseFinder = finders[0];
339 for (
size_t i = 1; i < finders.size(); i++) {
340 coarseFinder.add(finders[i]);
343 const auto& t0Coarse = coarseFinder.getMinimum();
344 if (m_saveHistograms) {
345 m_recBunch->addHistogram(coarseFinder.getHistogram(
"chi2_coarse_",
346 "coarse T0; t_{0} [ns]; -2 log L"));
348 if (t0Coarse.position < minT0 or t0Coarse.position > maxT0 or not t0Coarse.valid) {
349 B2DEBUG(20,
"Coarse T0 finder: returning invalid or out of range T0");
361 double timeMin = TOPRecoManager::getMinTime() + t0Coarse.position;
362 double timeMax = TOPRecoManager::getMaxTime() + t0Coarse.position;
363 double t0min = t0Coarse.position - m_timeRangeFine / 2;
364 double t0max = t0Coarse.position + m_timeRangeFine / 2;
366 for (
const auto& reco : pdfConstructors) {
368 numPhotons.push_back(0);
369 auto& finder = finders.back();
370 std::set<int> nfotSet;
371 const auto& binCenters = finder.getBinCenters();
372 for (
unsigned i = 0; i < binCenters.size(); i++) {
373 double t0 = binCenters[i];
374 auto LL = reco.getLogL(t0, timeMin, timeMax, m_sigmaSmear);
375 finder.add(i, -2 * LL.logL);
376 if (i == 0) numPhotons.back() = LL.numPhotons;
377 nfotSet.insert(LL.numPhotons);
379 if (nfotSet.size() != 1) B2ERROR(
"Different number of photons used for log likelihood of different time shifts");
382 if (finders.size() == 0)
return;
383 auto finder = finders[0];
384 for (
size_t i = 1; i < finders.size(); i++) {
385 finder.add(finders[i]);
388 const auto& t0Fine = finder.getMinimum();
389 if (m_saveHistograms) {
390 m_recBunch->addHistogram(finder.getHistogram(
"chi2_fine_",
391 "precise T0; t_{0} [ns]; -2 log L"));
393 if (t0Fine.position < t0min or t0Fine.position > t0max or not t0Fine.valid) {
394 B2DEBUG(20,
"Fine T0 finder: returning invalid or out of range T0");
403 int bunchNo = lround(T0.position / m_bunchTimeSep);
404 double offset = T0.position - m_bunchTimeSep * bunchNo;
405 if (not m_commonT0->isCalibrated()) {
406 double deltaOffset = offset - m_runningOffset;
407 if (fabs(deltaOffset + m_bunchTimeSep) < fabs(deltaOffset)) {
408 offset += m_bunchTimeSep;
410 }
else if (fabs(deltaOffset - m_bunchTimeSep) < fabs(deltaOffset)) {
411 offset -= m_bunchTimeSep;
415 double error = T0.error;
419 double tau = 10 + m_success / 2;
420 if (tau > m_tau) tau = m_tau;
421 double a = exp(-1.0 / tau);
422 m_runningOffset = a * m_runningOffset + (1 - a) * offset;
423 double err1 = a * m_runningError;
424 double err2 = (1 - a) * error;
425 m_runningError = sqrt(err1 * err1 + err2 * err2);
429 double bunchTime = bunchNo * m_bunchTimeSep;
430 m_recBunch->setReconstructed(bunchNo, bunchTime, offset, error,
431 m_runningOffset, m_runningError, m_fineSearch);
433 Const::TOP,
"bunchFinder"));
438 if (finders.size() == topTracks.size()) {
439 for (
size_t itrk = 0; itrk < topTracks.size(); itrk++) {
440 const auto& trk = topTracks[itrk];
441 const auto& reco = pdfConstructors[itrk];
442 auto& finder = finders[itrk];
443 const auto& t0trk = finder.getMinimum();
444 auto* timeZero = m_timeZeros.appendNew(trk.getModuleID(),
445 t0trk.position - bunchTime,
446 t0trk.error, numPhotons[itrk]);
447 timeZero->setAssumedMass(reco.getHypothesis().getMass());
448 if (not t0trk.valid) timeZero->setInvalid();
449 timeZero->addRelationTo(trk.getExtHit());
451 if (m_saveHistograms) {
452 std::string num = std::to_string(itrk);
453 auto chi2 = finder.getHistogram(
"chi2_" + num,
454 "precise T0 single track; t_{0} [ns]; -2 log L");
455 auto pdf = top1Dpdfs[itrk].getHistogram(
"pdf1D_" + num,
456 "PDF projected to time axis; time [ns]");
457 TH1F hits((
"hits_" + num).c_str(),
458 "time distribution of hits (t0-subtracted); time [ns]",
459 pdf.GetNbinsX(), pdf.GetXaxis()->GetXmin(), pdf.GetXaxis()->GetXmax());
460 for (
const auto& hit : trk.getSelectedHits()) {
461 hits.Fill(hit.time - t0trk.position);
463 timeZero->setHistograms(chi2, pdf, hits);
470 if (m_correctDigits) {
471 for (
auto& digit : m_topDigits) {
472 digit.subtractT0(bunchTime);
473 digit.addStatus(TOPDigit::c_EventT0Subtracted);
474 if (m_HLTmode and m_subtractRunningOffset) {
475 digit.subtractT0(m_runningOffset);
476 double err = digit.getTimeError();
477 digit.setTimeError(sqrt(err * err + m_runningError * m_runningError));
478 digit.addStatus(TOPDigit::c_BunchOffsetSubtracted);
486 void TOPBunchFinderModule::terminate()
488 B2RESULT(
"TOPBunchFinder: event T0 determined for " << m_success <<
"/"
489 << m_processed <<
" events");
496 std::vector<double> logL;
497 std::vector<double> priors;
499 if (m_usePIDLikelihoods) {
507 for (
const auto& type : Const::chargedStableSet) {
508 logL.push_back(pid->getLogL(type, subset));
509 priors.push_back(m_priors[abs(type.getPDGCode())]);
514 if (not cdcdedx and not vxddedx) {
518 for (
const auto& type : Const::chargedStableSet) {
519 if (cdcdedx and vxddedx) {
520 logL.push_back(cdcdedx->getLogL(type) + vxddedx->getLogL(type));
521 }
else if (cdcdedx) {
522 logL.push_back(cdcdedx->getLogL(type));
524 logL.push_back(vxddedx->getLogL(type));
526 priors.push_back(m_priors[abs(type.getPDGCode())]);
531 auto logL_max = logL[0];
532 for (
auto x : logL) {
533 if (x > logL_max) logL_max = x;
537 std::vector<double> probability(logL.size());
538 for (
unsigned i = 0; i < logL.size(); ++i) {
539 probability[i] = exp(logL[i] - logL_max) * priors[i];
544 for (
unsigned i = 0; i < probability.size(); ++i) {
545 if (probability[i] > probability[i0]) i0 = i;
547 return Const::chargedStableSet.at(i0);
Container for likelihoods obtained by the CDC dE/dx PID (CDCDedxPIDModule).
Provides a type-safe way to pass members of the chargedStableSet set.
A class for sets of detector IDs whose content is limited to restricted set of valid detector IDs.
int getPDG() const
Return PDG code of particle.
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
Accessor to arrays stored in the data store.
Type-safe access to single objects in the data store.
Bunch finder: searches for the bunch crossing where the interaction happened using track-based TOP li...
Minimum finder using tabulated chi^2 values in one dimension.
Binned one dimensional PDF (a projection of PDF to time axis)
double getExpectedSignal() const
Returns expected number of signal photons.
double getExpectedDeltaPhotons() const
Returns expected number of delta-ray photons.
double getExpectedBG() const
Returns expected number of background photons.
int getNumOfPhotons() const
Returns number of photons.
PDF construction and log likelihood determination for a given track and particle hypothesis.
void switchOffDeltaRayPDF() const
Exclude delta-ray PDF in log likelihood calculation.
bool isValid() const
Checks the object status.
Reconstructed track at TOP.
bool isValid() const
Checks if track is successfully constructed.
const TOPBarHit * getBarHit() const
Returns bar hit of MC particle assigned to this track (if any)
const MCParticle * getMCParticle() const
Returns MC particle assigned to this track (if any)
Class that bundles various TrackFitResults.
Container for likelihoods obtained by the VXD dE/dx PID (VXDDedxPIDModule).
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.
Structure for storing the extracted event t0s together with its detector and its uncertainty.