modified: .gitignore

modified:   .vscode/settings.json
	modified:   Analyzer.C
	modified:   Calibration.C
	modified:   GainMatchQQQ.C
	modified:   QQQ_Calcheck.C
This commit is contained in:
Vignesh Sitaraman 2025-12-16 15:41:21 -05:00
parent aee3a2467d
commit 97880940be
6 changed files with 657 additions and 606 deletions

5
.gitignore vendored
View File

@ -10,6 +10,7 @@ AnasenMS
data/ data/
data_proton/ data_proton/
Sudarshan/
Analyzer_C_ACLiC_dict0713aaa966_dictContent.h Analyzer_C_ACLiC_dict0713aaa966_dictContent.h
.gitignore .gitignore
Analyzer_C_ACLiC_dict5411fecd5c_dictUmbrella.h Analyzer_C_ACLiC_dict5411fecd5c_dictUmbrella.h
@ -19,3 +20,7 @@ MakePlotsQQQ.C
MakePlotsQQQ.h MakePlotsQQQ.h
MakePlotsSX3.C MakePlotsSX3.C
MakePlotsSX3.h MakePlotsSX3.h
qqq_gains_det3.dat
qqq_relative_gains.dat
Armory/CorrelateQQQ.h
QQQStage2.C

View File

@ -121,7 +121,10 @@
"MakePlotsSX3.C": "cpp", "MakePlotsSX3.C": "cpp",
"QQQ_Calibcheck.C": "cpp", "QQQ_Calibcheck.C": "cpp",
"QQQ_Calcheck.C": "cpp", "QQQ_Calcheck.C": "cpp",
"makeplots.C": "cpp" "makeplots.C": "cpp",
"GlobalMinimizeQQQ.C": "cpp",
"QQQStage2.C": "cpp",
"inspect.C": "cpp"
}, },
"github-enterprise.uri": "https://fsunuc.physics.fsu.edu" "github-enterprise.uri": "https://fsunuc.physics.fsu.edu"
} }

View File

@ -48,7 +48,7 @@ PW pwinstance;
TVector3 hitPos; TVector3 hitPos;
// TVector3 anodeIntersection; // TVector3 anodeIntersection;
std::map<int, std::pair<double, double>> slopeInterceptMap; std::map<int, std::pair<double, double>> slopeInterceptMap;
// SX3 Calibration Arrays
const int MAX_DET = 24; const int MAX_DET = 24;
const int MAX_UP = 4; const int MAX_UP = 4;
const int MAX_DOWN = 4; const int MAX_DOWN = 4;
@ -58,6 +58,15 @@ bool backGainValid[MAX_DET][MAX_BK] = {{false}};
double frontGain[MAX_DET][MAX_BK][MAX_UP][MAX_DOWN] = {{{{0}}}}; double frontGain[MAX_DET][MAX_BK][MAX_UP][MAX_DOWN] = {{{{0}}}};
bool frontGainValid[MAX_DET][MAX_BK][MAX_UP][MAX_DOWN] = {{{{false}}}}; bool frontGainValid[MAX_DET][MAX_BK][MAX_UP][MAX_DOWN] = {{{{false}}}};
// QQQ Calibration Arrays
const int MAX_QQQ = 4;
const int MAX_RING = 16;
const int MAX_WEDGE = 16;
double qqqGain[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
bool qqqGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
double qqqCalib[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
bool qqqCalibValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
bool HitNonZero; bool HitNonZero;
bool sx3ecut; bool sx3ecut;
bool qqqEcut; bool qqqEcut;
@ -187,6 +196,52 @@ void Analyzer::Begin(TTree * /*tree*/)
frontGain[idf][bkf][uf][df] = fgain; frontGain[idf][bkf][uf][df] = fgain;
frontGainValid[idf][bkf][uf][df] = true; frontGainValid[idf][bkf][uf][df] = true;
} }
// QQQ Gain Matching and Calibration
// ----------------------- 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)
{
qqqGain[det][ring][wedge] = gainw;
// qqqrGain[det][ring][wedge] = gainr;
qqqGainValid[det][ring][wedge] = (gainw > 0);
// qqqrGainValid[det][ring][wedge] = (gainr > 0);
}
infile.close();
std::cout << "Loaded QQQ gains from " << filename << std::endl;
}
}
// ----------------------- Load QQQ Calibrations
{
std::string filename = "qqq_Calib.txt";
std::ifstream infile(filename);
if (!infile.is_open())
{
std::cerr << "Error opening " << filename << "!" << std::endl;
}
else
{
int det, ring, wedge;
double slope;
while (infile >> det >> ring >> wedge >> slope)
{
qqqCalib[det][ring][wedge] = slope;
qqqCalibValid[det][ring][wedge] = (slope > 0);
}
infile.close();
std::cout << "Loaded QQQ calibrations from " << filename << std::endl;
}
}
} }
Bool_t Analyzer::Process(Long64_t entry) Bool_t Analyzer::Process(Long64_t entry)
@ -323,9 +378,9 @@ Bool_t Analyzer::Process(Long64_t entry)
} }
} }
sx3_contr.CalSX3Pos(sx3ID[0].first, sx3ChUp, sx3ChDn, sx3ChBk, sx3EUp, sx3EDn); // sx3_contr.CalSX3Pos(sx3ID[0].first, sx3ChUp, sx3ChDn, sx3ChBk, sx3EUp, sx3EDn);
hitPos = sx3_contr.GetHitPos(); // hitPos = sx3_contr.GetHitPos();
HitNonZero = true; // HitNonZero = true;
// hitPos.Print(); // hitPos.Print();
} }
} }
@ -372,18 +427,49 @@ Bool_t Analyzer::Process(Long64_t entry)
if (qqq.id[i] == qqq.id[j]) if (qqq.id[i] == qqq.id[j])
{ // must be same detector { // must be same detector
if (qqq.e[i] > 100)
qqqEcut = true;
if (qqq.id[i] == qqq.id[j])
{
int chWedge = -1; int chWedge = -1;
int chRing = -1; int chRing = -1;
if (qqq.ch[i] < qqq.ch[j]) float eWedgeRaw = 0.0;
float eWedge = 0.0;
float eWedgeMeV = 0.0;
float eRingRaw = 0.0;
float eRing = 0.0;
float eRingMeV = 0.0;
// plug in gains
if (qqq.ch[i] < 16 && qqq.ch[j] >= 16 && /*qqqrGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16] &&*/ qqqGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16])
{ {
chRing = qqq.ch[j] - 16;
chWedge = qqq.ch[i]; chWedge = qqq.ch[i];
eWedgeRaw = qqq.e[i];
eWedge = qqq.e[i] * qqqGain[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] */ && qqqGainValid[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16])
{
chWedge = qqq.ch[j];
eWedge = qqq.e[j] * qqqGain[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 else
continue;
// plug in calibrations
if (qqqCalibValid[qqq.id[i]][chRing][chWedge])
{ {
chRing = qqq.ch[i]; eWedgeMeV = eWedge * qqqCalib[qqq.id[i]][chRing][chWedge] / 1000;
chWedge = qqq.ch[j] - 16; eRingMeV = eRing * qqqCalib[qqq.id[i]][chRing][chWedge] / 1000;
} }
else
continue;
// printf(" ID : %d , chWedge : %d, chRing : %d \n", qqq.id[i], chWedge, chRing); // printf(" ID : %d , chWedge : %d, chRing : %d \n", qqq.id[i], chWedge, chRing);
double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5);
@ -404,6 +490,7 @@ Bool_t Analyzer::Process(Long64_t entry)
} }
} }
} }
}
// //======================= PC // //======================= PC
// Calculate the crossover points and put them into an array // Calculate the crossover points and put them into an array

View File

@ -28,9 +28,9 @@ const int MAX_QQQ = 4;
const int MAX_RING = 16; const int MAX_RING = 16;
const int MAX_WEDGE = 16; const int MAX_WEDGE = 16;
double qqqwGain[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}}; double qqqwGain[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{0}}};
double qqqrGain[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 qqqwGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
bool qqqrGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}}; // bool qqqrGainValid[MAX_QQQ][MAX_RING][MAX_WEDGE] = {{{false}}};
void Calibration::Begin(TTree * /*tree*/) void Calibration::Begin(TTree * /*tree*/)
{ {
@ -50,9 +50,9 @@ void Calibration::Begin(TTree * /*tree*/)
while (infile >> det >> ring >> wedge >> gainw >> gainr) while (infile >> det >> ring >> wedge >> gainw >> gainr)
{ {
qqqwGain[det][ring][wedge] = gainw; qqqwGain[det][ring][wedge] = gainw;
qqqrGain[det][ring][wedge] = gainr; // qqqrGain[det][ring][wedge] = gainr;
qqqwGainValid[det][ring][wedge] = (gainw > 0); qqqwGainValid[det][ring][wedge] = (gainw > 0);
qqqrGainValid[det][ring][wedge] = (gainr > 0); // qqqrGainValid[det][ring][wedge] = (gainr > 0);
} }
infile.close(); infile.close();
std::cout << "Loaded QQQ gains from " << filename << std::endl; std::cout << "Loaded QQQ gains from " << filename << std::endl;
@ -96,7 +96,7 @@ Bool_t Calibration::Process(Long64_t entry)
float eWedge = 0.0; float eWedge = 0.0;
float eRingRaw = 0.0; float eRingRaw = 0.0;
float eRing = 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]) 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]; chWedge = qqq.ch[i];
eWedgeRaw = qqq.e[i]; eWedgeRaw = qqq.e[i];
@ -104,16 +104,16 @@ Bool_t Calibration::Process(Long64_t entry)
// printf("Wedge E: %.2f Gain: %.4f \n", eWedge, qqqGain[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; chRing = qqq.ch[j] - 16;
eRingRaw = qqq.e[j]; eRingRaw = qqq.e[j];
eRing = qqq.e[j] * qqqrGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16]; 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]) 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]; chWedge = qqq.ch[j];
eWedge = qqq.e[j] * qqqwGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16]; eWedge = qqq.e[j] * qqqwGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16];
eWedgeRaw = qqq.e[j]; eWedgeRaw = qqq.e[j];
chRing = qqq.ch[i] - 16; chRing = qqq.ch[i] - 16;
eRing = qqq.e[i] * qqqrGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16]; eRing = qqq.e[i];// * qqqrGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
eRingRaw = qqq.e[i]; eRingRaw = qqq.e[i];
} }
else else
@ -137,8 +137,14 @@ Bool_t Calibration::Process(Long64_t entry)
const double MIN_ADC = 1500.0; const double MIN_ADC = 1500.0;
const double MAX_ADC = 3000.0; const double MAX_ADC = 3000.0;
if (eWedge >= MIN_ADC && eWedge <= MAX_ADC && // if (eWedge >= MIN_ADC && eWedge <= MAX_ADC &&
eRing >= MIN_ADC && eRing <= MAX_ADC) // eRing >= MIN_ADC && eRing <= MAX_ADC)
double ratio = (eWedge > 0.0) ? (eRing / eWedge) : 0.0;
double maxslope = 1.5;
bool validPoint = false;
if (ratio < maxslope && ratio > 1. / maxslope)
{ {
// Accumulate data for gain matching // Accumulate data for gain matching
dataPoints[{qqq.id[i], chRing, chWedge}].emplace_back(eWedge, eRing); dataPoints[{qqq.id[i], chRing, chWedge}].emplace_back(eWedge, eRing);

View File

@ -14,6 +14,9 @@
#include <numeric> #include <numeric>
#include "Armory/HistPlotter.h" #include "Armory/HistPlotter.h"
#include "TVector3.h" #include "TVector3.h"
#include "TGraphErrors.h"
#include "TF1.h"
#include <cmath>
TH2F *hQQQFVB; TH2F *hQQQFVB;
HistPlotter *plotter; HistPlotter *plotter;
@ -137,223 +140,170 @@ Bool_t GainMatchQQQ::Process(Long64_t entry)
return kTRUE; return kTRUE;
} }
void GainMatchQQQ::Terminate() void GainMatchQQQ::Terminate()
{ {
const int MAX_DET = 4; const int MAX_DET = 4;
const int MAX_RING = 16; const int MAX_RING = 16;
const int MAX_WEDGE = 16; const int MAX_WEDGE = 16;
// We store gains locally just for the "corrected" plot,
// but the file will output Slopes for the global minimizer.
double gainW[MAX_DET][MAX_RING][MAX_WEDGE] = {{{0}}}; double gainW[MAX_DET][MAX_RING][MAX_WEDGE] = {{{0}}};
double gainR[MAX_DET][MAX_RING][MAX_WEDGE] = {{{0}}}; double gainR[MAX_DET][MAX_RING][MAX_WEDGE] = {{{0}}};
bool gainValid[MAX_DET][MAX_RING][MAX_WEDGE] = {{{false}}}; bool gainValid[MAX_DET][MAX_RING][MAX_WEDGE] = {{{false}}};
// Output file for the Minimizer
std::ofstream outFile("qqq_GainMatch.txt"); std::ofstream outFile("qqq_GainMatch.txt");
if (!outFile.is_open())
{
std::cerr << "Error opening output file!" << std::endl;
return;
}
// Parameters for sigma-clipping // Benchmark/Debug file
const int MIN_POINTS = 5; std::ofstream benchFile("benchmark_diff.txt");
const int MAX_ITER = 5; benchFile << "ID Wedge Ring Chi2NDF Slope SlopeErr" << std::endl;
const double CLIP_SIGMA = 3.0;
if (!outFile.is_open()) { std::cerr << "Error opening output file!" << std::endl; return; }
const int MIN_POINTS = 50;
const int MAX_ITER = 3; // Outlier rejection passes
const double CLIP_SIGMA = 2.5; // Sigma threshold for outliers
for (const auto &kv : dataPoints) for (const auto &kv : dataPoints)
{ {
auto key = kv.first; auto key = kv.first;
auto [id, ring, wedge] = key; auto [id, ring, wedge] = key;
const auto &pts_in = kv.second; const auto &pts = kv.second;
if (pts_in.size() < (size_t)MIN_POINTS)
continue;
// Make a working copy of the points for clipping if (pts.size() < (size_t)MIN_POINTS) continue;
std::vector<std::pair<double, double>> pts = pts_in;
bool solved = false; std::vector<std::pair<double, double>> current_pts = pts;
double final_gW = 0.0;
double final_gR = 0.0;
// make a vector of ring wedge as I go through all points and fit a tgraph on the fly
// Iterative sigma-clipping loop double finalSlope = 0.0;
double finalSlopeErr = 0.0;
bool converged = false;
// --- Iterative Fitting ---
for (int iter = 0; iter < MAX_ITER; ++iter) for (int iter = 0; iter < MAX_ITER; ++iter)
{ {
// Compute sums if (current_pts.size() < (size_t)MIN_POINTS) break;
double sum_w2 = 0.0;
double sum_wr = 0.0; std::vector<double> x, y, ex, ey;
double sum_r2 = 0.0;
for (const auto &p : pts) for (const auto &p : current_pts)
{ {
double w = p.first; x.push_back(p.first); // Wedge E
double r = p.second; y.push_back(p.second); // Ring E
sum_w2 += w * w; ex.push_back(std::sqrt(std::abs(p.first))); // Error in X (Poisson)
sum_wr += w * r; ey.push_back(std::sqrt(std::abs(p.second))); // Error in Y (Poisson)
sum_r2 += r * r;
// Sanity check to avoid 0 error
if(ex.back() < 1.0) ex.back() = 1.0;
if(ey.back() < 1.0) ey.back() = 1.0;
} }
// Guard against degenerate cases // 2. Create Graph
if (sum_w2 <= 0.0 || sum_wr <= 0.0) TGraphErrors *gr = new TGraphErrors(current_pts.size(), x.data(), y.data(), ex.data(), ey.data());
{
// // fallback to single-parameter linear fit (original method) // 3. Fit Linear Function through Origin
// // Use ROOT TGraph fitting as fallback TF1 *f1= new TF1("calibFit", "[0]*x", 0, 16000);
// if (pts.size() >= 2) f1->SetParameter(0, 1.0);
// {
// std::vector<double> wE, rE; // "Q"=Quiet, "N"=NoDraw, "S"=ResultPtr
// wE.reserve(pts.size()); // We do NOT use "W" (Ignore weights), we want to use the errors we set.
// rE.reserve(pts.size()); int fitStatus = gr->Fit(f1, "QNS");
// for (const auto &pr : pts)
// { if (fitStatus != 0) {
// wE.push_back(pr.first); delete gr; delete f1;
// rE.push_back(pr.second);
// }
// TGraph g(static_cast<int>(wE.size()), wE.data(), rE.data());
// TF1 f("f_fallback", "[0]*x", 0, 16000);
// g.Fit(&f, "QNR");
// double slope = f.GetParameter(0);
// if (slope > 0)
// {
// // distribute correction symmetrically:
// double alpha = slope; // r ≈ slope * w => alpha = slope
// double gW_try = std::sqrt(alpha);
// double gR_try = 1.0 / gW_try;
// final_gW = gW_try;
// final_gR = gR_try;
// solved = true;
// }
// }
break; break;
} }
// alpha = sum(w*r) / sum(w^2) finalSlope = f1->GetParameter(0);
double alpha = sum_wr / sum_w2; double chi2 = f1->GetChisquare();
double ndf = f1->GetNDF();
if (!(alpha > 0.0) || !std::isfinite(alpha)) // Get the statistical error on the slope
{ double rawErr = f1->GetParError(0);
// // degenerate; fallback to TF1 fit as above
// if (pts.size() >= 2) // SCALING ERROR:
// { // If Chi2/NDF > 1, the data scatters more than Poisson stats predict.
// std::vector<double> wE, rE; // // We inflate the error by sqrt(Chi2/NDF) to be conservative for the Minimizer.
// wE.reserve(pts.size()); // double redChi2 = (ndf > 0) ? (chi2 / ndf) : 1.0;
// rE.reserve(pts.size()); // double inflation = (redChi2 > 1.0) ? std::sqrt(redChi2) : 1.0;
// for (const auto &pr : pts)
// { // finalSlopeErr = rawErr * inflation;
// wE.push_back(pr.first);
// rE.push_back(pr.second); // 4. Outlier Rejection
// } if (iter == MAX_ITER - 1) {
// TGraph g(static_cast<int>(wE.size()), wE.data(), rE.data()); converged = true;
// TF1 f("f_fallback2", "[0]*x", 0, 16000); delete gr; delete f1;
// g.Fit(&f, "QNR");
// double slope = f.GetParameter(0);
// if (slope > 0)
// {
// double gW_try = std::sqrt(slope);
// double gR_try = 1.0 / gW_try;
// final_gW = gW_try;
// final_gR = gR_try;
// solved = true;
// }
// }
break; break;
} }
// distribute correction between W and R // Calculate Residuals
double gW = std::sqrt(alpha);
double gR = 1.0 / gW;
// compute residuals and sigma
std::vector<double> residuals; std::vector<double> residuals;
residuals.reserve(pts.size()); double sumSqResid = 0.0;
for (const auto &p : pts) for(size_t k=0; k<current_pts.size(); ++k) {
{ double val = f1->Eval(current_pts[k].first);
double w = p.first; double res = current_pts[k].second - val;
double r = p.second;
double res = gW * w - gR * r;
residuals.push_back(res); residuals.push_back(res);
sumSqResid += res*res;
}
// double sigma = std::sqrt(sumSqResid / current_pts.size());
// // Filter
// std::vector<std::pair<double, double>> next_pts;
// for(size_t k=0; k<current_pts.size(); ++k) {
// if(std::abs(residuals[k]) < CLIP_SIGMA * sigma) {
// next_pts.push_back(current_pts[k]);
// }
// }
// if (next_pts.size() == current_pts.size()) {
// converged = true;
// delete gr; delete f1;
// break;
// }
// current_pts = next_pts;
// delete gr; delete f1;
} }
// mean and stddev (use population sigma here) if (!converged || finalSlope <= 0) continue;
double mean = 0.0;
for (double v : residuals)
mean += v;
mean /= residuals.size();
double var = 0.0; // --- Store/Output ---
for (double v : residuals)
var += (v - mean) * (v - mean);
var /= residuals.size();
double sigma = std::sqrt(var);
// If sigma is NaN or zero, accept and break // 1. Save locally for the verification plot (hAll)
if (!std::isfinite(sigma) || sigma == 0.0) // Approximate local gain for plotting purposes only
{ double gW_local = std::sqrt(finalSlope);
final_gW = gW; double gR_local = 1.0 / gW_local;
final_gR = gR; gainW[id][ring][wedge] = gW_local;
solved = true; gainR[id][ring][wedge] = gR_local;
break;
}
// Clip > CLIP_SIGMA and build new pts
size_t before = pts.size();
std::vector<std::pair<double, double>> new_pts;
new_pts.reserve(pts.size());
for (size_t k = 0; k < pts.size(); ++k)
{
if (std::fabs(residuals[k] - mean) <= CLIP_SIGMA * sigma)
new_pts.push_back(pts[k]);
}
pts.swap(new_pts);
size_t after = pts.size();
// If no points removed or too few remain, accept current solution
final_gW = gW;
final_gR = gR;
solved = true;
if (before == after || pts.size() < (size_t)MIN_POINTS)
break;
// otherwise iterate again with clipped pts
} // end iter loop
if (!solved)
continue;
// sanity checks: avoid ridiculous gains
if (!(final_gW > 0.0) || !(final_gR > 0.0) || !std::isfinite(final_gW) || !std::isfinite(final_gR))
continue;
// store gains
gainW[id][ring][wedge] = final_gW;
gainR[id][ring][wedge] = final_gR;
gainValid[id][ring][wedge] = true; gainValid[id][ring][wedge] = true;
// write out both gains: id wedge ring gW gR // 2. Write to File for Minimizer
outFile << id << " " << wedge << " " << ring << " " << final_gW << " " << final_gR << std::endl; // Format: ID Wedge Ring Slope Error
printf("Gain match Det%d Ring%d Wedge%d → gW=%.6f gR=%.6f\n", id, ring, wedge, final_gW, final_gR); outFile << id << " " << wedge << " " << ring << " " << finalSlope << " " << finalSlopeErr << std::endl;
// 3. Benchmark Info
benchFile << id << " " << wedge << " " << ring << " "
<< finalSlope << " " << finalSlopeErr << std::endl;
} }
outFile.close(); outFile.close();
benchFile.close();
std::cout << "Gain matching with Errors complete." << std::endl;
std::cout << "Gain matching complete." << std::endl; // Plotting the corrected data (Visual check using local approx gains)
// === Plot all gain-matched QQQ points together with a 2D histogram ===
// Fill the combined TH2F with corrected data
for (auto &kv : dataPoints) for (auto &kv : dataPoints)
{ {
int id, ring, wedge; int id, ring, wedge;
std::tie(id, ring, wedge) = kv.first; std::tie(id, ring, wedge) = kv.first;
if (!gainValid[id][ring][wedge]) if (!gainValid[id][ring][wedge]) continue;
continue;
auto &pts = kv.second; auto &pts = kv.second;
for (auto &pr : pts) for (auto &pr : pts)
{ {
double corrWedge = pr.first * gainW[id][ring][wedge]; double corrWedge = pr.first * gainW[id][ring][wedge];
double corrRing = pr.second * gainR[id][ring][wedge]; double corrRing = pr.second * gainR[id][ring][wedge];
// hAll->Fill(corrWedge, corrRing);
plotter->Fill2D("hAll", 4000, 0, 16000, 4000, 0, 16000, corrWedge, corrRing); plotter->Fill2D("hAll", 4000, 0, 16000, 4000, 0, 16000, corrWedge, corrRing);
plotter->Fill2D(Form("hGMQQQ_id%d_ring%d_wedge%d", id, ring, wedge), 400, 0, 16000, 400, 0, 16000, corrWedge, corrRing, "GainMatched");
} }
} }
// Optionally keep previous global histos too
plotter->FlushToDisk(); plotter->FlushToDisk();
} }

View File

@ -52,9 +52,9 @@ void QQQ_Calcheck::Begin(TTree * /*tree*/)
while (infile >> det >> ring >> wedge >> gainw>> gainr) while (infile >> det >> ring >> wedge >> gainw>> gainr)
{ {
qqqwGain[det][ring][wedge] = gainw; qqqwGain[det][ring][wedge] = gainw;
qqqrGain[det][ring][wedge] = gainr; // qqqrGain[det][ring][wedge] = gainr;
qqqwGainValid[det][ring][wedge] = (gainw > 0); qqqwGainValid[det][ring][wedge] = (gainw > 0);
qqqrGainValid[det][ring][wedge] = (gainr > 0); // qqqrGainValid[det][ring][wedge] = (gainr > 0);
} }
infile.close(); infile.close();
std::cout << "Loaded QQQ gains from " << filename << std::endl; std::cout << "Loaded QQQ gains from " << filename << std::endl;
@ -110,7 +110,7 @@ Bool_t QQQ_Calcheck::Process(Long64_t entry)
float eRing = 0.0; float eRing = 0.0;
float eRingMeV = 0.0; float eRingMeV = 0.0;
// plug in gains // plug in gains
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]) 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]; chWedge = qqq.ch[i];
eWedgeRaw = qqq.e[i]; eWedgeRaw = qqq.e[i];
@ -118,16 +118,16 @@ Bool_t QQQ_Calcheck::Process(Long64_t entry)
// printf("Wedge E: %.2f Gain: %.4f \n", eWedge, qqqGain[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; chRing = qqq.ch[j] - 16;
eRingRaw = qqq.e[j]; eRingRaw = qqq.e[j];
eRing = qqq.e[j] * qqqrGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i]-16]; 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]) 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]; chWedge = qqq.ch[j];
eWedge = qqq.e[j] * qqqwGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16]; eWedge = qqq.e[j] * qqqwGain[qqq.id[j]][qqq.ch[j]][qqq.ch[i] - 16];
eWedgeRaw = qqq.e[j]; eWedgeRaw = qqq.e[j];
chRing = qqq.ch[i] - 16; chRing = qqq.ch[i] - 16;
eRing = qqq.e[i] * qqqrGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16]; eRing = qqq.e[i];// * qqqrGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
eRingRaw = qqq.e[i]; eRingRaw = qqq.e[i];
} }
else else
@ -151,7 +151,7 @@ Bool_t QQQ_Calcheck::Process(Long64_t entry)
plotter->Fill2D(Form("hRCal_qqq%d", qqq.id[i]), 16, 0, 15, 1000, 0, 30, chRing, eRingMeV, "RingCal"); plotter->Fill2D(Form("hRCal_qqq%d", qqq.id[i]), 16, 0, 15, 1000, 0, 30, chRing, eRingMeV, "RingCal");
plotter->Fill2D(Form("hWCal_qqq%d", qqq.id[i]), 16, 0, 15, 1000, 0, 30, chWedge, eWedgeMeV, "WedgeCal"); plotter->Fill2D(Form("hWCal_qqq%d", qqq.id[i]), 16, 0, 15, 1000, 0, 30, chWedge, eWedgeMeV, "WedgeCal");
plotter->Fill2D("hRawQQQ", 4000, 0, 8000, 4000, 0, 8000, eWedgeRaw, eRingRaw); plotter->Fill2D("hRawQQQ", 4000, 0, 8000, 4000, 0, 8000, eWedgeRaw, eRingRaw);
plotter->Fill2D("hGMQQQ", 4000, 0, 16000, 4000, 0, 16000, eWedge, eRing); plotter->Fill2D("hGMQQQ", 4000, 0, 8000, 4000, 0, 8000, eWedge, eRing);
plotter->Fill2D("hCalQQQ", 4000, 0, 10, 4000, 0, 10, eWedgeMeV, eRingMeV); plotter->Fill2D("hCalQQQ", 4000, 0, 10, 4000, 0, 10, eWedgeMeV, eRingMeV);
} }
} }