10 #include <ecl/modules/eclDQM/eclDQM.h>
13 #include <boost/format.hpp>
14 #include <boost/range/combine.hpp>
17 #include <framework/core/HistoModule.h>
18 #include <framework/dataobjects/EventMetaData.h>
19 #include <framework/gearbox/Unit.h>
20 #include <framework/logging/Logger.h>
23 #include <ecl/dataobjects/ECLDigit.h>
24 #include <ecl/dataobjects/ECLCalDigit.h>
25 #include <ecl/dataobjects/ECLTrig.h>
26 #include <ecl/dataobjects/ECLDsp.h>
27 #include <ecl/utility/ECLChannelMapper.h>
28 #include <ecl/geometry/ECLGeometryPar.h>
31 #include <mdst/dataobjects/TRGSummary.h>
37 #include <TDirectory.h>
53 m_calibrationThrApsd("ECL_FPGA_StoreWaveform")
56 setDescription(
"ECL Data Quality Monitor");
57 setPropertyFlags(c_ParallelProcessingCertified);
59 m_WaveformOption = {
"psd",
"logic",
"rand",
"dphy",
"other"};
61 addParam(
"histogramDirectoryName", m_histogramDirectoryName,
62 "histogram directory in ROOT file", std::string(
"ECL"));
63 addParam(
"EnergyUpperThr", m_EnergyUpperThr,
"Upper threshold of energy deposition in event, [GeV]", 20.0 *
Belle2::Unit::GeV);
64 addParam(
"HitThresholds", m_HitThresholds,
"Thresholds to display hit occupancy, MeV", std::vector<double> {0, 5, 10, 50});
65 addParam(
"TotalEnergyThresholds", m_TotalEnergyThresholds,
"Thresholds to display total energy, MeV", std::vector<double> {0, 5, 7});
66 addParam(
"TimingThresholds", m_TimingThresholds,
"Thresholds (MeV) to display ECL timing", std::vector<double> {5, 10, 50});
67 addParam(
"HitNumberUpperlimits", m_HitNumberUpperLimits,
68 "Upper limit (# of hits) to display hit multiplicity", std::vector<double> {10000, 1000, 700, 200});
69 addParam(
"WaveformOption", m_WaveformOption,
"Option (all,psd,logic,rand,dphy,other) to display waveform flow",
71 addParam(
"DPHYTTYP", m_DPHYTTYP,
72 "Flag to control trigger of delayed bhabha events; 0 - select events by 'bha_delay' trigger bit, 1 - select by TTYP_DPHY",
false);
82 TDirectory* oldDir = gDirectory;
86 TDirectory* dirDAQ =
dynamic_cast<TDirectory*
>(oldDir->Get(m_histogramDirectoryName.c_str()));
87 if (!dirDAQ) dirDAQ = oldDir->mkdir(m_histogramDirectoryName.c_str());
91 h_evtot =
new TH1F(
"event",
"Total event bank", 1, 0, 1);
92 h_evtot->SetOption(
"LIVE");
94 h_quality =
new TH1F(
"quality",
"Fit quality flag. 0-good, 1-integer overflow, 2-low amplitude, 3-bad chi2", 4, 0, 4);
95 h_quality->GetXaxis()->SetTitle(
"Flag number");
96 h_quality->GetYaxis()->SetTitle(
"ECL hits count");
97 h_quality->SetFillColor(kPink - 4);
98 h_quality->SetOption(
"LIVE");
100 h_quality_other =
new TH1F(
"quality_other",
"Fit quality flag for unexpectedly saved waveforms", 4, 0, 4);
101 h_quality_other->GetXaxis()->SetTitle(
"Flag number. 0-good,1-int overflow,2-low amplitude,3-bad chi2");
102 h_quality_other->SetFillColor(kPink - 4);
103 h_quality_other->SetOption(
"LIVE");
105 h_bad_quality =
new TH1F(
"bad_quality",
"Fraction of hits with bad chi2 (qual=3) and E > 1 GeV vs Cell ID", 8736, 1, 8737);
106 h_bad_quality->GetXaxis()->SetTitle(
"Cell ID");
107 h_bad_quality->GetYaxis()->SetTitle(
"ECL hits count");
108 h_bad_quality->SetOption(
"LIVE");
110 h_trigtag1 =
new TH1F(
"trigtag1",
"Consistency b/w global event number and trigger tag. 0-good, 1-DQM error", 2, 0, 2);
111 h_trigtag1->GetXaxis()->SetTitle(
"Flag number");
112 h_trigtag1->GetYaxis()->SetTitle(
"Events count");
113 h_trigtag1->SetDrawOption(
"hist");
114 h_trigtag1->SetOption(
"LIVE");
115 h_trigtag1->SetFillColor(kPink - 4);
117 h_adc_hits =
new TH1F(
"adc_hits",
"Fraction of high-energy hits (E > 50 MeV)", 1001, 0, 1.001);
118 h_adc_hits->GetXaxis()->SetTitle(
"Fraction");
119 h_adc_hits->GetYaxis()->SetTitle(
"Events count");
120 h_adc_hits->SetOption(
"LIVE");
122 h_time_crate_Thr1GeV_large =
new TH1F(
"time_crate_Thr1GeV_large",
123 "Number of hits with timing outside #pm 100 ns per Crate ID (E > 1 GeV)",
125 h_time_crate_Thr1GeV_large->GetXaxis()->SetTitle(
"Crate ID (same as ECLCollector ID)");
126 h_time_crate_Thr1GeV_large->GetYaxis()->SetTitle(
"ECL hits count");
127 h_time_crate_Thr1GeV_large->SetOption(
"LIVE");
129 for (
const auto&
id : m_HitThresholds) {
130 std::string h_name, h_title;
131 h_name = str(boost::format(
"cid_Thr%1%MeV") %
id);
132 h_title = str(boost::format(
"Occupancy per Cell ID (E > %1% MeV)") %
id);
133 TH1F* h =
new TH1F(h_name.c_str(), h_title.c_str(), 8736, 1, 8737);
134 h->GetXaxis()->SetTitle(
"Cell ID");
135 h->GetYaxis()->SetTitle(
"Occupancy (hits / events_count)");
136 h->SetOption(
"LIVE");
140 for (
const auto&
id : m_TotalEnergyThresholds) {
141 std::string h_name, h_title;
142 h_name = str(boost::format(
"edep_Thr%1%MeV") %
id);
143 h_title = str(boost::format(
"Total energy (thr = %1% MeV)") %
id);
144 TH1F* h =
new TH1F(h_name.c_str(), h_title.c_str(), (
int)(100 * m_EnergyUpperThr), 0, m_EnergyUpperThr);
145 h->GetXaxis()->SetTitle(
"Energy, [GeV]");
146 h->SetOption(
"LIVE");
147 h_edeps.push_back(h);
150 for (
const auto&
id : m_TimingThresholds) {
151 std::string h_bar_name, h_bar_title;
152 std::string h_end_name, h_end_title;
153 h_bar_name = str(boost::format(
"time_barrel_Thr%1%MeV") %
id);
154 h_bar_title = str(boost::format(
"Reconstructed time for ECL barrel (E > %1% MeV)") %
id);
155 h_end_name = str(boost::format(
"time_endcaps_Thr%1%MeV") %
id);
156 h_end_title = str(boost::format(
"Reconstructed time for ECL endcaps (E > %1% MeV)") %
id);
157 TH1F* h_time_barrel =
new TH1F(h_bar_name.c_str(), h_bar_title.c_str(), 206, -1030, 1030);
158 TH1F* h_time_endcap =
new TH1F(h_end_name.c_str(), h_end_title.c_str(), 206, -1030, 1030);
159 h_time_barrel->GetXaxis()->SetTitle(
"Time, [ns]");
160 h_time_endcap->GetXaxis()->SetTitle(
"Time, [ns]");
161 h_time_barrel->SetOption(
"LIVE");
162 h_time_endcap->SetOption(
"LIVE");
163 h_time_barrels.push_back(h_time_barrel);
164 h_time_endcaps.push_back(h_time_endcap);
167 for (
const auto&
id : boost::combine(m_HitThresholds, m_HitNumberUpperLimits)) {
168 double id1 = 0, id2 = 0;
169 boost::tie(id1, id2) = id;
170 std::string h_name, h_title;
171 h_name = str(boost::format(
"ncev_Thr%1%MeV") % id1);
172 h_title = str(boost::format(
"Number of hits in event (E > %1% MeV)") % id1);
173 TH1F* h =
new TH1F(h_name.c_str(), h_title.c_str(), id2, 0, id2);
174 h->GetXaxis()->SetTitle(
"Number of hits");
175 h->SetOption(
"LIVE");
176 h_ncevs.push_back(h);
179 for (
int i = 0; i < ECL_CRATES; i++) {
181 std::string h_name, h_title;
182 h_name = str(boost::format(
"time_crate_%1%_Thr1GeV") % (crate));
183 h_title = str(boost::format(
"Reconstructed time for ECL crate #%1% with E > 1 GeV") % (crate));
184 TH1F* h =
new TH1F(h_name.c_str(), h_title.c_str(), 400, -100, 100);
185 h->GetXaxis()->SetTitle(
"Time [ns]");
186 h->SetOption(
"LIVE");
187 h_time_crate_Thr1GeV.push_back(h);
190 for (
const auto&
id : m_WaveformOption) {
191 if (
id !=
"all" &&
id !=
"psd" &&
id !=
"logic" &&
id !=
"rand" &&
id !=
"dphy" &&
id !=
"other")
192 B2WARNING(
"Waveform Options are not correctly assigned. They must be 'all', 'psd', 'logic', 'rand', 'dphy', 'other'!");
194 std::string h_cell_name;
195 if (
id ==
"other") h_title =
"Unexpectedly saved waveforms";
196 if (
id ==
"psd") h_title =
"#frac{Saved}{Expected} waveforms for high-energy hits (E > 50 MeV)";
197 if (
id ==
"logic") h_title =
"#frac{Saved}{Expected} waveforms for every 1000th event";
198 if (
id ==
"rand") h_title =
"#frac{Saved}{Expected} waveforms for random trigger events";
199 if (
id ==
"dphy") h_title =
"#frac{Saved}{Expected} waveforms for delayed bhabha (DPHY) events";
200 if (
id ==
"all") h_title =
"#frac{Saved}{Expected} waveforms for all events";
201 h_cell_name = str(boost::format(
"wf_cid_%1%") % (
id));
202 TH1F* h_cell =
new TH1F(h_cell_name.c_str(), h_title.c_str(), 8736, 1, 8737);
203 h_cell->GetXaxis()->SetTitle(
"Cell ID");
204 h_cell->SetOption(
"LIVE");
206 h_cell_psd_norm =
new TH1F(
"psd_cid",
"Normalization to psd hits for cid", 8736, 1, 8737);
207 h_cell_psd_norm->SetOption(
"LIVE");
210 h_evtot_logic =
new TH1F(
"event_logic",
"Event bank for logic", 1, 0, 1);
211 h_evtot_logic->SetOption(
"LIVE");
214 h_evtot_rand =
new TH1F(
"event_rand",
"Event bank for rand", 1, 0, 1);
215 h_evtot_rand->SetOption(
"LIVE");
218 h_evtot_dphy =
new TH1F(
"event_dphy",
"Event bank for dphy", 1, 0, 1);
219 h_evtot_dphy->SetOption(
"LIVE");
221 h_cells.push_back(h_cell);
226 h_trigtag2_trigid =
new TH2F(
"trigtag2_trigid",
"Internal data consistency vs crate. 0-good, 1-data corruption",
227 52, 1, 53, 11, -1, 10);
228 h_trigtag2_trigid->GetXaxis()->SetTitle(
"Crate ID (same as ECLCollector ID)");
229 h_trigtag2_trigid->GetYaxis()->SetTitle(
"Data consistency flag");
230 h_trigtag2_trigid->SetOption(
"LIVE");
232 h_pedmean_cellid =
new TProfile(
"pedmean_cellid",
"Pedestal vs Cell ID", 8736, 1, 8737);
233 h_pedmean_cellid->GetXaxis()->SetTitle(
"Cell ID");
234 h_pedmean_cellid->GetYaxis()->SetTitle(
"Ped. average (ADC units, #approx 0.05 MeV)");
235 h_pedmean_cellid->SetOption(
"LIVE");
237 h_pedrms_cellid =
new TProfile(
"pedrms_cellid",
"Pedestal stddev vs Cell ID",
239 h_pedrms_cellid->GetXaxis()->SetTitle(
"Cell ID");
240 h_pedrms_cellid->GetYaxis()->SetTitle(
"Ped. stddev (ADC units, #approx 0.05 MeV)");
241 h_pedrms_cellid->SetOption(
"LIVE");
243 h_pedrms_thetaid =
new TProfile(
"pedrms_thetaid",
"Pedestal stddev vs #theta ID",
245 h_pedrms_thetaid->GetXaxis()->SetTitle(
"#theta ID (0-12=FWD, 59-67=BWD endcap)");
246 h_pedrms_thetaid->GetYaxis()->SetTitle(
"Ped. stddev (ADC units, #approx 0.05 MeV)");
247 h_pedrms_thetaid->SetOption(
"LIVE");
249 h_trigtime_trigid =
new TH2F(
"trigtime_trigid",
"Trigger time vs Crate ID", 52, 1, 53, 145, 0, 145);
250 h_trigtime_trigid->GetXaxis()->SetTitle(
"Crate ID (same as ECLCollector ID)");
251 h_trigtime_trigid->GetYaxis()->SetTitle(
"Trigger time (only even, 0-142)");
252 h_trigtime_trigid->SetOption(
"LIVE");
262 m_ECLDigits.isRequired();
263 m_ECLCalDigits.isOptional();
264 m_ECLTrigs.isOptional();
265 m_ECLDsps.isOptional();
266 m_l1Trigger.isOptional();
268 if (!mapper.initFromDB()) B2FATAL(
"ECL DQM: Can't initialize eclChannelMapper");
270 ecltot.resize(m_TotalEnergyThresholds.size());
271 nhits.resize(m_HitNumberUpperLimits.size());
275 v_totalthrApsd.resize((m_calibrationThrApsd->getCalibVector()).size());
276 for (
size_t i = 0; i < v_totalthrApsd.size(); i++) v_totalthrApsd[i] = (
int)(m_calibrationThrApsd->getCalibVector())[i];
282 h_evtot_logic->Reset();
283 h_evtot_rand->Reset();
284 h_evtot_dphy->Reset();
286 h_quality_other->Reset();
287 h_bad_quality->Reset();
290 h_time_crate_Thr1GeV_large->Reset();
291 h_cell_psd_norm->Reset();
292 std::for_each(h_cids.begin(), h_cids.end(), [](
auto & it) {it->Reset();});
293 std::for_each(h_edeps.begin(), h_edeps.end(), [](
auto & it) {it->Reset();});
294 std::for_each(h_time_barrels.begin(), h_time_barrels.end(), [](
auto & it) {it->Reset();});
295 std::for_each(h_time_endcaps.begin(), h_time_endcaps.end(), [](
auto & it) {it->Reset();});
296 std::for_each(h_ncevs.begin(), h_ncevs.end(), [](
auto & it) {it->Reset();});
297 std::for_each(h_cells.begin(), h_cells.end(), [](
auto & it) {it->Reset();});
298 for (
int i = 0; i < ECL_CRATES; i++) h_time_crate_Thr1GeV[i]->Reset();
299 h_trigtag2_trigid->Reset();
300 h_pedmean_cellid->Reset();
301 h_pedrms_cellid->Reset();
302 h_pedrms_thetaid->Reset();
303 h_trigtime_trigid->Reset();
310 for (
auto& value : ecltot) value = 0;
311 for (
auto& value : nhits) value = 0;
312 bool bhatrig =
false;
314 if (m_l1Trigger.isValid() && m_DPHYTTYP) bhatrig = m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_DPHY;
315 else if (m_l1Trigger.isValid() && !m_DPHYTTYP) {
316 try { bhatrig = m_l1Trigger->testInput(
"bha_delay"); }
317 catch (
const std::exception&) { bhatrig =
false; }
321 if (m_eventmetadata.isValid()) {
322 if (m_eventmetadata->getErrorFlag() != 0x10) {
323 m_iEvent = m_eventmetadata->getEvent();
325 for (
const auto&
id : m_WaveformOption) {
326 if (
id ==
"logic" && m_iEvent % 1000 == 999) h_evtot_logic->Fill(0);
327 if (
id ==
"rand" && isRandomTrigger()) h_evtot_rand->Fill(0);
328 if (
id ==
"dphy" && bhatrig) h_evtot_dphy->Fill(0);
333 for (
auto& aECLDigit : m_ECLDigits) {
334 int i = aECLDigit.getCellId() - 1;
335 h_quality->Fill(aECLDigit.getQuality());
336 if (aECLDigit.getAmp() > 2.e04 && aECLDigit.getQuality() == 3) h_bad_quality->Fill(aECLDigit.getCellId());
337 if (aECLDigit.getAmp() >= (v_totalthrApsd[i] / 4 * 4)) NDigits ++;
338 for (
const auto&
id : m_WaveformOption) {
339 if (
id !=
"psd")
continue;
340 else if (
id ==
"psd" && (m_iEvent % 1000 == 999 ||
343 aECLDigit.getAmp() < (v_totalthrApsd[i] / 4 * 4)))
continue;
344 h_cell_psd_norm->Fill(aECLDigit.getCellId());
348 for (
auto& aECLTrig : m_ECLTrigs) {
349 double itrg = aECLTrig.getTimeTrig();
352 int tg = (int)itrg - 2 * ((
int)itrg / 8);
353 h_trigtime_trigid->Fill(aECLTrig.getTrigId(), tg);
354 trigtag1 += aECLTrig.getTrigTag();
355 h_trigtag2_trigid->Fill(aECLTrig.getTrigId(), aECLTrig.getTrigTagQualityFlag());
358 if (m_ECLTrigs.getEntries() > 0) {
360 trigtag1 /= m_ECLTrigs.getEntries();
361 int compar = (65535 & m_iEvent);
362 if (compar == trigtag1) flagtag = 0;
363 h_trigtag1->Fill(flagtag);
366 for (
auto& aECLCalDigit : m_ECLCalDigits) {
367 int cid = aECLCalDigit.getCellId();
368 double energy = aECLCalDigit.getEnergy();
369 double timing = aECLCalDigit.getTime();
371 for (
const auto&
id : m_HitThresholds) {
372 auto scale =
id / 1000.;
373 auto index = std::distance(m_HitThresholds.begin(), std::find(m_HitThresholds.begin(), m_HitThresholds.end(),
id));
374 if (energy > scale) {
375 h_cids[index]->Fill(cid);
380 for (
const auto&
id : m_TotalEnergyThresholds) {
381 auto scale =
id / 1000.;
382 auto index = std::distance(m_TotalEnergyThresholds.begin(), std::find(m_TotalEnergyThresholds.begin(),
383 m_TotalEnergyThresholds.end(),
id));
384 if (energy > scale) ecltot[index] += energy;
387 for (
const auto&
id : m_TimingThresholds) {
388 auto scale =
id / 1000.;
389 auto index = std::distance(m_TimingThresholds.begin(), std::find(m_TimingThresholds.begin(), m_TimingThresholds.end(),
id));
390 if (energy > scale) {
391 if (cid > ECL_FWD_CHANNELS && cid <= ECL_FWD_CHANNELS + ECL_BARREL_CHANNELS) h_time_barrels[index]->Fill(timing);
392 else h_time_endcaps[index]->Fill(timing);
396 if (energy > 1.000 && std::abs(timing) < 100.) h_time_crate_Thr1GeV[mapper.getCrateID(cid) - 1]->Fill(timing);
397 if (energy > 1.000 && std::abs(timing) > 100.) h_time_crate_Thr1GeV_large->Fill(mapper.getCrateID(cid));
400 for (
auto& h : h_edeps) {
401 auto index = std::distance(h_edeps.begin(), std::find(h_edeps.begin(), h_edeps.end(), h));
402 h->Fill(ecltot[index]);
405 for (
auto& h : h_ncevs) {
406 auto index = std::distance(h_ncevs.begin(), std::find(h_ncevs.begin(), h_ncevs.end(), h));
407 h->Fill(nhits[index]);
410 for (
auto& aECLDsp : m_ECLDsps) {
411 int i = aECLDsp.getCellId() - 1;
412 aECLDsp.getDspA(m_DspArray[i]);
413 m_PedestalMean[i] = 0;
414 m_PedestalRms[i] = 0;
416 for (
int j = 0; j < 16; j++) m_PedestalMean[i] += m_DspArray[i][j];
417 m_PedestalMean[i] /= 16;
418 h_pedmean_cellid->Fill(aECLDsp.getCellId(), m_PedestalMean[i]);
420 for (
int j = 0; j < 16; j++) m_PedestalRms[i] += pow(m_DspArray[i][j] - m_PedestalMean[i], 2);
421 m_PedestalRms[i] = sqrt(m_PedestalRms[i] / 15.);
422 h_pedrms_cellid->Fill(aECLDsp.getCellId(), m_PedestalRms[i]);
424 h_pedrms_thetaid->Fill(m_geom->GetThetaID(), m_PedestalRms[i]);
428 for (
const auto&
id : m_WaveformOption) {
429 auto index = std::distance(m_WaveformOption.begin(), std::find(m_WaveformOption.begin(), m_WaveformOption.end(),
id));
430 if (
id !=
"all" &&
id !=
"psd" &&
id !=
"logic" &&
id !=
"rand" &&
id !=
"dphy" &&
id !=
"other")
continue;
431 else if (
id ==
"psd" && (m_iEvent % 1000 == 999 || isRandomTrigger() || bhatrig ||
432 !aECLDigit || aECLDigit->
getAmp() < (v_totalthrApsd[i] / 4 * 4)))
continue;
433 else if (
id ==
"logic" && m_iEvent % 1000 != 999)
continue;
434 else if (
id ==
"rand" && (m_iEvent % 1000 == 999 || !isRandomTrigger()))
continue;
435 else if (
id ==
"dphy" && (m_iEvent % 1000 == 999 || !bhatrig))
continue;
436 else if (
id ==
"other" && (m_iEvent % 1000 == 999 || isRandomTrigger() || bhatrig ||
437 (aECLDigit && aECLDigit->
getAmp() >= (v_totalthrApsd[i] / 4 * 4))))
continue;
438 h_cells[index]->Fill(aECLDsp.getCellId());
439 if (
id ==
"other" && aECLDigit) h_quality_other->Fill(aECLDigit->
getQuality());
442 if (m_ECLDigits.getEntries() > 0)
443 h_adc_hits->Fill((
double)NDigits / (
double)m_ECLDigits.getEntries());
457 if (!m_l1Trigger.isValid())
return false;
458 return m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_RAND ||
459 m_l1Trigger->getTimType() == TRGSummary::ETimingType::TTYP_POIS;
This module is created to monitor ECL Data Quality.
virtual void initialize() override
Initialize the module.
virtual ~ECLDQMModule()
Destructor.
virtual void event() override
Event processor.
virtual void endRun() override
Call when a run ends.
virtual void terminate() override
Terminate.
virtual void beginRun() override
Call when a run begins.
virtual void defineHisto() override
Function to define histograms.
Class to store ECL digitized hits (output of ECLDigi) relation to ECLHit filled in ecl/modules/eclDig...
int getAmp() const
Get Fitting Amplitude.
int getQuality() const
Get Fitting Quality.
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
static const double GeV
Standard of [energy, momentum, mass].
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.