Belle II Software development
DQMHistAnalysisPXDTrackCharge.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8//+
9// File : DQMHistAnalysisPXDTrackCharge.cc
10// Description : Analysis of PXD Cluster Charge
11//-
12
13#include <dqm/analysis/modules/DQMHistAnalysisPXDTrackCharge.h>
14#include <TROOT.h>
15#include <TStyle.h>
16#include <TLatex.h>
17#include <vxd/geometry/GeoCache.h>
18
19#include <RooDataHist.h>
20#include <RooAbsPdf.h>
21#include <RooPlot.h>
22#include <RooFitResult.h>
23#include <RooMsgService.h>
24
25using namespace std;
26using namespace Belle2;
27
28//-----------------------------------------------------------------
29// Register the Module
30//-----------------------------------------------------------------
31REG_MODULE(DQMHistAnalysisPXDTrackCharge);
32
33//-----------------------------------------------------------------
34// Implementation
35//-----------------------------------------------------------------
36
39{
40 // This module CAN NOT be run in parallel!
41 setDescription("DQM Analysis for PXD Track-Cluster Charge");
42
43 // Parameter definition
44 addParam("histogramDirectoryName", m_histogramDirectoryName, "Name of Histogram dir", std::string("PXDER"));
45 addParam("RangeLow", m_rangeLow, "Lower border for fit", 20.);
46 addParam("RangeHigh", m_rangeHigh, "High border for fit", 80.);
47// addParam("PeakBefore", m_peakBefore, "Range for fit before peak (positive)", 5.);
48// addParam("PeakAfter", m_peakAfter, "Range for after peak", 40.);
49 addParam("excluded", m_excluded, "excluded module (indizes starting from 0 to 39)", std::vector<int>());
50 B2DEBUG(99, "DQMHistAnalysisPXDTrackCharge: Constructor done.");
51}
52
54{
55 B2DEBUG(99, "DQMHistAnalysisPXDTrackCharge: initialized.");
56
59
60 m_rfws = new RooWorkspace("w");
61 m_rfws->factory("Landau::landau(x[0,100],ml[20,10,50],sl[5,1,30])");
62 m_rfws->factory("Gaussian::gauss(x,mg[0],sg[2,0.1,10])");
63 m_rfws->factory("FCONV::lxg(x,landau,gauss)");
64
65 m_x = m_rfws->var("x");
66 m_x->setRange("signal", m_rangeLow, m_rangeHigh);
67
68 // collect the list of all PXD Modules in the geometry here
69 std::vector<VxdID> sensors = geo.getListOfSensors();
70 for (const auto& aVxdID : sensors) {
71 VXD::SensorInfoBase info = geo.getSensorInfo(aVxdID);
72 if (info.getType() != VXD::SensorInfoBase::PXD) continue;
73 m_PXDModules.push_back(aVxdID); // reorder, sort would be better
74
75 std::string name = "PXD_Track_Cluster_Charge_" + (std::string)aVxdID;
76 std::replace(name.begin(), name.end(), '.', '_');
77 m_cChargeMod[aVxdID] = new TCanvas((m_histogramDirectoryName + "/c_Fit_" + name).data());
78 if (aVxdID == VxdID("1.5.1")) {
79 for (int s = 0; s < 6; s++) {
80 for (int d = 0; d < 4; d++) {
81 m_cChargeModASIC[aVxdID][s][d] = new TCanvas((m_histogramDirectoryName + "/c_Fit_" + name + Form("_s%d_d%d", s + 1, d + 1)).data());
82 }
83 }
84 m_hChargeModASIC2d[aVxdID] = new TH2F(("hPXD_TCChargeMPV_" + name).data(),
85 ("PXD TCCharge MPV " + name + ";Switcher;DCD;MPV").data(),
86 6, 0.5, 6.5, 4, 0.5, 4.5);
87 m_cChargeModASIC2d[aVxdID] = new TCanvas((m_histogramDirectoryName + "/c_TCCharge_MPV_" + name).data());
88 }
89 }
90 if (m_PXDModules.size() == 0) {
91 // Backup if no geometry is present (testing...)
92 B2WARNING("No PXDModules in Geometry found! Use hard-coded setup.");
93 std::vector <string> mod = {
94 "1.1.1", "1.1.2", "1.2.1", "1.2.2", "1.3.1", "1.3.2", "1.4.1", "1.4.2",
95 "1.5.1", "1.5.2", "1.6.1", "1.6.2", "1.7.1", "1.7.2", "1.8.1", "1.8.2",
96 "2.1.1", "2.1.2", "2.2.1", "2.2.2", "2.3.1", "2.3.2", "2.4.1", "2.4.2",
97 "2.5.1", "2.5.2", "2.6.1", "2.6.2", "2.7.1", "2.7.2", "2.8.1", "2.8.2",
98 "2.9.1", "2.9.2", "2.10.1", "2.10.2", "2.11.1", "2.11.2", "2.12.1", "2.12.2"
99 };
100 for (const auto& it : mod) m_PXDModules.push_back(VxdID(it));
101 }
102 std::sort(m_PXDModules.begin(), m_PXDModules.end()); // back to natural order
103
104 gROOT->cd(); // this seems to be important, or strange things happen
105
106 m_cTrackedClusters = new TCanvas((m_histogramDirectoryName + "/c_TrackedClusters").data());
107 m_hTrackedClusters = new TH1F("hPXDTrackedClusters", "PXD Tracked Clusters/Event;Module", 40, 0, 40);
108 m_hTrackedClusters->Draw();
109 if (auto ax = m_hTrackedClusters->GetXaxis(); ax != nullptr) {
110 ax->Set(m_PXDModules.size(), 0, m_PXDModules.size());
111 for (unsigned int i = 0; i < m_PXDModules.size(); i++) {
112 TString ModuleName = (std::string)m_PXDModules[i];
113 ax->SetBinLabel(i + 1, ModuleName);
114 }
115 } else B2ERROR("no axis");
116
117 m_cCharge = new TCanvas((m_histogramDirectoryName + "/c_TrackCharge").data());
118 m_monObj->addCanvas(m_cCharge);
119
120 m_gCharge = new TGraphErrors();
121 m_gCharge->SetName("Track_Cluster_Charge");
122 m_gCharge->SetTitle("Track Cluster Charge");
123
125 m_line_up = new TLine(0, 10, m_PXDModules.size(), 10);
126 m_line_mean = new TLine(0, 16, m_PXDModules.size(), 16);
127 m_line_low = new TLine(0, 3, m_PXDModules.size(), 3);
128 m_line_up->SetHorizontal(true);
129 m_line_up->SetLineColor(kMagenta);// Green
130 m_line_up->SetLineWidth(3);
131 m_line_up->SetLineStyle(7);
132 m_line_mean->SetHorizontal(true);
133 m_line_mean->SetLineColor(kGreen);// Black
134 m_line_mean->SetLineWidth(3);
135 m_line_mean->SetLineStyle(4);
136 m_line_low->SetHorizontal(true);
137 m_line_low->SetLineColor(kMagenta);
138 m_line_low->SetLineWidth(3);
139 m_line_low->SetLineStyle(7);
140
141 m_fMean = new TF1("f_Mean", "pol0", 0, m_PXDModules.size());
142 m_fMean->SetParameter(0, 50);
143 m_fMean->SetLineColor(kYellow);
144 m_fMean->SetLineWidth(3);
145 m_fMean->SetLineStyle(7);
146 m_fMean->SetNpx(m_PXDModules.size());
147 m_fMean->SetNumberFitPoints(m_PXDModules.size());
148
149 registerEpicsPV("PXD:TrackCharge:Mean", "Mean");
150 registerEpicsPV("PXD:TrackCharge:Diff", "Diff");
151 registerEpicsPV("PXD:TrackCharge:Status", "Status");
152}
153
154
156{
157 B2DEBUG(99, "DQMHistAnalysisPXDTrackCharge: beginRun called.");
158
159 if (m_cCharge) m_cCharge->Clear();
161}
162
164{
165 // need to be done every event in case someone else modifies it.
166 RooMsgService::instance().setSilentMode(true);
167 RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
168
169 gStyle->SetOptStat(0);
170 gStyle->SetStatStyle(1);
171 gStyle->SetOptDate(22);// Date and Time in Bottom Right, does no work
172
173 if (m_cTrackedClusters and m_hTrackedClusters) { // tracked clusters
174 // we already have a plot, but we need to rearrange the X labels in a new plot and scale to events
175 std::string name = "Tracked_Clusters"; // new name
176 // update only if histogram is updated
177 if (auto hh2 = findHist(m_histogramDirectoryName, "PXD_Tracked_Clusters", true); hh2 != nullptr) {
178 m_cTrackedClusters->Clear();
179 m_cTrackedClusters->cd();
180 m_hTrackedClusters->Reset();
181
182 auto scale = hh2->GetBinContent(0);// overflow misused as event counter!
183 if (scale > 0) {
184 auto iscale = 1. / scale;
185 int j = 1;
186 for (int i = 0; i < 64; i++) {
187 auto layer = (((i >> 5) & 0x1) + 1);
188 auto ladder = ((i >> 1) & 0xF);
189 auto sensor = ((i & 0x1) + 1);
190
191 auto id = Belle2::VxdID(layer, ladder, sensor);
192 // Check if sensor exist
193 if (Belle2::VXD::GeoCache::getInstance().validSensorID(id)) {
194 m_hTrackedClusters->SetBinContent(j, hh2->GetBinContent(i + 1) * iscale);
195 j++;
196 }
197 }
198 }
199 m_hTrackedClusters->SetName(name.data());
200 m_hTrackedClusters->SetTitle("Tracked Clusters/Event");
201 m_hTrackedClusters->SetFillColor(kWhite);
202 m_hTrackedClusters->SetStats(kFALSE);
203 m_hTrackedClusters->SetLineStyle(1);// 2 or 3
204 m_hTrackedClusters->SetLineColor(kBlack);
205 m_hTrackedClusters->Draw("hist");
206
207 // get ref histogram
208 // no scaling! TODO this is a special reference plot, in which directory is it?
209 // TODO: we would expect that it changes with luminosity and maybe beam condition, but not clear how to factor this out. simple scaling seems not the right way.
210 if (auto href2 = findRefHist(name); href2 != nullptr) {
211 href2->SetLineStyle(3);// 2 or 3
212 href2->SetLineColor(kBlue);
213 href2->Draw("same,hist");
214 }
215
216 for (const auto& it : m_excluded) {
217 static std::map <int, TLatex*> ltmap;
218 auto tt = ltmap[it];
219 if (!tt) {
220 tt = new TLatex(it + 0.5, 0, (" " + std::string(m_PXDModules[it]) + " Module is excluded, please ignore").c_str());
221 tt->SetTextSize(0.035);
222 tt->SetTextAngle(90);// Rotated
223 tt->SetTextAlign(12);// Centered
224 ltmap[it] = tt;
225 }
226 tt->Draw();
227 }
228
230 }
231 } // end of tracked clusters plot
232
233 bool any_enought_flag = false;
234
235// auto landau = m_rfws->pdf("landau");
236// auto gauss = m_rfws->pdf("gauss");
237 auto model = m_rfws->pdf("lxg");
238
239 auto ml = m_rfws->var("ml");
240// auto sl = m_rfws->var("sl");
241// auto mg = m_rfws->var("mg");
242// auto sg = m_rfws->var("sg");
243
244 if (!m_cCharge) return;
245 m_gCharge->Set(0);
246
247 for (unsigned int i = 0; i < m_PXDModules.size(); i++) {
248 TCanvas* canvas = m_cChargeMod[m_PXDModules[i]];
249 if (canvas == nullptr) continue;
250
251 std::string name = "PXD_Track_Cluster_Charge_" + (std::string)m_PXDModules[i];
252 std::replace(name.begin(), name.end(), '.', '_');
253
254 if (auto hh1 = findHist(m_histogramDirectoryName, name, true); hh1 != nullptr) { // update only if histo was updated
255 canvas->cd();
256 canvas->Clear();
257
258 if (hh1->GetEntries() > 50) {
259
260 auto hdata = new RooDataHist(hh1->GetName(), hh1->GetTitle(), *m_x, dynamic_cast<const TH1*>(hh1));
261 auto plot = m_x->frame(RooFit::Title(hh1->GetTitle()));
262 /*auto r =*/ model->fitTo(*hdata, RooFit::Range("signal"));
263
264 model->paramOn(plot, RooFit::Format("NELU", RooFit::AutoPrecision(2)), RooFit::Layout(0.6, 0.9, 0.9));
265 hdata->plotOn(plot, RooFit::LineColor(kBlue)/*, RooFit::Range("plot"), RooFit::NormRange("signal")*/);
266 model->plotOn(plot, RooFit::LineColor(kRed), RooFit::Range("signal"), RooFit::NormRange("signal"));
267
268 plot->Draw("");
269
270// model->Print("");
271// ml->Print("");
272// sl->Print("");
273// mg->Print("");
274// sg->Print("");
275// cout << "ZZZ , " << Form("%d%02d%d ,", std::get<0>(t), std::get<1>(t), std::get<2>(t)) << ml->getValV() << "," << ml->getError() << "," << sl->getValV() << "," << sl->getError() << "," << sg->getValV() << "," << sg->getError() << endl;
276
277
278 int p = m_gCharge->GetN();
279 m_gCharge->SetPoint(p, i + 0.49, ml->getValV());
280 m_gCharge->SetPointError(p, 0.1, ml->getError()); // error in x is useless
281 m_monObj->setVariable(("trackcharge_" + (std::string)m_PXDModules[i]).c_str(), ml->getValV(), ml->getError());
282 } else {
283 hh1->Draw("hist"); // avoid to confuse people by showing nothing for low stat
284 }
285
286 // get ref histogram, no scaling
287 if (auto hist2 = findRefHist(m_histogramDirectoryName, name, ERefScaling::c_RefScaleEntries, hh1); hist2 != nullptr) {
288 B2DEBUG(20, "Draw Normalized " << hist2->GetName());
289 hist2->SetLineStyle(3);// 2 or 3
290 hist2->SetLineColor(kBlack);
291 hist2->SetStats(kFALSE);
292 hist2->Draw("same,hist");
293 }
294
295 // add coloring, cuts? based on fit, compare with ref?
296 auto status = makeStatus(hh1->GetEntries() >= 100, false, false); // only statistics, no alarm (yet)
297 colorizeCanvas(canvas, status);
298
299 canvas->Modified();
300 canvas->Update();
301 UpdateCanvas(canvas);
302
303 // means if ANY plot is > 100 entries, all plots are assumed to be o.k. from statistics
304 if (hh1->GetEntries() >= 1000) any_enought_flag = true;
305 }
306 }
307
308 // now loop per module over asics pairs (1.5.1)
309 for (unsigned int i = 0; i < m_PXDModules.size(); i++) {
310// TCanvas* canvas = m_cChargeMod[m_PXDModules[i]];
311 const VxdID& aVxdID = m_PXDModules[i];
312
313 if (m_hChargeModASIC2d[aVxdID]) m_hChargeModASIC2d[aVxdID]->Reset();
314 if (m_cChargeModASIC2d[aVxdID]) m_cChargeModASIC2d[aVxdID]->Clear();
315
316 for (int s = 1; s <= 6; s++) {
317 for (int d = 1; d <= 4; d++) {
318 std::string name = "PXD_Track_Cluster_Charge_" + (std::string)m_PXDModules[i] + Form("_sw%d_dcd%d", s, d);
319 std::replace(name.begin(), name.end(), '.', '_');
320
321 if (m_cChargeModASIC[aVxdID][s - 1][d - 1]) {
322 m_cChargeModASIC[aVxdID][s - 1][d - 1]->Clear();
323 m_cChargeModASIC[aVxdID][s - 1][d - 1]->cd();
324 }
325
326 if (auto hh1 = findHist(m_histogramDirectoryName, name); hh1 != nullptr) {
327 double mpv = 0.0;
328 if (hh1->GetEntries() > 50) {
329 auto hdata = new RooDataHist(hh1->GetName(), hh1->GetTitle(), *m_x, static_cast<const TH1*>(hh1));
330 auto plot = m_x->frame(RooFit::Title(hh1->GetTitle()));
331 /*auto r =*/ model->fitTo(*hdata, RooFit::Range("signal"));
332
333 if (m_cChargeModASIC[aVxdID][s - 1][d - 1]) {
334 model->paramOn(plot, RooFit::Format("NELU", RooFit::AutoPrecision(2)), RooFit::Layout(0.6, 0.9, 0.9));
335 hdata->plotOn(plot, RooFit::LineColor(kBlue)/*, RooFit::Range("plot"), RooFit::NormRange("signal")*/);
336 model->plotOn(plot, RooFit::LineColor(kRed), RooFit::Range("signal"), RooFit::NormRange("signal"));
337 }
338 plot->Draw("");
339
340 mpv = ml->getValV();
341 }
342
343 if (m_hChargeModASIC2d[aVxdID]) {
344 if (mpv > 0.0) m_hChargeModASIC2d[aVxdID]->Fill(s, d, mpv); // TODO check what is s, d
345 }
346 }
347 }
348 }
349
350 // Overview map of ASCI combinations
351 if (m_hChargeModASIC2d[aVxdID] && m_cChargeModASIC2d[aVxdID]) {
352 m_cChargeModASIC2d[aVxdID]->cd();
353 m_hChargeModASIC2d[aVxdID]->Draw("colz");
355 }
356 }
357
358 m_cCharge->cd();
359 m_cCharge->Clear();
360 m_gCharge->SetMinimum(0);
361 m_gCharge->SetMaximum(70);
362 auto ax = m_gCharge->GetXaxis();
363 if (ax) {
364 ax->Set(m_PXDModules.size(), 0, m_PXDModules.size());
365 for (unsigned int i = 0; i < m_PXDModules.size(); i++) {
366 TString ModuleName = (std::string)m_PXDModules[i];
367 ax->SetBinLabel(i + 1, ModuleName);
368 }
369 } else B2ERROR("no axis");
370
371 m_gCharge->SetLineColor(4);
372 m_gCharge->SetLineWidth(2);
373 m_gCharge->SetMarkerStyle(8);
374 m_gCharge->Draw("AP");
375
376 for (const auto& it : m_excluded) {
377 static std::map <int, TLatex*> ltmap;
378 auto tt = ltmap[it];
379 if (!tt) {
380 tt = new TLatex(it + 0.5, 0, (" " + std::string(m_PXDModules[it]) + " Module is excluded, please ignore").c_str());
381 tt->SetTextSize(0.035);
382 tt->SetTextAngle(90);// Rotated
383 tt->SetTextAlign(12);// Centered
384 ltmap[it] = tt;
385 }
386 tt->Draw();
387 }
388 m_cCharge->cd(0);
389 m_cCharge->Modified();
390 m_cCharge->Update();
392
393 double data = 0;
394 double diff = 0;
395 if (any_enought_flag) {
396// double currentMin, currentMax;
397 m_gCharge->Fit(m_fMean, "R");
398 double mean = m_gCharge->GetMean(2);
399 double maxi = mean + 15;
400 double mini = mean - 15;
401 m_line_up->SetY1(maxi);
402 m_line_up->SetY2(maxi);
403 m_line_mean->SetY1(mean);
404 m_line_mean->SetY2(mean);
405 m_line_low->SetY1(mini);
406 m_line_low->SetY2(mini);
407 data = mean; // m_fMean->GetParameter(0); // we are more interested in the maximum deviation from mean
408 // m_gCharge->GetMinimumAndMaximum(currentMin, currentMax);
409 diff = m_gCharge->GetRMS(2);// RMS of Y
410 // better, max deviation as fabs(data - currentMin) > fabs(currentMax - data) ? fabs(data - currentMin) : fabs(currentMax - data);
411 m_line_up->Draw();
412 m_line_mean->Draw();
413 m_line_low->Draw();
414
415 m_monObj->setVariable("trackcharge", mean, diff);
416 }
417
418 setEpicsPV("Mean", data);
419 setEpicsPV("Diff", diff);
420
421 // FIXME: what is the acceptable limit?
422 auto status = makeStatus(any_enought_flag, fabs(data - 30) > 15. || diff > 8, fabs(data - 30.) > 20. || diff > 12);
423 colorizeCanvas(m_cCharge, status);
424
425 setEpicsPV("Status", status);
426}
427
429{
430 B2DEBUG(99, "DQMHistAnalysisPXDTrackCharge : endRun called");
431}
432
433
435{
436 B2DEBUG(99, "DQMHistAnalysisPXDTrackCharge: terminate called");
437
438 if (m_rfws) delete m_rfws;
439
442 if (m_cCharge) delete m_cCharge;
443 if (m_gCharge) delete m_gCharge;
444 if (m_line_up) delete m_line_up;
445 if (m_line_mean) delete m_line_mean;
446 if (m_line_low) delete m_line_low;
447 if (m_fMean) delete m_fMean;
448}
int registerEpicsPV(const std::string &pvname, const std::string &keyname="")
EPICS related Functions.
static MonitoringObject * getMonitoringObject(const std::string &name)
Get MonitoringObject with given name (new object is created if non-existing)
static void colorizeCanvas(TCanvas *canvas, EStatus status)
Helper function for Canvas colorization.
static void UpdateCanvas(const std::string &name, bool updated=true)
Mark canvas as updated (or not)
DQMHistAnalysisModule()
Constructor / Destructor.
@ c_RefScaleEntries
to number of entries (integral)
static EStatus makeStatus(bool enough, bool warn_flag, bool error_flag)
Helper function to judge the status for coloring and EPICS.
static TH1 * findRefHist(const std::string &dirname, const std::string &histname="", ERefScaling scaling=ERefScaling::c_RefScaleNone, const TH1 *hist=nullptr)
Find reference histogram.
void setEpicsPV(const std::string &keyname, double value)
Write value to a EPICS PV.
static TH1 * findHist(const std::string &dirname, const std::string &histname="", bool onlyIfUpdated=false)
Find histogram.
void terminate(void) override final
This method is called at the end of the event processing.
std::map< VxdID, std::array< std::array< TCanvas *, 4 >, 6 > > m_cChargeModASIC
Final Canvases for Fit and Ref per ASIC.
std::map< VxdID, TH2F * > m_hChargeModASIC2d
Final Canvas Fit and Ref per ASIC.
void endRun(void) override final
This method is called if the current run ends.
TLine * m_line_up
TLine object for upper limit of track cluster charge.
TGraphErrors * m_gCharge
Graph covering all modules.
std::vector< VxdID > m_PXDModules
IDs of all PXD Modules to iterate over.
std::string m_histogramDirectoryName
name of histogram directory
TLine * m_line_mean
TLine object for mean of track cluster charge.
TLine * m_line_low
TLine object for lower limit of track cluster charge.
std::vector< int > m_excluded
Indizes of excluded PXD Modules.
TH1F * m_hTrackedClusters
Histogram for TrackedClusters.
TCanvas * m_cTrackedClusters
Final Canvas for TrackedClusters.
std::map< VxdID, TCanvas * > m_cChargeMod
Final Canvases for Fit and Ref.
void beginRun(void) override final
Called when entering a new run.
void event(void) override final
This method is called for each event.
std::map< VxdID, TCanvas * > m_cChargeModASIC2d
Final Canvas Fit and Ref per ASIC.
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
Class to facilitate easy access to sensor information of the VXD like coordinate transformations or p...
Definition GeoCache.h:38
const std::vector< VxdID > getListOfSensors() const
Get list of all sensors.
Definition GeoCache.cc:59
const SensorInfoBase & getSensorInfo(Belle2::VxdID id) const
Return a reference to the SensorInfo of a given SensorID.
Definition GeoCache.cc:67
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition GeoCache.cc:214
Base class to provide Sensor Information for PXD and SVD.
Class to uniquely identify a any structure of the PXD and SVD.
Definition VxdID.h:32
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
Abstract base class for different kinds of events.
STL namespace.