ANASEN_analysis/pccal/fit_pc_energy_calibration.C
Vignesh Sitaraman 2bd4f4eb33 modified: TrackRecon.C
new file:   pccal/fit_pc_energy_calibration.C
2026-07-14 13:45:26 -04:00

92 lines
3.4 KiB
C

// Aggregates every run's raw PC energy-calibration points (written by
// TrackRecon.C's Terminate() into pc_calib_raw/points_*.dat, one file per run
// so parallel jobs never collide) into a single per-wire linear fit, pooling
// BOTH the 17F and 27Al datasets together -- the PC's wire-level gain isn't
// expected to differ meaningfully between the two campaigns, so calibration
// statistics from either dataset's alpha-source or proton-scattering runs are
// combined into one fit rather than kept separate.
//
// Run non-interactively from the top-level ANASEN-Analysis directory once all
// desired calibration runs have completed:
// root -q -l -b -e '.L pccal/fit_pc_energy_calibration.C' -e 'fit_pc_energy_calibration()'
//
// Writes pc_energy_calibration.dat (wire slope intercept, 48 rows), which
// TrackRecon.C's Begin() loads automatically on the next run to populate
// PC_Events_calibrated. Re-run this any time pc_calib_raw/ has new points --
// it always re-reads and re-fits everything currently on disk, so it's safe
// to call repeatedly as more calibration runs accumulate.
#include <TSystemDirectory.h>
#include <TSystemFile.h>
#include <TList.h>
#include <TString.h>
#include <fstream>
#include <iostream>
#include <vector>
void fit_pc_energy_calibration()
{
std::vector<std::pair<double, double>> pts[48]; // [wire] -> (ADC, dE_gas MeV)
TSystemDirectory dir("pc_calib_raw", "pc_calib_raw");
TList *files = dir.GetListOfFiles();
if (!files)
{
std::cerr << "fit_pc_energy_calibration: pc_calib_raw/ not found or empty -- "
<< "run TrackRecon.C with PC energy calibration enabled first." << std::endl;
return;
}
int nFiles = 0;
TIter next(files);
TSystemFile *f;
while ((f = (TSystemFile *)next()))
{
TString name = f->GetName();
if (f->IsDirectory() || !name.BeginsWith("points_") || !name.EndsWith(".dat"))
continue;
std::ifstream infile(std::string("pc_calib_raw/") + name.Data());
if (!infile.is_open())
continue;
int wire;
double adc, dE_gas;
while (infile >> wire >> adc >> dE_gas)
if (wire >= 0 && wire < 48)
pts[wire].push_back({adc, dE_gas});
++nFiles;
}
std::cout << "fit_pc_energy_calibration: read " << nFiles << " run file(s) from pc_calib_raw/" << std::endl;
std::ofstream outfile("pc_energy_calibration.dat");
outfile << std::scientific << std::setprecision(6);
for (int wire = 0; wire < 48; ++wire)
{
double slope = 1.0, intercept = 0.0;
bool ok = pts[wire].size() >= 2;
if (ok)
{
double sx = 0, sy = 0, sxx = 0, sxy = 0;
for (const auto &p : pts[wire])
{
sx += p.first;
sy += p.second;
sxx += p.first * p.first;
sxy += p.first * p.second;
}
double n = static_cast<double>(pts[wire].size());
double denom = n * sxx - sx * sx;
ok = std::isfinite(denom) && std::abs(denom) > 1e-12;
if (ok)
{
slope = (n * sxy - sx * sy) / denom;
intercept = (sy - slope * sx) / n;
}
}
if (!ok)
std::cerr << "fit_pc_energy_calibration: wire " << wire << " has too few points (" << pts[wire].size()
<< ") to fit -- writing identity (slope=1, intercept=0)" << std::endl;
outfile << wire << " " << slope << " " << intercept << "\n";
}
outfile.close();
std::cout << "fit_pc_energy_calibration: wrote pc_energy_calibration.dat" << std::endl;
}