Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-08-31 08:24:39

0001 #include <TH1D.h>
0002 #include <TCanvas.h>
0003 #include <TLine.h>
0004 #include <TStyle.h>
0005 #include <TFile.h>
0006 #include <TTree.h>
0007 #include <TGraph.h>
0008 #include <TMultiGraph.h>
0009 
0010 #include <iostream>
0011 #include <fstream>
0012 #include <iomanip>
0013 #include <string>
0014 #include <cmath>
0015 #include <filesystem>
0016 
0017 #include <fun4all/Fun4AllUtils.h>
0018 
0019 #include <mbd/MbdCalib.h>
0020 #include <mbd/MbdGeomV2.h>
0021 #include "get_runstr.h"
0022 
0023 R__LOAD_LIBRARY(libmbd.so)
0024 R__LOAD_LIBRARY(libmbd_io.so)
0025 
0026 
0027 // For each run in listfile, load the timecorr LUT and compute the per-TDC-bin ratio
0028 // relative to the first run for each channel.  The mean ratio over all TDC bins is
0029 // stored as one TTree entry per (run, channel) in timecorr_avg.root.
0030 void average_timecorr(const std::string& listfile = "tcorr.list")
0031 {
0032   constexpr int NPMT = 128;
0033 
0034   MbdGeom* mbdgeom = new MbdGeomV2();
0035 
0036   // Read file list
0037   std::vector<std::string> files;
0038   std::vector<int>         runs;
0039   {
0040     std::ifstream lf(listfile);
0041     if (!lf.is_open())
0042     {
0043       std::cerr << "Error: Could not open " << listfile << std::endl;
0044       return;
0045     }
0046     // Parse run number from the directory component: 000<run>-0000
0047     auto parse_run = [](const std::string& path) -> int
0048     {
0049       size_t slash2 = path.rfind('/');
0050       size_t slash1 = (slash2 == std::string::npos) ? std::string::npos : path.rfind('/', slash2 - 1);
0051       size_t start  = (slash1 == std::string::npos) ? 0 : slash1 + 1;
0052       std::string dir = path.substr(start, (slash2 == std::string::npos ? path.size() : slash2) - start);
0053       size_t dash = dir.find('-');
0054       if (dash == std::string::npos) return -1;
0055       try { return std::stoi(dir.substr(0, dash)); }
0056       catch (...) { return -1; }
0057     };
0058 
0059     std::string path;
0060     while (lf >> path)
0061     {
0062       int runno = parse_run(path);
0063       if (runno < 0)
0064       {
0065         std::cerr << "Warning: Could not parse run number from: " << path << std::endl;
0066         continue;
0067       }
0068       files.push_back(path);
0069       runs.push_back(runno);
0070     }
0071   }
0072 
0073   if (files.empty())
0074   {
0075     std::cerr << "Error: no valid files in " << listfile << std::endl;
0076     return;
0077   }
0078 
0079   int nruns = (int)files.size();
0080 
0081   // Load all calibrations
0082   std::vector<MbdCalib*> calibs(files.size());
0083   for (size_t i = 0; i < files.size(); i++)
0084   {
0085     std::cout << "Loading " << files[i] << std::endl;
0086     calibs[i] = new MbdCalib();
0087     calibs[i]->Download_TimeCorr(files[i]);
0088   }
0089 
0090   // Determine LUT size from first file
0091   int min_tdc, max_tdc, step; // NOLINT(readability-isolate-declaration)
0092   calibs[0]->get_tcorr_range(0, min_tdc, max_tdc, step);
0093   int ntdc = (max_tdc - min_tdc) / step + 1;
0094   std::cout << "LUT size: " << ntdc << " bins  [" << min_tdc << ", " << max_tdc << "]  step=" << step << std::endl;
0095 
0096   // TTree output
0097   TFile* fout = new TFile("timecorr_avg.root", "RECREATE");
0098   TTree* t = new TTree("t", "TimCorr LUT ratios vs first run");
0099   int    t_run;
0100   int    t_ch;
0101   double t_ratio;
0102   double t_delta;
0103   t->Branch("run",   &t_run,   "run/I");
0104   t->Branch("ch",    &t_ch,    "ch/I");
0105   t->Branch("ratio", &t_ratio, "ratio/D");
0106   t->Branch("delta", &t_delta, "delta/D");
0107 
0108   // ratio_by_ch / delta_by_ch [ch][run_index] — filled alongside TTree for the PDF
0109   std::vector<std::vector<double>> ratio_by_ch(NPMT, std::vector<double>(files.size(), 0.));
0110   std::vector<std::vector<double>> delta_by_ch(NPMT, std::vector<double>(files.size(), 0.));
0111 
0112   // lut_sum[ch][ilut]: sum of val across all runs for every bin (all tdc range)
0113   std::vector<std::vector<double>> lut_sum(NPMT, std::vector<double>(ntdc, 0.));
0114 
0115   // For each run and channel, compute mean(LUT[run][ch][tdc] / LUT[ref][ch][tdc]) over all tdc bins
0116   for (size_t irun = 0; irun < files.size(); irun++)
0117   {
0118     t_run = runs[irun];
0119     for (int ipmt = 0; ipmt < NPMT; ipmt++)
0120     {
0121       int ifeech = mbdgeom->get_feech(ipmt, 0);
0122 
0123       double sum       = 0.;
0124       double sum_delta = 0.;
0125       int    ngood     = 0;
0126       for (int ilut = 0; ilut < ntdc; ilut++)
0127       {
0128         int itdc = ilut*step;
0129         float val = calibs[irun]->get_tcorr(ifeech, itdc);
0130         lut_sum[ipmt][ilut] += val; // accumulate over all bins for avg LUT
0131 
0132         // select good region of itdc (13450 is min good tdc, in ch116)
0133         if ( itdc<1400. || itdc>13450. )
0134         {
0135           continue;
0136         }
0137 
0138         float ref = calibs[0]->get_tcorr(ifeech, itdc);
0139         //if (std::abs(ref) < 1e-9) continue; // skip zero reference bins
0140         sum       += val / ref;
0141         sum_delta += val - ref;
0142         ngood++;
0143       }
0144 
0145       t_ch    = ipmt;
0146       t_ratio = (ngood > 0) ? sum       / ngood : 0.;
0147       t_delta = (ngood > 0) ? sum_delta / ngood : 0.;
0148       ratio_by_ch[ipmt][irun] = t_ratio;
0149       delta_by_ch[ipmt][irun] = t_delta;
0150       t->Fill();
0151     }
0152   }
0153 
0154   fout->cd();
0155   t->Write();
0156   std::cout << "Saved " << t->GetEntries() << " entries to timecorr_avg.root" << std::endl;
0157 
0158   // Per-channel mean delta: <delta>[ch] = mean over runs of delta_by_ch[ch][irun]
0159   std::vector<double> mean_delta(NPMT, 0.);
0160   for (int ipmt = 0; ipmt < NPMT; ipmt++)
0161   {
0162     for (int ir = 0; ir < nruns; ir++) mean_delta[ipmt] += delta_by_ch[ipmt][ir];
0163     mean_delta[ipmt] /= nruns;
0164   }
0165 
0166   // avg_lut[ch][ilut] = mean(val) - <delta>[ch]  (shift whole LUT by mean offset)
0167   std::vector<std::vector<double>> avg_lut(NPMT, std::vector<double>(ntdc, 0.));
0168   for (int ipmt = 0; ipmt < NPMT; ipmt++)
0169   {
0170     for (int ilut = 0; ilut < ntdc; ilut++)
0171     {
0172       avg_lut[ipmt][ilut] = lut_sum[ipmt][ilut] / nruns - mean_delta[ipmt];
0173     }
0174   }
0175 
0176   // Write average calibration file in same format as mbd_timecorr.calib
0177   {
0178     std::ofstream calout("avg_mbd_timecorr.calib");
0179     calout << std::fixed << std::setprecision(5);
0180     for (int ipmt = 0; ipmt < NPMT; ipmt++)
0181     {
0182       int ifeech = mbdgeom->get_feech(ipmt,0);
0183       calout << ifeech << "\t" << ntdc << "\t" << min_tdc << "\t" << max_tdc << "\n";
0184       for (int ilut = 0; ilut < ntdc; ilut++)
0185       {
0186         calout << avg_lut[ipmt][ilut];
0187         calout << ((ilut % 10 == 9) ? "\n" : " ");
0188       }
0189       if (ntdc % 10 != 0) calout << "\n";
0190     }
0191     std::cout << "Wrote avg_mbd_timecorr.calib" << std::endl;
0192   }
0193 
0194   // PDF: two pages per channel
0195   //   Page A: ratio vs run index
0196   //   Page B: corrected LUT overlays (all runs shifted by -t_delta, plus reference)
0197   TCanvas* cpdf = new TCanvas("cpdf", "TimCorr Average", 1000, 500);
0198   cpdf->Divide(2, 1);
0199   const TString pdfname = "timecorr_average.pdf";
0200   cpdf->Print(pdfname + "[");
0201 
0202   // colour palette cycling over runs (skip white=0)
0203   const int NCOLS = 9;
0204   const int cols[NCOLS] = {kBlue, kRed, kGreen+2, kMagenta, kCyan+1,
0205                             kOrange+1, kViolet+1, kTeal+1, kPink+1};
0206 
0207   for (int ipmt = 0; ipmt < NPMT; ipmt++)
0208   {
0209     int ifeech = mbdgeom->get_feech(ipmt, 0);
0210 
0211     // --- Left pad: ratio vs run ---
0212     TGraph* gratio = new TGraph(nruns);
0213     TString gname  = "g_ratio_ch"; gname += ipmt;
0214     TString gtitle = "Ch "; gtitle += ipmt; gtitle += " ratio vs run;Run index;Mean LUT ratio";
0215     gratio->SetName(gname);
0216     gratio->SetTitle(gtitle);
0217     gratio->SetMarkerStyle(20);
0218     gratio->SetMarkerSize(0.7);
0219     for (int ir = 0; ir < nruns; ir++)
0220       gratio->SetPoint(ir, ir, ratio_by_ch[ipmt][ir]);
0221 
0222     cpdf->cd(1);
0223     gratio->Draw("AP");
0224 
0225     // --- Right pad: corrected LUT overlay (val - <delta>) for each run + avg ---
0226     // Build a multigraph so axes are set automatically
0227     TMultiGraph* mg = new TMultiGraph();
0228     TString mgtitle = "Ch "; mgtitle += ipmt;
0229     mgtitle += " corrected LUT;TDC;Time - <#Delta> (ns)";
0230     mg->SetTitle(mgtitle);
0231 
0232     for (size_t irun = 0; irun < files.size(); irun++)
0233     {
0234       TGraph* glut = new TGraph();
0235       for (int ilut = 0; ilut < ntdc; ilut++)
0236       {
0237         int itdc = ilut*step;
0238         if ( itdc>14200. )
0239         {
0240           continue;
0241         }
0242         float val = calibs[irun]->get_tcorr(ifeech, itdc);
0243         glut->AddPoint(itdc, val - mean_delta[ipmt]);
0244       }
0245       int col = cols[irun % NCOLS];
0246       glut->SetLineColor(col);
0247       glut->SetMarkerColor(col);
0248       glut->SetMarkerStyle(1);
0249       mg->Add(glut, "L");
0250     }
0251 
0252     // Average LUT overlay (bold black)
0253     TGraph* gavg = new TGraph();
0254     for (int ilut = 0; ilut < ntdc; ilut++)
0255     {
0256       int itdc = ilut*step;
0257       if ( itdc>13450. ) continue;
0258       gavg->AddPoint(itdc, avg_lut[ipmt][ilut]);
0259     }
0260     gavg->SetLineColor(kBlack);
0261     gavg->SetLineWidth(2);
0262     gavg->SetMarkerStyle(1);
0263     mg->Add(gavg, "L");
0264 
0265     cpdf->cd(2);
0266     mg->Draw("A");
0267 
0268     cpdf->Update();
0269     cpdf->Print(pdfname);
0270 
0271     delete gratio;
0272     delete mg; // also deletes the owned TGraph children
0273   }
0274 
0275   cpdf->Print(pdfname + "]");
0276   std::cout << "Created: " << pdfname << std::endl;
0277   delete cpdf;
0278 }
0279 
0280 
0281 // Store the full LUT for every run, channel, and TDC entry in a flat TTree.
0282 void timecorr_all(const std::string& listfile = "tcorr.list")
0283 {
0284   constexpr int NPMT = 128;
0285 
0286   MbdGeom* mbdgeom = new MbdGeomV2();
0287 
0288   // --- parse file list (same logic as average_timecorr) ---
0289   std::vector<std::string> files;
0290   std::vector<int>         runs;
0291   {
0292     std::ifstream lf(listfile);
0293     if (!lf.is_open())
0294     {
0295       std::cerr << "Error: Could not open " << listfile << std::endl;
0296       return;
0297     }
0298     auto parse_run = [](const std::string& path) -> int
0299     {
0300       size_t slash2 = path.rfind('/');
0301       size_t slash1 = (slash2 == std::string::npos) ? std::string::npos : path.rfind('/', slash2 - 1);
0302       size_t start  = (slash1 == std::string::npos) ? 0 : slash1 + 1;
0303       std::string dir = path.substr(start, (slash2 == std::string::npos ? path.size() : slash2) - start);
0304       size_t dash = dir.find('-');
0305       if (dash == std::string::npos) return -1;
0306       try { return std::stoi(dir.substr(0, dash)); }
0307       catch (...) { return -1; }
0308     };
0309     std::string path;
0310     while (lf >> path)
0311     {
0312       int runno = parse_run(path);
0313       if (runno < 0)
0314       {
0315         std::cerr << "Warning: Could not parse run number from: " << path << std::endl;
0316         continue;
0317       }
0318       files.push_back(path);
0319       runs.push_back(runno);
0320     }
0321   }
0322   if (files.empty())
0323   {
0324     std::cerr << "Error: no valid files in " << listfile << std::endl;
0325     return;
0326   }
0327 
0328   // --- load calibrations ---
0329   std::vector<MbdCalib*> calibs(files.size());
0330   for (size_t i = 0; i < files.size(); i++)
0331   {
0332     std::cout << "Loading " << files[i] << std::endl;
0333     calibs[i] = new MbdCalib();
0334     calibs[i]->Download_TimeCorr(files[i]);
0335   }
0336 
0337   // --- LUT geometry from first file ---
0338   int min_tdc, max_tdc, step; // NOLINT(readability-isolate-declaration)
0339   calibs[0]->get_tcorr_range(0, min_tdc, max_tdc, step);
0340   int ntdc = (max_tdc - min_tdc) / step + 1;
0341   std::cout << "LUT: " << ntdc << " entries  tdc=[" << min_tdc << "," << max_tdc << "]  step=" << step << std::endl;
0342 
0343   // --- TTree ---
0344   TFile* fout = new TFile("timecorr.root", "RECREATE");
0345   TTree* t    = new TTree("t", "Full timecorr LUT dump");
0346 
0347   int      t_run;
0348   Short_t  t_ch;
0349   Short_t  t_index;
0350   UShort_t t_tdc;
0351   Float_t  t_time;
0352 
0353   t->Branch("run",   &t_run,   "run/I");
0354   t->Branch("ch",    &t_ch,    "ch/S");
0355   t->Branch("index", &t_index, "index/S");
0356   t->Branch("tdc",   &t_tdc,   "tdc/s");   // lowercase s = unsigned short
0357   t->Branch("time",  &t_time,  "time/F");
0358 
0359   for (size_t irun = 0; irun < files.size(); irun++)
0360   {
0361     t_run = runs[irun];
0362     for (int ipmt = 0; ipmt < NPMT; ipmt++)
0363     {
0364       int ifeech = mbdgeom->get_feech(ipmt, 0);
0365       t_ch = (Short_t)ipmt;
0366       for (int ilut = 0; ilut < ntdc; ilut++)
0367       {
0368         int itdc   = min_tdc + ilut * step;
0369         t_index    = (Short_t)ilut;
0370         t_tdc      = (UShort_t)itdc;
0371         t_time     = calibs[irun]->get_tcorr(ifeech, itdc);
0372         t->Fill();
0373       }
0374     }
0375   }
0376 
0377   fout->cd();
0378   t->Write();
0379   std::cout << "Saved " << t->GetEntries() << " entries to timecorr.root" << std::endl;
0380 
0381   for (auto* c : calibs) delete c;
0382   delete fout;
0383 }
0384 
0385 
0386 void comp_timecorr(const std::string &file1 = "00065735-0000/mbd_timecorr.calib", const std::string &file2 = "00078986-0000/mbd_timecorr.calib")
0387 {
0388   gStyle->SetOptStat(0);
0389 
0390   constexpr int NPMT  = 128;   // MBD PMTs
0391   constexpr int NTDC = 1000;   // 1000 values stored per channel
0392   constexpr double BAD_THRESHOLD = 0.1;   // 100 ps
0393 
0394   int verbose = 0;
0395 
0396   // Get run numbers
0397   int runno1 = Fun4AllUtils::GetRunSegment( std::filesystem::path( std::filesystem::path(file1).parent_path() ).filename().append(".root") ).first;
0398   int runno2 = Fun4AllUtils::GetRunSegment( std::filesystem::path( std::filesystem::path(file2).parent_path() ).filename().append(".root") ).first;
0399   std::cout << "Processing " << runno1 << "\t" << runno2 << std::endl;
0400 
0401   MbdGeom *mbdgeom = new MbdGeomV2();
0402   // ------------------------------------------------------------
0403   // Load calibrations
0404   // ------------------------------------------------------------
0405   MbdCalib *calib1 = new MbdCalib();
0406   MbdCalib *calib2 = new MbdCalib();
0407 
0408   std::cout << "Downloading time corrections from:\n" << "  " << file1 << "\n" << "  " << file2 << std::endl;
0409 
0410   calib1->Download_TimeCorr(file1);
0411   calib2->Download_TimeCorr(file2);
0412 
0413   int step1, min1, max1;  // NOLINT(readability-isolate-declaration)
0414   int step2, min2, max2;  // NOLINT(readability-isolate-declaration)
0415   calib1->get_tcorr_range(0,min1,max1,step1);
0416   calib2->get_tcorr_range(0,min2,max2,step2);
0417   if ( (step1 != step2) || (min1!=min2) || (max1!=max2) )
0418   {
0419     std::cerr << "timecorr shape differs" << std::endl;
0420     std::cerr << "min: " << min1 << "\t" << min2 << std::endl;
0421     std::cerr << "max: " << max1 << "\t" << max2 << std::endl;
0422     std::cerr << "steps: " << step1 << "\t" << step2 << std::endl;
0423     return;
0424   }
0425 
0426   // ------------------------------------------------------------
0427   // Histograms
0428   // ------------------------------------------------------------
0429   TH1 *h_tdiff[NPMT];
0430   TH1 *h_tdifftot;
0431   TString name;
0432   TString title;
0433 
0434   int nbins = ((max1-min1)/step1) + 1;
0435   std::cout << nbins << std::endl;
0436   for (int ipmt = 0; ipmt < NPMT; ++ipmt)
0437   {
0438     name = "h_tdiff"; name += ipmt;
0439     title = name; title += ", runs "; title += runno1; title += "-"; title += runno2;
0440     h_tdiff[ipmt] = new TH1F( name, title, nbins, min1-0.5, max1+0.5);
0441     h_tdiff[ipmt]->SetXTitle("TDC");
0442     h_tdiff[ipmt]->SetYTitle("tdiff [ns]");
0443   }
0444   title = "time diffs, all channels and TDCs, runs "; title += runno1; title += "-"; title += runno2;
0445   h_tdifftot = new TH1F( "h_tdifftot", title, 1000, -0.2, 0.2);
0446   h_tdifftot->SetXTitle("tdiff [ns]");
0447 
0448   // ------------------------------------------------------------
0449   // Comparison
0450   // ------------------------------------------------------------
0451   if ( verbose )
0452   {
0453     std::cout << std::fixed << std::setprecision(4);
0454     std::cout << "Ch  TDC  TimeCorr1  TimeCorr2  Diff" << std::endl;
0455     std::cout << "----------------------------------------" << std::endl;
0456   }
0457   std::ofstream outfile("bad_comp_timecorr.txt");
0458   outfile << std::fixed << std::setprecision(4);
0459   outfile << "Ch  TDC  TimeCorr1  TimeCorr2  Diff" << std::endl;
0460   outfile << "----------------------------------------" << std::endl;
0461   
0462   for (int ipmt = 0; ipmt < NPMT; ++ipmt)
0463   {
0464     int ifeech = mbdgeom->get_feech(ipmt,0);
0465 
0466     for (int itdc = 0; itdc < NTDC; ++itdc)
0467     {
0468       float t1 = calib1->get_tcorr(ifeech, itdc);
0469       float t2 = calib2->get_tcorr(ifeech, itdc);
0470       float diff = t2 - t1;
0471 
0472       h_tdiff[ipmt]->SetBinContent(itdc+1,diff);
0473       h_tdifftot->Fill(diff);
0474 
0475       if (std::abs(diff) > BAD_THRESHOLD)
0476       {
0477         if ( verbose )
0478         {
0479           std::cout << std::setw(3) << ipmt << "  "
0480             << std::setw(3) << itdc << "  "
0481             << std::setw(10) << t1 << "  "
0482             << std::setw(10) << t2 << "  "
0483             << std::setw(8)  << diff
0484             << std::endl;
0485         }
0486         outfile << std::setw(3) << ipmt << "  "
0487           << std::setw(3) << itdc << "  "
0488           << std::setw(10) << t1 << "  "
0489           << std::setw(10) << t2 << "  "
0490           << std::setw(8)  << diff
0491           << std::endl;
0492       }
0493     }
0494   }
0495 
0496   // ------------------------------------------------------------
0497   // Plot
0498   // ------------------------------------------------------------
0499   TCanvas *ac[100];
0500   int icv = 0;
0501   
0502   ac[icv] = new TCanvas("ac0", "MBD TimeCorr by PMT", 1200, 600);
0503   TString pdfname = "comp_timecorr_"; pdfname += runno1; pdfname += "_"; pdfname += runno2; pdfname += ".pdf";
0504   ac[icv]->Print(pdfname + "[");
0505 
0506   // NOLINTBEGIN(modernize-loop-convert)
0507   for (int ipmt = 0; ipmt < NPMT; ++ipmt)
0508   {
0509     h_tdiff[ipmt]->Draw("hist");
0510 
0511     gPad->Modified();
0512     gPad->Update();
0513     ac[icv]->Print(pdfname);
0514   }
0515   // NOLINTEND(modernize-loop-convert)
0516 
0517   h_tdifftot->Draw();
0518   ac[icv]->Print(pdfname);
0519   ac[icv]->Print(pdfname + "]");
0520 
0521   icv++;
0522 
0523   outfile.close();
0524 }