#define Calibration_cxx #include #include #include #include #include #include #include #include #include #include "Armory/HistPlotter.h" #include "TVector3.h" #include "Calibration.h" TH2F *hQQQFVB; HistPlotter *plotter; int padID = 0; TCutG *cut; std::map, std::vector>> 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 per–channel 1D spectra in ADC from stored gain-matched data //---------------------------------------------------------------------- std::map, 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"; }