17#include <TDirectory.h>
19#include <TFitResult.h>
31#include <yaml-cpp/emitter.h>
32#include <yaml-cpp/emittermanip.h>
33#include <yaml-cpp/node/node.h>
53 FairRootManager* ioman = FairRootManager::Instance();
54 if (ioman !=
nullptr) {
58 fCbmEvtArray = (TClonesArray*) ioman->GetObject(
"CbmEvent");
66 if (gSystem->AccessPathName(
fOutputPath.c_str(), kFileExists)) {
68 LOG(warning) <<
"Could not create output directory\n Setting output path at current location:\n";
72 fReportFile = std::make_unique<TFile>(Form(
"%s/cbm_sts_time_cal_report.root",
fOutputPath.c_str()),
"RECREATE");
73 fReportFit = std::make_unique<TFile>(Form(
"%s/cbm_sts_time_cal_fits.root",
fOutputPath.c_str()),
"RECREATE");
82 for (
unsigned int asic_idx = 0; asic_idx < 16; asic_idx++) {
83 fWalkMapRaw[address][asic_idx] = std::vector<double>(32, 0);
84 auto loaded_par =
fWalkMap.Get(address, asic_idx);
85 if (loaded_par.size() == 31) {
86 for (
int adc = 1; adc <= 31; adc++) {
87 fWalkMapRaw[address][asic_idx][adc] = loaded_par[adc - 1];
95 LOG(debug) << Form(
"Setting user define time calibration file: %s", f_name.c_str());
103 if (TString(
fParFile.c_str()).EndsWith(
".yaml") || TString(
fParFile.c_str()).EndsWith(
".yml")) {
104 LOG(info) << Form(
"Loading time calibration from parameter file: %s",
fParFile.c_str());
113 LOG(debug) << Form(
"Booking histograms for module: 0x%x", address);
115 std::string h_name, h_title;
121 std::string smart_name = Form(
"U%d_L%d_M%d", unit, ladd, modu);
123 for (
int asic_idx = 0; asic_idx < 16; asic_idx++) {
124 h_name = Form(
"0x%x_%02d", address, asic_idx);
125 h_title = Form(
"%s_%02d", smart_name.c_str(), asic_idx);
131 fH2D[h_name]->GetXaxis()->SetTitle(
133 fH2D[h_name]->GetYaxis()->SetTitle(
"Charge_{StsDigi} [ADC]");
136 h_name = Form(
"0x%x_dt_vs_channel", address);
137 h_title = smart_name;
138 fH2D[h_name] = std::make_unique<TH2D>(h_name.c_str(), h_title.c_str(), 2048, 0, 2048, nb_time_bins,
141 fH2D[h_name]->GetYaxis()->SetTitle(
143 fH2D[h_name]->GetXaxis()->SetTitle(
"Channel_{StsDigi}");
150 LOG(info) <<
"Running CbmStsTimeCal - Entry " <<
entry_;
166 size_t nb_ref_digis =
fDigiManager->GetNofDigis(Digi::GetSystem());
168 LOG(info) << nb_sts_digis <<
"\t" << nb_ref_digis;
171 for (
size_t ref_digi_idx = 0; ref_digi_idx < nb_ref_digis - 1; ref_digi_idx++) {
172 const Digi* ref_digi = &ref_digis_[ref_digi_idx];
173 double ref_digi_time = ref_digi->GetTime();
182 int lo = 0, hi = nb_sts_digis - 1;
184 int m = (lo + hi) / 2;
185 if (sts_digis_[m].GetTime() >= first_digi_in_window) {
195 lo = 0, hi = nb_sts_digis - 1;
197 int m = (lo + hi + 1) / 2;
198 if (sts_digis_[m].GetTime() <= last_digi_in_window) {
206 if (lower_hitB > upper_hitB) {
207 LOG(debug) <<
"Not time match found for the current hit within the time window";
211 for (
int sts_digi_idx = lower_hitB; sts_digi_idx < upper_hitB; sts_digi_idx++) {
212 const CbmStsDigi* sts_digi = &sts_digis_[sts_digi_idx];
213 int32_t sts_digi_addr = sts_digi->
GetAddress();
220 int32_t sts_digi_chan = sts_digi->
GetChannel();
221 int32_t sts_digi_char = sts_digi->GetCharge();
222 int32_t asic_idx = sts_digi_chan / 128;
223 double sts_digi_time = sts_digi->GetTime();
225 fH2D[Form(
"0x%x_%02d", sts_digi_addr, asic_idx)]->Fill(ref_digi_time - sts_digi_time, sts_digi_char);
226 fH2D[Form(
"0x%x_dt_vs_channel", sts_digi_addr)]->Fill(sts_digi_chan, ref_digi_time - sts_digi_time);
243 if (
h_x ==
nullptr) {
249 std::unique_ptr<TCanvas> canvas = std::make_unique<TCanvas>(
"_c0",
"", pad_x, pad_y);
252 double line_width = 0.06;
253 double pave0_top_edge = 0.95;
254 double pave0_bot_edge = pave0_top_edge - line_width * 3;
255 double pave1_top_edge = pave0_bot_edge;
256 double pave1_bot_edge = pave1_top_edge - line_width * 3;
258 h_x->SetLineStyle(1);
259 h_x->SetLineWidth((0.002 * pad_y));
260 h_x->SetLineColor(kBlack);
261 h_x->DrawClone(
"histo");
264 f_x->SetTitle(
"Fitted function");
265 f_x->SetLineStyle(1);
266 f_x->SetLineWidth((0.002 * pad_y));
267 f_x->SetLineColor(kRed);
268 f_x->DrawClone(
"same");
273 f_peak->SetLineStyle(kDotted);
274 f_peak->SetLineWidth((0.002 * pad_y));
275 f_peak->SetLineColor(kBlue);
276 f_peak->DrawClone(
"same");
277 std::unique_ptr<TPaveText> pave = std::make_unique<TPaveText>(0.16, pave0_bot_edge, 0.45, pave0_top_edge,
"NDC");
278 pave->SetBorderSize(1);
279 pave->SetFillColor(0);
280 pave->SetTextAlign(12);
281 pave->AddText(Form(
"p0 = %.3f",
f_peak->GetParameter(0)))->SetTextColor(kBlue);
282 pave->AddText(Form(
"p1 = %.3f",
f_peak->GetParameter(1)))->SetTextColor(kBlue);
283 pave->AddText(Form(
"p2 = %.3f",
f_peak->GetParameter(2)))->SetTextColor(kBlue);
288 f_bkgd->SetTitle(
"Background");
289 f_bkgd->SetLineStyle(kDotted);
290 f_bkgd->SetLineWidth((0.002 * pad_y));
291 f_bkgd->SetLineColor(kOrange);
292 f_bkgd->DrawClone(
"same");
293 std::unique_ptr<TPaveText> pave = std::make_unique<TPaveText>(0.16, pave1_bot_edge, 0.45, pave1_top_edge,
"NDC");
294 pave->SetBorderSize(1);
295 pave->SetFillColor(0);
296 pave->SetTextAlign(12);
297 pave->AddText(Form(
"p0 = %.3f",
f_bkgd->GetParameter(0)))->SetTextColor(kOrange);
298 pave->AddText(Form(
"p1 = %.3f",
f_bkgd->GetParameter(1)))->SetTextColor(kOrange);
299 pave->AddText(Form(
"p2 = %.3f",
f_bkgd->GetParameter(2)))->SetTextColor(kOrange);
304 offset.SetLineWidth(0.004 * pad_y);
305 offset.SetLineColor(kGray);
306 offset.SetLineStyle(kDotted);
310 std::unique_ptr<TPaveText> fit_pave = std::make_unique<TPaveText>(0.65, 0.75, 0.95, 0.95,
"NDC");
311 fit_pave->SetBorderSize(1);
312 fit_pave->SetFillColor(0);
313 fit_pave->SetTextAlign(12);
314 fit_pave->AddText(Form(
"NDF = %d",
fit_ptr->Ndf()));
315 fit_pave->AddText(Form(
"Chi2 = %.3f",
fit_ptr->Chi2()));
316 fit_pave->AddText(Form(
"PRob = %E",
fit_ptr->Prob()));
317 fit_pave->DrawClone();
319 return (TCanvas*) canvas->Clone();
327 h_x = std::make_unique<TH1D>(*
h);
328 h_x->Scale(1. /
h_x->Integral());
331 double time_resolution = 4.8;
332 double h_max =
h_x->GetBinCenter(
h_x->GetMaximumBin());
333 double fit_x_min = h_max - 10. * time_resolution;
334 double fit_x_max = h_max + 10. * time_resolution;
336 f_x = std::make_unique<TF1>(
"f_x",
"[0]*TMath::Gaus(x, [1], [2]) + [3] + [4]*x + [5]*x*x", fit_x_min, fit_x_max);
337 f_peak = std::make_unique<TF1>(
"f_peak",
"[0]*TMath::Gaus(x, [1], [2])", fit_x_min, fit_x_max);
338 f_bkgd = std::make_unique<TF1>(
"f_bkgd",
"[0] + [1]*x + [2]*x*x", fit_x_min, fit_x_max);
341 f_x->SetParameter(0, 0.5);
342 f_x->SetParameter(1, h_max);
343 f_x->SetParameter(2, time_resolution);
344 f_x->SetParameter(5, -1e-4);
347 f_x->SetParLimits(0, 0.0, 1.0);
348 f_x->SetParLimits(1, h_max - 2. * time_resolution, h_max + 2. * time_resolution);
349 f_x->SetParLimits(2, 3.125, 25);
350 f_x->SetParLimits(5, -1, 0.0);
353 fit_ptr =
h_x->Fit(
"f_x",
"SQN0",
"", fit_x_min, fit_x_max);
363 bool par_out_of_limits =
364 fit_ptr->Parameter(1) < h_max - 2. * time_resolution || h_max + 2. * time_resolution <
fit_ptr->Parameter(1);
380 double module_offset = 0;
381 TH2D* dt_vs_chn =
fH2D[Form(
"0x%x_dt_vs_channel", address)].get();
382 if (dt_vs_chn !=
nullptr) {
383 TH1D* p_y = (TH1D*) dt_vs_chn->ProjectionY();
385 double peak = p_y->GetBinCenter(p_y->GetMaximumBin());
388 TCanvas* drawing = offset_fit.
Draw();
389 if (drawing !=
nullptr) {
391 drawing->Write(Form(
"0x%x_offset", address));
398 module_offset = peak;
401 return module_offset;
412 for (
unsigned int asic_idx = 0; asic_idx < 16; asic_idx++) {
414 double adc_channel[32];
415 double adc_channel_err[32];
416 double time_offset[32];
417 double time_offset_err[32];
420 std::string h_name = Form(
"0x%x_%02d", module, asic_idx);
421 if (!
fH2D.count(h_name))
return;
423 auto h =
fH2D[h_name].get();
425 for (
int adc = 1; adc <= 31; adc++) {
426 TH1D* h_x =
h->ProjectionX(Form(
"%s_dt", h_name.c_str()), adc, adc);
429 TCanvas* drawing = offset_fit.
Draw();
430 if (drawing !=
nullptr) {
431 std::string fit_folder = Form(
"0x%x/%02d", module, asic_idx);
432 TDirectory* dir = (TDirectory*)
fReportFit->Get(fit_folder.c_str());
437 drawing->Write(Form(
"0x%x_%02d_%02d", module, asic_idx, adc));
441 time_offset[n_pts] = offset_fit.
fit_ptr->Parameter(1);
442 time_offset_err[n_pts] = offset_fit.
fit_ptr->Parameter(2);
448 time_offset[n_pts] = module_offset;
449 time_offset_err[n_pts] = h_x->GetRMS();
451 adc_channel[n_pts] = adc;
452 adc_channel_err[n_pts] = 0;
455 fWalkMapRaw[module][asic_idx][adc] += time_offset[n_pts];
461 fG1D[h_name] = std::make_unique<TGraphErrors>(n_pts, adc_channel, time_offset, adc_channel_err, time_offset_err);
462 fG1D[h_name]->SetTitle(
464 fG1D[h_name]->GetXaxis()->SetTitle(
"Charge_{StsDigi} [ADC]");
465 fG1D[h_name]->GetYaxis()->SetTitle(
476 double setup_offset = 0;
477 double min_sum_sigma = 999;
479 double module_avg_sigma = 0;
480 double module_avg_offset = 0;
483 for (
unsigned int asic_idx = 0; asic_idx < 16; asic_idx++) {
484 std::string h_name = Form(
"0x%x_%02d", module, asic_idx);
485 auto g =
fG1D[h_name].get();
487 int n_of_pto = g->GetN();
488 int lower_bound = n_of_pto > 5 ? n_of_pto - 5 : 0;
491 for (
int pto = n_of_pto; pto > lower_bound - 5; pto--) {
492 double offset = g->GetPointY(pto);
493 double sigma = g->GetErrorY(pto);
495 module_avg_sigma += sigma;
496 module_avg_offset += offset;
502 module_avg_sigma = n_of_values ? module_avg_sigma / n_of_values : -1;
503 module_avg_offset = n_of_values ? module_avg_offset / n_of_values : -1;
505 if (module_avg_sigma && module_avg_sigma < min_sum_sigma) {
506 min_sum_sigma = module_avg_sigma;
507 setup_offset = module_avg_offset;
516 std::string o_yaml_file =
fOutputPath +
"/StsTimeCalibration.yaml";
517 LOG(info) <<
"Writing parameter file to:" << o_yaml_file;
519 YAML::Emitter walk_map;
520 walk_map << YAML::BeginMap;
521 walk_map << YAML::Key <<
"timeOffset";
523 walk_map << YAML::Key <<
"WalkMap";
524 walk_map << YAML::Value << YAML::BeginMap;
526 walk_map << YAML::Key << fmt::format(
"0x{:x}", module);
527 walk_map << YAML::Value << YAML::BeginSeq;
528 for (
const auto& [asic, pars] : asics) {
530 walk_map << YAML::Flow << YAML::BeginSeq;
531 for (
const auto& value : pars) {
532 walk_map << fmt::format(
"{:+.3f}", value);
535 walk_map << YAML::EndSeq;
537 walk_map << YAML::EndSeq;
539 walk_map << YAML::EndMap << YAML::EndMap;
540 assert(walk_map.good());
542 std::ofstream walk_map_out(o_yaml_file);
543 assert(walk_map_out.is_open());
545 walk_map_out << walk_map.c_str();
546 walk_map_out.close();
555 for (
auto& [asic_idx, asic_par] : asics) {
556 for (
int adc = 1; adc <= 31; adc++) {
557 asic_par[adc - 1] = asic_par[adc];
576 std::unique_ptr<TCanvas> adc_vs_dt_1d =
577 std::make_unique<TCanvas>(
"adc_vs_dt_1d",
"adc_vs_dt_1d", 10, 10, 4 * 1024, 4 * 1024);
578 adc_vs_dt_1d->Divide(4, 4);
580 std::unique_ptr<TCanvas> adc_vs_dt_2d =
581 std::make_unique<TCanvas>(
"adc_vs_dt_2d",
"adc_vs_dt_2d", 10, 10, 4 * 1024, 4 * 1024);
582 adc_vs_dt_2d->Divide(4, 4);
584 std::unique_ptr<TCanvas> dt_vs_chn = std::make_unique<TCanvas>(
"dt_vs_chn",
"dt_vs_chn", 10, 10, 1024, 1024);
588 for (
int asic_idx = 0; asic_idx < 16; asic_idx++) {
589 adc_vs_dt_1d->cd(asic_idx + 1);
590 if (
fG1D[Form(
"0x%x_%02d", sensor, asic_idx)] !=
nullptr) {
591 fG1D[Form(
"0x%x_%02d", sensor, asic_idx)]->Draw(
"APL");
594 adc_vs_dt_2d->cd(asic_idx + 1);
595 if (
fH2D[Form(
"0x%x_%02d", sensor, asic_idx)] !=
nullptr) {
596 fH2D[Form(
"0x%x_%02d", sensor, asic_idx)]->Draw(
"colz");
601 if (
fH2D[Form(
"0x%x_dt_vs_channel", sensor)] !=
nullptr) {
602 fH2D[Form(
"0x%x_dt_vs_channel", sensor)]->Draw(
"colz");
605 adc_vs_dt_1d->Write(Form(
"adc_vs_dt_1d_0x%x", sensor));
606 adc_vs_dt_2d->Write(Form(
"adc_vs_dt_2d_0x%x", sensor));
607 dt_vs_chn->Write(Form(
"dt_vs_chn_0x%x", sensor));
ECbmModuleId
Enumerator for module Identifiers.
@ kTof
Time-of-flight Detector.
@ kSts
Silicon Tracking System.
@ kRich
Ring-Imaging Cherenkov Detector.
static CbmDigiManager * Instance()
Static instance.
CbmCutMap * fAnalysisCuts
std::unordered_set< int32_t > fAddressBook
std::unique_ptr< TFile > fReportFile
std::map< std::string, std::unique_ptr< TGraphErrors > > fG1D
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
Data class for a single-channel message in the STS.
XPU_D uint16_t GetChannel() const
Channel number in module @value Channel number.
XPU_D int32_t GetAddress() const
double FindModuleOffset(int32_t)
Extract Time general offset for a given module.
void SetWalkFile(std::string par_file)
Set parameter file used during unpacking.
void DrawResults()
Virtual function to draw analysis results.
void CheckTimeWalk()
Extract Time Walk parameters.
std::unique_ptr< TFile > fReportFit
void WriteYAML()
Write parameters file in YAML format.
void BookHistograms(int32_t address)
Book histograms.
void LoadWalkFromFile()
Load the time calibration parameters from user define file.
void CheckTiming()
Check timing for a specific digi type It fills StsDigi time difference respect to fRefSystem Digis hi...
std::unique_ptr< TFile > fReportOffset
TClonesArray * fCbmEvtArray
void InitTimeWalkMap(int32_t address)
Initialized the Time Walk map.
cbm::algo::sts::WalkMap fWalkMap
CbmDigiManager * fDigiManager
std::map< int, std::map< int, std::vector< double > > > fWalkMapRaw
double FindGlobalOffset()
Find a common offset for STS setup. It is taken as the average of the time offset for ADC > 25 for th...
Data class with information on a STS local track.
static int32_t GetChannelSide(uint32_t address)
uint32_t GetElementId(int32_t address, int32_t level)
Get the index of an element.
T ReadFromFile(fs::path path)
std::string_view ToString(T t)
std::unique_ptr< TH1 > h_x
std::unique_ptr< TF1 > f_x
std::unique_ptr< TF1 > f_peak
std::unique_ptr< TF1 > f_bkgd