CbmRoot
Loading...
Searching...
No Matches
CbmStsChannelQA.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Dario Ramirez [committer] */
4
5#include "CbmStsChannelQA.h"
6
7#include "CbmStsDigi.h"
8#include "TArrow.h"
9#include "TBox.h"
10#include "TPaveLabel.h"
11#include "TPaveText.h"
12#include "TText.h"
13
14#include <TParameter.h>
15
16#include <ctime>
17#include <iostream>
18#include <typeinfo>
19
20CbmStsChannelQA::CbmStsChannelQA(int dead_threshold) : fActiveMinEntries(dead_threshold) {}
21CbmStsChannelQA::CbmStsChannelQA(int dead_threshold, double noise_threshold,
22 std::optional<std::pair<size_t, size_t>> spill_on_off_threshold)
23 : fActiveMinEntries(dead_threshold)
24 , fSBThreshold(noise_threshold)
25 , fSpillThresholds(spill_on_off_threshold)
26{
27 assert(noise_threshold > 0);
28 if (fSpillThresholds.has_value()) {
29 assert(fSpillThresholds->first <= fSpillThresholds->second);
30 fSpillSections = {":ramp", ":spill_on", ":spill_off"};
31 }
32}
33
35{
36 FairRootManager* ioman = FairRootManager::Instance();
37 if (ioman != nullptr) {
39 fDigiManager->Init();
40
41 if (!fDigiManager->IsPresent(ECbmModuleId::kSts)) LOG(fatal) << GetName() << ": No StsDigi branch in input!";
42
43 LOG(info) << "CbmStsChannelQA configuration:";
44 LOG(info) << "Report lvl: " << fReportLvl;
45 LOG(info) << "Active channel minimum entries: " << fActiveMinEntries;
46 LOG(info) << "Noisy channel S/B thresholds: " << fSBThreshold;
47 if (fSpillThresholds.has_value()) {
48 LOG(info) << Form("Spill OFF: RefDet_DigiRate < %lu", fSpillThresholds->first);
49 LOG(info) << Form("Spill ON: RefDet_DigiRate > %lu", fSpillThresholds->second);
50 }
51 else {
52 LOG(info) << "No Spill section defined. Using all time slices";
53 }
54
55 return kSUCCESS;
56 }
57 return kERROR;
58}
59
60
62{
63 LOG(debug) << Form("Booking histograms for module_addr: 0x%x", address);
64
65 double dt_max = 120; // HARDCODE
66 auto t_binning = cbm_sts_utils::HBinning{uint32_t(dt_max / 3.125), 0, dt_max};
67
68 std::string h_name;
69 for (auto modifier : fSpillSections) {
70 h_name = Form("0x%x_charge_vs_channel%s", address, modifier);
71 LOG(debug) << h_name;
72 fH2D[h_name] = std::make_unique<TH2D>(h_name.c_str(), h_name.c_str(), 2048, 0, 2048, 31, 1, 32);
73 fH2D[h_name]->GetXaxis()->SetTitle("Channel_{StsDigi}");
74 fH2D[h_name]->GetYaxis()->SetTitle("Charge_{StsDigi} [ADC]");
75
76 LOG(debug) << h_name;
77 h_name = Form("0x%x_dt_vs_charge%s", address, modifier);
78 fH2D[h_name] = std::make_unique<TH2D>(h_name.c_str(), h_name.c_str(), 31, 1, 32, t_binning.n_of_bins,
79 t_binning.x_min, t_binning.x_max);
80 fH2D[h_name]->GetYaxis()->SetTitle("Charge_{StsDigi} [ADC]");
81 fH2D[h_name]->GetYaxis()->SetTitle("Time difference [ns]");
82
83 LOG(debug) << h_name;
84 h_name = Form("0x%x_dt_vs_channel%s", address, modifier);
85 fH2D[h_name] = std::make_unique<TH2D>(h_name.c_str(), h_name.c_str(), 2048, 0, 2048, t_binning.n_of_bins,
86 t_binning.x_min, t_binning.x_max);
87 fH2D[h_name]->GetXaxis()->SetTitle("Channel_{StsDigi}");
88 fH2D[h_name]->GetYaxis()->SetTitle("Time difference [ns]");
89 }
90
91 fAddressBook.insert(address);
92}
93
95{
96 for (auto& [address, time] : fLastDigiTime) {
97 for (int chn = 0; chn < 2048; chn++) {
98 time[chn] = -1;
99 }
100 }
101}
102
104{
105 LOG(info) << "Running CbmStsChannelQA ...";
106
107 // Get Spill status
108 size_t nb_ref_digis = fDigiManager->GetNofDigis(ECbmModuleId::kBmon);
109
115 int fSpillStatus = 0;
116 if (fSpillThresholds.has_value()) {
117 fSpillStatus = nb_ref_digis <= fSpillThresholds->first ? -1 : (nb_ref_digis <= fSpillThresholds->second ? 0 : 1);
118 }
119
120 std::string str_spill;
121 switch (fSpillStatus) {
122 case +1: {
123 fNbTsSpillOn++;
124 str_spill = fSpillSections[1];
125 break;
126 }
127 case -1: {
129 str_spill = fSpillSections[2];
130 break;
131 }
132 default: {
133 str_spill = fSpillSections[0];
134 break;
135 }
136 }
137
138 LOG(info) << Form("TS %d\t-\t Spill section: %s", entry_, str_spill.c_str());
139
140
141 auto sts_digis_ = fDigiManager->GetArray<CbmStsDigi>();
142 size_t nb_sts_digis = fDigiManager->GetNofDigis(ECbmModuleId::kSts);
143 for (size_t sts_digi_idx = 0; sts_digi_idx < nb_sts_digis; sts_digi_idx++) { // sts digi loop
144 const CbmStsDigi* sts_digi = &sts_digis_[sts_digi_idx];
145 int32_t sts_digi_addr = sts_digi->GetAddress();
146 int32_t sts_digi_chan = sts_digi->GetChannel();
147 int32_t sts_digi_char = sts_digi->GetCharge();
148 double sts_digi_time = sts_digi->GetTime();
149
150 if (!fAddressBook.count(sts_digi_addr)) {
151 BookHistograms(sts_digi_addr);
152
153 for (int chn = 0; chn < 2048; chn++) {
154 fLastDigiTime[sts_digi_addr][chn] = -1;
155 }
156 }
157
158 fH2D[Form("0x%x_charge_vs_channel%s", sts_digi_addr, str_spill.c_str())]->Fill(sts_digi_chan, sts_digi_char);
159
160 if (fLastDigiTime[sts_digi_addr][sts_digi_chan] > 0) {
161 fH2D[Form("0x%x_dt_vs_charge%s", sts_digi_addr, str_spill.c_str())]->Fill(
162 sts_digi_char, sts_digi_time - fLastDigiTime[sts_digi_addr][sts_digi_chan]);
163 fH2D[Form("0x%x_dt_vs_channel%s", sts_digi_addr, str_spill.c_str())]->Fill(
164 sts_digi_chan, sts_digi_time - fLastDigiTime[sts_digi_addr][sts_digi_chan]);
165 }
166
167 fLastDigiTime[sts_digi_addr][sts_digi_chan] = sts_digi_time;
168
169 } // end sts digi loop
170
172 entry_++;
173}
174
176{
177 const char* mod = fSpillThresholds.has_value() ? fSpillSections[1] : fSpillSections[0];
178 for (auto& module_addr : fAddressBook) {
179 auto h = (TH1D*) fH2D[Form("0x%x_charge_vs_channel%s", module_addr, mod)]->ProjectionX();
180 for (int chn = 0; chn < 2048; chn++) {
181 double entries = h->GetBinContent(chn + 1);
182
183 if (entries < fActiveMinEntries) {
184 fDeadChannelList[module_addr].push_back(chn);
185 }
186 }
187 }
188}
189
191{
192 for (auto& module_addr : fAddressBook) {
193 TH1D* h_sgn = fH2D[Form("0x%x_charge_vs_channel:spill_on", module_addr)]->ProjectionX();
194 TH1D* h_bkg = fH2D[Form("0x%x_charge_vs_channel:spill_off", module_addr)]->ProjectionX();
195
196 h_sgn->Scale(1. / fNbTsSpillOn);
197 h_bkg->Scale(1. / fNbTsSpillOff);
198 h_sgn->Add(h_bkg, -1);
199
200 for (int chn = 0; chn < 2048; chn++) {
201 double sgn = h_sgn->GetBinContent(chn + 1);
202 double bkg = h_bkg->GetBinContent(chn + 1);
203
204 if (bkg == 0) continue;
205
206 double sb_ratio = sgn / bkg;
207
208 if (sb_ratio < fSBThreshold) {
209 LOG(debug) << Form("Noisy channel 0x%x: %d, \tS/B: %0.4f", module_addr, chn, sb_ratio);
210 fNoisyChannelList[module_addr].push_back(chn);
211 }
212 }
213 }
214}
215
217{
218 std::string f_name = "cbm_sts_channel_qa_report.root";
219 std::unique_ptr<TFile> o_root_file = std::make_unique<TFile>(f_name.c_str(), "RECREATE");
220 int pad_size_x = 1000;
221 int pad_size_y = 1000;
222 for (auto& module_addr : fAddressBook) {
223 std::string c_name = Form("0x%x_channel", module_addr);
224 std::unique_ptr<TCanvas> c = std::make_unique<TCanvas>(c_name.c_str(), c_name.c_str(), pad_size_x, pad_size_y);
225 TH1D* h_sgn = fH2D[Form("0x%x_charge_vs_channel:spill_on", module_addr)]->ProjectionX();
226 TH1D* h_bkg = fH2D[Form("0x%x_charge_vs_channel:spill_off", module_addr)]->ProjectionX();
227
228 LOG(debug) << Form("Building report for 0x%x", module_addr);
229 h_sgn->Scale(1. / fNbTsSpillOn);
230 h_bkg->Scale(1. / fNbTsSpillOff);
231
232 h_sgn->SetLineColor(kRed);
233 h_bkg->SetLineColor(kBlack);
234
235 h_sgn->SetTitle("");
236 h_bkg->SetTitle("");
237
238 h_sgn->SetFillColorAlpha(kRed, 0.2);
239 h_bkg->SetFillColorAlpha(kBlack, 0.2);
240
241 double h_sgn_max = h_sgn->GetMaximum();
242 double h_bkg_max = h_bkg->GetMaximum();
243 double max = std::max(h_sgn_max, h_bkg_max);
244
245 h_sgn->SetMaximum(1.05 * max);
246 h_bkg->SetMaximum(1.05 * max);
247
248 c->cd(1);
249 gPad->SetLogy(1);
250 gPad->SetLeftMargin(0.15);
251 gPad->SetBottomMargin(0.12);
252 gPad->SetTopMargin(0.10);
253 gPad->SetRightMargin(0.12);
254
255 h_sgn->Draw("histo");
256 h_bkg->Draw("histo same");
257
258 // Draw a line for bad channels
259 if (fReportLvl > 1) {
260 LOG(debug) << Form("Drawing %d noisy channel markers: %lu", module_addr, fNoisyChannelList[module_addr].size());
261 for (auto& chn : fNoisyChannelList[module_addr]) {
262 TBox chn_box = TBox(chn + 0.2, 0.99 * max, chn + 0.8, 1.01 * max);
263 chn_box.SetLineColor(kBlue);
264 chn_box.SetFillColor(kBlue);
265 chn_box.DrawClone();
266 }
267 }
268
269 c->Write(Form("0x%x_channel:spill_on_vs_off.png", module_addr));
270 }
271}
272
274{
276 if (fSpillThresholds.has_value()) CheckNoisyChannels();
277
279
280 SaveToFile();
281
282 fH1D.clear();
283 fH2D.clear();
284
285 // Write normalization factor to file
286 std::unique_ptr<TFile> out_file = std::make_unique<TFile>("cbm_sts_channel_qa.root", "UPDATE");
287 TParameter<int>("fNbTsSpillOn", fNbTsSpillOn).Write();
288 TParameter<int>("fNbTsSpillOff", fNbTsSpillOff).Write();
289
290 std::ofstream dead_info("sts_dead_channels.info");
291 std::ofstream dead_par("sts_dead_channels.par");
292 dead_info << Form("# Module\t Number of dead channels\n");
293 int n_of_dead_chn = 0;
294 for (auto& [module_addr, list] : fDeadChannelList) {
295 dead_info << Form("0x%x\t%lu\n", module_addr, list.size());
296 for (int& dead_chn : list) {
297 dead_par << module_addr << "\t" << dead_chn << std::endl;
298 }
299 n_of_dead_chn += list.size();
300 }
301 dead_info << Form("# Total Number of dead channels: %d\n", n_of_dead_chn);
302
303 std::ofstream noisy_info("sts_noisy_channels.info");
304 std::ofstream noisy_par("sts_noisy_channels.par");
305 noisy_info << Form("# Module\t Number of noisy channels\n");
306 int n_of_noisy_chn = 0;
307 for (auto& [module_addr, list] : fNoisyChannelList) {
308 noisy_info << Form("0x%x\t%lu\n", module_addr, list.size());
309 for (int& noisy_chn : list) {
310 noisy_par << module_addr << "\t" << noisy_chn << std::endl;
311 }
312 n_of_noisy_chn += list.size();
313 }
314 noisy_info << Form("# Total Number of noisy channels: %d\n", n_of_noisy_chn);
315}
@ kSts
Silicon Tracking System.
Definition CbmDefs.h:48
@ kBmon
Bmon Counter.
Definition CbmDefs.h:57
friend fscal max(fscal x, fscal y)
friend fscal sgn(fscal x)
static constexpr size_t size()
Definition KfSimdPseudo.h:2
static CbmDigiManager * Instance()
Static instance.
std::unordered_set< int32_t > fAddressBook
std::map< std::string, std::unique_ptr< TH2D > > fH2D
void SaveToFile()
It write all mapped objects to the FairRunAna sink file.
std::map< std::string, std::unique_ptr< TH1D > > fH1D
CbmDigiManager * fDigiManager
std::map< int32_t, std::vector< int > > fNoisyChannelList
void BookHistograms(int32_t)
Book histograms.
void Exec(Option_t *)
const int fActiveMinEntries
std::map< int32_t, std::vector< int > > fDeadChannelList
std::vector< const char * > fSpillSections
const double fSBThreshold
std::map< int32_t, double[2048]> fLastDigiTime
CbmStsChannelQA()=default
void CheckNoisyChannels()
Check for dead channels. Fills fNoisyChannelList map.
const std::optional< std::pair< size_t, size_t > > fSpillThresholds
void CheckDeadChannels()
Check for dead channels. Fills fDeadChannelList map.
Data class for a single-channel message in the STS.
Definition CbmStsDigi.h:40
XPU_D uint16_t GetChannel() const
Channel number in module @value Channel number.
Definition CbmStsDigi.h:93
XPU_D int32_t GetAddress() const
Definition CbmStsDigi.h:74
Data class with information on a STS local track.
Structure to hold the binning for 1D histogram.
Definition CbmStsUtils.h:92