ANASEN_analysis/Calibration.C
Vignesh Sitaraman c32215e293 modified: .vscode/settings.json
modified:   Calibration.C
	modified:   GainMatchQQQ.C
	new file:   QQQ_Calcheck.C
	new file:   QQQ_Calcheck.h
	new file:   makeplots.C
2025-11-26 11:32:16 -05:00

260 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define Calibration_cxx
#include <TH2.h>
#include <TF1.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TMath.h>
#include <TCutG.h>
#include <fstream>
#include <utility>
#include <algorithm>
#include "Armory/HistPlotter.h"
#include "TVector3.h"
#include "Calibration.h"
TH2F *hQQQFVB;
HistPlotter *plotter;
int padID = 0;
TCutG *cut;
std::map<std::tuple<int, int, int>, std::vector<std::pair<double, double>>> dataPoints;
bool qqqEcut = false;
// Gain Arrays
const int MAX_QQQ = 4;
const int MAX_RING = 16;
const int MAX_WEDGE = 16;
double qqqwGain[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
double qqqrGain[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
bool qqqwGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
bool qqqrGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
void Calibration::Begin(TTree * /*tree*/)
{
plotter = new HistPlotter("Calib.root", "TFILE");
// ----------------------- Load QQQ Gains
{
std::string filename = "qqq_GainMatch.txt";
std::ifstream infile(filename);
if (!infile.is_open())
{
std::cerr << "Error opening " << filename << "!" << std::endl;
}
else
{
int det, ring, wedge;
double gainw,gainr;
while (infile >> det >> ring >> wedge >> gainw>>gainr)
{
qqqwGain[det][ring][wedge] = gainw;
qqqrGain[det][ring][wedge] = gainr;
qqqwGainValid[det][ring][wedge] = (gainw > 0);
qqqrGainValid[det][ring][wedge] = (gainr > 0);
}
infile.close();
std::cout << "Loaded QQQ gains from " << filename << std::endl;
}
}
for (int det = 0; det < MAX_QQQ; det++)
{
for (int ring = 0; ring < MAX_RING; ring++)
{
for (int wedge = 0; wedge < MAX_WEDGE; wedge++)
{
TString hname = Form("hCal_qqq%d_ring%d_wedge%d", det, ring, wedge);
TString htitle = Form("QQQ det%d ring%d wedge%d; Energy (arb); Counts", det, ring, wedge);
// hQQQSpectra[det][ring][wedge] = new TH1F(hname, htitle, 4000, 0, 16000);
}
}
}
}
Bool_t Calibration::Process(Long64_t entry)
{
b_qqqMulti->GetEntry(entry);
b_qqqID->GetEntry(entry);
b_qqqCh->GetEntry(entry);
b_qqqE->GetEntry(entry);
b_qqqT->GetEntry(entry);
qqq.CalIndex();
for (int i = 0; i < qqq.multi; i++)
{
for (int j = i + 1; j < qqq.multi; j++)
{
if (qqq.e[i] > 100)
qqqEcut = true;
if (qqq.id[i] == qqq.id[j])
{
int chWedge = -1;
int chRing = -1;
float eWedgeRaw = 0.0;
float eWedge = 0.0;
float eRingRaw = 0.0;
float eRing = 0.0;
if (qqq.ch[i] < 16 && qqq.ch[j] >= 16 && qqqrGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16] && qqqwGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16])
{
chWedge = qqq.ch[i];
eWedgeRaw = qqq.e[i];
eWedge = qqq.e[i] * qqqwGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
// printf("Wedge E: %.2f Gain: %.4f \n", eWedge, qqqGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16]);
chRing = qqq.ch[j] - 16;
eRingRaw = qqq.e[j];
eRing = qqq.e[j] * qqqrGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i]-16];
}
else if (qqq.ch[j] < 16 && qqq.ch[i] >= 16 && qqqrGainValid[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16] && qqqwGainValid[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16])
{
chWedge = qqq.ch[j];
eWedge = qqq.e[j] * qqqwGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16];
eWedgeRaw = qqq.e[j];
chRing = qqq.ch[i] - 16;
eRing = qqq.e[i] * qqqrGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
eRingRaw = qqq.e[i];
}
else
continue;
// hQQQFVB->Fill(eWedge, eRing);
plotter->Fill2D(Form("hRaw_qqq%d_ring%d_wedge%d", qqq.id[i], chRing, chWedge), 400, 0, 16000, 400, 0, 16000, eWedgeRaw, eRingRaw, "ERaw");
plotter->Fill2D(Form("hGM_qqq%d_ring%d_wedge%d", qqq.id[i], chRing, chWedge), 400, 0, 16000, 400, 0, 16000, eWedge, eRing, "EGM");
plotter->Fill2D("hRawQQQ", 4000, 0, 16000, 4000, 0, 16000, eWedgeRaw, eRingRaw);
plotter->Fill2D("hGMQQQ", 4000, 0, 16000, 4000, 0, 16000, eWedge, eRing);
TString histName = Form("hQQQFVB_id%d_r%d_w%d", qqq.id[i], chRing, chWedge);
// TH2F *hist2d = (TH2F *)gDirectory->Get(histName);
// if (!hist2d)
// {
// hist2d = new TH2F(histName, Form("QQQ Det%d R%d W%d;Wedge E;Ring E", qqq.id[i], chRing, chWedge), 400, 0, 16000, 400, 0, 16000);
// }
// hist2d->Fill(eWedge, eRing);
// if (cut && cut->IsInside(eWedge, eRing))
{
// Accumulate data for gain matching
dataPoints[{qqq.id[i], chRing, chWedge}].emplace_back(eWedge, eRing);
}
}
}
}
return kTRUE;
}
void Calibration::Terminate()
{
const double AM241_PEAK = 5485.56;
const double P_PEAK=7000; // keV
double calibArray[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
bool calibValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
std::ofstream outFile("qqq_Calib.txt");
if (!outFile.is_open())
{
std::cerr << "Error opening qqq_Calib.txt!" << std::endl;
return;
}
//----------------------------------------------------------------------
// 1. Create perchannel 1D spectra in ADC from stored gain-matched data
//----------------------------------------------------------------------
std::map<std::tuple<int, int, int>, TH1F *> spectra;
for (auto &kv : dataPoints)
{
int det, ring, wedge;
std::tie(det, ring, wedge) = kv.first;
TString hname = Form("hSpec_d%d_r%d_w%d", det, ring, wedge);
TH1F *h = new TH1F(hname, hname, 4000, 0, 16000);
for (auto &p : kv.second)
{
double eWedge = p.first; // already gain-matched ADC
double eRing = p.second;
// Use ring ADC for calibration (cleaner alpha peak)
h->Fill(eRing);
}
spectra[kv.first] = h;
}
//----------------------------------------------------------------------
// 2. Fit Am-241 peak and extract keV/ADC calibration slope
//----------------------------------------------------------------------
for (auto &kv : spectra)
{
int det, ring, wedge;
std::tie(det, ring, wedge) = kv.first;
TH1F *h = kv.second;
if (!h || h->GetEntries() < 50)
continue;
int binMax = h->GetMaximumBin();
double adcPeak = h->GetXaxis()->GetBinCenter(binMax);
if (adcPeak <= 0)
continue;
// double slope_keV = AM241_PEAK / adcPeak; // keV per ADC
double slope_keV = P_PEAK / adcPeak; // keV per ADC
calibArray[det][ring][wedge] = slope_keV;
calibValid[det][ring][wedge] = true;
outFile << det << " " << ring << " " << wedge << " "
<< slope_keV << "\n";
// printf("QQQ DET=%d R=%d W=%d ADCpeak=%.1f slope_keV=%.6f\n",det, ring, wedge, adcPeak, slope_keV);
}
outFile.close();
std::cout << "Wrote QQQ calibration file qqq_Calib.txt\n";
//----------------------------------------------------------------------
// 3. Build fully calibrated 2D combined histogram
//----------------------------------------------------------------------
TH2F *hCal = new TH2F("hCal",
"All QQQ Calibrated;Wedge Energy (keV);Ring Energy (keV)",
800, 0, 7000,
800, 0, 7000);
for (auto &kv : dataPoints)
{
int det, ring, wedge;
std::tie(det, ring, wedge) = kv.first;
if (!calibValid[det][ring][wedge])
continue;
double slope = calibArray[det][ring][wedge];
for (auto &p : kv.second)
{
double eWGM = p.first; // gain matched ADC
double eRGM = p.second;
double eWkeV = eWGM * slope / 1000;
double eRkeV = eRGM * slope / 1000;
hCal->Fill(eWkeV, eRkeV);
plotter->Fill2D("hCalQQQ", 4000, 0, 100, 4000, 0, 100, eWkeV, eRkeV);
plotter->Fill2D(Form("hRCal_qqq%d", det ), 16,0,15, 400, 0, 24, ring, eRkeV, "RingCal");
plotter->Fill2D(Form("hWCal_qqq%d", det ), 16,0,15, 400, 0, 24, wedge, eWkeV, "WedgeCal");
}
}
plotter->FlushToDisk();
std::cout << "Calibrated 2D QQQ histogram saved.\n";
}