new file: eloss_calculations/alpha_lookup_20MeV_3pc_350Torr.dat new file: eloss_calculations/alpha_lookup_20MeV_4pc_350Torr.dat new file: eloss_calculations/aluminum_lookup_80MeV_3pc_350Torr.dat new file: eloss_calculations/aluminum_lookup_80MeV_4pc_350Torr.dat new file: eloss_calculations/fluorine_lookup_70MeV_3pc_350Torr.dat new file: eloss_calculations/fluorine_lookup_70MeV_4pc_350Torr.dat new file: eloss_calculations/oxygen_lookup_70MeV_3pc_350Torr.dat new file: eloss_calculations/oxygen_lookup_70MeV_4pc_350Torr.dat new file: eloss_calculations/proton_lookup_20MeV_3pc_350Torr.dat new file: eloss_calculations/proton_lookup_20MeV_4pc_350Torr.dat modified: run_tr.sh book keeping new file: scan_slope_runs.sh diagnostic plots to figure out the slope correection for the PC model_invert new file: scratch/plot_slope_scan.C diagnostic plots to figure out the slope correection for the PC model_invert
346 lines
12 KiB
C
346 lines
12 KiB
C
#include <TFile.h>
|
|
#include <TH1.h>
|
|
#include <TF1.h>
|
|
#include <TFitResult.h>
|
|
#include <TGraph.h>
|
|
#include <TMultiGraph.h>
|
|
#include <TCanvas.h>
|
|
#include <TLegend.h>
|
|
#include <TLine.h>
|
|
#include <TString.h>
|
|
|
|
void plot_slope_scan()
|
|
{
|
|
// =========================================================================
|
|
// --- Configuration ---
|
|
// =========================================================================
|
|
|
|
// Set to true to inspect each Gaussian fit. Double-click the canvas to advance.
|
|
bool checkFits = false;
|
|
gStyle->SetOptStat(0);
|
|
double slopes[] = {0.40, 0.42, 0.44, 0.46, 0.48, 0.50, 0.52, 0.54, 0.56, 0.58, 0.60, 0.62, 0.64, 0.66};
|
|
const int N = 14; // Updated to 14 to match the size of your slopes array
|
|
|
|
// int runs[] = {9, 12, 18, 19, 20, 21};
|
|
// const int NRUNS = 6;
|
|
// int runs[] = {9, 12};
|
|
// const int NRUNS = 2;
|
|
int runs[] = {18, 19, 20, 21};
|
|
const int NRUNS = 4;
|
|
Int_t runColors[6] = {kRed + 1, kBlue + 2, kGreen + 2, kOrange + 1, kViolet + 2, kCyan + 2};
|
|
|
|
// --- Initialize Graphs ---
|
|
TGraph *gStdDevRun[NRUNS];
|
|
TGraph *gMeanRun[NRUNS];
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
gStdDevRun[ir] = new TGraph(N);
|
|
gMeanRun[ir] = new TGraph(N);
|
|
}
|
|
TGraph *gStdDevSum = new TGraph(N);
|
|
TGraph *gMeanSum = new TGraph(N);
|
|
|
|
TH1 *h1[NRUNS][N];
|
|
|
|
// --- Load Data ---
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
h1[ir][i] = nullptr;
|
|
TString path = TString::Format("slope_scan/run%03d/slope_%.2f.root", runs[ir], slopes[i]);
|
|
TFile *f = TFile::Open(path);
|
|
|
|
if (!f || f->IsZombie())
|
|
continue;
|
|
|
|
TH1 *t1 = (TH1 *)f->Get("pczfix-sx3pczguess_A1C2");
|
|
if (t1)
|
|
{
|
|
t1->SetDirectory(nullptr);
|
|
h1[ir][i] = t1;
|
|
}
|
|
f->Close();
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// --- Calculate Mean & StdDev with Bounded Gaussian Fit ---
|
|
// =========================================================================
|
|
std::vector<int> nPtsRun(NRUNS, 0);
|
|
int nPtsSum = 0;
|
|
double fitWindow = 15.0; // Window around the peak to fit (mm)
|
|
|
|
TCanvas *cDebug = nullptr;
|
|
if (checkFits)
|
|
{
|
|
cDebug = new TCanvas("cDebug", "Fit Diagnostic Debugger", 0, 0, 800, 600);
|
|
}
|
|
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
TH1 *hsum = nullptr;
|
|
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
if (!h1[ir][i] || h1[ir][i]->GetEntries() <= 0)
|
|
continue;
|
|
|
|
// 1. Find center of the highest peak
|
|
int maxBin = h1[ir][i]->GetMaximumBin();
|
|
double peakX = h1[ir][i]->GetXaxis()->GetBinCenter(maxBin);
|
|
|
|
// 2. Define the fit
|
|
TF1 *gfit = new TF1("gfit", "gaus", peakX - fitWindow, peakX + fitWindow);
|
|
|
|
// 3. Fit Conditionally (Draw if checking, otherwise run quietly in background)
|
|
TString fitOpt = checkFits ? "RQS" : "RQS0";
|
|
|
|
if (checkFits)
|
|
cDebug->cd(); // Ensure we draw on the debug canvas
|
|
TFitResultPtr fitRes = h1[ir][i]->Fit(gfit, fitOpt);
|
|
|
|
// --- DIAGNOSTIC PAUSE ---
|
|
if (checkFits)
|
|
{
|
|
h1[ir][i]->SetTitle(TString::Format("Run %d | Slope %.2f", runs[ir], slopes[i]));
|
|
h1[ir][i]->GetXaxis()->SetRangeUser(peakX - 50, peakX + 50); // Zoom in X
|
|
|
|
// Scale Y-axis to the maximum of this specific zoomed window + 20% headroom
|
|
h1[ir][i]->SetMaximum(h1[ir][i]->GetMaximum() * 1.2);
|
|
|
|
h1[ir][i]->Draw();
|
|
cDebug->Modified();
|
|
cDebug->Update();
|
|
printf("Visual Check: Run %d | Slope %.2f. Double-click canvas to continue...\n", runs[ir], slopes[i]);
|
|
while (cDebug->WaitPrimitive())
|
|
;
|
|
}
|
|
|
|
double mean, stddev;
|
|
if (fitRes >= 0)
|
|
{ // If fit succeeds
|
|
mean = gfit->GetParameter(1);
|
|
stddev = gfit->GetParameter(2);
|
|
}
|
|
else
|
|
{ // Fallback to raw stats if fit fails
|
|
mean = h1[ir][i]->GetMean();
|
|
stddev = h1[ir][i]->GetStdDev();
|
|
}
|
|
|
|
gStdDevRun[ir]->SetPoint(nPtsRun[ir], slopes[i], stddev);
|
|
gMeanRun[ir]->SetPoint(nPtsRun[ir]++, slopes[i], mean);
|
|
|
|
delete gfit;
|
|
|
|
// Build the cumulative sum histogram
|
|
if (!hsum)
|
|
hsum = (TH1 *)h1[ir][i]->Clone(TString::Format("hsum_%.2f", slopes[i]));
|
|
else
|
|
hsum->Add(h1[ir][i]);
|
|
}
|
|
|
|
// --- Process Summed Histogram ---
|
|
if (hsum && hsum->GetEntries() > 0)
|
|
{
|
|
int maxBinSum = hsum->GetMaximumBin();
|
|
double peakXSum = hsum->GetXaxis()->GetBinCenter(maxBinSum);
|
|
TF1 *gfitSum = new TF1("gfitSum", "gaus", peakXSum - fitWindow, peakXSum + fitWindow);
|
|
|
|
TString fitOptSum = checkFits ? "RQS" : "RQS0";
|
|
if (checkFits)
|
|
cDebug->cd();
|
|
|
|
TFitResultPtr fitResSum = hsum->Fit(gfitSum, fitOptSum);
|
|
|
|
// --- DIAGNOSTIC PAUSE FOR SUM ---
|
|
if (checkFits)
|
|
{
|
|
hsum->SetTitle(TString::Format("SUMMED RUNS | Slope %.2f", slopes[i]));
|
|
hsum->GetXaxis()->SetRangeUser(peakXSum - 50, peakXSum + 50);
|
|
|
|
// Scale Y-axis for the sum + 20% headroom
|
|
hsum->SetMaximum(hsum->GetMaximum() * 1.2);
|
|
|
|
hsum->Draw();
|
|
cDebug->Modified();
|
|
cDebug->Update();
|
|
printf("Visual Check: SUMMED | Slope %.2f. Double-click canvas to continue...\n", slopes[i]);
|
|
while (cDebug->WaitPrimitive())
|
|
;
|
|
}
|
|
|
|
// if (fitResSum >= 0)
|
|
// {
|
|
// gStdDevSum->SetPoint(nPtsSum, slopes[i], gfitSum->GetParameter(2));
|
|
// gMeanSum->SetPoint(nPtsSum++, slopes[i], gfitSum->GetParameter(1));
|
|
// }
|
|
// else
|
|
// {
|
|
// gStdDevSum->SetPoint(nPtsSum, slopes[i], hsum->GetStdDev());
|
|
// gMeanSum->SetPoint(nPtsSum++, slopes[i], hsum->GetMean());
|
|
// }
|
|
|
|
// delete gfitSum;
|
|
// delete hsum;
|
|
}
|
|
}
|
|
|
|
if (checkFits && cDebug)
|
|
{
|
|
delete cDebug; // Clean up debug canvas before plotting final results
|
|
}
|
|
|
|
// =========================================================================
|
|
// ---- Canvas 1: StdDev and Mean vs Slope
|
|
// =========================================================================
|
|
TCanvas *c1 = new TCanvas("c_stats", "1D Residual Stats vs Slope", 0, 0, 1600, 600);
|
|
c1->Divide(2, 1);
|
|
|
|
c1->cd(1);
|
|
gPad->SetGrid(1, 1);
|
|
TLegend *leg1 = new TLegend(0.78, 0.45, 0.97, 0.88);
|
|
leg1->SetBorderSize(1);
|
|
TMultiGraph *mg1 = new TMultiGraph("mg_stddev", "StdDev(pczfix - sx3pczguess) vs Slope;Slope;StdDev (mm)");
|
|
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
if (nPtsRun[ir] == 0)
|
|
continue;
|
|
gStdDevRun[ir]->SetLineColor(runColors[ir]);
|
|
gStdDevRun[ir]->SetMarkerColor(runColors[ir]);
|
|
gStdDevRun[ir]->SetLineWidth(2);
|
|
gStdDevRun[ir]->SetMarkerStyle(20 + ir);
|
|
mg1->Add(gStdDevRun[ir], "PL");
|
|
leg1->AddEntry(gStdDevRun[ir], TString::Format("run %d", runs[ir]), "lp");
|
|
}
|
|
if (nPtsSum > 0)
|
|
{
|
|
gStdDevSum->SetLineColor(kBlack);
|
|
gStdDevSum->SetLineWidth(3);
|
|
gStdDevSum->SetLineStyle(kDashed);
|
|
gStdDevSum->SetMarkerStyle(29);
|
|
mg1->Add(gStdDevSum, "PL");
|
|
leg1->AddEntry(gStdDevSum, "sum", "lp");
|
|
}
|
|
mg1->Draw("A");
|
|
leg1->Draw();
|
|
|
|
double bestSlope = 0, bestStdDev = 1e9;
|
|
for (int i = 0; i < gStdDevRun[0]->GetN(); i++)
|
|
{
|
|
double x, y;
|
|
gStdDevRun[0]->GetPoint(i, x, y);
|
|
if (y > 0 && y < bestStdDev)
|
|
{
|
|
bestStdDev = y;
|
|
bestSlope = x;
|
|
}
|
|
}
|
|
|
|
TLine *lb = new TLine(bestSlope, mg1->GetHistogram()->GetMinimum(),
|
|
bestSlope, mg1->GetHistogram()->GetMaximum());
|
|
lb->SetLineColor(kRed);
|
|
lb->SetLineStyle(kDashed);
|
|
lb->Draw();
|
|
printf(">>> Best slope (Run %d) = %.2f StdDev=%.2f mm\n", runs[0], bestSlope, bestStdDev);
|
|
|
|
c1->cd(2);
|
|
gPad->SetGrid(1, 1);
|
|
TLegend *leg2 = new TLegend(0.78, 0.45, 0.97, 0.88);
|
|
leg2->SetBorderSize(1);
|
|
TMultiGraph *mg2 = new TMultiGraph("mg_mean", "Mean(pczfix - sx3pczguess) vs Slope;Slope;Mean Offset (mm)");
|
|
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
if (nPtsRun[ir] == 0)
|
|
continue;
|
|
gMeanRun[ir]->SetLineColor(runColors[ir]);
|
|
gMeanRun[ir]->SetMarkerColor(runColors[ir]);
|
|
gMeanRun[ir]->SetLineWidth(2);
|
|
gMeanRun[ir]->SetMarkerStyle(20 + ir);
|
|
mg2->Add(gMeanRun[ir], "PL");
|
|
leg2->AddEntry(gMeanRun[ir], TString::Format("run %d", runs[ir]), "lp");
|
|
}
|
|
if (nPtsSum > 0)
|
|
{
|
|
gMeanSum->SetLineColor(kBlack);
|
|
gMeanSum->SetLineWidth(3);
|
|
gMeanSum->SetLineStyle(kDashed);
|
|
gMeanSum->SetMarkerStyle(29);
|
|
mg2->Add(gMeanSum, "PL");
|
|
leg2->AddEntry(gMeanSum, "sum", "lp");
|
|
}
|
|
mg2->Draw("A");
|
|
|
|
TLine *lz = new TLine(slopes[0], 0, slopes[N - 1], 0);
|
|
lz->SetLineColor(kGray + 2);
|
|
lz->SetLineStyle(kDotted);
|
|
lz->Draw();
|
|
leg2->Draw();
|
|
|
|
c1->SaveAs("slope_scan_1d_metric.png");
|
|
|
|
// =========================================================================
|
|
// ---- Canvas 2: Per-slope pads, overlaying the 1D Residual distributions
|
|
// =========================================================================
|
|
TCanvas *c2 = new TCanvas("c_perslope_1d", "Per-slope 1D Residuals: all runs overlaid", 0, 100, 1800, 1200);
|
|
c2->Divide(4, 4);
|
|
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
c2->cd(i + 1);
|
|
gPad->SetGrid(1, 1);
|
|
TLegend *legS = new TLegend(0.62, 0.55, 0.88, 0.88);
|
|
legS->SetBorderSize(0);
|
|
|
|
// --- STEP A: Pre-scan to find the highest Y value across all runs for this slope ---
|
|
double maxY = 0;
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
if (!h1[ir][i] || h1[ir][i]->GetEntries() <= 0)
|
|
continue;
|
|
|
|
// Set X range first so GetMaximum() doesn't accidentally grab a tail far away
|
|
h1[ir][i]->GetXaxis()->SetRangeUser(-50, 50);
|
|
if (h1[ir][i]->GetMaximum() > maxY)
|
|
{
|
|
maxY = h1[ir][i]->GetMaximum();
|
|
}
|
|
}
|
|
|
|
// --- STEP B: Draw with the dynamically scaled Y-axis ---
|
|
bool first = true;
|
|
for (int ir = 0; ir < NRUNS; ir++)
|
|
{
|
|
if (!h1[ir][i] || h1[ir][i]->GetEntries() <= 0)
|
|
continue;
|
|
|
|
h1[ir][i]->SetLineColor(runColors[ir]);
|
|
h1[ir][i]->SetLineWidth(2);
|
|
h1[ir][i]->SetTitle(TString::Format("slope=%.2f;Residual (mm);Counts", slopes[i]));
|
|
|
|
if (first)
|
|
{
|
|
// Set the pad's Y-axis using the global max + 15% buffer so the legend fits cleanly
|
|
h1[ir][i]->SetMaximum(maxY * 1.15);
|
|
h1[ir][i]->Draw("HIST");
|
|
first = false;
|
|
}
|
|
else
|
|
{
|
|
h1[ir][i]->Draw("HIST SAME");
|
|
}
|
|
legS->AddEntry(h1[ir][i], TString::Format("run %d", runs[ir]), "l");
|
|
}
|
|
if (!first)
|
|
legS->Draw();
|
|
}
|
|
|
|
c2->SaveAs("slope_scan_perslope_1d.png");
|
|
c2->Modified();
|
|
c2->Update();
|
|
while (gPad->WaitPrimitive())
|
|
;
|
|
} |