10 #include <framework/core/HistoModule.h>
13 #include <top/modules/TOPDQM/TOPDQMModule.h>
14 #include <top/geometry/TOPGeometryPar.h>
17 #include <framework/datastore/StoreArray.h>
18 #include <framework/datastore/StoreObjPtr.h>
21 #include <framework/gearbox/Unit.h>
22 #include <framework/gearbox/Const.h>
23 #include <framework/logging/Logger.h>
26 #include <top/dataobjects/TOPDigit.h>
27 #include <top/dataobjects/TOPPull.h>
28 #include <top/dataobjects/TOPLikelihood.h>
29 #include <mdst/dataobjects/Track.h>
33 #include "TDirectory.h"
36 #include <boost/format.hpp>
62 setDescription(
"TOP DQM histogrammer");
63 setPropertyFlags(c_ParallelProcessingCertified);
66 addParam(
"histogramDirectoryName", m_histogramDirectoryName,
67 "histogram directory in ROOT file",
string(
"TOP"));
68 addParam(
"momentumCut", m_momentumCut,
69 "momentum cut used to histogram pulls etc.", 2.0);
70 addParam(
"pValueCut", m_pValueCut,
71 "track p-value cut used to histogram pulls etc.", 0.001);
72 addParam(
"usePionID", m_usePionID,
73 "use pion ID from TOP to histogram pulls etc.",
true);
74 addParam(
"cutNphot", m_cutNphot,
"Cut on total number of photons", 3);
78 TOPDQMModule::~TOPDQMModule()
82 void TOPDQMModule::defineHisto()
85 TDirectory* oldDir = gDirectory;
86 oldDir->mkdir(m_histogramDirectoryName.c_str())->cd();
89 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
90 m_numModules = geo->getNumModules();
91 double bunchTimeSep = geo->getNominalTDC().getSyncTimeBase() / 24;
93 m_BoolEvtMonitor =
new TH1F(
"BoolEvtMonitor",
"Event desynchronization monitoring",
95 m_BoolEvtMonitor->GetXaxis()->SetTitle(
"good/bad event entries");
97 m_recoTime =
new TH1F(
"recoTime",
"reco: time distribution",
99 m_recoTime->GetXaxis()->SetTitle(
"time [ns]");
101 m_recoTimeBg =
new TH1F(
"recoTimeBg",
"reco: time distribution (bkg)",
103 m_recoTimeBg->GetXaxis()->SetTitle(
"time [ns]");
105 m_recoTimeMinT0 =
new TH1F(
"recoTimeMinT0",
"reco: time in respect to first PDF peak",
107 m_recoTimeMinT0->GetXaxis()->SetTitle(
"time [ns]");
109 m_recoTimeDiff =
new TH1F(
"recoTimeDiff",
"reco: time resolution",
111 m_recoTimeDiff->GetXaxis()->SetTitle(
"time residual [ns]");
113 m_recoPull =
new TH1F(
"recoPull",
"reco: pulls",
115 m_recoPull->GetXaxis()->SetTitle(
"pull");
117 m_recoTimeDiff_Phic =
new TH2F(
"recoTimeDiff_Phic",
118 "reco: time resolution vs. phiCer",
119 90, -180, 180, 100, -1.0, 1.0);
120 m_recoTimeDiff_Phic->GetXaxis()->SetTitle(
"Cerenkov azimuthal angle [deg]");
121 m_recoTimeDiff_Phic->GetYaxis()->SetTitle(
"time residuals [ns]");
123 m_recoPull_Phic =
new TProfile(
"recoPull_Phic",
124 "reco: pulls vs phiCer",
125 90, -180, 180, -10, 10,
"S");
126 m_recoPull_Phic->GetXaxis()->SetTitle(
"Cerenkov azimuthal angle [deg]");
127 m_recoPull_Phic->GetYaxis()->SetTitle(
"pulls");
130 m_goodHits =
new TH1F(
"goodHits",
"Number of good hits per bar", m_numModules, 0.5, m_numModules + 0.5);
131 m_badHits =
new TH1F(
"badHits",
"Number of bad hits per bar", m_numModules, 0.5, m_numModules + 0.5);
132 m_goodHits->SetOption(
"LIVE");
133 m_badHits->SetOption(
"LIVE");
134 m_goodHits->SetMinimum(0);
135 m_badHits->SetMinimum(0);
137 m_goodHits->GetXaxis()->SetTitle(
"slot no.");
138 m_goodHits->GetYaxis()->SetTitle(
"hits / slot");
139 m_badHits->GetXaxis()->SetTitle(
"slot number");
140 m_badHits->GetYaxis()->SetTitle(
"hits / slot");
143 m_window_vs_slot =
new TH2F(
"window_vs_slot",
"Distribution of hits: raw timing",
144 16, 0.5, 16.5, 512, 0, 512);
145 m_window_vs_slot->SetXTitle(
"slot number");
146 m_window_vs_slot->SetYTitle(
"window number w.r.t reference window");
147 m_window_vs_slot->SetOption(
"LIVE");
148 m_window_vs_slot->SetStats(kFALSE);
150 m_bunchOffset =
new TH1F(
"bunchOffset",
"Reconstructed bunch: current offset",
151 100, -bunchTimeSep / 2, bunchTimeSep / 2);
152 m_bunchOffset->SetXTitle(
"offset [ns]");
153 m_bunchOffset->SetYTitle(
"events/bin");
154 m_bunchOffset->SetOption(
"LIVE");
155 m_bunchOffset->SetMinimum(0);
157 m_time =
new TH1F(
"goodHitTimes",
"Time distribution of good hits",
159 m_time->SetXTitle(
"time [ns]");
160 m_time->SetYTitle(
"hits/bin");
161 m_time->SetOption(
"LIVE");
162 m_time->SetMinimum(0);
165 m_goodHitsPerEventAll =
new TH1F(
"goodHitsPerEventAll",
"Number of good hits per event", MaxEvents, 0, MaxEvents);
166 m_badHitsPerEventAll =
new TH1F(
"badHitsPerEventAll",
"Number of bad hits per event", MaxEvents, 0, MaxEvents);
167 m_goodHitsPerEventAll->SetOption(
"LIVE");
168 m_badHitsPerEventAll->SetOption(
"LIVE");
169 m_goodHitsPerEventAll->SetMinimum(0);
170 m_badHitsPerEventAll->SetMinimum(0);
171 m_goodHitsPerEventAll->GetXaxis()->SetTitle(
"hits / event");
172 m_goodHitsPerEventAll->GetYaxis()->SetTitle(
"Events");
173 m_badHitsPerEventAll->GetXaxis()->SetTitle(
"hits / event");
174 m_badHitsPerEventAll->GetYaxis()->SetTitle(
"Events");
178 m_goodTDCAll =
new TH1F(
"goodTDCAll",
"Raw time distribution of good hits",
179 BinNumRT, 0, MaxRawTime);
180 m_goodTDCAll->SetXTitle(
"raw time [samples]");
181 m_goodTDCAll->SetYTitle(
"hits / sample");
182 m_goodTDCAll->SetOption(
"LIVE");
183 m_goodTDCAll->SetMinimum(0);
185 m_badTDCAll =
new TH1F(
"badTDCAll",
"Raw time distribution of bad hits",
186 BinNumRT, 0, MaxRawTime);
187 m_badTDCAll->SetXTitle(
"raw time [samples]");
188 m_badTDCAll->SetYTitle(
"hits / sample");
189 m_badTDCAll->SetOption(
"LIVE");
190 m_badTDCAll->SetMinimum(0);
192 m_goodHitsPerEventProf =
new TProfile(
"goodHitsPerEventProf",
"Good hits per event vs. slot number",
193 16, 0.5, 16.5, 0, MaxEvents);
194 m_goodHitsPerEventProf->SetXTitle(
"slot number");
195 m_goodHitsPerEventProf->SetYTitle(
"hits per event");
196 m_goodHitsPerEventProf->SetOption(
"LIVE");
197 m_goodHitsPerEventProf->SetStats(kFALSE);
198 m_goodHitsPerEventProf->SetMinimum(0);
200 m_badHitsPerEventProf =
new TProfile(
"badHitsPerEventProf",
"Bad hits per event vs. slot number",
201 16, 0.5, 16.5, 0, MaxEvents);
202 m_badHitsPerEventProf->SetXTitle(
"slot number");
203 m_badHitsPerEventProf->SetYTitle(
"hits per event");
204 m_badHitsPerEventProf->SetOption(
"LIVE");
205 m_badHitsPerEventProf->SetStats(kFALSE);
206 m_badHitsPerEventProf->SetMinimum(0);
208 m_TOPOccAfterInjLER =
new TH1F(
"TOPOccInjLER",
"TOPOccInjLER/Time;Time in #mus;Nhits/Time (#mus bins)", 4000, 0, 20000);
209 m_TOPOccAfterInjHER =
new TH1F(
"TOPOccInjHER",
"TOPOccInjHER/Time;Time in #mus;Nhits/Time (#mus bins)", 4000, 0, 20000);
210 m_TOPEOccAfterInjLER =
new TH1F(
"TOPEOccInjLER",
"TOPEOccInjLER/Time;Time in #mus;Triggers/Time (#mus bins)", 4000, 0, 20000);
211 m_TOPEOccAfterInjHER =
new TH1F(
"TOPEOccInjHER",
"TOPEOccInjHER/Time;Time in #mus;Triggers/Time (#mus bins)", 4000, 0, 20000);
213 for (
int i = 0; i < m_numModules; i++) {
220 name = str(format(
"window_vs_asic_%1%") % (module));
221 title = str(format(
"Distribution of hits: raw timing for slot #%1%") % (module));
222 h2 =
new TH2F(name.c_str(), title.c_str(), 64, 0, 64, 512, 0, 512);
223 h2->SetOption(
"LIVE");
224 h2->SetStats(kFALSE);
225 h2->SetXTitle(
"ASIC number");
226 h2->SetYTitle(
"window number w.r.t reference window");
228 m_window_vs_asic.push_back(h2);
230 name = str(format(
"good_hits_xy_%1%") % (module));
231 title = str(format(
"Number of good hits in x-y for slot #%1%") % (module));
232 h2 =
new TH2F(name.c_str(), title.c_str(), 64, 0.5, 64.5, 8, 0.5, 8.5);
233 h2->SetOption(
"LIVE");
234 h2->SetStats(kFALSE);
235 h2->GetXaxis()->SetTitle(
"pixel column");
236 h2->GetYaxis()->SetTitle(
"pixel row");
238 m_goodHitsXY.push_back(h2);
240 name = str(format(
"bad_hits_xy_%1%") % (module));
241 title = str(format(
"Number of bad hits in x-y for slot #%1%") % (module));
242 h2 =
new TH2F(name.c_str(), title.c_str(), 64, 0.5, 64.5, 8, 0.5, 8.5);
243 h2->SetOption(
"LIVE");
244 h2->SetStats(kFALSE);
245 h2->GetXaxis()->SetTitle(
"pixel column");
246 h2->GetYaxis()->SetTitle(
"pixel row");
248 m_badHitsXY.push_back(h2);
250 name = str(format(
"good_hits_asics_%1%") % (module));
251 title = str(format(
"Number of good hits for asics for slot #%1%") % (module));
252 h2 =
new TH2F(name.c_str(), title.c_str(), 64, 0, 64, 8, 0, 8);
253 h2->SetOption(
"LIVE");
254 h2->SetStats(kFALSE);
255 h2->GetXaxis()->SetTitle(
"ASIC number");
256 h2->GetYaxis()->SetTitle(
"ASIC channel");
258 m_goodHitsAsics.push_back(h2);
260 name = str(format(
"bad_hits_asics_%1%") % (module));
261 title = str(format(
"Number of bad hits for asics for slot #%1%") % (module));
262 h2 =
new TH2F(name.c_str(), title.c_str(), 64, 0, 64, 8, 0, 8);
263 h2->SetOption(
"LIVE");
264 h2->SetStats(kFALSE);
265 h2->GetXaxis()->SetTitle(
"ASIC number");
266 h2->GetYaxis()->SetTitle(
"ASIC channel");
268 m_badHitsAsics.push_back(h2);
270 name = str(format(
"good_TDC_%1%") % (module));
271 title = str(format(
"Raw time distribution of good hits for slot #%1%") % (module));
272 h1 =
new TH1F(name.c_str(), title.c_str(), BinNumRT, 0, MaxRawTime);
273 h1->SetOption(
"LIVE");
274 h1->GetXaxis()->SetTitle(
"raw time [samples]");
275 h1->GetYaxis()->SetTitle(
"hits per sample");
277 m_goodTdc.push_back(h1);
279 name = str(format(
"bad_TDC_%1%") % (module));
280 title = str(format(
"Raw time distribution of bad hits for slot #%1%") % (module));
281 h1 =
new TH1F(name.c_str(), title.c_str(), BinNumRT, 0, MaxRawTime);
282 h1->SetOption(
"LIVE");
283 h1->GetXaxis()->SetTitle(
"raw time [samples]");
284 h1->GetYaxis()->SetTitle(
"hits per sample");
286 m_badTdc.push_back(h1);
288 name = str(format(
"good_timing_%1%") % (module));
289 title = str(format(
"Timing distribution of good hits for slot #%1%") % (module));
290 h1 =
new TH1F(name.c_str(), title.c_str(), 100, -20, 80);
291 h1->SetOption(
"LIVE");
292 h1->GetXaxis()->SetTitle(
"time [ns]");
293 h1->GetYaxis()->SetTitle(
"hits per time bin");
295 m_goodTiming.push_back(h1);
297 name = str(format(
"good_channel_hits_%1%") % (module));
298 title = str(format(
"Number of good hits by channel for slot #%1%") % (module));
299 int numPixels = geo->getModule(i + 1).getPMTArray().getNumPixels();
300 h1 =
new TH1F(name.c_str(), title.c_str(), numPixels, 0, numPixels);
301 h1->SetOption(
"LIVE");
302 h1->GetXaxis()->SetTitle(
"channel number");
303 h1->GetYaxis()->SetTitle(
"hits pre channel");
305 m_goodChannelHits.push_back(h1);
307 name = str(format(
"bad_channel_hits_%1%") % (module));
308 title = str(format(
"Number of bad hits by channel for slot #%1%") % (module));
309 h1 =
new TH1F(name.c_str(), title.c_str(), numPixels, 0, numPixels);
310 h1->SetOption(
"LIVE");
311 h1->GetXaxis()->SetTitle(
"channel number");
312 h1->GetYaxis()->SetTitle(
"hits pre channel");
314 m_badChannelHits.push_back(h1);
316 name = str(format(
"good_hits_per_event%1%") % (module));
317 title = str(format(
"Number of good hits per event for slot #%1%") % (module));
318 h1 =
new TH1F(name.c_str(), title.c_str(), MaxEvents, 0, MaxEvents);
319 h1->SetOption(
"LIVE");
320 h1->GetXaxis()->SetTitle(
"hits / event");
322 m_goodHitsPerEvent.push_back(h1);
324 name = str(format(
"bad_hits_per_event%1%") % (module));
325 title = str(format(
"Number of bad hits per event for slot #%1%") % (module));
326 h1 =
new TH1F(name.c_str(), title.c_str(), MaxEvents, 0, MaxEvents);
327 h1->SetOption(
"LIVE");
328 h1->GetXaxis()->SetTitle(
"hits / event");
330 m_badHitsPerEvent.push_back(h1);
332 name = str(format(
"good_hits_xy_track_%1%") % (module));
333 title = str(format(
"Hits per track, each channel, slot #%1%") % (module));
334 h3 =
new TProfile2D(name.c_str(), title.c_str(), 64, 0.5, 64.5, 8, 0.5, 8.5, 0, 1000);
335 h3->SetOption(
"LIVE");
336 h3->SetStats(kFALSE);
337 h3->GetXaxis()->SetTitle(
"pixel column");
338 h3->GetYaxis()->SetTitle(
"pixel row");
340 m_goodHitsXYTrack.push_back(h3);
342 name = str(format(
"good_hits_xy_track_bkg_%1%") % (module));
343 title = str(format(
"Hits per bkg track, each channel, slot #%1%") % (module));
344 h3 =
new TProfile2D(name.c_str(), title.c_str(), 64, 0.5, 64.5, 8, 0.5, 8.5, 0, 1000);
345 h3->SetOption(
"LIVE");
346 h3->SetStats(kFALSE);
347 h3->GetXaxis()->SetTitle(
"pixel column");
348 h3->GetYaxis()->SetTitle(
"pixel row");
350 m_goodHitsXYTrackBkg.push_back(h3);
357 void TOPDQMModule::initialize()
363 m_rawFTSW.isOptional();
364 m_digits.isRequired();
365 m_recBunch.isOptional();
366 m_tracks.isOptional();
370 void TOPDQMModule::beginRun()
372 m_BoolEvtMonitor->Reset();
374 m_recoTimeDiff->Reset();
375 m_recoTimeDiff_Phic->Reset();
377 m_recoPull_Phic->Reset();
379 m_recoTimeBg->Reset();
380 m_recoTimeMinT0->Reset();
384 m_window_vs_slot->Reset();
385 m_bunchOffset->Reset();
387 m_goodTDCAll->Reset();
388 m_badTDCAll->Reset();
389 m_goodHitsPerEventProf->Reset();
390 m_goodHitsPerEventAll->Reset();
391 m_badHitsPerEventProf->Reset();
392 m_badHitsPerEventAll->Reset();
393 m_TOPOccAfterInjLER->Reset();
394 m_TOPOccAfterInjHER->Reset();
395 m_TOPEOccAfterInjLER->Reset();
396 m_TOPEOccAfterInjHER->Reset();
398 for (
int i = 0; i < m_numModules; i++) {
399 m_window_vs_asic[i]->Reset();
400 m_goodHitsXY[i]->Reset();
401 m_badHitsXY[i]->Reset();
402 m_goodHitsAsics[i]->Reset();
403 m_badHitsAsics[i]->Reset();
404 m_goodTdc[i]->Reset();
405 m_badTdc[i]->Reset();
406 m_goodTiming[i]->Reset();
407 m_goodChannelHits[i]->Reset();
408 m_badChannelHits[i]->Reset();
409 m_goodHitsPerEvent[i]->Reset();
410 m_badHitsPerEvent[i]->Reset();
411 m_goodHitsXYTrack[i]->Reset();
412 m_goodHitsXYTrackBkg[i]->Reset();
416 void TOPDQMModule::event()
419 bool recBunchValid =
false;
420 if (m_recBunch.isValid()) {
421 recBunchValid = m_recBunch->isReconstructed();
425 m_bunchOffset->Fill(m_recBunch->getCurrentOffset());
428 std::vector<int> n_good(16, 0);
429 std::vector<int> n_bad(16, 0);
430 std::vector<int> n_good_first(16, 0);
431 std::vector<int> n_good_second(16, 0);
432 std::vector<int> n_good_pixel_hits(16 * 512, 0);
434 int Ndigits = m_digits.getEntries();
436 for (
const auto& digit : m_digits) {
437 int x = digit.getFirstWindow() != m_digits[0]->getFirstWindow() ? 1 : 0 ;
438 m_BoolEvtMonitor->Fill(x);
442 for (
const auto& digit : m_digits) {
443 int i = digit.getModuleID() - 1;
444 if (i < 0 || i >= m_numModules) {
445 B2ERROR(
"Invalid module ID found in TOPDigits: ID = " << i + 1);
449 int ch = digit.getChannel();
450 int asic_no = ch / 8, asic_ch = ch % 8;
452 m_window_vs_slot->Fill(digit.getModuleID(), digit.getRawTime() / 64 + 220);
453 m_window_vs_asic[i]->Fill(digit.getChannel() / 8, digit.getRawTime() / 64 + 220);
455 if (digit.getHitQuality() != TOPDigit::c_Junk) {
456 m_goodHits->Fill(i + 1);
457 m_goodHitsXY[i]->Fill(digit.getPixelCol(), digit.getPixelRow());
458 m_goodHitsAsics[i]->Fill(asic_no, asic_ch);
459 m_goodTdc[i]->Fill(digit.getRawTime());
460 m_goodTDCAll->Fill(digit.getRawTime());
462 m_goodTiming[i]->Fill(digit.getTime());
463 m_time->Fill(digit.getTime());
465 m_goodChannelHits[i]->Fill(digit.getChannel());
466 if (digit.getTime() > 0 && digit.getTime() < 20) n_good_first[i]++;
467 if (digit.getTime() > 20 && digit.getTime() < 50) n_good_second[i]++;
468 n_good_pixel_hits[(digit.getModuleID() - 1) * 512 + (digit.getPixelID() - 1)]++;
471 m_badHits->Fill(i + 1);
472 m_badHitsXY[i]->Fill(digit.getPixelCol(), digit.getPixelRow());
473 m_badHitsAsics[i]->Fill(asic_no, asic_ch);
474 m_badTdc[i]->Fill(digit.getRawTime());
475 m_badTDCAll->Fill(digit.getRawTime());
476 m_badChannelHits[i]->Fill(digit.getChannel());
481 for (
int i = 0; i < 16; i++) {
482 m_goodHitsPerEventProf->Fill(i + 1, n_good[i]);
483 m_badHitsPerEventProf->Fill(i + 1, n_bad[i]);
484 m_goodHitsPerEvent[i]->Fill(n_good[i]);
485 m_goodHitsPerEventAll->Fill(n_good[i]);
486 m_badHitsPerEvent[i]->Fill(n_bad[i]);
487 m_badHitsPerEventAll->Fill(n_bad[i]);
489 bool slot_has_track = (n_good_first[i] + n_good_second[i]) > m_cutNphot;
490 for (
int j = 0; j < 512; j++) {
491 int col = j % 64 + 1, row = j / 64 + 1;
493 m_goodHitsXYTrack[i]->Fill(col, row, n_good_pixel_hits[i * 512 + j]);
495 m_goodHitsXYTrackBkg[i]->Fill(col, row, n_good_pixel_hits[i * 512 + j]);
499 for (
const auto& track : m_tracks) {
500 const auto* trackFit = track.getTrackFitResultWithClosestMass(Const::pion);
501 if (!trackFit)
continue;
502 if (trackFit->getMomentum().Mag() < m_momentumCut)
continue;
503 if (trackFit->getPValue() < m_pValueCut)
continue;
507 if (top->getLogL_pi() < top->getLogL_K())
continue;
508 if (top->getLogL_pi() < top->getLogL_p())
continue;
511 const auto pulls = track.getRelationsWith<
TOPPull>();
512 for (
const auto& pull : pulls) {
513 if (pull.isSignal()) {
514 double phiCer = pull.
getPhiCer() / Unit::deg;
515 m_recoTimeDiff->Fill(pull.getTimeDiff(), pull.getWeight());
516 m_recoTimeDiff_Phic->Fill(phiCer, pull.getTimeDiff(), pull.getWeight());
517 m_recoPull->Fill(pull.getPull(), pull.getWeight());
518 m_recoPull_Phic->Fill(phiCer, pull.getPull(), pull.getWeight());
520 m_recoTime->Fill(pull.getTime());
521 m_recoTimeBg->Fill(pull.getTime(), pull.getWeight());
522 m_recoTimeMinT0->Fill(pull.getTimeDiff());
527 for (
auto& it : m_rawFTSW) {
528 B2DEBUG(29,
"TTD FTSW : " << hex << it.GetTTUtime(0) <<
" " << it.GetTTCtime(0) <<
" EvtNr " << it.GetEveNo(0) <<
" Type " <<
529 (it.GetTTCtimeTRGType(0) & 0xF) <<
" TimeSincePrev " << it.GetTimeSincePrevTrigger(0) <<
" TimeSinceInj " <<
530 it.GetTimeSinceLastInjection(0) <<
" IsHER " << it.GetIsHER(0) <<
" Bunch " << it.GetBunchNumber(0));
531 auto difference = it.GetTimeSinceLastInjection(0);
532 if (difference != 0x7FFFFFFF) {
533 unsigned int nentries = m_digits.getEntries();
534 float diff2 = difference / 127.;
535 if (it.GetIsHER(0)) {
536 m_TOPOccAfterInjHER->Fill(diff2, nentries);
537 m_TOPEOccAfterInjHER->Fill(diff2);
539 m_TOPOccAfterInjLER->Fill(diff2, nentries);
540 m_TOPEOccAfterInjLER->Fill(diff2);
548 void TOPDQMModule::endRun()
552 void TOPDQMModule::terminate()
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
Class to store TOP log likelihoods (output of TOPReconstructor).
Class to store photon pull in respect to PDF used in reconstruction.
double getPhiCer() const
Return Cerenkov azimuthal angle.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.