A lot of the files are identical to old ones, but the main changes are: 1) EXFit2.C in sx3cal - Finds front/right gains for each strip using the known middle two pad edges, but gainmatches all backs 2) Define new 'fix' loci, arising from the step-ladder correction to A1C2 events. This is tested in scratch/sx3z_vs_pcz/testmodel.h, will be given a better name in the future. 3) Explore A1C2 and A1C3 loci in detail 4) environment variables to 'flip' and 'offset' wires during sort. All env vars are set in shell scripts that call them 5) environment variables that allow for timestamp bounds to be set and unset. Default limiting values are 0 and dbl_max so no harm done unless these specific env vars are set. 6) Some bookkeeping indicating 27Al instead of 26Al in all places.
640 lines
22 KiB
C
640 lines
22 KiB
C
#define DataDump_cxx
|
|
|
|
#include "DataDump.h"
|
|
#include "Armory/ClassPW.h"
|
|
#include "Armory/HistPlotter.h"
|
|
|
|
#include <TH2.h>
|
|
#include <TStyle.h>
|
|
#include <TCanvas.h>
|
|
#include <TMath.h>
|
|
#include <TBranch.h>
|
|
#include "TVector3.h"
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <map>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <utility>
|
|
#include <algorithm>
|
|
|
|
// Global instances
|
|
PW pw_contr;
|
|
PW pwinstance;
|
|
TVector3 hitPos;
|
|
long long int gcount=0;
|
|
|
|
class Event {
|
|
public:
|
|
TVector3 pos;
|
|
int ch1=-1; //ring# for QQQ, anode# for PC
|
|
int ch2=-1; //wedge# for QQQ, cathode# for PC
|
|
double Energy1=-1; //Front for QQQ, Anode for PC
|
|
double Energy2=-1; //Back for QQQ, Cathode for PC
|
|
double Time1=-1;
|
|
double Time2=-1;
|
|
Event(TVector3 p, double E1, double E2, double T1, double T2): pos(p), Energy1(E1), Energy2(E2), Time1(T1), Time2(T2) {}
|
|
};
|
|
/*
|
|
void testfunction()
|
|
{
|
|
for(auto cathode: cathodes) {
|
|
std::unordered_set<int> chans;
|
|
chans.insert(cathode.ch);
|
|
}
|
|
}
|
|
*/
|
|
// Calibration globals
|
|
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}}};
|
|
// TCutg *cutQQQ;
|
|
|
|
// PC Arrays
|
|
double pcSlope[48];
|
|
double pcIntercept[48];
|
|
|
|
HistPlotter *plotter;
|
|
|
|
bool HitNonZero;
|
|
bool sx3ecut;
|
|
bool qqqEcut;
|
|
|
|
|
|
void DataDump::Begin(TTree * /*tree*/)
|
|
{
|
|
TString option = GetOption();
|
|
plotter = new HistPlotter("Analyzer_QQQ.root", "TFILE");
|
|
|
|
pw_contr.ConstructGeo();
|
|
pwinstance.ConstructGeo();
|
|
|
|
// ---------------------------------------------------------
|
|
// 1. CRITICAL FIX: Initialize PC Arrays to Default (Raw)
|
|
// ---------------------------------------------------------
|
|
for (int i = 0; i < 48; i++) {
|
|
pcSlope[i] = 1.0; // Default slope = 1 (preserves Raw energy)
|
|
pcIntercept[i] = 0.0; // Default intercept = 0
|
|
}
|
|
|
|
// Calculate Crossover Geometry ONCE
|
|
TVector3 a, c, diff;
|
|
double a2, ac, c2, adiff, cdiff, denom, alpha;
|
|
|
|
for (size_t i = 0; i < pwinstance.An.size(); i++)
|
|
{
|
|
a = pwinstance.An[i].first - pwinstance.An[i].second;
|
|
for (size_t j = 0; j < pwinstance.Ca.size(); j++)
|
|
{
|
|
c = pwinstance.Ca[j].first - pwinstance.Ca[j].second;
|
|
diff = pwinstance.An[i].first - pwinstance.Ca[j].first;
|
|
a2 = a.Dot(a);
|
|
c2 = c.Dot(c);
|
|
ac = a.Dot(c);
|
|
adiff = a.Dot(diff);
|
|
cdiff = c.Dot(diff);
|
|
denom = a2 * c2 - ac * ac;
|
|
alpha = (ac * cdiff - c2 * adiff) / denom;
|
|
|
|
Crossover[i][j][0].x = pwinstance.An[i].first.X() + alpha * a.X();
|
|
Crossover[i][j][0].y = pwinstance.An[i].first.Y() + alpha * a.Y();
|
|
Crossover[i][j][0].z = pwinstance.An[i].first.Z() + alpha * a.Z();
|
|
|
|
if (Crossover[i][j][0].z < -190 || Crossover[i][j][0].z > 190 || (i+j)%24 == 12 )
|
|
{
|
|
Crossover[i][j][0].z = 9999999;
|
|
}
|
|
|
|
Crossover[i][j][1].x = alpha;
|
|
Crossover[i][j][1].y = 0;
|
|
}
|
|
}
|
|
|
|
// Load PC Calibrations
|
|
std::ifstream inputFile("slope_intercept_results.txt");
|
|
if (inputFile.is_open())
|
|
{
|
|
std::string line;
|
|
int index;
|
|
double slope, intercept;
|
|
while (std::getline(inputFile, line))
|
|
{
|
|
std::stringstream ss(line);
|
|
ss >> index >> slope >> intercept;
|
|
if (index >= 0 && index <= 47)
|
|
{
|
|
pcSlope[index] = slope;
|
|
pcIntercept[index] = intercept;
|
|
}
|
|
}
|
|
inputFile.close();
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "Error opening slope_intercept.txt" << std::endl;
|
|
}
|
|
|
|
// ... (Load QQQ Gains and Calibs - same as before) ...
|
|
{
|
|
std::string filename = "qqq_GainMatch.dat";
|
|
std::ifstream infile(filename);
|
|
if (infile.is_open())
|
|
{
|
|
int det, ring, wedge;
|
|
double gainw, gainr;
|
|
while (infile >> det >> wedge >> ring >> gainw >> gainr)
|
|
{
|
|
qqqGain[det][wedge][ring] = gainw;
|
|
qqqGainValid[det][wedge][ring] = (gainw > 0);
|
|
}
|
|
infile.close();
|
|
}
|
|
}
|
|
{
|
|
std::string filename = "qqq_Calib.dat";
|
|
std::ifstream infile(filename);
|
|
if (infile.is_open())
|
|
{
|
|
int det, ring, wedge;
|
|
double slope;
|
|
while (infile >> det >> wedge >> ring >> slope)
|
|
{
|
|
qqqCalib[det][wedge][ring] = slope;
|
|
qqqCalibValid[det][wedge][ring] = (slope > 0);
|
|
}
|
|
infile.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool_t DataDump::Process(Long64_t entry)
|
|
{
|
|
hitPos.Clear();
|
|
HitNonZero = false;
|
|
bool qqq1000cut = false;
|
|
b_sx3Multi->GetEntry(entry);
|
|
b_sx3ID->GetEntry(entry);
|
|
b_sx3Ch->GetEntry(entry);
|
|
b_sx3E->GetEntry(entry);
|
|
b_sx3T->GetEntry(entry);
|
|
b_qqqMulti->GetEntry(entry);
|
|
b_qqqID->GetEntry(entry);
|
|
b_qqqCh->GetEntry(entry);
|
|
b_qqqE->GetEntry(entry);
|
|
b_qqqT->GetEntry(entry);
|
|
b_pcMulti->GetEntry(entry);
|
|
b_pcID->GetEntry(entry);
|
|
b_pcCh->GetEntry(entry);
|
|
b_pcE->GetEntry(entry);
|
|
b_pcT->GetEntry(entry);
|
|
|
|
sx3.CalIndex();
|
|
qqq.CalIndex();
|
|
pc.CalIndex();
|
|
|
|
// QQQ Processing
|
|
int qqqCount = 0;
|
|
int qqqAdjCh = 0;
|
|
// REMOVE WHEN RERUNNING USING THE NEW CALIBRATION FILE
|
|
for (int i = 0; i < qqq.multi; i++)
|
|
{
|
|
if ((qqq.id[i] == 3 || qqq.id[i] == 1) && qqq.ch[i] < 16)
|
|
{
|
|
qqq.ch[i] = 16 - qqq.ch[i];
|
|
}
|
|
}
|
|
for (int i = 0; i < qqq.multi; i++)
|
|
{
|
|
if (qqq.id[i] == 0 && qqq.ch[i] >= 16)
|
|
{
|
|
qqq.ch[i] = 31 - qqq.ch[i] + 16;
|
|
}
|
|
}
|
|
|
|
std::vector<std::tuple<int,int,double,int,double>> qqqlist;
|
|
std::vector<Event> QQQ_Events, PC_Events;
|
|
std::vector<Event> QQQ_Events_Raw, PC_Events_Raw;
|
|
bool PCQQQTimeCut = false;
|
|
for (int i = 0; i < qqq.multi; i++)
|
|
{
|
|
for (int j = i + 1; j < qqq.multi; j++)
|
|
{
|
|
if (qqq.id[i] == qqq.id[j])
|
|
{
|
|
qqqCount++;
|
|
|
|
int chWedge = -1;
|
|
int chRing = -1;
|
|
double eWedge = 0.0;
|
|
double eWedgeMeV = 0.0;
|
|
double eRing = 0.0;
|
|
double eRingMeV = 0.0;
|
|
double tRing = 0.0;
|
|
double tWedge = 0.0;
|
|
|
|
if (qqq.ch[i] < 16 && qqq.ch[j] >= 16 && qqqGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16])
|
|
{
|
|
chWedge = qqq.ch[i];
|
|
eWedge = qqq.e[i] * qqqGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
|
|
chRing = qqq.ch[j] - 16;
|
|
eRing = qqq.e[j];
|
|
tRing = static_cast<double>(qqq.t[j]);
|
|
tWedge = static_cast<double>(qqq.t[i]);
|
|
}
|
|
else if (qqq.ch[j] < 16 && 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];
|
|
chRing = qqq.ch[i] - 16;
|
|
eRing = qqq.e[i];
|
|
tRing = static_cast<double>(qqq.t[i]);
|
|
tWedge = static_cast<double>(qqq.t[j]);
|
|
}
|
|
else
|
|
continue;
|
|
|
|
if (qqqCalibValid[qqq.id[i]][chWedge][chRing]) {
|
|
eWedgeMeV = eWedge * qqqCalib[qqq.id[i]][chWedge][chRing] / 1000;
|
|
eRingMeV = eRing * qqqCalib[qqq.id[i]][chWedge][chRing] / 1000;
|
|
}
|
|
else
|
|
continue;
|
|
|
|
double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5);
|
|
double rho = 50. + 40. / 16. * (chRing + 0.5);
|
|
|
|
Event qqqevent(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),23+75+30), eRingMeV, eWedgeMeV, tRing, tWedge);
|
|
Event qqqeventr(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),23+75+30), eRing, eWedge, tRing, tWedge);
|
|
QQQ_Events.push_back(qqqevent);
|
|
QQQ_Events_Raw.push_back(qqqeventr);
|
|
qqqlist.push_back(std::tuple(qqq.id[i],chRing,eRingMeV,chWedge,eWedgeMeV));
|
|
} //end if qqq.id[i] == qqq.id[j]
|
|
}//inner qqq loop, j
|
|
}//outer qqq loop, i
|
|
|
|
// PC Gain Matching and Filling
|
|
double anodeT = -99999;
|
|
double cathodeT = 99999;
|
|
int anodeIndex = -1;
|
|
int cathodeIndex = -1;
|
|
|
|
|
|
int aID = 0;
|
|
int cID = 0;
|
|
double aE = 0;
|
|
double cE = 0;
|
|
double aESum = 0;
|
|
double cESum = 0;
|
|
double aEMax = 0;
|
|
int aIDMax = 0;
|
|
anodeHits.clear();
|
|
cathodeHits.clear();
|
|
anodeTimes.clear();
|
|
cathodeTimes.clear();
|
|
corrcatMax.clear();
|
|
corranoMax.clear();
|
|
|
|
std::array<bool,24> caths_seen{0}, anos_seen{0};
|
|
std::vector<std::tuple<int,double,double>> anodeChunks, cathodeChunks;
|
|
for (int i = 0; i < pc.multi; i++)
|
|
{
|
|
if (pc.e[i] > 4)
|
|
{
|
|
;//plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast<double>(pc.e[i]), "hRawPC");
|
|
} else
|
|
continue;
|
|
|
|
if (pc.index[i] < 48) {
|
|
pc.e[i] = pcSlope[pc.index[i]] * pc.e[i] + pcIntercept[pc.index[i]];
|
|
//plotter->Fill2D("PC_Index_VS_GainMatched_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], pc.e[i], "hGMPC");
|
|
}
|
|
|
|
if (pc.index[i] < 24) {
|
|
anodeT = static_cast<double>(pc.t[i]);
|
|
anodeIndex = pc.index[i];
|
|
anos_seen[anodeIndex] = 1;
|
|
anodeHits.push_back(std::pair<int, double>(pc.index[i], pc.e[i]));
|
|
anodeTimes.push_back(anodeT);
|
|
anodeChunks.push_back(std::tuple<int,double,double>(pc.index[i],anodeT,pc.e[i]));
|
|
} else {
|
|
cathodeT = static_cast<double>(pc.t[i]);
|
|
cathodeIndex = pc.index[i] - 24;
|
|
caths_seen[cathodeIndex] = 1;
|
|
cathodeChunks.push_back(std::tuple<int,double,double>(pc.index[i]-24,cathodeT,pc.e[i]));
|
|
cathodeHits.push_back(std::pair<int, double>(pc.index[i] - 24, pc.e[i]));
|
|
cathodeTimes.push_back(cathodeT);
|
|
}
|
|
}//end of pc.multi loop
|
|
|
|
if(anodeHits.size() && cathodeHits.size()) {
|
|
for(size_t ii=0; ii<anodeHits.size(); ii++) {
|
|
const auto& an = anodeHits.at(ii);
|
|
const auto& at = anodeTimes.at(ii);
|
|
for(size_t jj=0; jj<cathodeHits.size(); jj++) {
|
|
const auto& ca = cathodeHits.at(jj);
|
|
const auto& ct = cathodeTimes.at(jj);
|
|
plotter->Fill2D("ach_minus_cch_vs_ach",60,-30,30,24,0,24,an.first-ca.first,an.first);
|
|
plotter->Fill2D("ach_minus_cch_vs_dt",60,-30,30,400,-1000,1000,an.first-ca.first,at-ct);
|
|
plotter->Fill2D("ach_vs_cch",24,0,24,24,0,24,an.first,ca.first);
|
|
}
|
|
}
|
|
gcount++;
|
|
}
|
|
bool all_three = anodeHits.size() > 0 && cathodeHits.size() > 0 && qqqlist.size() > 0;
|
|
|
|
if(all_three) std::cout << "---" << std::endl;
|
|
for(size_t ii=0; ii<anodeHits.size() && all_three; ii++) {
|
|
const auto& an = anodeHits.at(ii);
|
|
const auto& at = anodeTimes.at(ii);
|
|
std::cout << "an" << std::setprecision(16) << ", " << an.first << ", " << an.second << ", " << at << " ,-1, -1" << std::endl;
|
|
}
|
|
|
|
for(size_t jj=0; jj<cathodeHits.size() && all_three; jj++) {
|
|
const auto& ca = cathodeHits.at(jj);
|
|
const auto& ct = cathodeTimes.at(jj);
|
|
std::cout << "ca" << std::setprecision(16) << ", " << ca.first << ", " << ca.second << ", " << ct << " ,-1, -1" << std::endl;
|
|
}
|
|
|
|
for(size_t jj=0; jj<qqqlist.size() && all_three; jj++) {
|
|
const auto[id,chr,er,chw,ew] = qqqlist.at(jj);
|
|
std::cout << "q" << std::setprecision(16) << ", " << id << ", " << chr << ", " << er << ", " << chw << ", " << ew << std::endl;
|
|
}
|
|
if(all_three) std::cout << " --end-- " << std::endl;
|
|
|
|
if(gcount == 100)
|
|
return -1;
|
|
// std::sort(anodeChunks.begin(),anodeChunks.end(),);
|
|
if (anodeHits.size() >= 1 && cathodeHits.size() >= 1)
|
|
{
|
|
// 2. CRITICAL FIX: Define reference vector 'a'
|
|
// In Analyzer.cxx, 'a' was left over from the loop. We use the first anode wire as reference here.
|
|
// (Assuming pwinstance.An is populated and wires are generally parallel).
|
|
TVector3 refAnode = pwinstance.An[0].first - pwinstance.An[0].second;
|
|
for (const auto &anode : anodeHits)
|
|
{
|
|
aID = anode.first;
|
|
aE = anode.second;
|
|
aESum += aE;
|
|
if (aE > aEMax)
|
|
{
|
|
aEMax = aE;
|
|
aIDMax = aID;
|
|
}
|
|
}
|
|
|
|
for (const auto &cathode : cathodeHits)
|
|
{
|
|
cID = cathode.first;
|
|
cE = cathode.second;
|
|
for (int j = -4; j < 3; j++)
|
|
{
|
|
if ((aIDMax + 24 + j) % 24 == 23 - cID)
|
|
{
|
|
corrcatMax.push_back(std::pair<int, double>(cID, cE));
|
|
cESum += cE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TVector3 anodeIntersection;
|
|
anodeIntersection.Clear();
|
|
if (corrcatMax.size() > 0)
|
|
{
|
|
double x = 0, y = 0, z = 0;
|
|
for (const auto &corr : corrcatMax)
|
|
{
|
|
if (Crossover[aIDMax][corr.first][0].z > 9000000)
|
|
continue;
|
|
if (cESum > 0)
|
|
{
|
|
x += (corr.second) / cESum * Crossover[aIDMax][corr.first][0].x;
|
|
y += (corr.second) / cESum * Crossover[aIDMax][corr.first][0].y;
|
|
z += (corr.second) / cESum * Crossover[aIDMax][corr.first][0].z;
|
|
}
|
|
}
|
|
if (x == 0 && y == 0 && z == 0)
|
|
;
|
|
// to ignore events with no valid crossover points
|
|
else
|
|
anodeIntersection = TVector3(x, y, z);
|
|
}
|
|
bool PCQQQPhiCut = false;
|
|
// flip the algorithm for cathode 1 multi anode events
|
|
if ((hitPos.Phi() > (anodeIntersection.Phi() - TMath::PiOver4())) && (hitPos.Phi() < (anodeIntersection.Phi() + TMath::PiOver4()))) {
|
|
PCQQQPhiCut = true;
|
|
}
|
|
|
|
if (anodeIntersection.Z() != 0)
|
|
{
|
|
plotter->Fill1D("PC_Z_Projection", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
plotter->Fill2D("Z_Proj_VsDelTime", 600, -300, 300, 200, -2000, 2000, anodeIntersection.Z(), anodeT - cathodeT, "hPCzQQQ");
|
|
plotter->Fill2D("IntPhi_vs_QQQphi", 100, -200, 200, 80, -200, 200, anodeIntersection.Phi() * 180. / TMath::Pi(), hitPos.Phi() * 180. / TMath::Pi(), "hPCQQQ");
|
|
plotter->Fill2D("Inttheta_vs_QQQtheta", 90, 0, 180, 20, 0, 45, anodeIntersection.Theta() * 180. / TMath::Pi(), hitPos.Theta() * 180. / TMath::Pi(), "hPCQQQ");
|
|
plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut), 90, 0, 180, 20, 0, 45, anodeIntersection.Theta() * 180. / TMath::Pi(), hitPos.Theta() * 180. / TMath::Pi(), "hPCQQQ");
|
|
plotter->Fill2D("IntPhi_vs_QQQphi_TC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 100, -200, 200, 80, -200, 200, anodeIntersection.Phi() * 180. / TMath::Pi(), hitPos.Phi() * 180. / TMath::Pi(), "hPCQQQ");
|
|
}
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() >= 2)
|
|
plotter->Fill1D("PC_Z_Projection_TC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() == 1)
|
|
{
|
|
plotter->Fill1D("PC_Z_proj_1C", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
plotter->Fill2D("IntersectionPhi_vs_AnodeZ_1C", 400, -200, 200, 600, -300, 300, anodeIntersection.Phi() * 180. / TMath::Pi(), anodeIntersection.Z(), "hPCzQQQ");
|
|
}
|
|
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() == 2)
|
|
{
|
|
plotter->Fill1D("PC_Z_proj_2C", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
plotter->Fill2D("IntersectionPhi_vs_AnodeZ_2C", 400, -200, 200, 600, -300, 300, anodeIntersection.Phi() * 180. / TMath::Pi(), anodeIntersection.Z(), "hGMPC");
|
|
}
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() > 2)
|
|
{
|
|
plotter->Fill1D("PC_Z_proj_nC", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
plotter->Fill2D("IntersectionPhi_vs_AnodeZ_nC", 400, -200, 200, 600, -300, 300, anodeIntersection.Phi() * 180. / TMath::Pi(), anodeIntersection.Z(), "hGMPC");
|
|
}
|
|
if (anodeHits.size() > 0 && cathodeHits.size() > 0)
|
|
plotter->Fill2D("AHits_vs_CHits", 12, 0, 11, 6, 0, 5, anodeHits.size(), cathodeHits.size(), "hRawPC");
|
|
|
|
// make another plot with nearest neighbour constraint
|
|
bool hasNeighbourAnodes = false;
|
|
bool hasNeighbourCathodes = false;
|
|
|
|
// 1. Check Anodes for neighbours (including wrap-around 0-23)
|
|
for (size_t i = 0; i < anodeHits.size(); i++)
|
|
{
|
|
for (size_t j = i + 1; j < anodeHits.size(); j++)
|
|
{
|
|
int diff = std::abs(anodeHits[i].first - anodeHits[j].first);
|
|
if (diff == 1 || diff == 23)
|
|
{ // 23 handles the cylindrical wrap
|
|
hasNeighbourAnodes = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hasNeighbourAnodes)
|
|
break;
|
|
}
|
|
|
|
// 2. Check Cathodes for neighbours (including wrap-around 0-23)
|
|
for (size_t i = 0; i < cathodeHits.size(); i++)
|
|
{
|
|
for (size_t j = i + 1; j < cathodeHits.size(); j++)
|
|
{
|
|
int diff = std::abs(cathodeHits[i].first - cathodeHits[j].first);
|
|
if (diff == 1 || diff == 23)
|
|
{
|
|
hasNeighbourCathodes = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hasNeighbourCathodes)
|
|
break;
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// FILL PLOTS
|
|
// ---------------------------------------------------------
|
|
if (anodeHits.size() > 0 && cathodeHits.size() > 0)
|
|
{
|
|
plotter->Fill2D("AHits_vs_CHits_NA" + std::to_string(hasNeighbourAnodes), 12, 0, 11, 6, 0, 5, anodeHits.size(), cathodeHits.size(), "hRawPC");
|
|
plotter->Fill2D("AHits_vs_CHits_NC" + std::to_string(hasNeighbourCathodes), 12, 0, 11, 6, 0, 5, anodeHits.size(), cathodeHits.size(), "hRawPC");
|
|
|
|
// Constraint Plot: Only fill if BOTH planes have adjacent hits
|
|
// This effectively removes events with only isolated single-wire hits (noise)
|
|
if (hasNeighbourAnodes && hasNeighbourCathodes)
|
|
{
|
|
plotter->Fill2D("AHits_vs_CHits_NN", 12, 0, 11, 6, 0, 5, anodeHits.size(), cathodeHits.size(), "hRawPC");
|
|
}
|
|
}
|
|
|
|
if (HitNonZero && anodeIntersection.Z() != 0)
|
|
{
|
|
pw_contr.CalTrack2(hitPos, anodeIntersection);
|
|
plotter->Fill1D("VertexRecon", 600, -300, 300, pw_contr.GetZ0());
|
|
plotter->Fill1D("VertexRecon_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -300, 300, pw_contr.GetZ0());
|
|
|
|
if (cathodeHits.size() == 2)
|
|
plotter->Fill1D("VertexRecon_2c_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -300, 300, pw_contr.GetZ0());
|
|
}
|
|
|
|
for (int i = 0; i < qqq.multi; i++)
|
|
{
|
|
if (PCQQQTimeCut)
|
|
{
|
|
plotter->Fill2D("PC_XY_Projection_QQQ_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, anodeIntersection.X(), anodeIntersection.Y(), "hPCQQQ");
|
|
}
|
|
plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, anodeIntersection.X(), anodeIntersection.Y(), "hPCQQQ");
|
|
|
|
for (int j = i + 1; j < qqq.multi; j++)
|
|
{
|
|
if (qqq.id[i] == qqq.id[j])
|
|
{
|
|
int chWedge = -1;
|
|
int chRing = -1;
|
|
double eWedge = 0.0;
|
|
double eWedgeMeV = 0.0;
|
|
double eRing = 0.0;
|
|
double eRingMeV = 0.0;
|
|
double tRing = 0.0;
|
|
int qqqID = -1;
|
|
if (qqq.ch[i] < 16 && qqq.ch[j] >= 16 && qqqGainValid[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16])
|
|
{
|
|
chWedge = qqq.ch[i];
|
|
eWedge = qqq.e[i] * qqqGain[qqq.id[i]][qqq.ch[i]][qqq.ch[j] - 16];
|
|
chRing = qqq.ch[j] - 16;
|
|
eRing = qqq.e[j];
|
|
tRing = static_cast<double>(qqq.t[j]);
|
|
qqqID = qqq.id[i];
|
|
}
|
|
else if (qqq.ch[j] < 16 && 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];
|
|
chRing = qqq.ch[i] - 16;
|
|
tRing = static_cast<double>(qqq.t[i]);
|
|
eRing = qqq.e[i];
|
|
qqqID = qqq.id[i];
|
|
}
|
|
else
|
|
continue;
|
|
|
|
if (qqqCalibValid[qqq.id[i]][chRing][chWedge])
|
|
{
|
|
eWedgeMeV = eWedge * qqqCalib[qqq.id[i]][chRing][chWedge] / 1000;
|
|
eRingMeV = eRing * qqqCalib[qqq.id[i]][chRing][chWedge] / 1000;
|
|
}
|
|
else
|
|
continue;
|
|
|
|
// if (anodeIntersection.Z() != 0)
|
|
{
|
|
plotter->Fill2D("PC_Z_vs_QQQRing", 600, -300, 300, 16, 0, 16, anodeIntersection.Z(), chRing, "hPCzQQQ");
|
|
}
|
|
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() == 2)
|
|
{
|
|
plotter->Fill2D("PC_Z_vs_QQQRing_2C", 600, -300, 300, 16, 0, 16, anodeIntersection.Z(), chRing, "hPCzQQQ");
|
|
plotter->Fill2D("PC_Z_vs_QQQRing_2C" + std::to_string(qqq.id[i]), 600, -300, 300, 16, 0, 16, anodeIntersection.Z(), chRing, "hPCzQQQ");
|
|
plotter->Fill2D("PC_Z_vs_QQQWedge_2C", 600, -300, 300, 16, 0, 16, anodeIntersection.Z(), chWedge, "hPCzQQQ");
|
|
}
|
|
plotter->Fill2D("Vertex_V_QQQRingTC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -300, 300, 16, 0, 16, pw_contr.GetZ0(), chRing, "hPCQQQ");
|
|
double phi = TMath::ATan2(anodeIntersection.Y(), anodeIntersection.X()) * 180. / TMath::Pi();
|
|
plotter->Fill2D("PolarAngle_Vs_QQQWedge" + std::to_string(qqqID), 360, -360, 360, 16, 0, 16, phi, chWedge, "hPCQQQ");
|
|
// plotter->Fill2D("EdE_PC_vs_QQQ_timegate_ls1000"+std::to_string())
|
|
|
|
plotter->Fill2D("PC_Z_vs_QQQRing_Det" + std::to_string(qqqID), 600, -300, 300, 16, 0, 16, anodeIntersection.Z(), chRing, "hPCQQQ");
|
|
//double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5);
|
|
//double rho = 50. + 40. / 16. * (chRing + 0.5);
|
|
|
|
for (int k = 0; k < pc.multi; k++)
|
|
{
|
|
if(pc.index[k] >= 24)
|
|
continue;
|
|
|
|
double sinTheta = TMath::Sin(hitPos.Theta());
|
|
|
|
plotter->Fill2D("CalibratedQQQE_RvsPCE_TC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k]*sinTheta, "hPCQQQ");
|
|
plotter->Fill2D("CalibratedQQQE_WvsPCE_TC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k]*sinTheta, "hPCQQQ");
|
|
plotter->Fill2D("PCQQQ_dTimevsdPhi", 200, -2000, 2000, 80, -200, 200, tRing - static_cast<double>(pc.t[k]), (hitPos.Phi()-anodeIntersection.Phi()) * 180. / TMath::Pi(), "hTiming");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < sx3.multi; i++)
|
|
{
|
|
// plotting sx3 strip hits vs anode phi
|
|
if (sx3.ch[i] < 8)
|
|
plotter->Fill2D("AnodePhi_vs_SX3Strip", 100, -200, 200, 8 * 24, 0, 8 * 24, anodeIntersection.Phi() * 180. / TMath::Pi(), sx3.id[i] * 8 + sx3.ch[i]);
|
|
}
|
|
|
|
if (anodeIntersection.Z() != 0 && cathodeHits.size() == 3)
|
|
{
|
|
plotter->Fill1D("PC_Z_proj_3C", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ");
|
|
}
|
|
|
|
plotter->Fill2D("AnodeMaxE_Vs_Cathode_Sum_Energy", 2000, 0, 30000, 2000, 0, 30000, aEMax, cESum, "hGMPC");
|
|
plotter->Fill1D("Correlated_Cathode_MaxAnode", 6, 0, 5, corrcatMax.size(), "hGMPC");
|
|
plotter->Fill2D("Correlated_Cathode_VS_MaxAnodeEnergy", 6, 0, 5, 2000, 0, 30000, corrcatMax.size(), aEMax, "hGMPC");
|
|
plotter->Fill1D("AnodeHits", 12, 0, 11, anodeHits.size(), "hGMPC");
|
|
plotter->Fill2D("AnodeMaxE_vs_AnodeHits", 12, 0, 11, 2000, 0, 30000, anodeHits.size(), aEMax, "hGMPC");
|
|
|
|
if (anodeHits.size() < 1)
|
|
{
|
|
plotter->Fill1D("NoAnodeHits_CathodeHits", 6, 0, 5, cathodeHits.size(), "hGMPC");
|
|
}
|
|
|
|
return kTRUE;
|
|
}
|
|
|
|
void DataDump::Terminate()
|
|
{
|
|
plotter->FlushToDisk();
|
|
}
|