Belle II Software development
CDCDedxBadWireAlgorithm.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#include <cdc/calibration/CDCdEdx/CDCDedxBadWireAlgorithm.h>
10
11#include <cdc/geometry/CDCGeometryPar.h>
12#include <framework/utilities/MathHelpers.h>
13
14#include <TCanvas.h>
15#include <TLegend.h>
16#include <TLine.h>
17#include <TMath.h>
18#include <TStyle.h>
19
20using namespace Belle2;
21using namespace CDC;
22using namespace std;
23
24//-----------------------------------------------------------------
25// Implementation
26//-----------------------------------------------------------------
28 CalibrationAlgorithm("CDCDedxElectronCollector"),
29 c_nwireCDC(c_nSenseWires),
30 m_isMakePlots(true),
31 m_isADC(false),
32 m_varBins(100),
33 m_varMin(0.0),
34 m_varMax(7.0),
35 m_meanThres(1.0),
36 m_rmsThres(1.0),
37 m_fracThres(1.0),
38 m_varName("hitdedx"),
39 m_suffix("")
40{
41 // Set module properties
42 setDescription("A calibration algorithm for CDC dE/dx bad wires");
43}
44
45//-----------------------------------------------------------------
46// Run the calibration
47//-----------------------------------------------------------------
49{
50
52
53 //old wg for book-keeping previous bad+dead
54 if (!m_DBBadWires.isValid() || !m_DBWireGains.isValid())
55 B2FATAL("There is no valid payload for BadWire and/or Wirgain");
56
57 // Get data objects
58 auto ttree = getObjectPtr<TTree>("tree");
59 if (ttree->GetEntries() < 1000) return c_NotEnoughData;
60
61 vector<int>* wire = 0;
62 ttree->SetBranchAddress("wire", &wire);
63
64 vector<double>* hitvar = 0;
65 if (m_isADC) ttree->SetBranchAddress("adccorr", &hitvar);
66 else ttree->SetBranchAddress("dedxhit", &hitvar);
67
68 if (m_isADC) m_varName = "hitadc";
69 m_suffix = Form("%s_%s", m_varName.data(), m_suffix.data());
70
71 //IL = Inner Layer and OL = Outer Layer
72 array<TH1D*, 2> hvarL;
73 string label[2] = {"IL", "OL"};
74 for (int il = 0; il < 2; il++) {
75 hvarL[il] = new TH1D(Form("hvar%s_%s", label[il].data(), m_suffix.data()), "", m_varBins, m_varMin, m_varMax);
76 hvarL[il]->SetTitle(Form("dist (%s) %s; %s; %s", label[il].data(), m_suffix.data(), m_varName.data(), "entries"));
77 }
78
79 map<int, vector<double>> vhitvar;
80
81 m_slWireBoundary = (m_exp < 40) ? 1280 : 2240;
82
83 for (int i = 0; i < ttree->GetEntries(); ++i) {
84 ttree->GetEvent(i);
85 for (unsigned int ih = 0; ih < wire->size(); ++ih) {
86 int jwire = wire->at(ih);
87 double ivalue = hitvar->at(ih);
88 vhitvar[wire->at(ih)].push_back(ivalue);
89
90 if (jwire < m_slWireBoundary) hvarL[0]->Fill(ivalue);
91 else hvarL[1]->Fill(ivalue);
92 }
93 }
94
95 m_amean_IL = hvarL[0]->GetMean();
96 m_arms_IL = hvarL[0]->GetRMS();
97 m_amean_OL = hvarL[1]->GetMean();
98 m_arms_OL = hvarL[1]->GetRMS();
99
100 // Commenting minstat cut on March 2024,
101 //it is not worth to skip the calibration if there is more than 5% bad/dead wires
102
103 //return if >5% bad wire or null histogram
104 // int minstat = 0;
105 // for (unsigned int jw = 0; jw < c_nwireCDC; ++jw)
106 // if (vhitvar[jw].size() <= 100) minstat++;
107 // if (minstat > 0.05 * c_nwireCDC) return c_NotEnoughData;
108
109 if (m_amean_IL == 0 || m_arms_IL == 0 || m_amean_OL == 0 || m_arms_OL == 0) return c_NotEnoughData;
110
111 map<int, vector<double>> qapars;
112 vector<double> vdefectwires, vbadwires, vdeadwires;
113
114 for (unsigned int jw = 0; jw < c_nwireCDC; ++jw) {
115 int ncount = 0, tcount = 0;
116 double nmean = 0.;
117 for (unsigned int jh = 0; jh < vhitvar[jw].size(); ++jh) {
118 double jvalue = vhitvar[jw][jh];
119 if (jvalue < m_varMax) {
120 ncount++;
121 nmean += jvalue;
122 } else tcount++;
123 }
124
125 bool badwire = false;
126 if (ncount < 100) {
127 qapars[0].push_back(0);
128 qapars[1].push_back(0);
129 qapars[2].push_back(0);
130 badwire = true; //partial dead
131 } else {
132 nmean = nmean / ncount;
133 if (int(jw) < m_slWireBoundary) {
134 if (abs(nmean - m_amean_IL) / m_amean_IL > m_meanThres) badwire = true;
135 } else
136 {if (abs(nmean - m_amean_OL) / m_amean_OL > m_meanThres) badwire = true;}
137
138 double nrms = 0.;
139 for (unsigned int kh = 0; kh < vhitvar[jw].size(); ++kh) {
140 double kvalue = vhitvar[jw][kh];
141 if (kvalue < m_varMax) nrms += square(kvalue - nmean);
142 }
143
144 nrms = sqrt(nrms / ncount);
145 if (int(jw) < m_slWireBoundary)
146 {if (abs(nrms - m_arms_IL) / m_arms_IL > m_rmsThres) badwire = true;}
147 else
148 {if (abs(nrms - m_arms_OL) / m_arms_OL > m_rmsThres) badwire = true;}
149
150 double badfrac = 0.0;
151 if (tcount > 0) badfrac = (1.0 * tcount) / (tcount + ncount);
152 if (badfrac > m_fracThres) badwire = true;
153
154 qapars[0].push_back(nmean);
155 qapars[1].push_back(nrms);
156 qapars[2].push_back(badfrac);
157 }
158
159 if (badwire) {
160 vdefectwires.push_back(0.0);
161 if (ncount == 0) vdeadwires.push_back(jw);
162 else vbadwires.push_back(jw);
163 } else vdefectwires.push_back(1.0);
164 }
165
166
167 if (m_isMakePlots) {
168 //1. plot bad and good wire plots.
169 plotWireDist(vbadwires, vhitvar);
170
171 //2. plots wire status map
172 plotBadWireMap(vbadwires, vdeadwires);
173
174 //3. plot control parameters histograms
175 plotQaPars(qapars);
176
177 //4. plot statistics related histograms
179 }
180
181 // Save payloads
182 B2INFO("dE/dx Badwire Calibration done: " << vdefectwires.size() << " wires");
183 CDCDedxBadWires* c_badwires = new CDCDedxBadWires(vdefectwires);
184 saveCalibration(c_badwires, "CDCDedxBadWires");
185
186 m_suffix.clear();
187
188 return c_OK;
189}
190
191//------------------------------------
193{
194
195 int cruns = 0;
196 for (auto expRun : getRunList()) {
197 if (cruns == 0) B2INFO("CDCDedxBadWires: start exp " << expRun.first << " and run " << expRun.second << "");
198 cruns++;
199 }
200
201 const auto erStart = getRunList()[0];
202 int estart = erStart.first;
203 int rstart = erStart.second;
204
205 const auto erEnd = getRunList()[cruns - 1];
206 int rend = erEnd.second;
207
208 m_exp = estart;
209
210 updateDBObjPtrs(1, rstart, estart);
211
212 if (m_suffix.length() > 0) m_suffix = Form("%s_e%d_r%dr%d", m_suffix.data(), estart, rstart, rend);
213 else m_suffix = Form("e%d_r%dr%d", estart, rstart, rend);
214}
215
216
217//------------------------------------
218void CDCDedxBadWireAlgorithm::plotWireDist(const vector<double>& inwires,
219 map<int, vector<double>>& vhitvar)
220{
221
222 TList* bdlist = new TList();
223 bdlist->SetName("badwires");
224
225 TList* goodlist = new TList();
226 goodlist->SetName("goodwires");
227
228 TList* hflist = new TList();
229 hflist->SetName("highfracwires");
230
231 for (unsigned int jw = 0; jw < c_nwireCDC; ++jw) {
232
233 TH1D* hvar = new TH1D(Form("%s_wire%d", m_suffix.data(), jw), "", m_varBins, m_varMin, m_varMax);
234 hvar->SetUniqueID(jw);
235
236 TH1D* hvarhf = new TH1D(Form("hf%s_wire%d", m_suffix.data(), jw), "", m_varBins, m_varMin, m_varMax);
237 hvarhf->SetUniqueID(jw);
238 hvarhf->SetTitle(Form("%s, wire = %d; %s; entries", m_suffix.data(), jw, m_varName.data()));
239
240 int ncount = 0, tcount = 0;
241
242 for (unsigned int jh = 0; jh < vhitvar[jw].size(); ++jh) {
243 double jvalue = vhitvar[jw][jh];
244 if (jvalue < m_varMax) {
245 ncount++;
246 hvar->Fill(jvalue);
247 } else {
248 tcount++;
249 if (jvalue < m_varMax * 10.) hvarhf->Fill(jvalue / 10.);
250 }
251 }
252
253 double badfrac = 0.0;
254 if (tcount > 0) badfrac = (1.0 * tcount) / (tcount + ncount);
255 hvar->SetTitle(Form("%s, wire = %d; %s; %0.01f", m_suffix.data(), jw, m_varName.data(), badfrac * 100));
256
257 bool isbad = false;
258 if (count(inwires.begin(), inwires.end(), jw)) isbad = true;
259
260 double oldwg = m_DBWireGains->getWireGain(jw);
261 if (oldwg == 0) {
262 hvar->SetLineWidth(2);
263 hvar->SetLineColor(kRed);
264 }
265
266 if (isbad) {
267 bdlist->Add(hvar);
268 hflist->Add(hvarhf);
269 } else {
270 if (hvar->Integral() > 100) goodlist->Add(hvar);
271 }
272 }
273
274 printCanvas(bdlist, hflist, kYellow - 9);
275 printCanvas(goodlist, hflist, kGreen);
276
277 delete bdlist;
278 delete goodlist;
279 delete hflist;
280}
281
282//------------------------------------
283void CDCDedxBadWireAlgorithm::printCanvas(TList* list, TList* hflist, Color_t color)
284{
285
286 string listname = list->GetName();
287 string sfx = Form("%s_%s", listname.data(), m_suffix.data());
288
289 TCanvas ctmp(Form("cdcdedx_%s", sfx.data()), "", 1200, 1200);
290 ctmp.Divide(4, 4);
291 ctmp.SetBatch(kTRUE);
292
293 stringstream psname;
294 psname << Form("cdcdedx_bdcal_%s.pdf[", sfx.data());
295 ctmp.Print(psname.str().c_str());
296 psname.str("");
297 psname << Form("cdcdedx_bdcal_%s.pdf", sfx.data());
298
299 for (int ih = 0; ih < list->GetSize(); ih++) {
300
301 TH1D* hist = (TH1D*)list->At(ih);
302 int jw = hist->GetUniqueID();
303
304 double frac = stod(hist->GetYaxis()->GetTitle());
305
306 double amean = (jw < m_slWireBoundary) ? m_amean_IL : m_amean_OL;
307 double arms = (jw < m_slWireBoundary) ? m_arms_IL : m_arms_OL;
308
309 TPaveText* pinfo = new TPaveText(0.40, 0.63, 0.89, 0.89, "NBNDC");
310
311 pinfo->AddText(Form("#mu: %0.2f(%0.2f#pm%0.2f)", hist->GetMean(), amean, m_meanThres * amean));
312 pinfo->AddText(Form("#sigma: %0.2f(%0.2f#pm%0.2f)", hist->GetRMS(), arms, m_rmsThres * arms));
313 pinfo->AddText(Form("N: %0.00f", hist->Integral()));
314 pinfo->AddText(Form("hf: %0.00f%%(%0.00f%%)", frac, m_fracThres * 100));
315 setTextCosmetics(pinfo, 0.04258064);
316
317 ctmp.cd(ih % 16 + 1);
318 hist->GetYaxis()->SetTitle("entries");
319 hist->SetFillColor(color);
320 hist->SetStats(0);
321 hist->Draw();
322 pinfo->Draw("same");
323
324 if (listname == "badwires") {
325 TH1D* histhf = (TH1D*)hflist->At(ih);
326 if (hist->GetMaximum() < histhf->GetMaximum()) hist->SetMaximum(histhf->GetMaximum() * 1.05);
327 histhf->SetFillColor(kGray);
328 histhf->SetStats(0);
329 histhf->Draw("same");
330 }
331
332 if (((ih + 1) % 16 == 0) || ih == (list->GetSize() - 1)) {
333 ctmp.Print(psname.str().c_str());
334 ctmp.Clear("D");
335 }
336 }
337
338 psname.str("");
339 psname << Form("cdcdedx_bdcal_%s.pdf]", sfx.data());
340 ctmp.Print(psname.str().c_str());
341}
342
343//------------------------------------
344void CDCDedxBadWireAlgorithm::plotBadWireMap(const vector<double>& vbadwires, const vector<double>& vdeadwires)
345{
346
347 TCanvas cmap(Form("cmap_%s", m_suffix.data()), "", 800, 800);
348 cmap.SetTitle("CDC dE/dx bad wire status");
349
350 int total = 0;
351 TH2F* hxyAll = getHistoPattern(vbadwires, "all", total);
352 hxyAll->SetTitle(Form("wire status map (%s)", m_suffix.data()));
353 setHistCosmetics(hxyAll, kGray);
354 hxyAll->Draw();
355
356 int nbad = 0.0;
357 TH2F* hxyBad = getHistoPattern(vbadwires, "bad", nbad);
358 if (hxyBad) {
359 setHistCosmetics(hxyBad, kRed);
360 hxyBad->Draw("same");
361 }
362
363 int ndead = 0.0;
364 TH2F* hxyDead = getHistoPattern(vdeadwires, "dead", ndead);
365 if (hxyDead) {
366 setHistCosmetics(hxyDead, kBlack);
367 hxyDead->Draw("same");
368 }
369
370 int ndefect = nbad + ndead;
371 auto leg = new TLegend(0.68, 0.80, 0.90, 0.92);
372 leg->SetBorderSize(0);
373 leg->SetLineWidth(3);
374 leg->SetHeader(Form("total defective: %d (~%0.02f%%)", ndefect, 100.*(ndefect) / c_nwireCDC));
375 leg->AddEntry(hxyBad, Form("bad #rightarrow %d", nbad), "p");
376 leg->AddEntry(hxyDead, Form("dead #rightarrow %d", ndead), "p");
377 leg->Draw();
378
379 gStyle->SetLegendTextSize(0.025);
380 TPaveText* pt = new TPaveText(-0.30, -1.47, -0.31, -1.30, "br");
381 setTextCosmetics(pt, 0.02258064);
382
383 TText* text = pt->AddText("CDC-wire map: counter-clockwise and start from +x");
384 text->SetTextColor(kGray + 1);
385 pt->Draw("same");
386
387 cmap.SaveAs(Form("cdcdedx_bdcal_wiremap_%s.pdf", m_suffix.data()));
388
389 delete hxyAll;
390 delete hxyBad;
391 delete hxyDead;
392}
393
394//------------------------------------
395TH2F* CDCDedxBadWireAlgorithm::getHistoPattern(const vector<double>& inwires, const string& suffix, int& total)
396{
397
398 B2INFO("Creating CDCGeometryPar object");
400
401 TH2F* temp = new TH2F(Form("temp_%s_%s", m_suffix.data(), suffix.data()), "", 2400, -1.2, 1.2, 2400, -1.2, 1.2);
402
403 int jwire = -1;
404 total = 0;
405 for (unsigned int ilay = 0; ilay < c_maxNSenseLayers; ++ilay) {
406 for (unsigned int iwire = 0; iwire < cdcgeo.nWiresInLayer(ilay); ++iwire) {
407 jwire++;
408 double phi = 2.*TMath::Pi() * (float(iwire) / float(cdcgeo.nWiresInLayer(ilay)));
409 double radius = cdcgeo.senseWireR(ilay) / 100.;
410 double x = radius * cos(phi);
411 double y = radius * sin(phi);
412 if (suffix == "all") {
413 total++;
414 temp->Fill(x, y);
415 } else {
416 if (count(inwires.begin(), inwires.end(), jwire)) {
417 temp->Fill(x, y);
418 total++;
419 }
420 }
421 }
422 }
423 return temp;
424}
425
426//------------------------------------
427void CDCDedxBadWireAlgorithm::plotQaPars(map<int, vector<double>>& qapars)
428{
429
430 string qaname[3] = {"mean", "rms", "high_fraction"};
431
432 double lineminIL[3] = {m_amean_IL* (1 - m_meanThres), m_arms_IL* (1 - m_rmsThres), m_fracThres * 100};
433 double linemaxIL[3] = {m_amean_IL* (1 + m_meanThres), m_arms_IL* (1 + m_rmsThres), m_fracThres * 100};
434
435 double lineminOL[3] = {m_amean_OL* (1 - m_meanThres), m_arms_OL* (1 - m_rmsThres), m_fracThres * 100};
436 double linemaxOL[3] = {m_amean_OL* (1 + m_meanThres), m_arms_OL* (1 + m_rmsThres), m_fracThres * 100};
437
438 for (int iqa = 0; iqa < 3; iqa++) {
439
440 TH1D histqa(Form("%s_%s", qaname[iqa].data(), m_suffix.data()), "", c_nwireCDC, -0.5, 14335.5);
441
442 for (unsigned int jw = 0; jw < c_nwireCDC; jw++) {
443 if (iqa == 2) histqa.SetBinContent(jw + 1, qapars[iqa][jw] * 100);
444 else histqa.SetBinContent(jw + 1, qapars[iqa][jw]);
445 }
446
447 TCanvas c_pars(Form("c_pars_%d", iqa), "", 800, 600);
448 c_pars.cd();
449 gPad->SetGridy();
450
451 histqa.SetTitle(Form("%s vs wires (%s); wire ; %s", qaname[iqa].data(), m_suffix.data(), qaname[iqa].data()));
452 histqa.SetStats(0);
453 histqa.Draw();
454
455 TLine* lminIL = new TLine(-0.5, lineminIL[iqa], 2239.5, lineminIL[iqa]);
456 lminIL->SetLineColor(kRed);
457 lminIL->Draw("same");
458 TLine* lmaxIL = new TLine(-0.5, linemaxIL[iqa], 2239.5, linemaxIL[iqa]);
459 lmaxIL->SetLineColor(kRed);
460 lmaxIL->Draw("same");
461 TLine* lminOL = new TLine(2239.5, lineminOL[iqa], 14335.5, lineminOL[iqa]);
462 lminOL->SetLineColor(kRed);
463 lminOL->Draw("same");
464 TLine* lmaxOL = new TLine(2239.5, linemaxOL[iqa], 14335.5, linemaxOL[iqa]);
465 lmaxOL->SetLineColor(kRed);
466 lmaxOL->Draw("same");
467
468 c_pars.Print(Form("cdcdedx_bdcal_%s_%s.root", qaname[iqa].data(), m_suffix.data()));
469 c_pars.Print(Form("cdcdedx_bdcal_%s_%s.pdf", qaname[iqa].data(), m_suffix.data()));
470
471 delete lmaxIL;
472 delete lminIL;
473 }
474}
475
476//------------------------------------
478{
479
480 TCanvas cstats("cstats", "cstats", 1000, 500);
481 cstats.SetBatch(kTRUE);
482 cstats.Divide(2, 1);
483
484 cstats.cd(1);
485 auto hestats = getObjectPtr<TH1I>("hestats");
486 if (hestats) {
487 hestats->SetName(Form("htstats_%s", m_suffix.data()));
488 hestats->SetStats(0);
489 hestats->DrawCopy("");
490 }
491
492 cstats.cd(2);
493 auto htstats = getObjectPtr<TH1I>("htstats");
494 if (htstats) {
495 htstats->SetName(Form("htstats_%s", m_suffix.data()));
496 htstats->SetStats(0);
497 htstats->DrawCopy("");
498 }
499
500 cstats.Print(Form("cdcdedx_bdcal_qastats_%s.pdf", m_suffix.data()));
501}
void setHistCosmetics(TH2F *hist, Color_t color)
function to change histogram styles
void plotBadWireMap(const std::vector< double > &vbadwires, const std::vector< double > &vdeadwires)
function to plot wire status map (all, bad and dead)
double m_varMax
max range for input variable
double m_rmsThres
rms Threshold accepted for good wire
double m_varMin
min range for input variable
int m_slWireBoundary
Boundary between inner layers: SL0 (<40), SL0+SL1 (>=40)
double m_amean_IL
average mean of dedx for inner wires
std::string m_varName
std::string to set var name (adc or dedx)
void getExpRunInfo()
function to get extract calibration run/exp
unsigned int c_nwireCDC
number of wires in CDC
bool m_isMakePlots
produce plots for status
DBObjPtr< CDCDedxBadWires > m_DBBadWires
Badwire DB object.
std::string m_suffix
suffix std::string for naming plots
void setTextCosmetics(TPaveText *pt, double size)
function to change text styles
CDCDedxBadWireAlgorithm()
Constructor: Sets the description, the properties and the parameters of the algorithm.
DBObjPtr< CDCGeometry > m_cdcGeo
Geometry of CDC.
int m_exp
exp no to set SL boundaries
double m_meanThres
mean Threshold accepted for good wire
DBObjPtr< CDCDedxWireGain > m_DBWireGains
Wiregain DB object.
double m_fracThres
high-frac Threshold accepted for good wire
int m_varBins
number of bins for input variable
void printCanvas(TList *list, TList *hflist, Color_t color)
function to print canvas
void plotQaPars(std::map< int, std::vector< double > > &qapars)
function to plot the QA (decision) parameters
void plotEventStats()
function to draw the stats
virtual EResult calibrate() override
cdcdedx badwire algorithm
void plotWireDist(const std::vector< double > &inwires, std::map< int, std::vector< double > > &vhitvar)
function to draw per wire plots
double m_arms_IL
average rms of dedx for inner wires
double m_arms_OL
average rms of dedx for outer wires
double m_amean_OL
average mean of dedx for outer wires
bool m_isADC
Use adc if(true) else dedx for calibration.
TH2F * getHistoPattern(const std::vector< double > &inwires, const std::string &suffix, int &total)
function to get wire map with input file (all, bad and dead)
dE/dx wire gain calibration constants
The Class for CDC Geometry Parameters.
unsigned nWiresInLayer(int layerId) const
Returns wire numbers in a layer.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
double senseWireR(int layerId) const
Returns radius of sense wire in each layer.
void saveCalibration(TClonesArray *data, const std::string &name)
Store DBArray payload with given name with default IOV.
static void updateDBObjPtrs(const unsigned int event, const int run, const int experiment)
Updates any DBObjPtrs by calling update(event) for DBStore.
void setDescription(const std::string &description)
Set algorithm description (in constructor)
const std::vector< Calibration::ExpRun > & getRunList() const
Get the list of runs for which calibration is called.
EResult
The result of calibration.
@ c_OK
Finished successfully =0 in Python.
@ c_NotEnoughData
Needs more data =2 in Python.
CalibrationAlgorithm(const std::string &collectorModuleName)
Constructor - sets the prefix for collected objects (won't be accesses until execute(....
std::shared_ptr< T > getObjectPtr(const std::string &name, const std::vector< Calibration::ExpRun > &requestedRuns)
Get calibration data object by name and list of runs, the Merge function will be called to generate t...
constexpr T square(const T &x)
Calculate the square of the input.
Definition MathHelpers.h:21
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.