From 103ddb39580d4a40c924b722460430c351899389 Mon Sep 17 00:00:00 2001 From: Sudarsan B Date: Tue, 24 Mar 2026 15:55:40 -0400 Subject: [PATCH] new sx3 gainmatch for 17F data's first part --- Analyzer.C | 29 +- Armory/ANASEN_model.C | 2 +- Armory/ClassPW.h | 99 +- Armory/ClassPW.h.Questionable.Feb2026 | 491 ++++++ Armory/ClassPW.h.modified | 489 ++++++ Armory/SX3Geom.h | 1 + DataDump.C | 639 ++++++++ DataDump.h | 132 ++ MakeVertex.C | 2045 ++++++++++++++----------- MakeVertex.h | 194 +-- MakeVertexSX3.C | 958 ++++++++++++ MakeVertexSX3.C.backup | 1114 ++++++++++++++ MakeVertexSX3.h | 132 ++ ProcessRun.sh | 12 +- TrackRecon.C.backup | 742 +++++++++ feeder.py | 24 + rootlogon.C | 3 + run_19_22.sh | 33 + run_sx3.sh | 30 + sx3cal/17F/backgains.dat | 23 + sx3cal/17F/backgains.dat.unity | 96 ++ sx3cal/17F/frontgains.dat | 12 + sx3cal/17F/frontgains.dat.unity | 24 + sx3cal/17F/rightgains.dat | 16 + sx3cal/17F/rightgains.dat.unity | 24 + sx3cal/26Al/backgains.dat | 28 + sx3cal/26Al/backgains.dat.unity | 96 ++ sx3cal/26Al/frontgains.dat | 16 + sx3cal/26Al/frontgains.dat.unity | 20 + sx3cal/26Al/rightgains.dat | 16 + sx3cal/26Al/rightgains.dat.unity | 24 + sx3cal/EXFit.C | 8 +- sx3cal/LRFit.C | 8 +- sx3cal/backgains1.dat | 3 + sx3cal/backgains9.dat | 6 + sx3cal/frontgains1.dat | 3 + sx3cal/frontgains9.dat | 3 + sx3cal/rightgains1.dat | 3 + sx3cal/rightgains13.dat | 3 + sx3cal/rightgains9.dat | 3 + 40 files changed, 6528 insertions(+), 1076 deletions(-) create mode 100644 Armory/ClassPW.h.Questionable.Feb2026 create mode 100644 Armory/ClassPW.h.modified create mode 100644 DataDump.C create mode 100644 DataDump.h create mode 100644 MakeVertexSX3.C create mode 100644 MakeVertexSX3.C.backup create mode 100644 MakeVertexSX3.h create mode 100644 TrackRecon.C.backup create mode 100644 feeder.py create mode 100644 rootlogon.C create mode 100644 run_19_22.sh create mode 100644 run_sx3.sh create mode 100644 sx3cal/17F/backgains.dat create mode 100644 sx3cal/17F/backgains.dat.unity create mode 100644 sx3cal/17F/frontgains.dat create mode 100644 sx3cal/17F/frontgains.dat.unity create mode 100644 sx3cal/17F/rightgains.dat create mode 100644 sx3cal/17F/rightgains.dat.unity create mode 100644 sx3cal/26Al/backgains.dat create mode 100644 sx3cal/26Al/backgains.dat.unity create mode 100644 sx3cal/26Al/frontgains.dat create mode 100644 sx3cal/26Al/frontgains.dat.unity create mode 100644 sx3cal/26Al/rightgains.dat create mode 100644 sx3cal/26Al/rightgains.dat.unity create mode 100644 sx3cal/backgains1.dat create mode 100644 sx3cal/backgains9.dat create mode 100644 sx3cal/frontgains1.dat create mode 100644 sx3cal/frontgains9.dat create mode 100644 sx3cal/rightgains1.dat create mode 100644 sx3cal/rightgains13.dat create mode 100644 sx3cal/rightgains9.dat diff --git a/Analyzer.C b/Analyzer.C index 986006c..f9eed6e 100644 --- a/Analyzer.C +++ b/Analyzer.C @@ -856,22 +856,21 @@ Bool_t Analyzer::Process(Long64_t entry) // // hZProj->Draw(); // hanVScatsum->Draw("colz"); - // // TFile *outRoot = new TFile("Histograms.root", "RECREATE"); + TFile *outRoot = new TFile("Histograms.root", "RECREATE"); - // // if (!outRoot->IsOpen()) - // // { - // // std::cerr << "Error opening file for writing!" << std::endl; - // // return; - // // } + if (!outRoot->IsOpen()) + { + std::cerr << "Error opening file for writing!" << std::endl; + return; + } // // // Loop through histograms and write them to the ROOT file - // // for (int i = 0; i < 48; i++) - // // { - // // if (hPC_E[i] != nullptr) - // // { - // // hPC_E[i]->Write(); // Write histogram to file - // // } - // // } - - // // outRoot->Close(); + for (int i = 0; i < 48; i++) + { + if (hPC_E[i] != nullptr) + { + hPC_E[i]->Write(); // Write histogram to file + } + } + outRoot->Close(); } diff --git a/Armory/ANASEN_model.C b/Armory/ANASEN_model.C index 72bc262..e21d4c6 100644 --- a/Armory/ANASEN_model.C +++ b/Armory/ANASEN_model.C @@ -42,7 +42,7 @@ void ANASEN_model(int anodeID1 = -1, int anodeID2 = -1, int cathodeID1 = -1, int //--- making ANASEN const int nWire = 24; const int wireShift = 3; - const int zLen = 350; //mm + const int zLen = 300; //mm const int radiusA = 38; const int radiusC = 43; diff --git a/Armory/ClassPW.h b/Armory/ClassPW.h index 9cce5ae..535e19a 100755 --- a/Armory/ClassPW.h +++ b/Armory/ClassPW.h @@ -61,6 +61,9 @@ public: double GetTrackTheta() const { return trackVec.Theta(); } double GetTrackPhi() const { return trackVec.Phi(); } double GetZ0(); + + Coord Crossover[24][24][2]; + inline std::tuple, double, double, double> GetPseudoWire(const std::vector>& cluster, std::string type); @@ -115,7 +118,8 @@ private: const int nWire = 24; const int wireShift = 3; //const float zLen = 380; // mm - const float zLen = 348.6; // mm +// const float zLen = 348.6; // mm + const float zLen = 174.3*2; // mm const float radiusA = 37; const float radiusC = 43; @@ -149,35 +153,72 @@ inline void PW::ConstructGeo() std::pair p1; // anode std::pair q1; // cathode - // anode and cathode start at pos-Y axis and count in right-Hand - // anode wire shift is right-hand. - // cathode wire shift is left-hand. + double k = TMath::TwoPi()/24.; //48 solder thru holes, wires in every other one + double offset_a1 = -6*k-3*k; + double offset_c1 = -4*k -2*k - TMath::TwoPi()/48; //correct for a half-turn + std::cerr << "Here!" << std::endl; +#include "../scratch/testing.h" + double offset_a2 = offset_a1+wireShift*k; + double offset_c2 = offset_c1-wireShift*k; for (int i = 0; i < nWire; i++) { - // Anode rotate right-hand - p1.first.SetXYZ(radiusA * TMath::Cos(TMath::TwoPi() / nWire * (i) + TMath::PiOver2()), - radiusA * TMath::Sin(TMath::TwoPi() / nWire * (i) + TMath::PiOver2()), - zLen / 2); - p1.second.SetXYZ(radiusA * TMath::Cos(TMath::TwoPi() / nWire * (i + wireShift) + TMath::PiOver2()), - radiusA * TMath::Sin(TMath::TwoPi() / nWire * (i + wireShift) + TMath::PiOver2()), - -zLen / 2); - An.push_back(p1); + // Anode rotate right-hand coming in towards +z riding with the beam. In this frame, +x is to the right, and +y down + //updated Feb 2026, Sudarsan B. Photographs indicate that anode wires twist right handed, as one moves from -z to +z with the convention above + //wire indices increase leftward as one moves to +z (hence -k factor), but wires themselves twist rightward - as indicated by offset_a2 being more +ve w.r.t offset_a1 + //'First' is -z locus, 'second' is +z locus + p1.first.SetXYZ(radiusA * TMath::Cos(-k*i + offset_a1), + radiusA * TMath::Sin(-k*i + offset_a1), + -zLen / 2); + p1.second.SetXYZ(radiusA * TMath::Cos(-k*i + offset_a2), + radiusA * TMath::Sin(-k*i + offset_a2), + +zLen / 2); - // Cathod rotate left-hand with the 3 wire offset accounted for (+1 from the calculated offset from the PC coincidence spectrum) - q1.first.SetXYZ(radiusC * TMath::Cos(TMath::TwoPi() / nWire * (i + wireShift + 1) + TMath::PiOver2()), - radiusC * TMath::Sin(TMath::TwoPi() / nWire * (i + wireShift + 1) + TMath::PiOver2()), - zLen / 2); - q1.second.SetXYZ(radiusC * TMath::Cos(TMath::TwoPi() / nWire * (i + 1) + TMath::PiOver2()), - radiusC * TMath::Sin(TMath::TwoPi() / nWire * (i + 1) + TMath::PiOver2()), - -zLen / 2); + // Cathodes twist left-hand as indicated by offset_c2 being more negative than offset_c1, under the same system, while wires increase rightward (hence +k factor) + q1.first.SetXYZ(radiusC * TMath::Cos(k*i + offset_c1), + radiusC * TMath::Sin(k*i + offset_c1), + -zLen / 2); + q1.second.SetXYZ(radiusC * TMath::Cos(k*i + offset_c2), + radiusC * TMath::Sin(k*i + offset_c2), + zLen / 2); + An.push_back(p1); Ca.push_back(q1); } - // correcting for the fact that the order of the cathode wires is reversed - std::reverse(Ca.begin(), Ca.end()); - // adjusting for the 3 wire offset, the rbegin and rend are used as the rotation of the wires is done in the opposite direction i.e. 1,2,3 -> 3,1,2 - // NOT NECESSARY ANY MORE, HAS BEEN IMCORPORATED INTO THE WIREOFFSET IN THE BEGINNING - // std::rotate(Ca.rbegin(), Ca.rbegin() + 4, Ca.rend()); + + + // Calculate Crossover Geometry ONCE + TVector3 a, c, diff; + double a2, ac, c2, adiff, cdiff, denom, alpha; + + for (size_t i = 0; i < An.size(); i++) + { + //a = An[i].first - An[i].second; + a = An[i].second - An[i].first; + for (size_t j = 0; j < Ca.size(); j++) + { + c = Ca[j].second- Ca[j].first; + diff = An[i].second - Ca[j].second; + 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 = An[i].second.X() + alpha * a.X(); + Crossover[i][j][0].y = An[i].second.Y() + alpha * a.Y(); + Crossover[i][j][0].z = An[i].second.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; + } + } + dAngle = wireShift * TMath::TwoPi() / nWire; anodeLength = TMath::Sqrt(zLen * zLen + TMath::Power(2 * radiusA * TMath::Sin(dAngle / 2), 2)); @@ -276,8 +317,8 @@ PW::GetPseudoWire(const std::vector>& cluster, std avgvec.second = avgvec.second*(1.0/sumEnergy); double phi1 = avgvec.first.Phi(); double phi2 = avgvec.second.Phi(); - avgvec.first.SetXYZ(radiusA*TMath::Cos(phi1), radiusA*TMath::Sin(phi1), zLen/2); - avgvec.second.SetXYZ(radiusA*TMath::Cos(phi2), radiusA*TMath::Sin(phi2), -zLen/2); + avgvec.first.SetXYZ(radiusA*TMath::Cos(phi1), radiusA*TMath::Sin(phi1), -zLen/2); + avgvec.second.SetXYZ(radiusA*TMath::Cos(phi2), radiusA*TMath::Sin(phi2), zLen/2); /*if(cluster.size()>1) { std::cout << "\t\t avg1(r,phi,z):" << avgvec.first.Perp() << " " << avgvec.first.Phi()*180/M_PI << " " << avgvec.first.Z() << std::endl; std::cout << "\t\t avg2(r,phi,z):" << avgvec.second.Perp() << " " << avgvec.second.Phi()*180/M_PI << " " << avgvec.second.Z() << std::endl; @@ -296,8 +337,8 @@ PW::GetPseudoWire(const std::vector>& cluster, std avgvec.second = avgvec.second*(1.0/sumEnergy); double phi1 = avgvec.first.Phi(); double phi2 = avgvec.second.Phi(); - avgvec.first.SetXYZ(radiusC*TMath::Cos(phi1), radiusC*TMath::Sin(phi1), zLen/2); - avgvec.second.SetXYZ(radiusC*TMath::Cos(phi2), radiusC*TMath::Sin(phi2), -zLen/2); + avgvec.first.SetXYZ(radiusC*TMath::Cos(phi1), radiusC*TMath::Sin(phi1), -zLen/2); + avgvec.second.SetXYZ(radiusC*TMath::Cos(phi2), radiusC*TMath::Sin(phi2), zLen/2); } return std::tuple(avgvec, sumEnergy, maxEnergy, tsMaxEnergy); } @@ -317,7 +358,7 @@ inline std::tuple PW: if(apSumE && cpSumE) { a = apwire.first - apwire.second; c = cpwire.first - cpwire.second; - diff = apwire.first - cpwire.first; + diff = apwire.first- cpwire.first; a2 = a.Dot(a); c2 = c.Dot(c); ac = a.Dot(c); diff --git a/Armory/ClassPW.h.Questionable.Feb2026 b/Armory/ClassPW.h.Questionable.Feb2026 new file mode 100644 index 0000000..ebe083a --- /dev/null +++ b/Armory/ClassPW.h.Questionable.Feb2026 @@ -0,0 +1,491 @@ +#ifndef ClassPW_h +#define ClassPW_h + +#include +#include +#include +#include +#include + +struct PWHitInfo +{ + std::pair nearestWire; // anode, cathode + std::pair nearestDist; // anode, cathode + + std::pair nextNearestWire; // anode, cathode + std::pair nextNearestDist; // anode, cathode + + void Clear() + { + nearestWire.first = -1; + nearestWire.second = -1; + nearestDist.first = 999999999; + nearestDist.second = 999999999; + nextNearestWire.first = -1; + nextNearestWire.second = -1; + nextNearestDist.first = 999999999; + nextNearestDist.second = 999999999; + } +}; + +struct Coord +{ + float x, y, z; + Coord() : x(0), y(0), z(0) {} + Coord(const TVector3 &vec) + { + x = vec.X(); // TVector3's X() returns the x-coordinate + y = vec.Y(); // TVector3's Y() returns the y-coordinate + z = vec.Z(); // TVector3's Z() returns the z-coordinate + } +}; + +//! ######################################################## +class PW +{ // proportional wire +public: + PW() { ClearHitInfo(); }; + ~PW() {}; + + PWHitInfo GetHitInfo() const { return hitInfo; } + std::pair GetNearestID() const { return hitInfo.nearestWire; } + std::pair GetNearestDistance() const { return hitInfo.nearestDist; } + std::pair Get2ndNearestID() const { return hitInfo.nextNearestWire; } + std::pair Get2ndNearestDistance() const { return hitInfo.nextNearestDist; } + + std::vector> An; // the anode wire position vector in space + std::vector> Ca; // the cathode wire position vector in space + + TVector3 GetTrackPos() const { return trackPos; } + TVector3 GetTrackVec() const { return trackVec; } + double GetTrackTheta() const { return trackVec.Theta(); } + double GetTrackPhi() const { return trackVec.Phi(); } + double GetZ0(); + + inline std::tuple, double, double, double> GetPseudoWire(const std::vector>& cluster, std::string type); + + inline std::tuple + FindCrossoverProperties(const std::vector>& a_cluster, const std::vector>& c_cluster); + + inline std::vector>> + Make_Clusters(std::unordered_map> wireEvents); + + int GetNumWire() const { return nWire; } + double GetDeltaAngle() const { return dAngle; } + double GetAnodeLength() const { return anodeLength; } + double GetCathodeLength() const { return cathodeLength; } + TVector3 GetAnodeDn(short id) const { return An[id].first; } + TVector3 GetAnodeUp(short id) const { return An[id].second; } + TVector3 GetCathodeDn(short id) const { return Ca[id].first; } + TVector3 GetCathodeUp(short id) const { return Ca[id].second; } + + TVector3 GetAnodneMid(short id) const { return (An[id].first + An[id].second) * 0.5; } + double GetAnodeTheta(short id) const { return (An[id].first - An[id].second).Theta(); } + double GetAnodePhi(short id) const { return (An[id].first - An[id].second).Phi(); } + + TVector3 GetCathodneMid(short id) const { return (Ca[id].first + Ca[id].second) * 0.5; } + double GetCathodeTheta(short id) const { return (Ca[id].first - Ca[id].second).Theta(); } + double GetCathodePhi(short id) const { return (Ca[id].first - Ca[id].second).Phi(); } + + void ClearHitInfo(); + void ConstructGeo(); + void FindWireID(TVector3 pos, TVector3 direction, bool verbose = false); + void CalTrack(TVector3 sx3Pos, int anodeID, int cathodeID, bool verbose = false); + void CalTrack2(TVector3 sx3Pos, TVector3 anodeInt, bool verbose = false); + + void Print() + { + printf(" The nearest | Anode: %2d(%5.2f) Cathode: %2d(%5.2f)\n", hitInfo.nearestWire.first, + hitInfo.nearestDist.first, + hitInfo.nearestWire.second, + hitInfo.nearestDist.second); + + printf(" The 2nd nearest | Anode: %2d(%5.2f) Cathode: %2d(%5.2f)\n", hitInfo.nextNearestWire.first, + hitInfo.nextNearestDist.first, + hitInfo.nextNearestWire.second, + hitInfo.nextNearestDist.second); + } + +private: + PWHitInfo hitInfo; + + TVector3 trackPos; + TVector3 trackVec; + + const int nWire = 24; + const int wireShift = 3; + //const float zLen = 380; // mm + const float zLen = 348.6; // mm + const float radiusA = 37; + const float radiusC = 43; + + double dAngle; + double anodeLength; + double cathodeLength; + + // std::vector> An; // the anode wire position vector in space + // std::vector> Ca; // the cathode wire position vector in space + + double Distance(TVector3 a1, TVector3 a2, TVector3 b1, TVector3 b2) + { + TVector3 na = a1 - a2; + TVector3 nb = b1 - b2; + TVector3 nd = (na.Cross(nb)).Unit(); + return TMath::Abs(nd.Dot(a1 - b2)); + } +}; + +inline void PW::ClearHitInfo() +{ + hitInfo.Clear(); +} + +inline void PW::ConstructGeo() +{ + + An.clear(); + Ca.clear(); + + std::pair p1; // anode + std::pair q1; // cathode + + // anode and cathode start at pos-Y axis and count in right-Hand + // anode wire shift is right-hand. + // cathode wire shift is left-hand. + + for (int i = 0; i < nWire; i++) + { + // Anode rotate right-hand + //updated Feb 2026, Sudarsan B + p1.first.SetXYZ(radiusA * TMath::Cos(TMath::TwoPi() / nWire * (i) + TMath::PiOver2()), + radiusA * TMath::Sin(TMath::TwoPi() / nWire * (i) + TMath::PiOver2()), + zLen / 2); + p1.second.SetXYZ(radiusA * TMath::Cos(TMath::TwoPi() / nWire * (i + wireShift) + TMath::PiOver2()), + radiusA * TMath::Sin(TMath::TwoPi() / nWire * (i + wireShift) + TMath::PiOver2()), + -zLen / 2); + An.push_back(p1); + + // Cathod rotate left-hand with the 3 wire offset accounted for (+1 from the calculated offset from the PC coincidence spectrum) + q1.first.SetXYZ(radiusC * TMath::Cos(TMath::TwoPi() / nWire * (i + wireShift + 1) + TMath::PiOver2()), + radiusC * TMath::Sin(TMath::TwoPi() / nWire * (i + wireShift + 1) + TMath::PiOver2()), + zLen / 2); + q1.second.SetXYZ(radiusC * TMath::Cos(TMath::TwoPi() / nWire * (i + 1) + TMath::PiOver2()), + radiusC * TMath::Sin(TMath::TwoPi() / nWire * (i + 1) + TMath::PiOver2()), + -zLen / 2); + Ca.push_back(q1); + } + // correcting for the fact that the order of the cathode wires is reversed + std::reverse(Ca.begin(), Ca.end()); + // adjusting for the 3 wire offset, the rbegin and rend are used as the rotation of the wires is done in the opposite direction i.e. 1,2,3 -> 3,1,2 + // NOT NECESSARY ANY MORE, HAS BEEN IMCORPORATED INTO THE WIREOFFSET IN THE BEGINNING + // std::rotate(Ca.rbegin(), Ca.rbegin() + 4, Ca.rend()); + + dAngle = wireShift * TMath::TwoPi() / nWire; + anodeLength = TMath::Sqrt(zLen * zLen + TMath::Power(2 * radiusA * TMath::Sin(dAngle / 2), 2)); + cathodeLength = TMath::Sqrt(zLen * zLen + TMath::Power(2 * radiusC * TMath::Sin(dAngle / 2), 2)); //chord length subtending an angle alpha is 2rsin(alpha/2) +} + +inline std::vector>> +PW::Make_Clusters(std::unordered_map> wireEvents) { + std::vector>> wireClusters; + std::vector> wireCluster; + //TODO: Write a macro once, call it twice + int wirecount=0; + while(wirecount < 24) { + if(wireEvents.find(wirecount)==wireEvents.end()) { + wirecount++; + continue; + } + wireCluster.clear(); + int ctr2=wirecount; + do { + wireCluster.emplace_back(wireEvents[ctr2]); + ctr2+=1; + if(ctr2==24 || ctr2-wirecount == 7) break; //loose logic, needs to be looked at. + } while(wireEvents.find(ctr2)!=wireEvents.end()); + wireClusters.push_back(std::move(wireCluster)); + wirecount = ctr2; //we already dealt with wires until the last value of ctr2 + } + + if(wireClusters.size() > 1) { //Deal with wraparound if required + auto first_cluster = wireClusters.front(); //front and back provide references to the elements themselves. less copy, can modify etc + auto last_cluster = wireClusters.back(); + if(std::get<0>(last_cluster.back())==23 && std::get<0>(first_cluster.front())==0) { + last_cluster.insert(last_cluster.end(),first_cluster.begin(),first_cluster.end()); + } + wireClusters.erase(wireClusters.begin()); //canonically, erase() needs an iterator, hence begin() not front() + //TODO: Can also deal with 'gaps' of missing wires similarly. end of one segment and beginning of another segment will be separated by missing wire --> combine the two + //TODO: Also needs some development regarding the time-correlation. Don't put wires in the same cluster if they aren't time coincident + } + return wireClusters; + + /*if(aClusters.size()>1 || cClusters.size() > 1) { + std::cout << " ============== " << std::endl; + } + if(aClusters.size()>1 && cClusters.size() >=1) { + std::cout << aClusters.size() << " new anode clusters ----> " << std::endl; + int cc=1; + for(auto ac : aClusters) { + std::cout << " Cluster " << cc << std::endl; + double first_ts = std::get<2>(ac.at(0)); + for(auto item : ac) { + std::cout << " \t" << std::get<0>(item) << " " << std::get<1>(item) << " " << std::get<2>(item)-first_ts << std::endl; + } + std::cout << " ------" << std::endl; + cc++; + } + } + + if(cClusters.size()>=1 ) { + std::cout << cClusters.size() << " new cathode clusters ----> " << std::endl; + int cc=1; + for(auto ac : cClusters) { + std::cout << " Cluster " << cc << std::endl; + double first_ts = std::get<2>(ac.at(0)); + for(auto item : ac) { + std::cout << " \t" << std::get<0>(item) << " " << std::get<1>(item) << " " << std::get<2>(item)-first_ts << std::endl; + } + std::cout << " ------" << std::endl; + cc++; + } + } */ +} + +inline std::tuple, double, double, double> +PW::GetPseudoWire(const std::vector>& cluster, std::string type) { + std::pair avgvec = std::pair(TVector3(0,0,0),TVector3(0,0,0)); + double sumEnergy = 0; + double maxEnergy = 0; + double tsMaxEnergy = 0; + if(type=="ANODE") { + //if(cluster.size()>1) std::cout << " -------anodes" << std::endl; + for( auto wire : cluster) { + avgvec.first += std::get<1>(wire)*TVector3(An.at(std::get<0>(wire)).first.X(), An.at(std::get<0>(wire)).first.Y(), 0) ; + avgvec.second += std::get<1>(wire)*TVector3(An.at(std::get<0>(wire)).second.X(), An.at(std::get<0>(wire)).second.Y(), 0); + sumEnergy += std::get<1>(wire); + if(std::get<1>(wire) > maxEnergy) { + maxEnergy = std::get<1>(wire); + tsMaxEnergy = std::get<2>(wire); + } + /*if(cluster.size()>1) { + std::cout << "\t\t ch:" << std::get<0>(wire) << " " << std::get<1>(wire) << " " << std::get<2>(wire) << std::endl; + std::cout << "\t\t w1(r,phi,z):" << An.at(std::get<0>(wire)).first.Perp() << " " << An.at(std::get<0>(wire)).first.Phi()*180/M_PI << " " << An.at(std::get<0>(wire)).first.Z() << std::endl; + std::cout << "\t\t w2(r,phi,z):" << An.at(std::get<0>(wire)).second.Perp() << " " << An.at(std::get<0>(wire)).second.Phi()*180/M_PI << " " << An.at(std::get<0>(wire)).second.Z() << std::endl; + }*/ + } + avgvec.first = avgvec.first*(1.0/sumEnergy); + avgvec.second = avgvec.second*(1.0/sumEnergy); + double phi1 = avgvec.first.Phi(); + double phi2 = avgvec.second.Phi(); + avgvec.first.SetXYZ(radiusA*TMath::Cos(phi1), radiusA*TMath::Sin(phi1), zLen/2); + avgvec.second.SetXYZ(radiusA*TMath::Cos(phi2), radiusA*TMath::Sin(phi2), -zLen/2); + /*if(cluster.size()>1) { + std::cout << "\t\t avg1(r,phi,z):" << avgvec.first.Perp() << " " << avgvec.first.Phi()*180/M_PI << " " << avgvec.first.Z() << std::endl; + std::cout << "\t\t avg2(r,phi,z):" << avgvec.second.Perp() << " " << avgvec.second.Phi()*180/M_PI << " " << avgvec.second.Z() << std::endl; + }*/ + } else if(type =="CATHODE") { + for( auto wire : cluster) { + avgvec.first += std::get<1>(wire)*TVector3(Ca.at(std::get<0>(wire)).first.X(), Ca.at(std::get<0>(wire)).first.Y(), 0) ; + avgvec.second += std::get<1>(wire)*TVector3(Ca.at(std::get<0>(wire)).second.X(), Ca.at(std::get<0>(wire)).second.Y(), 0); + sumEnergy += std::get<1>(wire); + if(std::get<1>(wire) > maxEnergy) { + maxEnergy = std::get<1>(wire); + tsMaxEnergy = std::get<2>(wire); + } + } + avgvec.first = avgvec.first*(1.0/sumEnergy); + avgvec.second = avgvec.second*(1.0/sumEnergy); + double phi1 = avgvec.first.Phi(); + double phi2 = avgvec.second.Phi(); + avgvec.first.SetXYZ(radiusC*TMath::Cos(phi1), radiusC*TMath::Sin(phi1), zLen/2); + avgvec.second.SetXYZ(radiusC*TMath::Cos(phi2), radiusC*TMath::Sin(phi2), -zLen/2); + } + return std::tuple(avgvec, sumEnergy, maxEnergy, tsMaxEnergy); +} + +inline std::tuple PW::FindCrossoverProperties(const std::vector>& a_cluster, + const std::vector>& c_cluster) { + //std::pair apwire = GetPseudoWire(a_cluster,"ANODE",anodeSumE); + //std::pair cpwire = GetPseudoWire(c_cluster,"CATHODE",cathodeSumE); + auto [apwire, apSumE, apMaxE, apTSMaxE] = GetPseudoWire(a_cluster,"ANODE"); + auto [cpwire, cpSumE, cpMaxE, cpTSMaxE] = GetPseudoWire(c_cluster,"CATHODE"); + + TVector3 crossover; + crossover.Clear(); + TVector3 a, c, diff; + double a2, ac, c2, adiff, cdiff, denom, alpha=0; + + if(apSumE && cpSumE) { + a = apwire.first - apwire.second; + c = cpwire.first - cpwire.second; + diff = apwire.first - cpwire.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 = apwire.first + alpha*a; + if(crossover.z() < -190 || crossover.Z() > 190 ) { + alpha = 9999999; + apSumE=-1; cpSumE=-1; + apMaxE=-1; cpMaxE=-1; + apTSMaxE=-1; cpTSMaxE=-1; + } + } + //std::cout << apSumE << " " << cpSumE << " " << " " << crossover.Perp() << std::endl; + return std::tuple(crossover,alpha,apSumE,cpSumE,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); +} + +inline void PW::FindWireID(TVector3 pos, TVector3 direction, bool verbose) +{ + + hitInfo.Clear(); + double phi = direction.Phi(); + + for (int i = 0; i < nWire; i++) + { + + double disA = 99999999; + double phiS = An[i].first.Phi() - TMath::PiOver4(); + double phiL = An[i].second.Phi() + TMath::PiOver4(); + // printf("A%2d: %f %f | %f\n", i, phiS * TMath::RadToDeg(), phiL * TMath::RadToDeg(), phi * TMath::RadToDeg()); + if (phi > 0 && phiS > phiL) + phiL = phiL + TMath::TwoPi(); + if (phi < 0 && phiS > phiL) + phiS = phiS - TMath::TwoPi(); + + if (phiS < phi && phi < phiL) + { + disA = Distance(pos, pos + direction, An[i].first, An[i].second); + if (disA < hitInfo.nearestDist.first) + { + hitInfo.nearestDist.first = disA; + hitInfo.nearestWire.first = i; + } + } + + double disC = 99999999; + phiS = Ca[i].second.Phi() - TMath::PiOver4(); + phiL = Ca[i].first.Phi() + TMath::PiOver4(); + // printf("C%2d: %f %f\n", i, phiS * TMath::RadToDeg(), phiL * TMath::RadToDeg()); + if (phi > 0 && phiS > phiL) + phiL = phiL + TMath::TwoPi(); + if (phi < 0 && phiS > phiL) + phiS = phiS - TMath::TwoPi(); + + if (phiS < phi && phi < phiL) + { + disC = Distance(pos, pos + direction, Ca[i].first, Ca[i].second); + if (disC < hitInfo.nearestDist.second) + { + hitInfo.nearestDist.second = disC; + hitInfo.nearestWire.second = i; + } + } + + if (verbose) + printf(" %2d | %8.2f, %8.2f\n", i, disA, disC); + } + + //==== find the 2nd nearest wire + short anode1 = hitInfo.nearestWire.first; + short aaa1 = anode1 - 1; + if (aaa1 < 0) + aaa1 += nWire; + short aaa2 = (anode1 + 1) % nWire; + + double haha1 = Distance(pos, pos + direction, An[aaa1].first, An[aaa1].second); + double haha2 = Distance(pos, pos + direction, An[aaa2].first, An[aaa2].second); + if (haha1 < haha2) + { + hitInfo.nextNearestWire.first = aaa1; + hitInfo.nextNearestDist.first = haha1; + } + else + { + hitInfo.nextNearestWire.first = aaa2; + hitInfo.nextNearestDist.first = haha2; + } + + short cathode1 = hitInfo.nearestWire.second; + short ccc1 = cathode1 - 1; + if (ccc1 < 0) + ccc1 += nWire; + short ccc2 = (cathode1 + 1) % nWire; + + haha1 = Distance(pos, pos + direction, Ca[ccc1].first, Ca[ccc1].second); + haha2 = Distance(pos, pos + direction, Ca[ccc2].first, Ca[ccc2].second); + if (haha1 < haha2) + { + hitInfo.nextNearestWire.second = ccc1; + hitInfo.nextNearestDist.second = haha1; + } + else + { + hitInfo.nextNearestWire.second = ccc2; + hitInfo.nextNearestDist.second = haha2; + } + + if (verbose) + Print(); +} + +inline void PW::CalTrack(TVector3 sx3Pos, int anodeID, int cathodeID, bool verbose) +{ + + trackPos = sx3Pos; + + TVector3 n1 = (An[anodeID].first - An[anodeID].second).Cross((sx3Pos - An[anodeID].second)).Unit(); + TVector3 n2 = (Ca[cathodeID].first - Ca[cathodeID].second).Cross((sx3Pos - Ca[cathodeID].second)).Unit(); + + // if the handiness of anode and cathode revered, it should be n2 cross n1 + trackVec = (n2.Cross(n1)).Unit(); + + if (verbose) + printf("Theta, Phi = %f, %f \n", trackVec.Theta() * TMath::RadToDeg(), trackVec.Phi() * TMath::RadToDeg()); +} + + +inline void PW::CalTrack2(TVector3 siPos, TVector3 anodeInt, bool verbose) +{ + + double mx, my; + double z; + mx = siPos.X() / (siPos.X() - anodeInt.X()); + my = siPos.Y() / (siPos.Y() - anodeInt.Y()); + z=siPos.Z() + mx * (anodeInt.Z() - siPos.Z()); + // if (mx == my) + { + trackVec=TVector3(0,0,z); + } + + if (verbose) + printf("X slope = %f and Y slope = %f \n", mx, my); +} + +/*inline TVector3 PW::CalTrack3(TVector3 siPos, TVector3 anodeInt, bool verbose) +{ + + TVector3 v = anodeInt-siPos; + double t_minimum = -1.0*(siPos.X()*v.X()+siPos.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + TVector3 vector_closest_to_z = siPos + t_minimum*v; + + return vector_closest_to_z; + if (verbose) + printf("X slope = %f and Y slope = %f \n", mx, my); +}*/ + +inline double PW::GetZ0() +{ + + double x = trackPos.X(); + double y = trackPos.Y(); + double rho = TMath::Sqrt(x * x + y * y); + double theta = trackVec.Theta(); + + return trackVec.Z(); +} + +#endif diff --git a/Armory/ClassPW.h.modified b/Armory/ClassPW.h.modified new file mode 100644 index 0000000..fa3d319 --- /dev/null +++ b/Armory/ClassPW.h.modified @@ -0,0 +1,489 @@ +#ifndef ClassPW_h +#define ClassPW_h + +#include +#include +#include +#include +#include + +struct PWHitInfo +{ + std::pair nearestWire; // anode, cathode + std::pair nearestDist; // anode, cathode + + std::pair nextNearestWire; // anode, cathode + std::pair nextNearestDist; // anode, cathode + + void Clear() + { + nearestWire.first = -1; + nearestWire.second = -1; + nearestDist.first = 999999999; + nearestDist.second = 999999999; + nextNearestWire.first = -1; + nextNearestWire.second = -1; + nextNearestDist.first = 999999999; + nextNearestDist.second = 999999999; + } +}; + +struct Coord +{ + float x, y, z; + Coord() : x(0), y(0), z(0) {} + Coord(const TVector3 &vec) + { + x = vec.X(); // TVector3's X() returns the x-coordinate + y = vec.Y(); // TVector3's Y() returns the y-coordinate + z = vec.Z(); // TVector3's Z() returns the z-coordinate + } +}; + +//! ######################################################## +class PW +{ // proportional wire +public: + PW() { ClearHitInfo(); }; + ~PW() {}; + + PWHitInfo GetHitInfo() const { return hitInfo; } + std::pair GetNearestID() const { return hitInfo.nearestWire; } + std::pair GetNearestDistance() const { return hitInfo.nearestDist; } + std::pair Get2ndNearestID() const { return hitInfo.nextNearestWire; } + std::pair Get2ndNearestDistance() const { return hitInfo.nextNearestDist; } + + std::vector> An; // the anode wire position vector in space + std::vector> Ca; // the cathode wire position vector in space + + TVector3 GetTrackPos() const { return trackPos; } + TVector3 GetTrackVec() const { return trackVec; } + double GetTrackTheta() const { return trackVec.Theta(); } + double GetTrackPhi() const { return trackVec.Phi(); } + double GetZ0(); + + inline std::tuple, double, double, double> GetPseudoWire(const std::vector>& cluster, std::string type); + + inline std::tuple + FindCrossoverProperties(const std::vector>& a_cluster, const std::vector>& c_cluster); + + inline std::vector>> + Make_Clusters(std::unordered_map> wireEvents); + + int GetNumWire() const { return nWire; } + double GetDeltaAngle() const { return dAngle; } + double GetAnodeLength() const { return anodeLength; } + double GetCathodeLength() const { return cathodeLength; } + TVector3 GetAnodeDn(short id) const { return An[id].first; } + TVector3 GetAnodeUp(short id) const { return An[id].second; } + TVector3 GetCathodeDn(short id) const { return Ca[id].first; } + TVector3 GetCathodeUp(short id) const { return Ca[id].second; } + + TVector3 GetAnodneMid(short id) const { return (An[id].first + An[id].second) * 0.5; } + double GetAnodeTheta(short id) const { return (An[id].first - An[id].second).Theta(); } + double GetAnodePhi(short id) const { return (An[id].first - An[id].second).Phi(); } + + TVector3 GetCathodneMid(short id) const { return (Ca[id].first + Ca[id].second) * 0.5; } + double GetCathodeTheta(short id) const { return (Ca[id].first - Ca[id].second).Theta(); } + double GetCathodePhi(short id) const { return (Ca[id].first - Ca[id].second).Phi(); } + + void ClearHitInfo(); + void ConstructGeo(); + void FindWireID(TVector3 pos, TVector3 direction, bool verbose = false); + void CalTrack(TVector3 sx3Pos, int anodeID, int cathodeID, bool verbose = false); + void CalTrack2(TVector3 sx3Pos, TVector3 anodeInt, bool verbose = false); + + void Print() + { + printf(" The nearest | Anode: %2d(%5.2f) Cathode: %2d(%5.2f)\n", hitInfo.nearestWire.first, + hitInfo.nearestDist.first, + hitInfo.nearestWire.second, + hitInfo.nearestDist.second); + + printf(" The 2nd nearest | Anode: %2d(%5.2f) Cathode: %2d(%5.2f)\n", hitInfo.nextNearestWire.first, + hitInfo.nextNearestDist.first, + hitInfo.nextNearestWire.second, + hitInfo.nextNearestDist.second); + } + +private: + PWHitInfo hitInfo; + + TVector3 trackPos; + TVector3 trackVec; + + const int nWire = 24; + const int wireShift = 3; + //const float zLen = 380; // mm + const float zLen = 348.6; // mm + const float radiusA = 37; + const float radiusC = 43; + + double dAngle; + double anodeLength; + double cathodeLength; + + // std::vector> An; // the anode wire position vector in space + // std::vector> Ca; // the cathode wire position vector in space + + double Distance(TVector3 a1, TVector3 a2, TVector3 b1, TVector3 b2) + { + TVector3 na = a1 - a2; + TVector3 nb = b1 - b2; + TVector3 nd = (na.Cross(nb)).Unit(); + return TMath::Abs(nd.Dot(a1 - b2)); + } +}; + +inline void PW::ClearHitInfo() +{ + hitInfo.Clear(); +} + +inline void PW::ConstructGeo() +{ + + An.clear(); + Ca.clear(); + + std::pair p1; // anode + std::pair q1; // cathode + + double k = TMath::TwoPi()/24.; //48 solder thru holes, wires in every other one + double offset_a1 = -6*k-3*k; + double offset_c1 = -3*k - TMath::TwoPi()/48; //correct for a half-turn + double offset_a2 = offset_a1+3*k; + double offset_c2 = offset_c1-3*k; + + for (int i = 0; i < nWire; i++) + { + // Anode rotate right-hand coming in towards +z riding with the beam. In this frame, +x is to the right, and +y down + //updated Feb 2026, Sudarsan B. Photographs indicate that anode wires twist right handed, as one moves from -z to +z with the convention above + //'First' is -z locus, 'second' is +z locus + p1.first.SetXYZ(radiusA * TMath::Cos(-k*i + offset_a1), + radiusA * TMath::Sin(-k*i + offset_a1), + -zLen / 2); + p1.second.SetXYZ(radiusA * TMath::Cos(-k*i + offset_a2), + radiusA * TMath::Sin(-k*i + offset_a2), + +zLen / 2); + + // Cathodes rotate left-hand, under the same system. k is positive + q1.first.SetXYZ(radiusC * TMath::Cos(k*i + offset_c1), + radiusC * TMath::Sin(k*i + offset_c1), + -zLen / 2); + q1.second.SetXYZ(radiusC * TMath::Cos(k*i + offset_c2), + radiusC * TMath::Sin(k*i + offset_c2), + zLen / 2); + An.push_back(p1); + Ca.push_back(q1); + } + + dAngle = wireShift * TMath::TwoPi() / nWire; + anodeLength = TMath::Sqrt(zLen * zLen + TMath::Power(2 * radiusA * TMath::Sin(dAngle / 2), 2)); + cathodeLength = TMath::Sqrt(zLen * zLen + TMath::Power(2 * radiusC * TMath::Sin(dAngle / 2), 2)); //chord length subtending an angle alpha is 2rsin(alpha/2) +} + +inline std::vector>> +PW::Make_Clusters(std::unordered_map> wireEvents) { + std::vector>> wireClusters; + std::vector> wireCluster; + //TODO: Write a macro once, call it twice + int wirecount=0; + while(wirecount < 24) { + if(wireEvents.find(wirecount)==wireEvents.end()) { + wirecount++; + continue; + } + wireCluster.clear(); + int ctr2=wirecount; + do { + wireCluster.emplace_back(wireEvents[ctr2]); + ctr2+=1; + if(ctr2==24 || ctr2-wirecount == 7) break; //loose logic, needs to be looked at. + } while(wireEvents.find(ctr2)!=wireEvents.end()); + wireClusters.push_back(std::move(wireCluster)); + wirecount = ctr2; //we already dealt with wires until the last value of ctr2 + } + + if(wireClusters.size() > 1) { //Deal with wraparound if required + auto first_cluster = wireClusters.front(); //front and back provide references to the elements themselves. less copy, can modify etc + auto last_cluster = wireClusters.back(); + if(std::get<0>(last_cluster.back())==23 && std::get<0>(first_cluster.front())==0) { + last_cluster.insert(last_cluster.end(),first_cluster.begin(),first_cluster.end()); + } + wireClusters.erase(wireClusters.begin()); //canonically, erase() needs an iterator, hence begin() not front() + //TODO: Can also deal with 'gaps' of missing wires similarly. end of one segment and beginning of another segment will be separated by missing wire --> combine the two + //TODO: Also needs some development regarding the time-correlation. Don't put wires in the same cluster if they aren't time coincident + } + return wireClusters; + + /*if(aClusters.size()>1 || cClusters.size() > 1) { + std::cout << " ============== " << std::endl; + } + if(aClusters.size()>1 && cClusters.size() >=1) { + std::cout << aClusters.size() << " new anode clusters ----> " << std::endl; + int cc=1; + for(auto ac : aClusters) { + std::cout << " Cluster " << cc << std::endl; + double first_ts = std::get<2>(ac.at(0)); + for(auto item : ac) { + std::cout << " \t" << std::get<0>(item) << " " << std::get<1>(item) << " " << std::get<2>(item)-first_ts << std::endl; + } + std::cout << " ------" << std::endl; + cc++; + } + } + + if(cClusters.size()>=1 ) { + std::cout << cClusters.size() << " new cathode clusters ----> " << std::endl; + int cc=1; + for(auto ac : cClusters) { + std::cout << " Cluster " << cc << std::endl; + double first_ts = std::get<2>(ac.at(0)); + for(auto item : ac) { + std::cout << " \t" << std::get<0>(item) << " " << std::get<1>(item) << " " << std::get<2>(item)-first_ts << std::endl; + } + std::cout << " ------" << std::endl; + cc++; + } + } */ +} + +inline std::tuple, double, double, double> +PW::GetPseudoWire(const std::vector>& cluster, std::string type) { + std::pair avgvec = std::pair(TVector3(0,0,0),TVector3(0,0,0)); + double sumEnergy = 0; + double maxEnergy = 0; + double tsMaxEnergy = 0; + if(type=="ANODE") { + //if(cluster.size()>1) std::cout << " -------anodes" << std::endl; + for( auto wire : cluster) { + avgvec.first += std::get<1>(wire)*TVector3(An.at(std::get<0>(wire)).first.X(), An.at(std::get<0>(wire)).first.Y(), 0) ; + avgvec.second += std::get<1>(wire)*TVector3(An.at(std::get<0>(wire)).second.X(), An.at(std::get<0>(wire)).second.Y(), 0); + sumEnergy += std::get<1>(wire); + if(std::get<1>(wire) > maxEnergy) { + maxEnergy = std::get<1>(wire); + tsMaxEnergy = std::get<2>(wire); + } + /*if(cluster.size()>1) { + std::cout << "\t\t ch:" << std::get<0>(wire) << " " << std::get<1>(wire) << " " << std::get<2>(wire) << std::endl; + std::cout << "\t\t w1(r,phi,z):" << An.at(std::get<0>(wire)).first.Perp() << " " << An.at(std::get<0>(wire)).first.Phi()*180/M_PI << " " << An.at(std::get<0>(wire)).first.Z() << std::endl; + std::cout << "\t\t w2(r,phi,z):" << An.at(std::get<0>(wire)).second.Perp() << " " << An.at(std::get<0>(wire)).second.Phi()*180/M_PI << " " << An.at(std::get<0>(wire)).second.Z() << std::endl; + }*/ + } + avgvec.first = avgvec.first*(1.0/sumEnergy); + avgvec.second = avgvec.second*(1.0/sumEnergy); + double phi1 = avgvec.first.Phi(); + double phi2 = avgvec.second.Phi(); + avgvec.first.SetXYZ(radiusA*TMath::Cos(phi1), radiusA*TMath::Sin(phi1), -zLen/2); + avgvec.second.SetXYZ(radiusA*TMath::Cos(phi2), radiusA*TMath::Sin(phi2), zLen/2); + /*if(cluster.size()>1) { + std::cout << "\t\t avg1(r,phi,z):" << avgvec.first.Perp() << " " << avgvec.first.Phi()*180/M_PI << " " << avgvec.first.Z() << std::endl; + std::cout << "\t\t avg2(r,phi,z):" << avgvec.second.Perp() << " " << avgvec.second.Phi()*180/M_PI << " " << avgvec.second.Z() << std::endl; + }*/ + } else if(type =="CATHODE") { + for( auto wire : cluster) { + avgvec.first += std::get<1>(wire)*TVector3(Ca.at(std::get<0>(wire)).first.X(), Ca.at(std::get<0>(wire)).first.Y(), 0) ; + avgvec.second += std::get<1>(wire)*TVector3(Ca.at(std::get<0>(wire)).second.X(), Ca.at(std::get<0>(wire)).second.Y(), 0); + sumEnergy += std::get<1>(wire); + if(std::get<1>(wire) > maxEnergy) { + maxEnergy = std::get<1>(wire); + tsMaxEnergy = std::get<2>(wire); + } + } + avgvec.first = avgvec.first*(1.0/sumEnergy); + avgvec.second = avgvec.second*(1.0/sumEnergy); + double phi1 = avgvec.first.Phi(); + double phi2 = avgvec.second.Phi(); + avgvec.first.SetXYZ(radiusC*TMath::Cos(phi1), radiusC*TMath::Sin(phi1), -zLen/2); + avgvec.second.SetXYZ(radiusC*TMath::Cos(phi2), radiusC*TMath::Sin(phi2), zLen/2); + } + return std::tuple(avgvec, sumEnergy, maxEnergy, tsMaxEnergy); +} + +inline std::tuple PW::FindCrossoverProperties(const std::vector>& a_cluster, + const std::vector>& c_cluster) { + //std::pair apwire = GetPseudoWire(a_cluster,"ANODE",anodeSumE); + //std::pair cpwire = GetPseudoWire(c_cluster,"CATHODE",cathodeSumE); + auto [apwire, apSumE, apMaxE, apTSMaxE] = GetPseudoWire(a_cluster,"ANODE"); + auto [cpwire, cpSumE, cpMaxE, cpTSMaxE] = GetPseudoWire(c_cluster,"CATHODE"); + + TVector3 crossover; + crossover.Clear(); + TVector3 a, c, diff; + double a2, ac, c2, adiff, cdiff, denom, alpha=0; + + if(apSumE && cpSumE) { + a = apwire.first - apwire.second; + c = cpwire.first - cpwire.second; + diff = apwire.first - cpwire.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 = apwire.first + alpha*a; + if(crossover.z() < -190 || crossover.Z() > 190 ) { + alpha = 9999999; + apSumE=-1; cpSumE=-1; + apMaxE=-1; cpMaxE=-1; + apTSMaxE=-1; cpTSMaxE=-1; + } + } + //std::cout << apSumE << " " << cpSumE << " " << " " << crossover.Perp() << std::endl; + return std::tuple(crossover,alpha,apSumE,cpSumE,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); +} + +inline void PW::FindWireID(TVector3 pos, TVector3 direction, bool verbose) +{ + + hitInfo.Clear(); + double phi = direction.Phi(); + + for (int i = 0; i < nWire; i++) + { + + double disA = 99999999; + double phiS = An[i].first.Phi() - TMath::PiOver4(); + double phiL = An[i].second.Phi() + TMath::PiOver4(); + // printf("A%2d: %f %f | %f\n", i, phiS * TMath::RadToDeg(), phiL * TMath::RadToDeg(), phi * TMath::RadToDeg()); + if (phi > 0 && phiS > phiL) + phiL = phiL + TMath::TwoPi(); + if (phi < 0 && phiS > phiL) + phiS = phiS - TMath::TwoPi(); + + if (phiS < phi && phi < phiL) + { + disA = Distance(pos, pos + direction, An[i].first, An[i].second); + if (disA < hitInfo.nearestDist.first) + { + hitInfo.nearestDist.first = disA; + hitInfo.nearestWire.first = i; + } + } + + double disC = 99999999; + phiS = Ca[i].second.Phi() - TMath::PiOver4(); + phiL = Ca[i].first.Phi() + TMath::PiOver4(); + // printf("C%2d: %f %f\n", i, phiS * TMath::RadToDeg(), phiL * TMath::RadToDeg()); + if (phi > 0 && phiS > phiL) + phiL = phiL + TMath::TwoPi(); + if (phi < 0 && phiS > phiL) + phiS = phiS - TMath::TwoPi(); + + if (phiS < phi && phi < phiL) + { + disC = Distance(pos, pos + direction, Ca[i].first, Ca[i].second); + if (disC < hitInfo.nearestDist.second) + { + hitInfo.nearestDist.second = disC; + hitInfo.nearestWire.second = i; + } + } + + if (verbose) + printf(" %2d | %8.2f, %8.2f\n", i, disA, disC); + } + + //==== find the 2nd nearest wire + short anode1 = hitInfo.nearestWire.first; + short aaa1 = anode1 - 1; + if (aaa1 < 0) + aaa1 += nWire; + short aaa2 = (anode1 + 1) % nWire; + + double haha1 = Distance(pos, pos + direction, An[aaa1].first, An[aaa1].second); + double haha2 = Distance(pos, pos + direction, An[aaa2].first, An[aaa2].second); + if (haha1 < haha2) + { + hitInfo.nextNearestWire.first = aaa1; + hitInfo.nextNearestDist.first = haha1; + } + else + { + hitInfo.nextNearestWire.first = aaa2; + hitInfo.nextNearestDist.first = haha2; + } + + short cathode1 = hitInfo.nearestWire.second; + short ccc1 = cathode1 - 1; + if (ccc1 < 0) + ccc1 += nWire; + short ccc2 = (cathode1 + 1) % nWire; + + haha1 = Distance(pos, pos + direction, Ca[ccc1].first, Ca[ccc1].second); + haha2 = Distance(pos, pos + direction, Ca[ccc2].first, Ca[ccc2].second); + if (haha1 < haha2) + { + hitInfo.nextNearestWire.second = ccc1; + hitInfo.nextNearestDist.second = haha1; + } + else + { + hitInfo.nextNearestWire.second = ccc2; + hitInfo.nextNearestDist.second = haha2; + } + + if (verbose) + Print(); +} + +inline void PW::CalTrack(TVector3 sx3Pos, int anodeID, int cathodeID, bool verbose) +{ + + trackPos = sx3Pos; + + TVector3 n1 = (An[anodeID].first - An[anodeID].second).Cross((sx3Pos - An[anodeID].second)).Unit(); + TVector3 n2 = (Ca[cathodeID].first - Ca[cathodeID].second).Cross((sx3Pos - Ca[cathodeID].second)).Unit(); + + // if the handiness of anode and cathode revered, it should be n2 cross n1 + trackVec = (n2.Cross(n1)).Unit(); + + if (verbose) + printf("Theta, Phi = %f, %f \n", trackVec.Theta() * TMath::RadToDeg(), trackVec.Phi() * TMath::RadToDeg()); +} + + +inline void PW::CalTrack2(TVector3 siPos, TVector3 anodeInt, bool verbose) +{ + + double mx, my; + double z; + mx = siPos.X() / (siPos.X() - anodeInt.X()); + my = siPos.Y() / (siPos.Y() - anodeInt.Y()); + z=siPos.Z() + mx * (anodeInt.Z() - siPos.Z()); + // if (mx == my) + { + trackVec=TVector3(0,0,z); + } + + if (verbose) + printf("X slope = %f and Y slope = %f \n", mx, my); +} + +/*inline TVector3 PW::CalTrack3(TVector3 siPos, TVector3 anodeInt, bool verbose) +{ + + TVector3 v = anodeInt-siPos; + double t_minimum = -1.0*(siPos.X()*v.X()+siPos.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + TVector3 vector_closest_to_z = siPos + t_minimum*v; + + return vector_closest_to_z; + if (verbose) + printf("X slope = %f and Y slope = %f \n", mx, my); +}*/ + +inline double PW::GetZ0() +{ + + double x = trackPos.X(); + double y = trackPos.Y(); + double rho = TMath::Sqrt(x * x + y * y); + double theta = trackVec.Theta(); + + return trackVec.Z(); +} + +#endif diff --git a/Armory/SX3Geom.h b/Armory/SX3Geom.h index 1b72241..12c2266 100755 --- a/Armory/SX3Geom.h +++ b/Armory/SX3Geom.h @@ -72,6 +72,7 @@ public: void sx3::fillevent(const std::string& positionstring, const int subchannel, const float value) { assert(subchannel>=0 && subchannel<4); + foundevent=1; if(positionstring=="FRONT_L") { frontL[subchannel].push_back(value); unmatched_front_chans.insert(subchannel); diff --git a/DataDump.C b/DataDump.C new file mode 100644 index 0000000..0ae4a7a --- /dev/null +++ b/DataDump.C @@ -0,0 +1,639 @@ +#define DataDump_cxx + +#include "DataDump.h" +#include "Armory/ClassPW.h" +#include "Armory/HistPlotter.h" + +#include +#include +#include +#include +#include +#include "TVector3.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 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> qqqlist; + std::vector QQQ_Events, PC_Events; + std::vector 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(qqq.t[j]); + tWedge = static_cast(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(qqq.t[i]); + tWedge = static_cast(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 caths_seen{0}, anos_seen{0}; + std::vector> 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(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(pc.t[i]); + anodeIndex = pc.index[i]; + anos_seen[anodeIndex] = 1; + anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); + anodeTimes.push_back(anodeT); + anodeChunks.push_back(std::tuple(pc.index[i],anodeT,pc.e[i])); + } else { + cathodeT = static_cast(pc.t[i]); + cathodeIndex = pc.index[i] - 24; + caths_seen[cathodeIndex] = 1; + cathodeChunks.push_back(std::tuple(pc.index[i]-24,cathodeT,pc.e[i])); + cathodeHits.push_back(std::pair(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; iiFill2D("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= 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(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(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(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(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(); +} diff --git a/DataDump.h b/DataDump.h new file mode 100644 index 0000000..4091c27 --- /dev/null +++ b/DataDump.h @@ -0,0 +1,132 @@ +#ifndef DataDump_h +#define DataDump_h + +#include +#include +#include +#include +#include +#include +#include // Required for vectors +#include // Required for std::pair + +#include "Armory/ClassDet.h" +#include "Armory/ClassPW.h" // YOU ADDED THIS (Correct! Defines Coord) + +class DataDump : public TSelector { +public : + TTree *fChain; //!pointer to the analyzed TTree or TChain + + // Declaration of leaf types + Det sx3; + Det qqq; + Det pc ; + Det misc; + + ULong64_t evID; + UInt_t run; + + // List of branches + TBranch *b_eventID; //! + TBranch *b_run; //! + TBranch *b_sx3Multi; //! + TBranch *b_sx3ID; //! + TBranch *b_sx3Ch; //! + TBranch *b_sx3E; //! + TBranch *b_sx3T; //! + TBranch *b_qqqMulti; //! + TBranch *b_qqqID; //! + TBranch *b_qqqCh; //! + TBranch *b_qqqE; //! + TBranch *b_qqqT; //! + TBranch *b_pcMulti; //! + TBranch *b_pcID; //! + TBranch *b_pcCh; //! + TBranch *b_pcE; //! + TBranch *b_pcT; //! + TBranch *b_miscMulti; //! + TBranch *b_miscID; //! + TBranch *b_miscCh; //! + TBranch *b_miscE; //! + TBranch *b_miscT; //! + TBranch *b_miscTf; //! + + // 1. Geometry Cache + Coord Crossover[24][24][2]; + + // 2. Persistent Vectors (REQUIRED for the optimized .cxx to work) + std::vector> anodeHits; + std::vector> cathodeHits; + std::vector> corrcatMax; + std::vector> corranoMax; + std::vector cathodeTimes; + std::vector anodeTimes; + + DataDump(TTree * /*tree*/ =0) : fChain(0) { } + virtual ~DataDump() { } + virtual Int_t Version() const { return 2; } + virtual void Begin(TTree *tree); + virtual void SlaveBegin(TTree *tree); + virtual void Init(TTree *tree); + virtual Bool_t Notify(); + virtual Bool_t Process(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } + virtual void SetOption(const char *option) { fOption = option; } + virtual void SetObject(TObject *obj) { fObject = obj; } + virtual void SetInputList(TList *input) { fInput = input; } + virtual TList *GetOutputList() const { return fOutput; } + virtual void SlaveTerminate(); + virtual void Terminate(); + + ClassDef(DataDump,0); +}; + +#endif + +#ifdef DataDump_cxx +void DataDump::Init(TTree *tree){ + + if (!tree) return; + fChain = tree; + fChain->SetMakeClass(1); + + fChain->SetBranchAddress("evID", &evID, &b_eventID); + fChain->SetBranchAddress("run", &run, &b_run); + + sx3.SetDetDimension(24,12); + qqq.SetDetDimension(4,32); + pc.SetDetDimension(2,24); + + fChain->SetBranchAddress("sx3Multi", &sx3.multi, &b_sx3Multi); + fChain->SetBranchAddress("sx3ID", &sx3.id, &b_sx3ID); + fChain->SetBranchAddress("sx3Ch", &sx3.ch, &b_sx3Ch); + fChain->SetBranchAddress("sx3E", &sx3.e, &b_sx3E); + fChain->SetBranchAddress("sx3T", &sx3.t, &b_sx3T); + fChain->SetBranchAddress("qqqMulti", &qqq.multi, &b_qqqMulti); + fChain->SetBranchAddress("qqqID", &qqq.id, &b_qqqID); + fChain->SetBranchAddress("qqqCh", &qqq.ch, &b_qqqCh); + fChain->SetBranchAddress("qqqE", &qqq.e, &b_qqqE); + fChain->SetBranchAddress("qqqT", &qqq.t, &b_qqqT); + fChain->SetBranchAddress("pcMulti", &pc.multi, &b_pcMulti); + fChain->SetBranchAddress("pcID", &pc.id, &b_pcID); + fChain->SetBranchAddress("pcCh", &pc.ch, &b_pcCh); + fChain->SetBranchAddress("pcE", &pc.e, &b_pcE); + fChain->SetBranchAddress("pcT", &pc.t, &b_pcT); + fChain->SetBranchAddress("miscMulti", &misc.multi, &b_miscMulti); + fChain->SetBranchAddress("miscID", &misc.id, &b_miscID); + fChain->SetBranchAddress("miscCh", &misc.ch, &b_miscCh); + fChain->SetBranchAddress("miscE", &misc.e, &b_miscE); + fChain->SetBranchAddress("miscT", &misc.t, &b_miscT); +} + +Bool_t DataDump::Notify(){ + return kTRUE; +} + +void DataDump::SlaveBegin(TTree * /*tree*/){ + // TString option = GetOption(); +} + +void DataDump::SlaveTerminate(){ +} +#endif // #ifdef DataDump_cxx diff --git a/MakeVertex.C b/MakeVertex.C index b6b9cec..805552d 100755 --- a/MakeVertex.C +++ b/MakeVertex.C @@ -1,5 +1,14 @@ #define MakeVertex_cxx +Int_t colors[40] = { + kBlack, kRed, kGreen, kBlue, kYellow, kMagenta, kCyan, kOrange, + kSpring, kTeal, kAzure, kViolet, kPink, kGray, kWhite, + kRed+2, kGreen+2, kBlue+2, kYellow+2, kMagenta+2, kCyan+2, kOrange+2, + kSpring+2, kTeal+2, kAzure+2, kViolet+2, kPink+2, + kRed-7, kGreen-7, kBlue-7, kYellow-7, kMagenta-7, kCyan-7, kOrange-7, + kSpring-7, kTeal-7, kAzure-7, kViolet-7, kPink-7, kGray+2 +}; + #include "MakeVertex.h" #include "Armory/ClassPW.h" #include "Armory/HistPlotter.h" @@ -10,7 +19,12 @@ #include #include #include -#include "TVector3.h" +#include +#include +#include +#include +#include +#include #include #include @@ -21,38 +35,61 @@ #include #include +bool realtime = true; +const double source_vertex = 53; //53 +const double qqq_z = 100.0; +const double anode_gain = 1.5146e-5; //channels --> MeV + +TApplication *app=NULL; +TH1F *hha=NULL,*hhc=NULL; +TH3D *frame=NULL; +TCanvas *can1=NULL,*can2=NULL; + +TPolyLine3D *pla[24]={NULL}; +TPolyLine3D *plc[24]={NULL}; +TPolyLine3D *qqqw[16][4]={NULL}; +TPolyLine3D *trajectory=NULL; +TGraph2D *qqqg=NULL, *crossoverg=NULL, *guessg=NULL; + +double z_to_crossover_rho(double z) { + return 9.20645e-5*z*z + 34.1973; +} + +double z_to_crossover_rho_cathode(double z) { + return 9.20645e-5*z*z + 34.1973; +} + // Global instances PW pw_contr; PW pwinstance; TVector3 hitPos; double qqqenergy, qqqtimestamp; -class Event -{ +class Event { public: - Event(TVector3 p, double e1, double e2, double t1, double t2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2) {} - Event(TVector3 p, double e1, double e2, double t1, double t2, int c1, int c2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2), ch1(c1), ch2(c2) {} + Event(TVector3 p, double e1, double e2, double t1, double t2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2) {} + Event(TVector3 p, double e1, double e2, double t1, double t2, int c1, int c2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2), ch1(c1), ch2(c2) {} + //Event(TVector3 p, double e1, double e2, double t1, double t2, int c1, int c2, int m1, int m2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2), ch1(c1), ch2(c2), multi1(m1), multi2(m2) {} - TVector3 pos; - int ch1 = -1; // int(ch1/16) gives qqq id, ch1%16 gives ring# - int ch2 = -1; // int(ch2/16) gives qqq id, ch2%16 gives wedge# - double Energy1 = -1; // Front for QQQ, Anode for PC - double Energy2 = -1; // Back for QQQ, Cathode for PC - double Time1 = -1; - double Time2 = -1; + TVector3 pos; + int ch1=-1; //int(ch1/16) gives qqq id, ch1%16 gives ring# + int ch2=-1; //int(ch2/16) gives qqq id, ch2%16 gives wedge# + double Energy1=-1; //Front for QQQ, Anode for PC + double Energy2=-1; //Back for QQQ, Cathode for PC + double Time1=-1; + double Time2=-1; + + //misc elements; + int multi1=-1, multi2=-1; }; // Calibration globals const int MAX_QQQ = 4; const int MAX_RING = 16; const int MAX_WEDGE = 16; -const double qqqpos = 100.0; -const double vertexpos = 14.2; -const double pcrad = 37.0; 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; double sx3BackGain[24][4][4] = {{{1.}}}; double sx3FrontGain[24][4] = {{1.}}; @@ -71,964 +108,1122 @@ bool qqqEcut; void MakeVertex::Begin(TTree * /*tree*/) { - TString option = GetOption(); - plotter = new HistPlotter("Analyzer_SX3.root", "TFILE"); - pw_contr.ConstructGeo(); - pwinstance.ConstructGeo(); + TString option = GetOption(); + plotter = new HistPlotter("Analyzer_SX3.root", "TFILE"); + pw_contr.ConstructGeo(); + pwinstance.ConstructGeo(); + if(gROOT->IsBatch()) realtime=false; - // --------------------------------------------------------- - // 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++) + // --------------------------------------------------------- + // 1. CRITICAL FIX: Initialize PC Arrays to Default (Raw) + // --------------------------------------------------------- + for (int i = 0; i < 48; i++) { - 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; + pcSlope[i] = 1.0; // Default slope = 1 (preserves Raw energy) + pcIntercept[i] = 0.0; // Default intercept = 0 } - } - // Load PC Calibrations - std::ifstream inputFile("slope_intercept_results.dat"); - if (inputFile.is_open()) - { - std::string line; - int index; - double slope, intercept; - while (std::getline(inputFile, line)) + // Load PC Calibrations + std::ifstream inputFile("slope_intercept_results.txt"); + if (inputFile.is_open()) { - std::stringstream ss(line); - ss >> index >> slope >> intercept; - if (index >= 0 && index <= 47) - { - pcSlope[index] = slope; - pcIntercept[index] = intercept; - } + 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(); } - inputFile.close(); - } - else - { - std::cerr << "Error opening slope_intercept.dat" << std::endl; - } - - // Load QQQ Cuts from file - // { - // std::string filename = "QQQ_PCCut.root"; - // TFile *cutFile = TFile::Open(filename.c_str(), "READ"); - // if (cutFile && !cutFile->IsZombie()) - // { - // cutQQQ = (TCutg *)cutFile->Get("cutQQQPC"); - // if (cutQQQ) - // { - // std::cout << "Loaded QQQ PC cut from " << filename << std::endl; - // } - // else - // { - // std::cerr << "Error: cutQQQPC not found in " << filename << std::endl; - // } - // cutFile->Close(); - // } - // } - - // ... (Load QQQ Gains and Calibs - same as before) ... - { - std::string filename = "qqq_GainMatch.dat"; - std::ifstream infile(filename); - if (infile.is_open()) + else { - 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); - // std::cout << "QQQ Gain Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " GainW " << gainw << " GainR " << gainr << std::endl; - } - infile.close(); + std::cerr << "Error opening slope_intercept.txt" << std::endl; } - } - { - std::string filename = "qqq_Calib.dat"; - std::ifstream infile(filename); - if (infile.is_open()) + + // ... (Load QQQ Gains and Calibs - same as before) ... { - int det, ring, wedge; - double slope; - while (infile >> det >> wedge >> ring >> slope) - { - qqqCalib[det][wedge][ring] = slope; - qqqCalibValid[det][wedge][ring] = (slope > 0); - // std::cout << "QQQ Calib Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " Slope " << slope << std::endl; - } - infile.close(); + 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); + // std::cout << "QQQ Gain Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " GainW " << gainw << " GainR " << gainr << std::endl; + } + infile.close(); + } } - } - { - std::ifstream infile("sx3cal/backgains.dat"); - std::string temp; - int backpos, frontpos, clkpos; - std::cout << "foo" << std::endl; - if (infile.is_open()) - while (infile >> clkpos >> temp >> frontpos >> temp >> backpos >> sx3BackGain[clkpos][frontpos][backpos]) - std::cout << sx3BackGain[clkpos][frontpos][backpos] << std::endl; - 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); + // std::cout << "QQQ Calib Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " Slope " << slope << std::endl; + } + infile.close(); + } + } - infile.open("sx3cal/frontgains.dat"); - if (infile.is_open()) - while (infile >> clkpos >> temp >> temp >> frontpos >> sx3FrontOffset[clkpos][frontpos] >> sx3FrontGain[clkpos][frontpos]) - std::cout << sx3FrontOffset[clkpos][frontpos] << " " << sx3FrontGain[clkpos][frontpos] << std::endl; - infile.close(); + { + std::ifstream infile("sx3cal/17F/backgains.dat"); + std::string temp; + int backpos, frontpos, clkpos; + if (infile.is_open()) + while(infile>>clkpos>>temp>>frontpos>>temp>>backpos>>sx3BackGain[clkpos][frontpos][backpos]) + ;//std::cout << sx3BackGain[clkpos][frontpos][backpos] << std::endl; + infile.close(); - infile.open("sx3cal/rightgains.dat"); - if (infile.is_open()) - while (infile >> clkpos >> frontpos >> temp >> sx3RightGain[clkpos][frontpos]) - { - sx3RightGain[clkpos][frontpos] = TMath::Abs(sx3RightGain[clkpos][frontpos]); - } - infile.close(); - } - std::cout << "aaa" << std::endl; + infile.open("sx3cal/17F/frontgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>temp>>temp>>frontpos>>sx3FrontOffset[clkpos][frontpos]>>sx3FrontGain[clkpos][frontpos]) + ;//std::cout << sx3FrontOffset[clkpos][frontpos] << " " << sx3FrontGain[clkpos][frontpos] << std::endl; + infile.close(); + + infile.open("sx3cal/17F/rightgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>frontpos>>temp>>sx3RightGain[clkpos][frontpos]) { + sx3RightGain[clkpos][frontpos]=TMath::Abs(sx3RightGain[clkpos][frontpos]); + } + infile.close(); + } + + if(realtime) { + can1 = new TCanvas("wireindex","c1",0,0,640,480); + can2 = new TCanvas("3d","c2",650,0,640,480); + can1->cd(); + //can2->SetFillColor(30); + frame = new TH3D("frame","frame",1000,-100,100,1000,-100,100,1000,-200,200); + hha =new TH1F("hha","Anode Ecal vs wire#",48,-12,36); + hhc =new TH1F("hhc","Cathode Ecal vs wire#",48,-12,36); + hha->SetLineColor(kRed); + hha->GetYaxis()->SetRangeUser(0,16384); + hha->GetXaxis()->SetTitle("press any key, interrupt/refresh or double click to continue.."); + hha->Draw(); + hhc->Draw("SAME"); + can1->Modified(); + can1->Update(); + can1->BuildLegend(); + + can2->cd(); + frame->Draw(); + for(int i=0; i<24; i++) { + plc[i] = new TPolyLine3D(2); + pla[i] = new TPolyLine3D(2); + pla[i]->SetPoint(0,pwinstance.An[i].first.X(),pwinstance.An[i].first.Y(),pwinstance.An[i].first.Z()); + pla[i]->SetPoint(1,pwinstance.An[i].second.X(),pwinstance.An[i].second.Y(),pwinstance.An[i].second.Z()); + plc[i]->SetPoint(0,pwinstance.Ca[i].first.X(),pwinstance.Ca[i].first.Y(),pwinstance.Ca[i].first.Z()); + plc[i]->SetPoint(1,pwinstance.Ca[i].second.X(),pwinstance.Ca[i].second.Y(),pwinstance.Ca[i].second.Z()); + plc[i]->SetLineStyle(kDotted); + pla[i]->SetLineStyle(kDotted); + pla[i]->SetLineWidth(1.); + plc[i]->SetLineWidth(1.); + plc[i]->Draw("same"); + pla[i]->Draw("same"); + plc[i]->SetLineColor(colors[i]); + pla[i]->SetLineColor(colors[i]); + } + crossoverg = new TGraph2D(1); + crossoverg->SetName("crossoverg"); + crossoverg->SetMarkerStyle(20); + crossoverg->SetMarkerColor(kBlue+3); + qqqg = new TGraph2D(1); + qqqg->SetName("qqqg"); + qqqg->SetMarkerColor(kRed); + qqqg->SetMarkerStyle(42); + + crossoverg->SetPoint(0,0,0,0); + qqqg->SetPoint(0,0,0,qqq_z); + crossoverg->Draw("P same"); + qqqg->Draw("P same"); + + trajectory=new TPolyLine3D(2); + trajectory->SetPoint(0,0,0,0); + trajectory->SetPoint(1,0,0,0); + trajectory->Draw("same"); + + can2->Modified(); + can2->Update(); + } } Bool_t MakeVertex::Process(Long64_t entry) { - hitPos.Clear(); - qqqenergy = -1; - qqqtimestamp = -1; - 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); + hitPos.Clear(); + qqqenergy = -1; + qqqtimestamp=-1; + 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(); + sx3.CalIndex(); + qqq.CalIndex(); + pc.CalIndex(); - std::vector sx3Events; - // if(sx3.multi>1) { - // std::array Fsx3; - // //std::cout << "-----" << std::endl; - // for(int i=0; i=12) continue; - // int id = sx3.id[i]; - // if(sx3.ch[i]>=8) { - // int sx3ch=sx3.ch[i]-8; - // sx3ch=(sx3ch+3)%4; - // if(sx3ch==0 || sx3ch==3) continue; - // float value=sx3.e[i]; - // int gch = sx3.id[i]*4+(sx3.ch[i]-8); - // Fsx3.at(id).fillevent("BACK",sx3ch,value); - // Fsx3.at(id).ts = static_cast(sx3.t[i]); - // plotter->Fill2D("sx3backs_raw",100,0,100,800,0,4096,gch,sx3.e[i]); - // } else { - // int sx3ch=sx3.ch[i]/2; - // double value=sx3.e[i]; - // if(sx3.ch[i]%2==0) { - // Fsx3.at(id).fillevent("FRONT_L",sx3ch,value*sx3RightGain[id][sx3ch]); - // } else { - // Fsx3.at(id).fillevent("FRONT_R",sx3ch,value); - // } - // } - // } - // for(int id=0; id<12; id++) { - // Fsx3.at(id).validate(); - // auto det = Fsx3.at(id); - // bool no_charge_sharing_strict = det.valid_front_chans.size()==1 && det.valid_back_chans.size()==1; - // if(det.valid) { - // //std::cout << det.frontEL << " " << det.frontEL*sx3RightGain[id][det.stripF] << std::endl; - // plotter->Fill2D("be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_b"+std::to_string(det.stripB),200,-1,1,800,0,8192, - // det.frontX,det.backE,"evsx"); - // //std::cout << sx3BackGain[id][det.stripF][det.stripB] << " " << sx3FrontGain[id][det.stripF] << std::endl; - // plotter->Fill2D("matched_be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_"+std::to_string(id*4+det.stripF),200,-30,30,800,0,8192, - // det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF],det.backE*sx3BackGain[id][det.stripF][det.stripB],"evsx_matched"); - // //plotter->Fill2D("fe_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_"+std::to_string(det.stripB),200,-1,1,800,0,4096,det.frontX,det.backE,"evsx"); - // plotter->Fill2D("l_vs_r_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),800,0,4096,800,0,4096,det.frontEL,det.frontER,"l_vs_r"); - // } - // if(det.valid && (id ==9 || id==7 || id == 1 || id==3) && det.stripF!=DEFAULT_NULL && det.stripB!=DEFAULT_NULL) { - // double z = det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF]; - // double backE = det.backE*sx3BackGain[id][det.stripF][det.stripB]; - // Event sx3ev(TVector3(0,0,z),backE,-1,det.ts,-1,det.stripB+4*id,det.stripF+4*id); - // sx3Events.push_back(sx3ev); - // } - // } - // } - // return kTRUE; - // QQQ Processing +/* for (int i = 0; i < pc.multi; i++) + { + std::cout << pc.index[i] << " " << pc.e[i] << " " << std::endl; + } +*/ std::vector sx3Events; + if(sx3.multi>1) { + std::array Fsx3; + //std::cout << "-----" << std::endl; + for(int i=0; i=12) continue; + if(sx3.ch[i]>=8) { + int sx3ch=sx3.ch[i]-8; + sx3ch=(sx3ch+3)%4; + if(sx3ch==0 || sx3ch==3) continue; + float value=sx3.e[i]; + int gch = sx3.id[i]*4+(sx3.ch[i]-8); + Fsx3.at(id).fillevent("BACK",sx3ch,value); + Fsx3.at(id).ts = static_cast(sx3.t[i]); + plotter->Fill2D("sx3backs_raw",100,0,100,800,0,4096,gch,sx3.e[i]); + } else { + int sx3ch=sx3.ch[i]/2; + double value=sx3.e[i]; + if(sx3.ch[i]%2==0) { + Fsx3.at(id).fillevent("FRONT_L",sx3ch,value*sx3RightGain[id][sx3ch]); + } else { + Fsx3.at(id).fillevent("FRONT_R",sx3ch,value); + } + } + } + for(int id=0; id<24; id++) { + //std::cout << id << " " << Fsx3.at(id).valid_front_chans.size() << " " << Fsx3.at(id).valid_back_chans.size() << std::endl;; + try { + Fsx3.at(id).validate(); + } catch(std::exception exc) { + std::cout << "oops! anyway" << std::endl; + continue; + } + auto det = Fsx3.at(id); + bool no_charge_sharing_strict = det.valid_front_chans.size()==1 && det.valid_back_chans.size()==1; + if(det.valid) { + //std::cout << det.frontEL << " " << det.frontEL*sx3RightGain[id][det.stripF] << std::endl; + plotter->Fill2D("be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_b"+std::to_string(det.stripB),200,-1,1,800,0,8192, + det.frontX,det.backE,"evsx"); - 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) - // if (qqq.id[i] == 1 && qqq.ch[i] < 16) //for run 12, 26Al - // { - // 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::cout << sx3BackGain[id][det.stripF][det.stripB] << " " << sx3FrontGain[id][det.stripF] << std::endl; + plotter->Fill2D("matched_be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),200,-30,30,800,0,8192, + det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF],det.backE*sx3BackGain[id][det.stripF][det.stripB],"evsx_matched"); + //plotter->Fill2D("fe_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_"+std::to_string(det.stripB),200,-1,1,800,0,4096,det.frontX,det.backE,"evsx"); + - std::vector QQQ_Events, PC_Events; - std::vector QQQ_Events_Raw, PC_Events_Raw; - std::vector QQQ_Events2; // clustering done + plotter->Fill2D("l_vs_r_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),800,0,4096,800,0,4096,det.frontEL,det.frontER,"l_vs_r"); + } + if(det.valid && (id ==9 || id==7 || id == 1 || id==3) && det.stripF!=DEFAULT_NULL && det.stripB!=DEFAULT_NULL) { + double z = det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF]; + double backE = det.backE*sx3BackGain[id][det.stripF][det.stripB]; + det.stripF=3-det.stripF; + double beta_n = 15.0 + TMath::ATan2((2*det.stripF-3)*40.30, 8.0*88.0*TMath::Cos(15.0*M_PI/180.0))*180./M_PI; //how much to add per strip to the starting position + double phi_n = ((-id+0.5)*30+beta_n); + phi_n+=45; + //phi_n-=120; + phi_n*=M_PI/180.; //starting-position phi + strip contribution + Event sx3ev(TVector3(88.0*TMath::Cos(phi_n),88.0*TMath::Sin(phi_n),z),backE,-1,det.ts,-1,det.stripB+4*id,det.stripF+4*id); + sx3Events.push_back(sx3ev); + } + } + } + //return kTRUE; + // QQQ Processing - std::unordered_map> qvecr[4], qvecw[4]; - if (qqq.multi > 1) - { - // if(qqq.multi>=3) std::cout << "-----" << std::endl; + int qqqCount = 0; + int qqqAdjCh = 0; + // REMOVE WHEN RERUNNING USING THE NEW CALIBRATION FILE for (int i = 0; i < qqq.multi; i++) { - // if(qqq.multi>=3) std::cout << std::setprecision(16) << "qqq"<< qqq.id[i] << " " << std::string(qqq.ch[i]/16?"ring":"wedge") << qqq.ch[i]%16 << " " << qqq.e[i] << " " << qqq.t[i] - qqq.t[0] << std::endl; - if (qqq.ch[i] / 16) - { - if (qvecr[qqq.id[i]].find(qqq.ch[i]) != qvecr[qqq.id[i]].end()) - std::cout << "mayday!" << std::endl; - qvecr[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i], qqq.ch[i], qqq.e[i], qqq.t[i]); - } - else - { - if (qvecw[qqq.id[i]].find(qqq.ch[i]) != qvecw[qqq.id[i]].end()) - std::cout << "mayday!" << std::endl; - qvecw[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i], qqq.ch[i], qqq.e[i], qqq.t[i]); - } + //if ((qqq.id[i] == 3 || qqq.id[i] == 1) && qqq.ch[i] < 16) + if (qqq.id[i] == 1 && qqq.ch[i] < 16) //for run 12, 26Al + { + qqq.ch[i] = 16 - qqq.ch[i]; + } } - } - - bool PCQQQTimeCut = false; - for (int i = 0; i < qqq.multi; i++) - { - plotter->Fill2D("QQQ_Index_Vs_Energy", 16 * 8, 0, 16 * 8, 2000, 0, 16000, qqq.index[i], qqq.e[i], "hRawQQQ"); - - for (int j = 0; j < qqq.multi; j++) + for (int i = 0; i < qqq.multi; i++) { - if (j == i) - continue; - plotter->Fill2D("QQQ_Coincidence_Matrix", 16 * 8, 0, 16 * 8, 16 * 8, 0, 16 * 8, qqq.index[i], qqq.index[j], "hRawQQQ"); + if (qqq.id[i] == 0 && qqq.ch[i] >= 16) + { + } } - for (int k = 0; k < pc.multi; k++) - { - if (pc.index[k] < 24 && pc.e[k] > 50) - { - plotter->Fill2D("QQQ_Vs_Anode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); - plotter->Fill2D("QQQ_Vs_PC_Index", 16 * 8, 0, 16 * 8, 24, 0, 24, qqq.index[i], pc.index[k], "hRawQQQ"); - } - else if (pc.index[k] >= 24 && pc.e[k] > 50) - { - plotter->Fill2D("QQQ_Vs_Cathode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); - } - } + std::vector QQQ_Events, PC_Events; + std::vector QQQ_Events_Raw, PC_Events_Raw; + std::vector QQQ_Events2; //clustering done - 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(qqq.t[j]); - tWedge = static_cast(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(qqq.t[i]); - tWedge = static_cast(qqq.t[j]); - } - else - continue; - - plotter->Fill1D("Wedgetime_Vs_Ringtime", 100, -1000, 1000, tWedge - tRing, "hTiming"); - plotter->Fill2D("RingE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chRing + qqq.id[i] * 16, eRing, "hRawQQQ"); - plotter->Fill2D("WedgeE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chWedge + qqq.id[i] * 16, eWedge, "hRawQQQ"); - - 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; - - if (eRingMeV / eWedgeMeV > 3.0 || eRingMeV / eWedgeMeV < 1.0 / 3.0) - continue; - // if(eRingMeV<4.0 || eWedgeMeV<4.0) continue; - - double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); - double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" - // z used to be 75+30+23=128 - // we found a 12mm shift towards the vertex later --> 116 - Event qqqevent(TVector3(rho * TMath::Cos(theta), rho * TMath::Sin(theta), qqqpos), eRingMeV, eWedgeMeV, tRing, tWedge, chRing + qqq.id[i] * 16, chWedge + qqq.id[i] * 16); - Event qqqeventr(TVector3(rho * TMath::Cos(theta), rho * TMath::Sin(theta), qqqpos), eRing, eWedge, tRing, tWedge, chRing + qqq.id[i] * 16, chWedge + qqq.id[i] * 16); - QQQ_Events.push_back(qqqevent); - QQQ_Events_Raw.push_back(qqqeventr); - plotter->Fill2D("QQQCartesianPlot", 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); - plotter->Fill2D("QQQCartesianPlot" + std::to_string(qqq.id[i]), 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); - if (PCQQQTimeCut) - { - plotter->Fill2D("PC_XY_Projection_QQQ_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); - } - plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); - } - else - continue; - - plotter->Fill2D("WedgeE_Vs_RingECal", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); - plotter->Fill2D("WedgeE_Vs_RingECal_selected", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); - - for (int k = 0; k < pc.multi; k++) - { - plotter->Fill2D("RingCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); - plotter->Fill2D("WedgeCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); - plotter->Fill2D("WedgeCh_vs_Anode_Index" + std::to_string(qqq.id[i]), 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k]); - plotter->Fill2D("RingCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); - plotter->Fill2D("WedgeCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); - - if (pc.index[k] < 24 && pc.e[k] > 50) - { - plotter->Fill2D("Timing_Difference_QQQ_PC", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); - plotter->Fill2D("DelT_Vs_QQQRingECal", 500, -2000, 2000, 1000, 0, 10, tRing - static_cast(pc.t[k]), eRingMeV, "hTiming"); - plotter->Fill2D("CalibratedQQQEvsPCE_R", 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); - plotter->Fill2D("CalibratedQQQEvsPCE_W", 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); - if (tRing - static_cast(pc.t[k]) < -150) // proton tests, 27Al - // if (tRing - static_cast(pc.t[k]) < -150 && tRing - static_cast(pc.t[k]) > -450) // 27Al - // if (tRing - static_cast(pc.t[k]) < -70 && tRing - static_cast(pc.t[k]) > -150) // 17F - { - PCQQQTimeCut = true; + std::unordered_map> qvecr[4], qvecw[4]; + if(qqq.multi>1) { + //if(qqq.multi>=3) std::cout << "-----" << std::endl; + for(int i=0; i= 24 && pc.e[k] > 50) - { - plotter->Fill2D("Timing_Difference_QQQ_PC_Cathode", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); - } - } // end of pc k loop - - if (!HitNonZero) - { - double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); - double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" - double x = rho * TMath::Cos(theta); - double y = rho * TMath::Sin(theta); - hitPos.SetXYZ(x, y, (qqqpos)); - qqqenergy = eRingMeV; - qqqtimestamp = tRing; - HitNonZero = true; } - } // if j==i - } // j loop end - } // i loop end - - plotter->Fill1D("QQQ_Multiplicity", 10, 0, 10, qqqCount, "hRawQQQ"); - - /*if(QQQ_Events.size()>=1) { - std::cout<< " ---->" << std::endl; - for(auto qe: QQQ_Events) { - std::cout << qe.ch1/16 << " " <> WireEvent; // this stores nearest neighbour wire events, or a 'cluster' - WireEvent aWireEvents, cWireEvents; // naming for book keeping - aWireEvents.clear(); - aWireEvents.reserve(24); - - // PC Gain Matching and Filling - double anodeT = -99999; - double cathodeT = 99999; - int anodeIndex = -1; - int cathodeIndex = -1; - for (int i = 0; i < pc.multi; i++) - { - if (pc.e[i] > 50) - { - plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast(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"); - } + bool PCSX3TimeCut = false; + bool PCASX3TimeCut = false; + bool PCCSX3TimeCut = false; + + bool PCQQQTimeCut = false; + bool PCAQQQTimeCut = false; + bool PCCQQQTimeCut = false; + for (int i = 0; i < qqq.multi; i++) { + plotter->Fill2D("QQQ_Index_Vs_Energy", 16 * 8, 0, 16 * 8, 2000, 0, 16000, qqq.index[i], qqq.e[i], "hRawQQQ"); - if (pc.index[i] < 24) - { - anodeT = static_cast(pc.t[i]); - anodeIndex = pc.index[i]; - aWireEvents[pc.index[i]] = std::tuple(pc.index[i], pc.e[i], static_cast(pc.t[i])); - } - else - { - cathodeT = static_cast(pc.t[i]); - cathodeIndex = pc.index[i] - 24; - cWireEvents[pc.index[i] - 24] = std::tuple(pc.index[i] - 24, pc.e[i], static_cast(pc.t[i])); - } - - if (anodeT != -99999 && cathodeT != 99999) - { - for (int j = 0; j < qqq.multi; j++) - { - plotter->Fill1D("PC_Time_qqq", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); - plotter->Fill2D("PC_Time_Vs_QQQ_ch", 200, -2000, 2000, 16 * 8, 0, 16 * 8, anodeT - cathodeT, qqq.ch[j], "hTiming"); - plotter->Fill2D("PC_Time_vs_AIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, anodeIndex, "hTiming"); - plotter->Fill2D("PC_Time_vs_CIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, cathodeIndex, "hTiming"); - // plotter->Fill1D("PC_Time_A" + std::to_string(anodeIndex) + "_C" + std::to_string(cathodeIndex), 200, -1000, 1000, anodeT - cathodeT, "TimingPC"); - } - - for (int j = 0; j < sx3.multi; j++) - { - plotter->Fill1D("PC_Time_sx3", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); - } - - plotter->Fill1D("PC_Time", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); - } - - for (int j = i + 1; j < pc.multi; j++) - { - plotter->Fill2D("PC_Coincidence_Matrix", 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); - plotter->Fill2D("PC_Coincidence_Matrix_anodeMinusCathode_lt_-200_" + std::to_string(anodeT - cathodeT < -200), 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); - plotter->Fill2D("Anode_V_Anode", 24, 0, 24, 24, 0, 24, pc.index[i], pc.index[j], "hGMPC"); - } - } - - anodeHits.clear(); - cathodeHits.clear(); - corrcatMax.clear(); - - int aID = 0; - int cID = 0; - double aE = 0; - double cE = 0; - double aESum = 0; - double cESum = 0; - double aEMax = 0; - int aIDMax = 0; - - for (int i = 0; i < pc.multi; i++) - { - // if (pc.e[i] > 100) - { - if (pc.index[i] < 24) - { - anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); - } - else if (pc.index[i] >= 24) - { - cathodeHits.push_back(std::pair(pc.index[i] - 24, pc.e[i])); - } - } - } - - std::sort(anodeHits.begin(), anodeHits.end(), [](std::pair a, std::pair b) - { return a.first < b.first; }); - std::sort(cathodeHits.begin(), cathodeHits.end(), [](std::pair a, std::pair b) - { return a.first < b.first; }); - - // clusters = collection of (collection of wires) where each wire is (index, energy, timestamp) - std::vector>> aClusters = pwinstance.Make_Clusters(aWireEvents); - std::vector>> cClusters = pwinstance.Make_Clusters(cWireEvents); - - std::vector> sumE_AC; - for (auto aCluster : aClusters) - { - for (auto cCluster : cClusters) - { - // if (aCluster.size() <= 1 && cCluster.size() <= 1) - // continue; - auto [crossover, alpha, apSumE, cpSumE, apMaxE, cpMaxE, apTSMaxE, cpTSMaxE] = pwinstance.FindCrossoverProperties(aCluster, cCluster); - if (alpha != 9999999 && apSumE != -1) - { - // Event PCEvent(crossover,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); - // Event PCEvent(crossover,apSumE,cpSumE,apTSMaxE,cpTSMaxE); - // Event PCEvent(crossover, apSumE, cpMaxE, apTSMaxE, cpTSMaxE); // run12 shows cathode-max and anode-sum provide best dE signals. - Event PCEvent(crossover, apSumE, cpMaxE, apTSMaxE, cpTSMaxE, aCluster.size(), cCluster.size()); // changed to include cluster size info --VS - // std::cout << apSumE << " " << crossover.Perp() << " " << apMaxE << " " << apTSMaxE << std::endl; - PC_Events.push_back(PCEvent); - sumE_AC.push_back(std::pair(apSumE, cpSumE)); - } - } - } - if (QQQ_Events.size() && PC_Events.size()) - plotter->Fill2D("PCEv_vs_QQQEv", 20, 0, 20, 20, 0, 20, QQQ_Events.size(), PC_Events.size()); - - for (auto pcevent : PC_Events) - { - for (auto sx3event : sx3Events) - { - plotter->Fill1D("dt_pcA_sx3B" + std::to_string(sx3event.ch2), 640, -2000, 2000, sx3event.Time1 - pcevent.Time1); - plotter->Fill1D("dt_pcC_sx3B" + std::to_string(sx3event.ch2), 640, -2000, 2000, sx3event.Time1 - pcevent.Time2); - plotter->Fill2D("dE_E_Anodesx3B", 400, 0, 10, 800, 0, 40000, sx3event.Energy1 * 0.001, pcevent.Energy1); - - plotter->Fill2D("dE_E_Cathodesx3B", 400, 0, 10, 800, 0, 10000, sx3event.Energy1 * 0.001, pcevent.Energy2); - double sx3z = sx3event.pos.Z() + (75.0 / 2.0) - 3.0; // w.r.t target origin at 90 for run12 - double sx3rho = 88.0; // approximate barrel radius - double sx3theta = TMath::ATan2(sx3rho, sx3z - vertexpos); - double pczguess = pcrad / TMath::Tan(sx3theta) + vertexpos; - plotter->Fill2D("pcz_vs_sx3pczguess", 300, 0, 200, 150, 0, 200, pczguess, pcevent.pos.Z()); - plotter->Fill2D("pcz_vs_sx3pczguess" + std::to_string(sx3event.ch2), 300, 0, 200, 150, 0, 200, pczguess, pcevent.pos.Z()); - plotter->Fill2D("pcz_vs_sx3z", 300, 0, 200, 150, 0, 200, sx3z, pcevent.pos.Z()); - } - } - - for (auto pcevent : PC_Events) - { - for (auto qqqevent : QQQ_Events) - { - plotter->Fill1D("dt_pcA_qqqR", 640, -2000, 2000, qqqevent.Time1 - pcevent.Time1); - plotter->Fill1D("dt_pcC_qqqW", 640, -2000, 2000, qqqevent.Time2 - pcevent.Time2); - plotter->Fill2D("dE_E_AnodeQQQR", 400, 0, 10, 800, 0, 40000, qqqevent.Energy1, pcevent.Energy1); - plotter->Fill2D("dE_E_CathodeQQQR", 400, 0, 10, 800, 0, 10000, qqqevent.Energy2, pcevent.Energy2); - double sinTheta = TMath::Sin((qqqevent.pos - TVector3(0, 0, vertexpos)).Theta()) / TMath::Sin((TVector3(51.5, 0, qqqpos) - TVector3(0, 0, vertexpos)).Theta()); - plotter->Fill2D("dE2_E_AnodeQQQR", 400, 0, 10, 800, 0, 40000, qqqevent.Energy1, pcevent.Energy1 * sinTheta); - plotter->Fill2D("dE2_E_CathodeQQQR", 400, 0, 10, 800, 0, 10000, qqqevent.Energy2, pcevent.Energy2 * sinTheta); - - if (qqqevent.pos.Phi() <= pcevent.pos.Phi() + TMath::Pi() / 4. && qqqevent.pos.Phi() >= pcevent.pos.Phi() - TMath::Pi() / 4.) - { - plotter->Fill1D("PCZ", 800, -200, 200, pcevent.pos.Z(), "phicut"); - double pcz_guess = pcrad / TMath::Tan((qqqevent.pos - TVector3(0, 0, vertexpos)).Theta()) + vertexpos; // this is ideally kept to be all QQQ+userinput for calibration of pcz - plotter->Fill2D("pczguess_vs_pc", 300, 0, 200, 150, 0, 200, pcz_guess, pcevent.pos.Z(), "phicut"); - plotter->Fill2D("pczguess_vs_pc_phi=" + std::to_string(qqqevent.pos.Phi() * 180. / M_PI), 300, 0, 200, 150, 0, 200, pcz_guess, pcevent.pos.Z(), "phicut"); - // plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); - } - - int aSize = pcevent.ch1; - int cSize = pcevent.ch2; - - if (cSize == 1) - { - if (aSize == 1) - plotter->Fill1D("pcz_a1c1Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize == 2) - plotter->Fill1D("pcz_a2c1Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize >= 3) - plotter->Fill1D("pcz_aNc1Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - } - else if (cSize == 2) - { - if (aSize == 1) - plotter->Fill1D("pcz_a1c2Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize == 2) - plotter->Fill1D("pcz_a2c2Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize >= 3) - plotter->Fill1D("pcz_aNc2Cluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - } - else if (cSize >= 3) - { - if (aSize == 1) - plotter->Fill1D("pcz_a1cNCluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize == 2) - plotter->Fill1D("pcz_a2cNCluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - else if (aSize >= 3) - plotter->Fill1D("pcz_aNcNCluster", 600, -300, 300, pcevent.pos.Z(), "hPCzQQQ"); - } - } - } - // HALFTIME! Can stop here in future versions - // return kTRUE; - - 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; - plotter->Fill2D("AnodeMax_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aIDMax, cID, "hRawPC"); - plotter->Fill2D("Anode_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aID, cID, "hRawPC"); - plotter->Fill2D("Anode_vs_CathodeE", 2000, 0, 30000, 2000, 0, 30000, aE, cE, "hGMPC"); - plotter->Fill2D("CathodeMult_V_CathodeE", 6, 0, 6, 2000, 0, 30000, cathodeHits.size(), cE, "hGMPC"); - for (int j = -4; j < 3; j++) - { - if ((aIDMax + 24 + j) % 24 == 23 - cID) - { - corrcatMax.push_back(std::pair(cID, cE)); - cESum += cE; - } - } - } - } - } - - TVector3 anodeIntersection, vector_closest_to_z; - anodeIntersection.Clear(); - vector_closest_to_z.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); - // << "Anode Intersection: " << anodeIntersection.X() << ", " << anodeIntersection.Y() << ", " << anodeIntersection.Z() << std::endl; - } - 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; - } - - for (double Tz = 60; Tz <= 100; Tz += 1.0) - { - TVector3 TargetPos(0, 0, Tz); - if (PCQQQPhiCut && anodeIntersection.Perp() > 0 && anodeIntersection.Z() != 0 && cathodeHits.size() >= 2) - { - plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 400, 0, 180, 90, 0, 90, (anodeIntersection - TargetPos).Theta() * 180. / TMath::Pi(), (hitPos - TargetPos).Theta() * 180. / TMath::Pi(), "TPosVariation"); - // plotter->Fill2D("R_ratio_to_Z_ratio" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 100, -2, 2, 100, -2, 2, (anodeIntersection - TargetPos).Z()/(hitPos-TargetPos).Z(), ((anodeIntersection - TargetPos).Perp()+2.5)/(hitPos-TargetPos).Perp(), "TPosVariation"); - } - } - - if (anodeIntersection.Z() != 0 && anodeIntersection.Perp() > 0 && HitNonZero) - { - 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)+ "_PC"+std::to_string(PCQQQPhiCut), 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, -1300, 1300, pw_contr.GetZ0()); - plotter->Fill1D("VertexRecon_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); - - if (cathodeHits.size() == 2) - plotter->Fill1D("VertexRecon_2c_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); - - TVector3 x2(anodeIntersection), x1(hitPos); - - TVector3 v = x2 - x1; - double t_minimum = -1.0 * (x1.X() * v.X() + x1.Y() * v.Y()) / (v.X() * v.X() + v.Y() * v.Y()); - vector_closest_to_z = x1 + t_minimum * v; - - plotter->Fill1D("VertexRecon_Z_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(), "customVertex"); - if (vector_closest_to_z.Perp() < 20) - { - plotter->Fill1D("VertexRecon_RadialCut_Z_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(), "customVertex"); - } - - plotter->Fill2D("VertexRecon_XY_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 100, -100, 100, 100, -100, 100, vector_closest_to_z.X(), vector_closest_to_z.Y(), "customVertex"); - if (cathodeHits.size() == 2) - { - plotter->Fill1D("VertexRecon2C_Z_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(), "customVertex"); - if (vector_closest_to_z.Perp() < 20) - { - plotter->Fill1D("VertexRecon2C_RadialCut_Z_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(), "customVertex"); - } - plotter->Fill2D("VertexRecon2C_XY_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 100, -100, 100, 100, -100, 100, vector_closest_to_z.X(), vector_closest_to_z.Y(), "customVertex"); - plotter->Fill2D("VertexRecon2C_RhoZ_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 100, -100, 100, 600, -1300, 1300, vector_closest_to_z.Perp(), vector_closest_to_z.Z(), "customVertex"); - plotter->Fill2D("VertexRecon2C_Z_vs_QQQE_TC" + std::to_string(PCQQQTimeCut) + "_PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, 800, 0, 20000, vector_closest_to_z.Z(), qqqenergy, "customVertex"); - } - } - - for (int i = 0; i < qqq.multi; i++) - { - if (anodeIntersection.Perp() > 0) - { // suppress x,y=0,0 events - 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(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(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"); + for (int j = 0; j < qqq.multi; j++) { + if (j == i) + continue; + plotter->Fill2D("QQQ_Coincidence_Matrix", 16 * 8, 0, 16 * 8, 16 * 8, 0, 16 * 8, qqq.index[i], qqq.index[j], "hRawQQQ"); } - 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"); + for (int k = 0; k < pc.multi; k++) { + if (pc.index[k] < 24 && pc.e[k] > 10) { + plotter->Fill2D("QQQ_Vs_Anode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + plotter->Fill2D("QQQ_Vs_PC_Index", 16 * 8, 0, 16 * 8, 24, 0, 24, qqq.index[i], pc.index[k], "hRawQQQ"); + } + else if (pc.index[k] >= 24 && pc.e[k] > 10) { + plotter->Fill2D("QQQ_Vs_Cathode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + } } - plotter->Fill2D("VertexRecon_QQQRingTC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, 16, 0, 16, vector_closest_to_z.Z(), 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 j = i + 1; j < qqq.multi; j++) { + if (qqq.id[i] == qqq.id[j]) { + qqqCount++; - for (int k = 0; k < pc.multi; k++) + 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(qqq.t[j]); + tWedge = static_cast(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(qqq.t[i]); + tWedge = static_cast(qqq.t[j]); + } + else + continue; + + plotter->Fill1D("Wedgetime_Vs_Ringtime", 100, -1000, 1000, tWedge - tRing, "hTiming"); + plotter->Fill2D("RingE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chRing + qqq.id[i] * 16, eRing, "hRawQQQ"); + plotter->Fill2D("WedgeE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chWedge + qqq.id[i] * 16, eWedge, "hRawQQQ"); + + 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; + + if(eRingMeV/eWedgeMeV > 3.0 || eRingMeV/eWedgeMeV<1.0/3.0) continue; + double theta = 2 * TMath::Pi() * (-qqq.id[i] * 16 + (15-chWedge) + 0.5)/(16*4); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + //z used to be 75+30+23=128 + //we found a 12mm shift towards the vertex later --> 116 + Event qqqevent(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),qqq_z), eRingMeV, eWedgeMeV, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + Event qqqeventr(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),qqq_z), eRing, eWedge, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + if(qqq.id[i]>=1) { + QQQ_Events.push_back(qqqevent); + QQQ_Events_Raw.push_back(qqqeventr); + } + plotter->Fill2D("QQQCartesianPlot", 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + plotter->Fill2D("QQQCartesianPlot" + std::to_string(qqq.id[i]), 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + else + continue; + + plotter->Fill2D("WedgeE_Vs_RingECal", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + plotter->Fill2D("WedgeE_Vs_RingECal_selected", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + + for (int k = 0; k < pc.multi; k++) + { + plotter->Fill2D("RingCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index" + std::to_string(qqq.id[i]), 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k]); + plotter->Fill2D("RingCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + + if (pc.index[k] < 24 && pc.e[k] > 10) + { + plotter->Fill2D("Timing_Difference_QQQ_PC", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + plotter->Fill2D("DelT_Vs_QQQRingECal", 500, -2000, 2000, 1000, 0, 10, tRing - static_cast(pc.t[k]), eRingMeV, "hTiming"); + plotter->Fill2D("CalibratedQQQEvsPCE_R", 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQEvsPCE_W", 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + if (tRing - static_cast(pc.t[k]) < -150) // proton tests, 27Al + { + PCAQQQTimeCut = true; + } + } + + if (pc.index[k] >= 24 && pc.e[k] > 10) { + if (tRing - static_cast(pc.t[k]) < -200) PCCQQQTimeCut = true; + plotter->Fill2D("Timing_Difference_QQQ_PC_Cathode", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + } + } //end of pc k loop + + if (!HitNonZero) { + //double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); + //double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + double theta = 2 * TMath::Pi() * (-qqq.id[i] * 16 + (15-chWedge) + 0.5)/(16*4); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + + double x = rho * TMath::Cos(theta); + double y = rho * TMath::Sin(theta); + hitPos.SetXYZ(x, y, qqq_z); + if(realtime) qqqg->SetPoint(0,hitPos.X(),hitPos.Y(),hitPos.Z()); + qqqenergy = eRingMeV; + qqqtimestamp = tRing; + HitNonZero = true; + } + } // if j==i + } //j loop end + } //i loop end + + PCQQQTimeCut = PCAQQQTimeCut && PCCQQQTimeCut; + plotter->Fill1D("QQQ_Multiplicity", 10, 0, 10, qqqCount, "hRawQQQ"); + + + typedef std::unordered_map> WireEvent; //this stores nearest neighbour wire events, or a 'cluster' + WireEvent aWireEvents, cWireEvents; //naming for book keeping + aWireEvents.clear(); + aWireEvents.reserve(24); + if(realtime) { + hha->Reset(); + hhc->Reset(); + } + // PC Gain Matching and Filling + double anodeT = -99999; + double cathodeT = 99999; + int anodeIndex = -1; + int cathodeIndex = -1; + for (int i = 0; i < pc.multi; i++) + { + //std::cout << pc.index[i] << " " << pc.e[i] << " " << std::endl; + if (pc.e[i] > 10) { - if (pc.index[k] >= 24) + plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast(pc.e[i]), "hRawPC"); + } else { continue; - - // double sinTheta = TMath::Sin((hitPos-vector_closest_to_z).Theta()); - double sinTheta = TMath::Sin((anodeIntersection - TVector3(0, 0, 90.0)).Theta()); - // double sinTheta = TMath::Sin((anodeIntersection-vector_closest_to_z).Theta()); - // double sinTheta = TMath::Sin((hitPos-TVector3(0,0,30.0)).Theta()); - // double sinTheta = TMath::Sin(hitPos.Theta()); - - if (cathodeHits.size() == 2 && PCQQQPhiCut) - { - plotter->Fill2D("CalibratedQQQE_RvsCPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k] * sinTheta, "hPCQQQ"); - plotter->Fill2D("CalibratedQQQE_WvsCPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k] * sinTheta, "hPCQQQ"); - plotter->Fill2D("CalibratedQQQE_RvsPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); - plotter->Fill2D("CalibratedQQQE_WvsPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); - plotter->Fill2D("PCQQQ_dTimevsdPhi", 200, -2000, 2000, 80, -200, 200, tRing - static_cast(pc.t[k]), (hitPos.Phi() - anodeIntersection.Phi()) * 180. / TMath::Pi(), "hTiming"); - } } - } /// qqq i==j case end - } // j loop end - } // qqq i loop end - TVector3 guessVertex(0, 0, 90.); // for run12, subtract anodeIntersection.Z() by ~74.0 seems to work - // rho=40.0 mm is halfway between the cathodes(rho=42) and anodes(rho=37) - double pcz_guess = 42.0 / TMath::Tan((hitPos - guessVertex).Theta()) + guessVertex.Z(); // this is ideally kept to be all QQQ+userinput for calibration of pcz - if (PCQQQTimeCut && PCQQQPhiCut && hitPos.Perp() > 0 && anodeIntersection.Perp() > 0 && cathodeHits.size() >= 2) - { - plotter->Fill2D("pczguess_vs_qqqE", 100, 0, 200, 800, 0, 20, pcz_guess, qqqenergy, "pczguess"); - double pczoffset = 30.0; - // plotter->Fill2D("pczguess_vs_pcz_rad="+std::to_string(hitPos.Perp()),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z(),"pczguess"); //entirely qqq-derived position vs entirely PC derived position - plotter->Fill2D("pczguess_vs_pcz_phi=" + std::to_string(hitPos.Phi() * 180. / M_PI), 100, 0, 200, 150, 0, 200, pcz_guess, anodeIntersection.Z() + pczoffset, "pczguess"); // entirely qqq-derived position vs entirely PC derived position - plotter->Fill2D("pczguess_vs_pcz", 100, 0, 200, 150, 0, 200, pcz_guess, anodeIntersection.Z() + pczoffset); - plotter->Fill2D("pcz_vs_pcPhi_rad=" + std::to_string(hitPos.Perp()), 360, 0, 360, 150, 0, 200, anodeIntersection.Phi() * 180. / M_PI, anodeIntersection.Z() + pczoffset, "pczguess"); - } - for (int i = 0; i < sx3.multi; i++) - { - // plotting sx3 strip hits vs anode phi - if (sx3.ch[i] < 8 && anodeIntersection.Perp() > 0) - plotter->Fill2D("PCPhi_vs_SX3Strip", 100, -200, 200, 8 * 24, 0, 8 * 24, anodeIntersection.Phi() * 180. / TMath::Pi(), sx3.id[i] * 8 + sx3.ch[i]); - } + 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 (anodeIntersection.Z() != 0 && cathodeHits.size() == 3) - { - plotter->Fill1D("PC_Z_proj_3C", 600, -300, 300, anodeIntersection.Z(), "hPCzQQQ"); - } + if (pc.index[i] < 24) + { + anodeT = static_cast(pc.t[i]); + anodeIndex = pc.index[i]; + aWireEvents[pc.index[i]] = std::tuple(pc.index[i],pc.e[i],static_cast(pc.t[i])); + if(realtime) hha->SetBinContent(hha->FindFixBin(anodeIndex),pc.e[i]); + } + else + { + cathodeT = static_cast(pc.t[i]); + cathodeIndex = pc.index[i] - 24; + cWireEvents[pc.index[i]-24] = std::tuple(pc.index[i]-24,pc.e[i],static_cast(pc.t[i])); + if(realtime) hhc->SetBinContent(hhc->FindFixBin(cathodeIndex),pc.e[i]); + } - 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 (anodeT != -99999 && cathodeT != 99999) + { + for (int j = 0; j < qqq.multi; j++) + { + plotter->Fill1D("PC_Time_qqq", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + plotter->Fill2D("PC_Time_Vs_QQQ_ch", 200, -2000, 2000, 16 * 8, 0, 16 * 8, anodeT - cathodeT, qqq.ch[j], "hTiming"); + plotter->Fill2D("PC_Time_vs_AIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, anodeIndex, "hTiming"); + plotter->Fill2D("PC_Time_vs_CIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, cathodeIndex, "hTiming"); + // plotter->Fill1D("PC_Time_A" + std::to_string(anodeIndex) + "_C" + std::to_string(cathodeIndex), 200, -1000, 1000, anodeT - cathodeT, "TimingPC"); + } - if (anodeHits.size() < 1) - { - plotter->Fill1D("NoAnodeHits_CathodeHits", 6, 0, 5, cathodeHits.size(), "hGMPC"); - } + for (int j = 0; j < sx3.multi; j++) + { + plotter->Fill1D("PC_Time_sx3", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } - return kTRUE; + plotter->Fill1D("PC_Time", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + for (int j = i + 1; j < pc.multi; j++) + { + plotter->Fill2D("PC_Coincidence_Matrix", 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("PC_Coincidence_Matrix_anodeMinusCathode_lt_-200_" + std::to_string(anodeT - cathodeT < -200), 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("Anode_V_Anode", 24, 0, 24, 24, 0, 24, pc.index[i], pc.index[j], "hGMPC"); + } + } + anodeHits.clear(); + cathodeHits.clear(); + corrcatMax.clear(); + + int aID = 0; + int cID = 0; + double aE = 0; + double cE = 0; + double aESum = 0; + double cESum = 0; + double aEMax = 0; + double cEMax = 0; + int aIDMax = 0; + int cIDMax = 0; + + for (int i = 0; i < pc.multi; i++) { + // if (pc.e[i] > 100) + { + if (pc.index[i] < 24) { + anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); + } + else if (pc.index[i] >= 24) { + cathodeHits.push_back(std::pair(pc.index[i] - 24, pc.e[i])); + } + } + } + + std::sort(anodeHits.begin(),anodeHits.end(),[](std::pair a, std::pair b) { + return a.first < b.first; + }); + + std::sort(cathodeHits.begin(),cathodeHits.end(),[](std::pair a, std::pair b) { + return a.first < b.first; + }); + + //clusters = collection of (collection of wires) where each wire is (index, energy, timestamp) + std::vector>> aClusters = pwinstance.Make_Clusters(aWireEvents); + std::vector>> cClusters = pwinstance.Make_Clusters(cWireEvents); + + std::vector> sumE_AC; + for(auto aCluster: aClusters) { + for(auto cCluster: cClusters) { + if(aCluster.size() ==0 ) continue; + if(cCluster.size() ==0 ) continue; + //both have at least 1, here. Keep the a1, c1 events + auto [crossover,alpha,apSumE,cpSumE,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE] = pwinstance.FindCrossoverProperties(aCluster, cCluster); + if(alpha!=9999999 && apSumE!=-1) { + //Event PCEvent(crossover,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); + //Event PCEvent(crossover,apSumE,cpSumE,apTSMaxE,cpTSMaxE); + Event PCEvent(crossover,apSumE,cpMaxE,apTSMaxE,cpTSMaxE); //run12 shows cathode-max and anode-sum provide best dE signals. + //std::cout << apSumE << " " << crossover.Perp() << " " << apMaxE << " " << apTSMaxE << std::endl; + //PCEvent.multi1=aCluster.size(); + //PCEvent.multi2=cCluster.size(); + PC_Events.push_back(PCEvent); + sumE_AC.push_back(std::pair(apSumE,cpSumE)); + } + } + } + if(QQQ_Events.size() && PC_Events.size()) + plotter->Fill2D("PCEv_vs_QQQEv",20,0,20,20,0,20,QQQ_Events.size(),PC_Events.size()); + + plotter->Fill2D("ac_vs_cc",20,0,20,20,0,20,aClusters.size(),cClusters.size(),"wiremult"); + for(auto cluster: aClusters) { + plotter->Fill1D("aClusters"+std::to_string(aClusters.size()),20,-5,15,cluster.size(),"wiremult"); + } + for(auto cluster: cClusters) { + plotter->Fill1D("cClusters"+std::to_string(cClusters.size()),20,-5,15,cluster.size(),"wiremult"); + } + + if(cClusters.size() && aClusters.size()) { + plotter->Fill2D("ac_vs_cc_ign0",20,0,20,20,0,20,aClusters.size(),cClusters.size(),"wiremult"); + } + + for(auto pcevent:PC_Events) { + if(aClusters.size()==1 && cClusters.size() == 1) { + //plotter->Fill1D("pcz_a"+std::to_string(aClusters.at(0).size())+"_c"+std::to_string(cClusters.at(0).size()),800,-200,200,pcevent.pos.Z(),"wiremult"); + std::string detid="_+_"; + if(sx3Events.size()) detid="+sx3"; + if(QQQ_Events.size()) detid="+qqq"; + plotter->Fill1D("pcz_a"+std::to_string(aClusters.at(0).size())+"_c"+std::to_string(cClusters.at(0).size())+detid,800,-200,200,pcevent.pos.Z(),"wiremult"); + } + + PCSX3TimeCut=false; + for(auto sx3event:sx3Events) { + plotter->Fill1D("dt_pcA_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time1,"hTiming"); + plotter->Fill1D("dt_pcC_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time2,"hTiming"); + if(sx3event.Time1 - pcevent.Time1 < 0)//-150 for alphas + PCASX3TimeCut = 1; + if(sx3event.Time1 - pcevent.Time2 < 0)//-200 for alphas + PCCSX3TimeCut = 1; + PCSX3TimeCut = PCASX3TimeCut && PCCSX3TimeCut; + + plotter->Fill1D("dt_pcA_sx3B",640,-2000,2000,sx3event.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_sx3B",640,-2000,2000,sx3event.Time1 - pcevent.Time2); + plotter->Fill2D("dE_E_Anodesx3B",400,0,10,800,0,40000,sx3event.Energy1*0.001,pcevent.Energy1); + plotter->Fill2D("dE_E_Cathodesx3B",400,0,10,800,0,10000,sx3event.Energy1*0.001,pcevent.Energy2); + plotter->Fill2D("sx3phi_vs_pcphi"+std::to_string(sx3event.Time1 - pcevent.Time1<-150),100,-360,360,100,-360,360,sx3event.pos.Phi()*180/M_PI,pcevent.pos.Phi()*180/M_PI); + if(PCSX3TimeCut) { + plotter->Fill2D("xyplot_sx3"+std::to_string(sx3event.ch2/4),100,-100,100,100,-100,100,sx3event.pos.X(),sx3event.pos.Y()); + plotter->Fill2D("xyplot_sx3"+std::to_string(sx3event.ch2/4),100,-100,100,100,-100,100,pcevent.pos.X(),pcevent.pos.Y()); + } + double sx3rho = 88.0;//approximate barrel radius + double sx3z = sx3event.pos.Z()+(75.0/2.0)-3.0; //w.r.t target origin at 90 for run12 + double pcz = pcevent.pos.Z(); + double calcsx3theta = TMath::ATan2(sx3rho-z_to_crossover_rho(pcz),sx3z-pcz); + plotter->Fill2D("dE2_E_Anodesx3B",400,0,10,800,0,40000,sx3event.Energy1*0.001,pcevent.Energy1*TMath::Sin(calcsx3theta)); + plotter->Fill2D("dE2_E_Cathodesx3B",400,0,10,800,0,10000,sx3event.Energy1*0.001,pcevent.Energy2*TMath::Sin(calcsx3theta)); + + + double sx3theta = TMath::ATan2(sx3rho,sx3z-source_vertex); + double pczguess = 37.0/TMath::Tan(sx3theta) + source_vertex; + double pcz_guess_int = z_to_crossover_rho(pcevent.pos.Z())/TMath::Tan(sx3theta) + source_vertex; + double sinTheta = TMath::Sin(sx3theta); + + TVector3 x2(pcevent.pos), x1(sx3event.pos); + TVector3 v = x2-x1; + double t_minimum = -1.0*(x1.X()*v.X()+x1.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + TVector3 vector_closest_to_z_sx3 = x1 + t_minimum*v; + plotter->Fill1D("VertexReconZ_SX3"+std::to_string(PCSX3TimeCut),600,-1300,1300,vector_closest_to_z_sx3.Z(),"hPCZSX3"); + plotter->Fill2D("VertexReconXY_SX3"+std::to_string(PCSX3TimeCut),100,-100,100,100,-100,100,vector_closest_to_z_sx3.X(),vector_closest_to_z_sx3.Y(),"hPCZSX3"); + + plotter->Fill2D("pcz_vs_sx3pczguess",300,0,200,600,-200,200,pczguess,pcevent.pos.Z()); //x-axis is all Si det, y-axis is PC anode+cathode only + plotter->Fill2D("pcz_vs_sx3pczguess_int",300,0,200,600,-200,200,pcz_guess_int,pcevent.pos.Z()); //x-axis is all Si det, y-axis is PC anode+cathode only + //plotter->Fill2D("pcz_vs_sx3pczguess_strip"+std::to_string(sx3event.ch2),300,0,200,600,-200,200,pczguess,pcevent.pos.Z()); + plotter->Fill2D("pcz_vs_sx3pczguess_phi"+std::to_string(sx3event.pos.Phi()*180/M_PI),300,0,200,600,-200,200,pczguess,pcevent.pos.Z()); + /*for(auto cc: cClusters) + for(auto ac: aClusters) { + plotter->Fill2D("pcz_sx3_phicut_a"+std::to_string(ac.size())+"_c"+std::to_string(cc.size())+"_sx3guess",300,0,200,600,-200,200,sx3z,pcevent.pos.Z(),"hPCZSX3"); + if(ac.size()==2 && cc.size()==1) { + plotter->Fill2D("pcz_sx3_phicut_a("+std::to_string(std::get<0>(ac.at(0)))+","+std::to_string(std::get<0>(ac.at(1)))+")_c"+std::to_string(std::get<0>(cc.at(0)))+"_sx3guess",300,0,200,600,-200,200,sx3z,pcevent.pos.Z(),"hPCZSX3"); + plotter->Fill2D("a2c1_vs_sx3_strip",24,0,24,64,0,64,0.5*(std::get<0>(ac.at(0))+std::get<0>(ac.at(1))),sx3event.ch2,"hPCZSX3"); + plotter->Fill2D("sx3phi_vs_pcphi"+std::to_string(sx3event.Time1 - pcevent.Time1<-150)+"_a("+std::to_string(std::get<0>(ac.at(0)))+","+std::to_string(std::get<0>(ac.at(1)))+")_c"+std::to_string(std::get<0>(cc.at(0))),100,-360,360,100,-360,360,sx3event.pos.Phi()*180/M_PI,pcevent.pos.Phi()*180/M_PI); + } + if(cc.size()==2 && ac.size()==1) { + plotter->Fill2D("pcz_sx3_phicut_c("+std::to_string(std::get<0>(cc.at(0)))+","+std::to_string(std::get<0>(cc.at(1)))+")_a"+std::to_string(std::get<0>(ac.at(0)))+"_sx3guess",300,0,200,600,-200,200,sx3z,pcevent.pos.Z(),"hPCZSX3"); + plotter->Fill2D("c2a1_vs_sx3_strip",24,0,24,64,0,64,0.5*(std::get<0>(cc.at(0))+std::get<0>(cc.at(1))),sx3event.ch2,"hPCZSX3"); + plotter->Fill2D("sx3phi_vs_pcphi"+std::to_string(sx3event.Time1 - pcevent.Time1<-150)+"_c("+std::to_string(std::get<0>(cc.at(0)))+","+std::to_string(std::get<0>(cc.at(1)))+")_a"+std::to_string(std::get<0>(ac.at(0))),100,-360,360,100,-360,360,sx3event.pos.Phi()*180/M_PI,pcevent.pos.Phi()*180/M_PI); + } + }*/ + + + plotter->Fill2D("pcz_vs_sx3z",300,0,200,600,-400,400,sx3z,pcevent.pos.Z()); + plotter->Fill2D("sx3E_vs_sx3z"+std::to_string(sx3event.ch2),400,0,10,300,0,200,sx3event.Energy1*0.001,sx3z); + plotter->Fill2D("pcdEA_vs_sx3z",800,0,20000,300,0,200,pcevent.Energy1,sx3z); + plotter->Fill2D("pcdE2A_vs_sx3z",800,0,20000,300,0,200,pcevent.Energy1*sinTheta,sx3z); + plotter->Fill2D("pcdEC_vs_sx3z",800,0,20000,300,0,200,pcevent.Energy2,sx3z); + plotter->Fill2D("pcdE2C_vs_sx3z",800,0,20000,300,0,200,pcevent.Energy2*sinTheta,sx3z); + plotter->Fill2D("phi_vs_stripnum",180,-180,180,48,0,48,pcevent.pos.Phi()*180./M_PI,sx3event.ch2); + plotter->Fill2D("E_theta_AnodeSX3",200,80,180,300,0,15,sx3theta*180/M_PI,sx3event.Energy1*0.001); + } + if(PCSX3TimeCut) { + plotter->Fill1D("PCZ_sx3",800,-200,200,pcevent.pos.Z(),"hPCZSX3"); + plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + for(auto cc: cClusters) + for(auto ac: aClusters) { + plotter->Fill1D("PCZsx3_phicut_a"+std::to_string(ac.size())+"_c"+std::to_string(cc.size()),800,-200,200,pcevent.pos.Z(),"hPCZSX3"); + } + } + } + + for(auto pcevent: PC_Events) { + for(auto qqqevent: QQQ_Events) { + plotter->Fill1D("dt_pcA_qqqR",640,-2000,2000,qqqevent.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_qqqW",640,-2000,2000,qqqevent.Time2 - pcevent.Time2); + plotter->Fill2D("phiPC_vs_phiQQQ",180,-360,360,180,-360,360,qqqevent.pos.Phi()*180/M_PI,pcevent.pos.Phi()*180/M_PI); + double sinTheta = TMath::Sin((qqqevent.pos - TVector3(0,0,source_vertex)).Theta());///TMath::Sin((TVector3(51.5,0,128.) - TVector3(0,0,85)).Theta()); + if((qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI > 52) { + plotter->Fill2D("dE2_E_AnodeQQQR_outer",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1*sinTheta); + plotter->Fill2D("dE2_E_CathodeQQQR_outer",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2*sinTheta); + plotter->Fill2D("dE_E_AnodeQQQR_outer",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1); + plotter->Fill2D("dE_E_CathodeQQQR_outer",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2); + } else { + plotter->Fill2D("dE2_E_AnodeQQQR_inner",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1*sinTheta); + plotter->Fill2D("dE2_E_CathodeQQQR_inner",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2*sinTheta); + plotter->Fill2D("dE_E_AnodeQQQR_inner",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1); + plotter->Fill2D("dE_E_CathodeQQQR_inner",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2); + } + + bool timecut = (qqqevent.Time1 - pcevent.Time1 < -150); + if(timecut) {// && qqqevent.pos.Phi() <= pcevent.pos.Phi()+TMath::Pi()/4. && qqqevent.pos.Phi() >= pcevent.pos.Phi()-TMath::Pi()/4. ) { + plotter->Fill2D("dE_theta_AnodeQQQR",75,0,90,400,0,20000,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,pcevent.Energy1); + plotter->Fill2D("dE2_theta_AnodeQQQR",75,0,90,400,0,20000,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,pcevent.Energy1*sinTheta); + + plotter->Fill2D("E_theta_AnodeQQQR",75,0,90,300,0,15,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,qqqevent.Energy1); + plotter->Fill2D("E2_theta_AnodeQQQR",75,0,90,300,0,15,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,qqqevent.Energy1); + plotter->Fill2D("Etot2_theta_AnodeQQQR",75,0,90,300,0,15,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,qqqevent.Energy1+pcevent.Energy1*anode_gain*sinTheta); + + plotter->Fill2D("dE_theta_CathodeQQQR",75,0,90,800,0,10000,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,pcevent.Energy2); + plotter->Fill2D("dE2_theta_CathodeQQQR",75,0,90,800,0,10000,(qqqevent.pos - TVector3(0,0,source_vertex)).Theta()*180/M_PI,pcevent.Energy2*sinTheta); + + plotter->Fill2D("dE_phi_AnodeQQQR",100,-180,180,800,0,40000,(qqqevent.pos - TVector3(0,0,source_vertex)).Phi()*180/M_PI,pcevent.Energy1); + + plotter->Fill2D("dE_phi_CathodeQQQR",100,-180,180,800,0,10000,(qqqevent.pos - TVector3(0,0,source_vertex)).Phi()*180/M_PI,pcevent.Energy2); + plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + plotter->Fill1D("PCZ_phicut_a"+std::to_string(aClusters.at(0).size())+"_c"+std::to_string(cClusters.at(0).size()),800,-200,200,pcevent.pos.Z(),"wiremult"); + + double pcz_guess_37 = 37./TMath::Tan((qqqevent.pos-TVector3(0,0,source_vertex)).Theta()) + source_vertex; + plotter->Fill2D("pczguess_vs_pc_37",180,0,200,150,0,200,pcz_guess_37,pcevent.pos.Z(),"phicut"); + + double pcz_guess_42 = 42./TMath::Tan((qqqevent.pos-TVector3(0,0,source_vertex)).Theta()) + source_vertex; + plotter->Fill2D("pczguess_vs_pc_42",180,0,200,150,0,200,pcz_guess_42,pcevent.pos.Z(),"phicut"); + + double pcz_guess_int = z_to_crossover_rho(pcevent.pos.Z())/TMath::Tan((qqqevent.pos-TVector3(0,0,source_vertex)).Theta()) + source_vertex; + //plotter->Fill2D("pczguess_vs_pc_int",180,0,200,150,0,200,pcz_guess_int,pcevent.pos.Z(),"phicut"); + plotter->Fill2D("pczguess_vs_pc_int",180,0,200,600,-400,400,pcz_guess_int,pcevent.pos.Z(),"phicut"); + + double qqqrho = qqqevent.pos.Perp(); + double qqqz = (qqqevent.pos - TVector3(0,0,source_vertex)).Z(); + double tan_theta = qqqrho/qqqz; + double pcz_guess_int2 = z_to_crossover_rho(pcevent.pos.Z())/tan_theta + source_vertex; + plotter->Fill2D("pczguess_vs_pc_int2",180,0,200,150,0,200,pcz_guess_int2,pcevent.pos.Z(),"phicut"); + plotter->Fill2D("pczguess_vs_pc_int2_a"+std::to_string(pcevent.multi1)+"_c"+std::to_string(pcevent.multi2),180,0,200,150,0,200,pcz_guess_int2,pcevent.pos.Z(),"phicut"); + + + double pcz_guess = pcz_guess_int; + plotter->Fill2D("pctheta_vs_qqqtheta",320,0,160,320,0,160,(qqqevent.pos-TVector3(0,0,source_vertex)).Theta()*180/M_PI,(pcevent.pos-TVector3(0,0,source_vertex)).Theta()*180/M_PI,"phicut"); + + plotter->Fill2D("pczguess_vs_pc_phi="+std::to_string(qqqevent.pos.Phi()*180./M_PI),300,0,200,150,0,200,pcz_guess,pcevent.pos.Z(),"phicut"); + + //plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + } + } + } + //HALFTIME! Can stop here in future versions + + 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; + plotter->Fill2D("AnodeMax_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aIDMax, cID, "hRawPC"); + plotter->Fill2D("Anode_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aID, cID, "hRawPC"); + plotter->Fill2D("Anode_vs_CathodeE", 2000, 0, 30000, 2000, 0, 30000, aE, cE, "hGMPC"); + plotter->Fill2D("CathodeMult_V_CathodeE", 6, 0, 6, 2000, 0, 30000, cathodeHits.size(), cE, "hGMPC"); + /*for (int j = -4; j < 3; j++) + { + if ((aIDMax + 24 + j) % 24 == 23 - cID) + { + corrcatMax.push_back(std::pair(cID, cE)); + cESum += cE; + } + }*/ + if((aIDMax + cID)%24 == 22 || (aIDMax + cID)%24==23 || (aIDMax + cID)%24>=0 || (aIDMax + cID)%24<=3 ) { + corrcatMax.push_back(std::pair(cID, cE)); + cESum += cE; + if(cE > cEMax) { + cEMax = cE; + cIDMax = cID; + } + } + } + } + } + + TVector3 anodeIntersection,vector_closest_to_z; + anodeIntersection.Clear(); + vector_closest_to_z.Clear(); + if (corrcatMax.size() > 0) + { + double x = 0, y = 0, z = 0; + for (const auto &corr : corrcatMax) + { + if (pwinstance.Crossover[aIDMax][corr.first][0].z > 9000000) + continue; + if (cESum > 0) + { + x += (corr.second) / cESum * pwinstance.Crossover[aIDMax][corr.first][0].x; + y += (corr.second) / cESum * pwinstance.Crossover[aIDMax][corr.first][0].y; + z += (corr.second) / cESum * pwinstance.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); + if(realtime) { + crossoverg->SetPoint(0,x,y,z); + } + //std::cout << "Anode Intersection: " << anodeIntersection.X() << ", " << anodeIntersection.Y() << ", " << anodeIntersection.Z() << " " << aIDMax << std::endl; + } + } + 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(anodeIndex!=-1 && cathodeIndex !=-1 && hitPos.Perp()!=0 && anodeIntersection.Perp()!=0 && realtime && PCQQQPhiCut && PCQQQTimeCut) { + can1->Modified(); + can1->Update(); + TVector3 x2(anodeIntersection); + TVector3 x1(hitPos); + TVector3 v = x2-x1; + double t_minimum = -1.0*(x1.X()*v.X()+x1.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + TVector3 r_rhoMin = x1 + t_minimum*v; + + trajectory->SetPoint(0,x1.X(),x1.Y(),x1.Z()); + trajectory->SetPoint(1,r_rhoMin.X(),r_rhoMin.Y(),r_rhoMin.Z()); + + for(auto cath: corrcatMax) { + plc[cath.first]->SetLineWidth(3); + //plc[cath.first]->SetLineStyle(kLine); + } + for(auto anodeW: anodeHits) { + pla[anodeW.first]->SetLineWidth(3); + //pla[anodeW.first]->SetLineStyle(kLine); + } + //can2->Modified(); + can2->Update(); + while(can1->WaitPrimitive()); + //pla[anodeIndex]->SetLineWidth(1); + //pla[anodeIndex]->SetLineStyle(kDotted); + for(auto anodeW: anodeHits) { + pla[anodeW.first]->SetLineWidth(1); + pla[anodeW.first]->SetLineStyle(kDotted); + } + for(auto cath: corrcatMax) { + plc[cathodeIndex]->SetLineStyle(kDotted); + plc[cath.first]->SetLineWidth(1); + } + + } + + //for (double Tz = 60; Tz <= 100; Tz += 1.0) + //{ + // TVector3 TargetPos(0, 0, Tz); + //if(PCQQQPhiCut && anodeIntersection.Perp()>0 && anodeIntersection.Z()!=0 && cathodeHits.size()>=2) { + //plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 400, 0, 180, 90, 0, 90, (anodeIntersection - TargetPos).Theta() * 180. / TMath::Pi(), (hitPos - TargetPos).Theta() * 180. / TMath::Pi(), "TPosVariation"); + //plotter->Fill2D("R_ratio_to_Z_ratio" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 100, -2, 2, 100, -2, 2, (anodeIntersection - TargetPos).Z()/(hitPos-TargetPos).Z(), ((anodeIntersection - TargetPos).Perp()+2.5)/(hitPos-TargetPos).Perp(), "TPosVariation"); + //} + //} + + if (anodeIntersection.Z() != 0 && anodeIntersection.Perp()>0 && HitNonZero) + { + 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)+ "_PC"+std::to_string(PCQQQPhiCut), 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 && anodeIntersection.Perp() > 0 && PCSX3TimeCut) { + plotter->Fill1D("PC_Z_Projection_sx3", 600, -200, 200, anodeIntersection.Z(), "hPCZSX3"); + } + 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, -1300, 1300, pw_contr.GetZ0()); + plotter->Fill1D("VertexRecon_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + if (cathodeHits.size() == 2) + plotter->Fill1D("VertexRecon_2c_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + TVector3 x2(anodeIntersection), x1(hitPos); + + TVector3 v = x2-x1; + double t_minimum = -1.0*(x1.X()*v.X()+x1.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + vector_closest_to_z = x1 + t_minimum*v; + + plotter->Fill1D("VertexRecon_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(),"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(),"customVertex"); + } + + plotter->Fill2D("VertexRecon_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y(),"customVertex"); + if(cathodeHits.size()==2) { + plotter->Fill1D("VertexRecon2C_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(),"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon2C_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z(),"customVertex"); + } + plotter->Fill2D("VertexRecon2C_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y(),"customVertex"); + plotter->Fill2D("VertexRecon2C_RhoZ_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 600,-1300,1300, vector_closest_to_z.Perp(), vector_closest_to_z.Z(),"customVertex"); + plotter->Fill2D("VertexRecon2C_Z_vs_QQQE_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, 800,0,20000, vector_closest_to_z.Z(), qqqenergy,"customVertex"); + } + + } + + for (int i = 0; i < qqq.multi; i++) + { + if(anodeIntersection.Perp() > 0) { //suppress x,y=0,0 events + 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_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100,hitPos.X(),hitPos.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(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(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"); + plotter->Fill2D("PC_Z_vs_QQQRho", 600, -300, 300, 40, 40, 110, anodeIntersection.Z(), hitPos.Perp(), "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("VertexRecon_QQQRingTC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, 16, 0, 16, vector_closest_to_z.Z(), 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-vector_closest_to_z).Theta()); + double sinTheta = TMath::Sin((anodeIntersection-TVector3(0,0,90.0)).Theta()); +// double sinTheta = TMath::Sin((anodeIntersection-vector_closest_to_z).Theta()); +// double sinTheta = TMath::Sin((hitPos-TVector3(0,0,30.0)).Theta()); +// double sinTheta = TMath::Sin(hitPos.Theta()); + + if(cathodeHits.size()==2 && PCQQQPhiCut) { + plotter->Fill2D("CalibratedQQQE_RvsCPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsCPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_RvsPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsPCE_TC" + std::to_string(PCQQQTimeCut), 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("PCQQQ_dTimevsdPhi", 200, -2000, 2000, 80, -200, 200, tRing - static_cast(pc.t[k]), (hitPos.Phi()-anodeIntersection.Phi()) * 180. / TMath::Pi(), "hTiming"); + } + + } + }///qqq i==j case end + } //j loop end + } // qqq i loop end + + TVector3 guessVertex(0,0,source_vertex); //for run12, subtract anodeIntersection.Z() by ~74.0 seems to work + //rho=40.0 mm is halfway between the cathodes(rho=42) and anodes(rho=37) +// double pcz_guess = 37.0/TMath::Tan((hitPos-guessVertex).Theta()) + guessVertex.Z(); //this is ideally kept to be all QQQ+userinput for calibration of pcz + double pcz_guess = z_to_crossover_rho(anodeIntersection.Z())/TMath::Tan((hitPos-guessVertex).Theta()) + guessVertex.Z(); //this is ideally kept to be all QQQ+userinput for calibration of pcz + if(PCQQQTimeCut && PCQQQPhiCut && hitPos.Perp()>0 && anodeIntersection.Perp()>0 && cathodeHits.size()>=2) { + plotter->Fill2D("pczguess_vs_qqqE",100,0,200,800,0,20,pcz_guess,qqqenergy,"pczguess"); + double pczoffset=0.0; + //plotter->Fill2D("pczguess_vs_pcz_rad="+std::to_string(hitPos.Perp()),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z(),"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz_phi="+std::to_string(hitPos.Phi()*180./M_PI),200,0,200,200,0,200,pcz_guess,anodeIntersection.Z()+pczoffset,"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz",200,0,200,200,0,200,pcz_guess,anodeIntersection.Z()+pczoffset); + plotter->Fill2D("pcz_vs_pcPhi_rad="+std::to_string(hitPos.Perp()),360,0,360,150,0,200,anodeIntersection.Phi()*180./M_PI,anodeIntersection.Z()+pczoffset,"pczguess"); + } + for (int i = 0; i < sx3.multi; i++) + { + // plotting sx3 strip hits vs anode phi + if (sx3.ch[i] < 8 && anodeIntersection.Perp()>0) + plotter->Fill2D("PCPhi_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"); + } + + if(anodeIntersection.Perp()!=0) { + plotter->Fill2D("AnodeMaxE_Vs_Cathode_Sum_Energy", 2000, 0, 20000, 2000, 0, 10000, aEMax, cESum, "hGMPC"); + plotter->Fill2D("AnodeSumE_Vs_Cathode_Max_Energy", 800, 0, 20000, 800, 0, 10000, aESum, cEMax, "hGMPC"); + plotter->Fill2D("AnodeMaxE_Vs_Cathode_Max_Energy", 800, 0, 20000, 800, 0, 10000, aEMax, cEMax, "hGMPC"); + //double sinTheta = TMath::Sin((anodeIntersection - TVector3(0,0,source_vertex)).Theta());///TMath::Sin((TVector3(51.5,0,128.) - TVector3(0,0,85)).Theta()); + //plotter->Fill2D("AnodeMaxE_Vs_Cathode_Max_Energy_path_corrected", 800, 0, 20000, 800, 0, 10000, aEMax*sinTheta, cEMax*sinTheta, "hGMPC"); + plotter->Fill2D("AnodeSumE_Vs_Cathode_Sum_Energy", 800, 0, 20000, 800, 0, 10000, aESum, cESum, "hGMPC"); + plotter->Fill2D("AnodeSumE_Vs_Cathode_Max_Energy_TC"+std::to_string(PCQQQTimeCut)+"_PC"+std::to_string(PCQQQPhiCut), 800, 0, 20000, 800, 0, 10000, aESum, cEMax, "hGMPC"); + //plotter->Fill2D("AnodeSumE_Vs_Cathode_Max_Energy_path_corrected"+std::to_string(PCQQQTimeCut)+"_PC"+std::to_string(PCQQQPhiCut), 800, 0, 20000, 800, 0, 10000, aESum*sinTheta, cEMax*sinTheta, "hGMPC"); + //plotter->Fill2D("AnodeSumE_Vs_Cathode_Max_Energy_path_corrected", 800, 0, 20000, 800, 0, 10000, aESum*sinTheta, cEMax*sinTheta, "hGMPC"); + + if(PCQQQTimeCut && PCQQQPhiCut) { + plotter->Fill2D("AnodeSumE_Vs_Cathode_Max_Energy_TC"+std::to_string(PCQQQTimeCut)+"_PC"+std::to_string(PCQQQPhiCut)+"_cMax"+std::to_string(cIDMax), 800, 0, 20000, 800, 0, 10000, aESum, cEMax, "hGMPC"); + } + //plotter->Fill2D("AnodeSumE_Vs_CathodeSum_Energy_path_corrected", 800, 0, 20000, 800, 0, 10000, aESum*sinTheta, cESum*sinTheta, "hGMPC"); + //plotter->Fill2D("AnodeSumE_Vs_CathodeSum_Energy_path_corrected_TC"+std::to_string(PCQQQTimeCut)+"_PC"+std::to_string(PCQQQPhiCut), 800, 0, 20000, 800, 0, 10000, aESum*sinTheta, cESum*sinTheta, "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 MakeVertex::Terminate() { - plotter->FlushToDisk(); + plotter->FlushToDisk(); } diff --git a/MakeVertex.h b/MakeVertex.h index 776ec5a..859ed8f 100644 --- a/MakeVertex.h +++ b/MakeVertex.h @@ -15,118 +15,128 @@ class MakeVertex : public TSelector { public : - TTree *fChain; //!pointer to the analyzed TTree or TChain + TTree *fChain; //!pointer to the analyzed TTree or TChain - // Declaration of leaf types - Det sx3; - Det qqq; - Det pc ; - Det misc; + // Declaration of leaf types + Det sx3; + Det qqq; + Det pc ; + Det misc; - ULong64_t evID; - UInt_t run; + ULong64_t evID; + UInt_t run; - // List of branches - TBranch *b_eventID; //! - TBranch *b_run; //! - TBranch *b_sx3Multi; //! - TBranch *b_sx3ID; //! - TBranch *b_sx3Ch; //! - TBranch *b_sx3E; //! - TBranch *b_sx3T; //! - TBranch *b_qqqMulti; //! - TBranch *b_qqqID; //! - TBranch *b_qqqCh; //! - TBranch *b_qqqE; //! - TBranch *b_qqqT; //! - TBranch *b_pcMulti; //! - TBranch *b_pcID; //! - TBranch *b_pcCh; //! - TBranch *b_pcE; //! - TBranch *b_pcT; //! - TBranch *b_miscMulti; //! - TBranch *b_miscID; //! - TBranch *b_miscCh; //! - TBranch *b_miscE; //! - TBranch *b_miscT; //! - TBranch *b_miscTf; //! + // List of branches + TBranch *b_eventID; //! + TBranch *b_run; //! + TBranch *b_sx3Multi; //! + TBranch *b_sx3ID; //! + TBranch *b_sx3Ch; //! + TBranch *b_sx3E; //! + TBranch *b_sx3T; //! + TBranch *b_qqqMulti; //! + TBranch *b_qqqID; //! + TBranch *b_qqqCh; //! + TBranch *b_qqqE; //! + TBranch *b_qqqT; //! + TBranch *b_pcMulti; //! + TBranch *b_pcID; //! + TBranch *b_pcCh; //! + TBranch *b_pcE; //! + TBranch *b_pcT; //! + TBranch *b_miscMulti; //! + TBranch *b_miscID; //! + TBranch *b_miscCh; //! + TBranch *b_miscE; //! + TBranch *b_miscT; //! + TBranch *b_miscTf; //! - // 1. Geometry Cache - Coord Crossover[24][24][2]; - // 2. Persistent Vectors (REQUIRED for the optimized .cxx to work) - std::vector> anodeHits; - std::vector> cathodeHits; - std::vector> corrcatMax; - std::vector> corranoMax; - std::vector cathodeTimes; - std::vector anodeTimes; - - MakeVertex(TTree * /*tree*/ =0) : fChain(0) { } - virtual ~MakeVertex() { } - virtual Int_t Version() const { return 2; } - virtual void Begin(TTree *tree); - virtual void SlaveBegin(TTree *tree); - virtual void Init(TTree *tree); - virtual Bool_t Notify(); - virtual Bool_t Process(Long64_t entry); - virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } - virtual void SetOption(const char *option) { fOption = option; } - virtual void SetObject(TObject *obj) { fObject = obj; } - virtual void SetInputList(TList *input) { fInput = input; } - virtual TList *GetOutputList() const { return fOutput; } - virtual void SlaveTerminate(); - virtual void Terminate(); + // 2. Persistent Vectors (REQUIRED for the optimized .cxx to work) + std::vector> anodeHits; + std::vector> cathodeHits; + std::vector> corrcatMax; + std::vector> corranoMax; + std::vector cathodeTimes; + std::vector anodeTimes; - ClassDef(MakeVertex,0); + MakeVertex(TTree * /*tree*/ =0) : fChain(0) { } + virtual ~MakeVertex() { } + virtual Int_t Version() const { + return 2; + } + virtual void Begin(TTree *tree); + virtual void SlaveBegin(TTree *tree); + virtual void Init(TTree *tree); + virtual Bool_t Notify(); + virtual Bool_t Process(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { + return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; + } + virtual void SetOption(const char *option) { + fOption = option; + } + virtual void SetObject(TObject *obj) { + fObject = obj; + } + virtual void SetInputList(TList *input) { + fInput = input; + } + virtual TList *GetOutputList() const { + return fOutput; + } + virtual void SlaveTerminate(); + virtual void Terminate(); + + ClassDef(MakeVertex,0); }; #endif #ifdef MakeVertex_cxx -void MakeVertex::Init(TTree *tree){ +void MakeVertex::Init(TTree *tree) { - if (!tree) return; - fChain = tree; - fChain->SetMakeClass(1); + if (!tree) return; + fChain = tree; + fChain->SetMakeClass(1); - fChain->SetBranchAddress("evID", &evID, &b_eventID); - fChain->SetBranchAddress("run", &run, &b_run); + fChain->SetBranchAddress("evID", &evID, &b_eventID); + fChain->SetBranchAddress("run", &run, &b_run); - sx3.SetDetDimension(24,12); - qqq.SetDetDimension(4,32); - pc.SetDetDimension(2,24); + sx3.SetDetDimension(24,12); + qqq.SetDetDimension(4,32); + pc.SetDetDimension(2,24); - fChain->SetBranchAddress("sx3Multi", &sx3.multi, &b_sx3Multi); - fChain->SetBranchAddress("sx3ID", &sx3.id, &b_sx3ID); - fChain->SetBranchAddress("sx3Ch", &sx3.ch, &b_sx3Ch); - fChain->SetBranchAddress("sx3E", &sx3.e, &b_sx3E); - fChain->SetBranchAddress("sx3T", &sx3.t, &b_sx3T); - fChain->SetBranchAddress("qqqMulti", &qqq.multi, &b_qqqMulti); - fChain->SetBranchAddress("qqqID", &qqq.id, &b_qqqID); - fChain->SetBranchAddress("qqqCh", &qqq.ch, &b_qqqCh); - fChain->SetBranchAddress("qqqE", &qqq.e, &b_qqqE); - fChain->SetBranchAddress("qqqT", &qqq.t, &b_qqqT); - fChain->SetBranchAddress("pcMulti", &pc.multi, &b_pcMulti); - fChain->SetBranchAddress("pcID", &pc.id, &b_pcID); - fChain->SetBranchAddress("pcCh", &pc.ch, &b_pcCh); - fChain->SetBranchAddress("pcE", &pc.e, &b_pcE); - fChain->SetBranchAddress("pcT", &pc.t, &b_pcT); - fChain->SetBranchAddress("miscMulti", &misc.multi, &b_miscMulti); - fChain->SetBranchAddress("miscID", &misc.id, &b_miscID); - fChain->SetBranchAddress("miscCh", &misc.ch, &b_miscCh); - fChain->SetBranchAddress("miscE", &misc.e, &b_miscE); - fChain->SetBranchAddress("miscT", &misc.t, &b_miscT); + fChain->SetBranchAddress("sx3Multi", &sx3.multi, &b_sx3Multi); + fChain->SetBranchAddress("sx3ID", &sx3.id, &b_sx3ID); + fChain->SetBranchAddress("sx3Ch", &sx3.ch, &b_sx3Ch); + fChain->SetBranchAddress("sx3E", &sx3.e, &b_sx3E); + fChain->SetBranchAddress("sx3T", &sx3.t, &b_sx3T); + fChain->SetBranchAddress("qqqMulti", &qqq.multi, &b_qqqMulti); + fChain->SetBranchAddress("qqqID", &qqq.id, &b_qqqID); + fChain->SetBranchAddress("qqqCh", &qqq.ch, &b_qqqCh); + fChain->SetBranchAddress("qqqE", &qqq.e, &b_qqqE); + fChain->SetBranchAddress("qqqT", &qqq.t, &b_qqqT); + fChain->SetBranchAddress("pcMulti", &pc.multi, &b_pcMulti); + fChain->SetBranchAddress("pcID", &pc.id, &b_pcID); + fChain->SetBranchAddress("pcCh", &pc.ch, &b_pcCh); + fChain->SetBranchAddress("pcE", &pc.e, &b_pcE); + fChain->SetBranchAddress("pcT", &pc.t, &b_pcT); + /*fChain->SetBranchAddress("miscMulti", &misc.multi, &b_miscMulti); + fChain->SetBranchAddress("miscID", &misc.id, &b_miscID); + fChain->SetBranchAddress("miscCh", &misc.ch, &b_miscCh); + fChain->SetBranchAddress("miscE", &misc.e, &b_miscE); + fChain->SetBranchAddress("miscT", &misc.t, &b_miscT);*/ } -Bool_t MakeVertex::Notify(){ - return kTRUE; +Bool_t MakeVertex::Notify() { + return kTRUE; } -void MakeVertex::SlaveBegin(TTree * /*tree*/){ - // TString option = GetOption(); +void MakeVertex::SlaveBegin(TTree * /*tree*/) { + // TString option = GetOption(); } -void MakeVertex::SlaveTerminate(){ +void MakeVertex::SlaveTerminate() { } #endif // #ifdef MakeVertex_cxx diff --git a/MakeVertexSX3.C b/MakeVertexSX3.C new file mode 100644 index 0000000..c468879 --- /dev/null +++ b/MakeVertexSX3.C @@ -0,0 +1,958 @@ +#define MakeVertexSX3_cxx + +#include "MakeVertexSX3.h" +#include "Armory/ClassPW.h" +#include "Armory/HistPlotter.h" +#include "Armory/SX3Geom.h" + +#include +#include +#include +#include +#include +#include "TVector3.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// Global instances +PW pw_contr; +PW pwinstance; +TVector3 hitPos; +double qqqenergy, qqqtimestamp; +class Event { +public: + Event(TVector3 p, double e1, double e2, double t1, double t2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2) {} + Event(TVector3 p, double e1, double e2, double t1, double t2, int c1, int c2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2), ch1(c1), ch2(c2) {} + + TVector3 pos; + int ch1=-1; //int(ch1/16) gives qqq id, ch1%16 gives ring# + int ch2=-1; //int(ch2/16) gives qqq id, ch2%16 gives wedge# + double Energy1=-1; //Front for QQQ, Anode for PC + double Energy2=-1; //Back for QQQ, Cathode for PC + double Time1=-1; + double Time2=-1; + +}; + +// 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; + +double sx3BackGain[24][4][4] = {{{1.}}}; +double sx3FrontGain[24][4] = {{1.}}; +double sx3FrontOffset[24][4] = {{0.}}; +double sx3RightGain[24][4] = {{1.}}; + +// PC Arrays +double pcSlope[48]; +double pcIntercept[48]; + +HistPlotter *plotter; + +bool HitNonZero; +bool sx3ecut; +bool qqqEcut; + +void MakeVertexSX3::Begin(TTree * /*tree*/) +{ + TString option = GetOption(); + plotter = new HistPlotter("Analyzer_SX3.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 Cuts from file + // { + // std::string filename = "QQQ_PCCut.root"; + // TFile *cutFile = TFile::Open(filename.c_str(), "READ"); + // if (cutFile && !cutFile->IsZombie()) + // { + // cutQQQ = (TCutg *)cutFile->Get("cutQQQPC"); + // if (cutQQQ) + // { + // std::cout << "Loaded QQQ PC cut from " << filename << std::endl; + // } + // else + // { + // std::cerr << "Error: cutQQQPC not found in " << filename << std::endl; + // } + // cutFile->Close(); + // } + // } + + // ... (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); + // std::cout << "QQQ Gain Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " GainW " << gainw << " GainR " << gainr << std::endl; + } + 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); + // std::cout << "QQQ Calib Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " Slope " << slope << std::endl; + } + infile.close(); + } + } + + { + std::ifstream infile("sx3cal/backgains.dat"); + std::string temp; + int backpos, frontpos, clkpos; + std::cout << "foo" << std::endl; + if (infile.is_open()) + while(infile>>clkpos>>temp>>frontpos>>temp>>backpos>>sx3BackGain[clkpos][frontpos][backpos]) + std::cout << sx3BackGain[clkpos][frontpos][backpos] << std::endl; + infile.close(); + + infile.open("sx3cal/frontgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>temp>>temp>>frontpos>>sx3FrontOffset[clkpos][frontpos]>>sx3FrontGain[clkpos][frontpos]) + std::cout << sx3FrontOffset[clkpos][frontpos] << " " << sx3FrontGain[clkpos][frontpos] << std::endl; + infile.close(); + + infile.open("sx3cal/rightgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>frontpos>>temp>>sx3RightGain[clkpos][frontpos]) { + sx3RightGain[clkpos][frontpos]=TMath::Abs(sx3RightGain[clkpos][frontpos]); + } + infile.close(); + + } + std::cout << "aaa" << std::endl; +} + +Bool_t MakeVertexSX3::Process(Long64_t entry) +{ + hitPos.Clear(); + qqqenergy = -1; + qqqtimestamp=-1; + 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(); + + std::vector sx3Events; + if(sx3.multi>1) { + std::array Fsx3; + //std::cout << "-----" << std::endl; + for(int i=0; i=12) continue; + int id = sx3.id[i]; + if(sx3.ch[i]>=8) { + int sx3ch=sx3.ch[i]-8; + sx3ch=(sx3ch+3)%4; + if(sx3ch==0 || sx3ch==3) continue; + float value=sx3.e[i]; + int gch = sx3.id[i]*4+(sx3.ch[i]-8); + Fsx3.at(id).fillevent("BACK",sx3ch,value); + Fsx3.at(id).ts = static_cast(sx3.t[i]); + plotter->Fill2D("sx3backs_raw",100,0,100,800,0,4096,gch,sx3.e[i]); + } else { + int sx3ch=sx3.ch[i]/2; + double value=sx3.e[i]; + if(sx3.ch[i]%2==0) { + Fsx3.at(id).fillevent("FRONT_L",sx3ch,value*sx3RightGain[id][sx3ch]); + } else { + Fsx3.at(id).fillevent("FRONT_R",sx3ch,value); + } + } + } + for(int id=0; id<12; id++) { + Fsx3.at(id).validate(); + auto det = Fsx3.at(id); + bool no_charge_sharing_strict = det.valid_front_chans.size()==1 && det.valid_back_chans.size()==1; + if(det.valid) { + //std::cout << det.frontEL << " " << det.frontEL*sx3RightGain[id][det.stripF] << std::endl; + plotter->Fill2D("be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_b"+std::to_string(det.stripB),200,-1,1,800,0,8192, + det.frontX,det.backE,"evsx"); + //std::cout << sx3BackGain[id][det.stripF][det.stripB] << " " << sx3FrontGain[id][det.stripF] << std::endl; + plotter->Fill2D("matched_be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),200,-30,30,800,0,8192, + det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF],det.backE*sx3BackGain[id][det.stripF][det.stripB],"evsx_matched"); + //plotter->Fill2D("fe_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_"+std::to_string(det.stripB),200,-1,1,800,0,4096,det.frontX,det.backE,"evsx"); + plotter->Fill2D("l_vs_r_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),800,0,4096,800,0,4096,det.frontEL,det.frontER,"l_vs_r"); + } + if(det.valid && (id ==9 || id==7 || id == 1 || id==3) && det.stripF!=DEFAULT_NULL && det.stripB!=DEFAULT_NULL) { + double z = det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF]; + double backE = det.backE*sx3BackGain[id][det.stripF][det.stripB]; + Event sx3ev(TVector3(0,0,z),backE,-1,det.ts,-1,det.stripB+4*id,det.stripF+4*id); + sx3Events.push_back(sx3ev); + } + } + } + //return kTRUE; + // 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) + if (qqq.id[i] == 1 && qqq.ch[i] < 16) //for run 12, 26Al + { + 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 QQQ_Events, PC_Events; + std::vector QQQ_Events_Raw, PC_Events_Raw; + std::vector QQQ_Events2; //clustering done + + std::unordered_map> qvecr[4], qvecw[4]; + if(qqq.multi>1) { + //if(qqq.multi>=3) std::cout << "-----" << std::endl; + for(int i=0; i=3) std::cout << std::setprecision(16) << "qqq"<< qqq.id[i] << " " << std::string(qqq.ch[i]/16?"ring":"wedge") << qqq.ch[i]%16 << " " << qqq.e[i] << " " << qqq.t[i] - qqq.t[0] << std::endl; + if(qqq.ch[i]/16) { + if(qvecr[qqq.id[i]].find(qqq.ch[i])!=qvecr[qqq.id[i]].end()) std::cout << "mayday!" << std::endl; + qvecr[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i],qqq.ch[i],qqq.e[i],qqq.t[i]); + } else { + if(qvecw[qqq.id[i]].find(qqq.ch[i])!=qvecw[qqq.id[i]].end()) std::cout << "mayday!" << std::endl; + qvecw[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i],qqq.ch[i],qqq.e[i],qqq.t[i]); + } + } + } + + bool PCQQQTimeCut = false; + for (int i = 0; i < qqq.multi; i++) { + plotter->Fill2D("QQQ_Index_Vs_Energy", 16 * 8, 0, 16 * 8, 2000, 0, 16000, qqq.index[i], qqq.e[i], "hRawQQQ"); + + for (int j = 0; j < qqq.multi; j++) { + if (j == i) + continue; + plotter->Fill2D("QQQ_Coincidence_Matrix", 16 * 8, 0, 16 * 8, 16 * 8, 0, 16 * 8, qqq.index[i], qqq.index[j], "hRawQQQ"); + } + + for (int k = 0; k < pc.multi; k++) { + if (pc.index[k] < 24 && pc.e[k] > 50) { + plotter->Fill2D("QQQ_Vs_Anode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + plotter->Fill2D("QQQ_Vs_PC_Index", 16 * 8, 0, 16 * 8, 24, 0, 24, qqq.index[i], pc.index[k], "hRawQQQ"); + } + else if (pc.index[k] >= 24 && pc.e[k] > 50) { + plotter->Fill2D("QQQ_Vs_Cathode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + } + } + + 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(qqq.t[j]); + tWedge = static_cast(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(qqq.t[i]); + tWedge = static_cast(qqq.t[j]); + } + else + continue; + + plotter->Fill1D("Wedgetime_Vs_Ringtime", 100, -1000, 1000, tWedge - tRing, "hTiming"); + plotter->Fill2D("RingE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chRing + qqq.id[i] * 16, eRing, "hRawQQQ"); + plotter->Fill2D("WedgeE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chWedge + qqq.id[i] * 16, eWedge, "hRawQQQ"); + + 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; + + if(eRingMeV/eWedgeMeV > 3.0 || eRingMeV/eWedgeMeV<1.0/3.0) continue; + //if(eRingMeV<4.0 || eWedgeMeV<4.0) continue; + + double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + //z used to be 75+30+23=128 + //we found a 12mm shift towards the vertex later --> 116 + Event qqqevent(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),116), eRingMeV, eWedgeMeV, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + Event qqqeventr(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),116), eRing, eWedge, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + QQQ_Events.push_back(qqqevent); + QQQ_Events_Raw.push_back(qqqeventr); + plotter->Fill2D("QQQCartesianPlot", 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + plotter->Fill2D("QQQCartesianPlot" + std::to_string(qqq.id[i]), 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + if (PCQQQTimeCut) { + plotter->Fill2D("PC_XY_Projection_QQQ_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + else + continue; + + plotter->Fill2D("WedgeE_Vs_RingECal", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + plotter->Fill2D("WedgeE_Vs_RingECal_selected", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + + for (int k = 0; k < pc.multi; k++) + { + plotter->Fill2D("RingCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index" + std::to_string(qqq.id[i]), 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k]); + plotter->Fill2D("RingCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + + if (pc.index[k] < 24 && pc.e[k] > 50) + { + plotter->Fill2D("Timing_Difference_QQQ_PC", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + plotter->Fill2D("DelT_Vs_QQQRingECal", 500, -2000, 2000, 1000, 0, 10, tRing - static_cast(pc.t[k]), eRingMeV, "hTiming"); + plotter->Fill2D("CalibratedQQQEvsPCE_R", 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQEvsPCE_W", 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + if (tRing - static_cast(pc.t[k]) < -150) // proton tests, 27Al + //if (tRing - static_cast(pc.t[k]) < -150 && tRing - static_cast(pc.t[k]) > -450) // 27Al + //if (tRing - static_cast(pc.t[k]) < -70 && tRing - static_cast(pc.t[k]) > -150) // 17F + { + PCQQQTimeCut = true; + } + } + + if (pc.index[k] >= 24 && pc.e[k] > 50) { + plotter->Fill2D("Timing_Difference_QQQ_PC_Cathode", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + } + } //end of pc k loop + + if (!HitNonZero) { + double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + double x = rho * TMath::Cos(theta); + double y = rho * TMath::Sin(theta); + hitPos.SetXYZ(x, y, (23 + 75 + 30)); + qqqenergy = eRingMeV; + qqqtimestamp = tRing; + HitNonZero = true; + } + } // if j==i + } //j loop end + } //i loop end + + plotter->Fill1D("QQQ_Multiplicity", 10, 0, 10, qqqCount, "hRawQQQ"); + + /*if(QQQ_Events.size()>=1) { + std::cout<< " ---->" << std::endl; + for(auto qe: QQQ_Events) { + std::cout << qe.ch1/16 << " " <> WireEvent; //this stores nearest neighbour wire events, or a 'cluster' + WireEvent aWireEvents, cWireEvents; //naming for book keeping + aWireEvents.clear(); + aWireEvents.reserve(24); + + // PC Gain Matching and Filling + double anodeT = -99999; + double cathodeT = 99999; + int anodeIndex = -1; + int cathodeIndex = -1; + for (int i = 0; i < pc.multi; i++) + { + if (pc.e[i] > 50) + { + plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast(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(pc.t[i]); + anodeIndex = pc.index[i]; + aWireEvents[pc.index[i]] = std::tuple(pc.index[i],pc.e[i],static_cast(pc.t[i])); + } + else + { + cathodeT = static_cast(pc.t[i]); + cathodeIndex = pc.index[i] - 24; + cWireEvents[pc.index[i]-24] = std::tuple(pc.index[i]-24,pc.e[i],static_cast(pc.t[i])); + } + + if (anodeT != -99999 && cathodeT != 99999) + { + for (int j = 0; j < qqq.multi; j++) + { + plotter->Fill1D("PC_Time_qqq", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + plotter->Fill2D("PC_Time_Vs_QQQ_ch", 200, -2000, 2000, 16 * 8, 0, 16 * 8, anodeT - cathodeT, qqq.ch[j], "hTiming"); + plotter->Fill2D("PC_Time_vs_AIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, anodeIndex, "hTiming"); + plotter->Fill2D("PC_Time_vs_CIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, cathodeIndex, "hTiming"); + // plotter->Fill1D("PC_Time_A" + std::to_string(anodeIndex) + "_C" + std::to_string(cathodeIndex), 200, -1000, 1000, anodeT - cathodeT, "TimingPC"); + } + + for (int j = 0; j < sx3.multi; j++) + { + plotter->Fill1D("PC_Time_sx3", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + plotter->Fill1D("PC_Time", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + for (int j = i + 1; j < pc.multi; j++) + { + plotter->Fill2D("PC_Coincidence_Matrix", 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("PC_Coincidence_Matrix_anodeMinusCathode_lt_-200_" + std::to_string(anodeT - cathodeT < -200), 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("Anode_V_Anode", 24, 0, 24, 24, 0, 24, pc.index[i], pc.index[j], "hGMPC"); + } + } + + anodeHits.clear(); + cathodeHits.clear(); + corrcatMax.clear(); + + int aID = 0; + int cID = 0; + double aE = 0; + double cE = 0; + double aESum = 0; + double cESum = 0; + double aEMax = 0; + int aIDMax = 0; + + + + for (int i = 0; i < pc.multi; i++) { + // if (pc.e[i] > 100) + { + if (pc.index[i] < 24) { + anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); + } + else if (pc.index[i] >= 24) { + cathodeHits.push_back(std::pair(pc.index[i] - 24, pc.e[i])); + } + } + } + + std::sort(anodeHits.begin(),anodeHits.end(),[](std::pair a, std::pair b){ return a.first < b.first;}); + std::sort(cathodeHits.begin(),cathodeHits.end(),[](std::pair a, std::pair b){ return a.first < b.first;}); + + //clusters = collection of (collection of wires) where each wire is (index, energy, timestamp) + std::vector>> aClusters = pwinstance.Make_Clusters(aWireEvents); + std::vector>> cClusters = pwinstance.Make_Clusters(cWireEvents); + + std::vector> sumE_AC; + for(auto aCluster: aClusters) { + for(auto cCluster: cClusters) { + if(aCluster.size()<=1 && cCluster.size()<=1) continue; + auto [crossover,alpha,apSumE,cpSumE,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE] = pwinstance.FindCrossoverProperties(aCluster, cCluster); + if(alpha!=9999999 && apSumE!=-1) { + //Event PCEvent(crossover,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); + //Event PCEvent(crossover,apSumE,cpSumE,apTSMaxE,cpTSMaxE); + Event PCEvent(crossover,apSumE,cpMaxE,apTSMaxE,cpTSMaxE); //run12 shows cathode-max and anode-sum provide best dE signals. + //std::cout << apSumE << " " << crossover.Perp() << " " << apMaxE << " " << apTSMaxE << std::endl; + PC_Events.push_back(PCEvent); + sumE_AC.push_back(std::pair(apSumE,cpSumE)); + } + } + } + if(QQQ_Events.size() && PC_Events.size()) + plotter->Fill2D("PCEv_vs_QQQEv",20,0,20,20,0,20,QQQ_Events.size(),PC_Events.size()); + + for(auto pcevent:PC_Events) { + for(auto sx3event:sx3Events) { + plotter->Fill1D("dt_pcA_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time2); + plotter->Fill2D("dE_E_Anodesx3B",400,0,10,800,0,40000,sx3event.Energy1*0.001,pcevent.Energy1); + + plotter->Fill2D("dE_E_Cathodesx3B",400,0,10,800,0,10000,sx3event.Energy1*0.001,pcevent.Energy2); + double sx3z = sx3event.pos.Z()+(75.0/2.0)+23.0-90.0; //w.r.t target origin at 90 for run12 + double sx3rho = 88.0; + double sx3theta = TMath::ATan2(sx3rho,sx3z); + double pczguess = 40.0/TMath::Tan(sx3theta) + 90.0; + plotter->Fill2D("pcz_vs_sx3pczguess",300,0,200,150,0,200,pczguess,pcevent.pos.Z()); + plotter->Fill2D("pcz_vs_sx3pczguess"+std::to_string(sx3event.ch2),300,0,200,150,0,200,pczguess,pcevent.pos.Z()); + plotter->Fill2D("pcz_vs_sx3z",300,0,200,150,0,200,sx3z+90,pcevent.pos.Z()); + } + } + + for(auto pcevent: PC_Events) { + for(auto qqqevent: QQQ_Events) { + plotter->Fill1D("dt_pcA_qqqR",640,-2000,2000,qqqevent.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_qqqW",640,-2000,2000,qqqevent.Time2 - pcevent.Time2); + plotter->Fill2D("dE_E_AnodeQQQR",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1); + plotter->Fill2D("dE_E_CathodeQQQR",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2); + double sinTheta = TMath::Sin((qqqevent.pos - TVector3(0,0,90)).Theta())/TMath::Sin((TVector3(51.5,0,128.) - TVector3(0,0,90)).Theta()); + plotter->Fill2D("dE2_E_AnodeQQQR",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1*sinTheta); + plotter->Fill2D("dE2_E_CathodeQQQR",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2*sinTheta); + + if(qqqevent.pos.Phi() <= pcevent.pos.Phi()+TMath::Pi()/4. && qqqevent.pos.Phi() >= pcevent.pos.Phi()-TMath::Pi()/4.) { + plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + double pcz_guess = 40.0/TMath::Tan((qqqevent.pos-TVector3(0,0,90)).Theta()) + 90; //this is ideally kept to be all QQQ+userinput for calibration of pcz + plotter->Fill2D("pczguess_vs_pc",300,0,200,150,0,200,pcz_guess,pcevent.pos.Z(),"phicut"); + plotter->Fill2D("pczguess_vs_pc_phi="+std::to_string(qqqevent.pos.Phi()*180./M_PI),300,0,200,150,0,200,pcz_guess,pcevent.pos.Z(),"phicut"); + //plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + } + } + } + //HALFTIME! Can stop here in future versions + //return kTRUE; + + 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; + plotter->Fill2D("AnodeMax_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aIDMax, cID, "hRawPC"); + plotter->Fill2D("Anode_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aID, cID, "hRawPC"); + plotter->Fill2D("Anode_vs_CathodeE", 2000, 0, 30000, 2000, 0, 30000, aE, cE, "hGMPC"); + plotter->Fill2D("CathodeMult_V_CathodeE", 6, 0, 6, 2000, 0, 30000, cathodeHits.size(), cE, "hGMPC"); + for (int j = -4; j < 3; j++) + { + if ((aIDMax + 24 + j) % 24 == 23 - cID) + { + corrcatMax.push_back(std::pair(cID, cE)); + cESum += cE; + } + } + } + } + } + + TVector3 anodeIntersection,vector_closest_to_z; + anodeIntersection.Clear(); + vector_closest_to_z.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); + // << "Anode Intersection: " << anodeIntersection.X() << ", " << anodeIntersection.Y() << ", " << anodeIntersection.Z() << std::endl; + } + 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; + } + + for (double Tz = 60; Tz <= 100; Tz += 1.0) + { + TVector3 TargetPos(0, 0, Tz); + if(PCQQQPhiCut && anodeIntersection.Perp()>0 && anodeIntersection.Z()!=0 && cathodeHits.size()>=2) { + plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 400, 0, 180, 90, 0, 90, (anodeIntersection - TargetPos).Theta() * 180. / TMath::Pi(), (hitPos - TargetPos).Theta() * 180. / TMath::Pi(), "TPosVariation"); + //plotter->Fill2D("R_ratio_to_Z_ratio" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 100, -2, 2, 100, -2, 2, (anodeIntersection - TargetPos).Z()/(hitPos-TargetPos).Z(), ((anodeIntersection - TargetPos).Perp()+2.5)/(hitPos-TargetPos).Perp(), "TPosVariation"); + } + } + + if (anodeIntersection.Z() != 0 && anodeIntersection.Perp()>0 && HitNonZero) + { + 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)+ "_PC"+std::to_string(PCQQQPhiCut), 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, -1300, 1300, pw_contr.GetZ0()); + plotter->Fill1D("VertexRecon_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + if (cathodeHits.size() == 2) + plotter->Fill1D("VertexRecon_2c_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + TVector3 x2(anodeIntersection), x1(hitPos); + + TVector3 v = x2-x1; + double t_minimum = -1.0*(x1.X()*v.X()+x1.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + vector_closest_to_z = x1 + t_minimum*v; + + plotter->Fill1D("VertexRecon_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + } + + plotter->Fill2D("VertexRecon_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y() ,"customVertex"); + if(cathodeHits.size()==2) { + plotter->Fill1D("VertexRecon2C_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon2C_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + } + plotter->Fill2D("VertexRecon2C_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y() ,"customVertex"); + plotter->Fill2D("VertexRecon2C_RhoZ_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 600,-1300,1300, vector_closest_to_z.Perp(), vector_closest_to_z.Z() ,"customVertex"); + plotter->Fill2D("VertexRecon2C_Z_vs_QQQE_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, 800,0,20000, vector_closest_to_z.Z(), qqqenergy ,"customVertex"); + } + + } + + for (int i = 0; i < qqq.multi; i++) + { + if(anodeIntersection.Perp() > 0) { //suppress x,y=0,0 events + 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(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(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("VertexRecon_QQQRingTC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, 16, 0, 16, vector_closest_to_z.Z(), 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-vector_closest_to_z).Theta()); + double sinTheta = TMath::Sin((anodeIntersection-TVector3(0,0,90.0)).Theta()); +// double sinTheta = TMath::Sin((anodeIntersection-vector_closest_to_z).Theta()); +// double sinTheta = TMath::Sin((hitPos-TVector3(0,0,30.0)).Theta()); +// double sinTheta = TMath::Sin(hitPos.Theta()); + + if(cathodeHits.size()==2 && PCQQQPhiCut) { + plotter->Fill2D("CalibratedQQQE_RvsCPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsCPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_RvsPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("PCQQQ_dTimevsdPhi", 200, -2000, 2000, 80, -200, 200, tRing - static_cast(pc.t[k]), (hitPos.Phi()-anodeIntersection.Phi()) * 180. / TMath::Pi(), "hTiming"); + } + + } + }///qqq i==j case end + } //j loop end + } // qqq i loop end + + TVector3 guessVertex(0,0,90.); //for run12, subtract anodeIntersection.Z() by ~74.0 seems to work + //rho=40.0 mm is halfway between the cathodes(rho=42) and anodes(rho=37) + double pcz_guess = 42.0/TMath::Tan((hitPos-guessVertex).Theta()) + guessVertex.Z(); //this is ideally kept to be all QQQ+userinput for calibration of pcz + if(PCQQQTimeCut && PCQQQPhiCut && hitPos.Perp()>0 && anodeIntersection.Perp()>0 && cathodeHits.size()>=2) { + plotter->Fill2D("pczguess_vs_qqqE",100,0,200,800,0,20,pcz_guess,qqqenergy,"pczguess"); + double pczoffset=30.0; + //plotter->Fill2D("pczguess_vs_pcz_rad="+std::to_string(hitPos.Perp()),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z(),"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz_phi="+std::to_string(hitPos.Phi()*180./M_PI),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z()+pczoffset,"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz",100,0,200,150,0,200,pcz_guess,anodeIntersection.Z()+pczoffset); + plotter->Fill2D("pcz_vs_pcPhi_rad="+std::to_string(hitPos.Perp()),360,0,360,150,0,200,anodeIntersection.Phi()*180./M_PI,anodeIntersection.Z()+pczoffset,"pczguess"); + } + for (int i = 0; i < sx3.multi; i++) + { + // plotting sx3 strip hits vs anode phi + if (sx3.ch[i] < 8 && anodeIntersection.Perp()>0) + plotter->Fill2D("PCPhi_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 MakeVertexSX3::Terminate() +{ + plotter->FlushToDisk(); +} diff --git a/MakeVertexSX3.C.backup b/MakeVertexSX3.C.backup new file mode 100644 index 0000000..17f0fad --- /dev/null +++ b/MakeVertexSX3.C.backup @@ -0,0 +1,1114 @@ +#define MakeVertexSX3_cxx + +#include +#include +#include +#include + +#include "MakeVertexSX3.h" +#include "Armory/ClassPW.h" +#include "Armory/HistPlotter.h" +#include "Armory/SX3Geom.h" +#include "gmsx3/intgm_sx3.h" + +#include +#include +#include +#include +#include +#include "TVector3.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// Global instances +PW pw_contr; +PW pwinstance; +TVector3 hitPos; +double qqqenergy, qqqtimestamp; +intgm_sx3 *matcher=NULL; + + +class Event { +public: + Event(TVector3 p, double e1, double e2, double t1, double t2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2) {} + Event(TVector3 p, double e1, double e2, double t1, double t2, int c1, int c2) : pos(p), Energy1(e1), Energy2(e2), Time1(t1), Time2(t2), ch1(c1), ch2(c2) {} + + TVector3 pos; + int ch1=-1; //int(ch1/16) gives qqq id, ch1%16 gives ring# + int ch2=-1; //int(ch2/16) gives qqq id, ch2%16 gives wedge# + double Energy1=-1; //Front for QQQ, Anode for PC + double Energy2=-1; //Back for QQQ, Cathode for PC + double Time1=-1; + double Time2=-1; + +}; + +/*std::vector +Make_QQQClusters(const std::unordered_map& qqqvec) { + std::vector qqqevents; //input events, but combine NN energies + + +}*/ + +// 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; + +double sx3BackGain[24][4][4] = {{{1.}}}; +double sx3FrontGain[24][4] = {{1.}}; +double sx3FrontOffset[24][4] = {{0.}}; +double sx3RightGain[24][4] = {{1.}}; + +// PC Arrays +double pcSlope[48]; +double pcIntercept[48]; + +HistPlotter *plotter; + +bool HitNonZero; +bool sx3ecut; +bool qqqEcut; + +void MakeVertexSX3::Begin(TTree * /*tree*/) +{ + TString option = GetOption(); + plotter = new HistPlotter("Analyzer_SX3.root", "TFILE"); + matcher = new intgm_sx3(plotter); + 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 Cuts from file + // { + // std::string filename = "QQQ_PCCut.root"; + // TFile *cutFile = TFile::Open(filename.c_str(), "READ"); + // if (cutFile && !cutFile->IsZombie()) + // { + // cutQQQ = (TCutg *)cutFile->Get("cutQQQPC"); + // if (cutQQQ) + // { + // std::cout << "Loaded QQQ PC cut from " << filename << std::endl; + // } + // else + // { + // std::cerr << "Error: cutQQQPC not found in " << filename << std::endl; + // } + // cutFile->Close(); + // } + // } + + // ... (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); + // std::cout << "QQQ Gain Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " GainW " << gainw << " GainR " << gainr << std::endl; + } + 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); + // std::cout << "QQQ Calib Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " Slope " << slope << std::endl; + } + infile.close(); + } + } + + { + std::ifstream infile("sx3cal/backgains.dat"); + std::string temp; + int backpos, frontpos, clkpos; + std::cout << "foo" << std::endl; + if (infile.is_open()) + while(infile>>clkpos>>temp>>frontpos>>temp>>backpos>>sx3BackGain[clkpos][frontpos][backpos]) + std::cout << sx3BackGain[clkpos][frontpos][backpos] << std::endl; + infile.close(); + + infile.open("sx3cal/frontgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>temp>>temp>>frontpos>>sx3FrontOffset[clkpos][frontpos]>>sx3FrontGain[clkpos][frontpos]) + std::cout << sx3FrontOffset[clkpos][frontpos] << " " << sx3FrontGain[clkpos][frontpos] << std::endl; + infile.close(); + + infile.open("sx3cal/rightgains.dat"); + if (infile.is_open()) + while(infile>>clkpos>>frontpos>>temp>>sx3RightGain[clkpos][frontpos]) { + sx3RightGain[clkpos][frontpos]=TMath::Abs(sx3RightGain[clkpos][frontpos]); + } + infile.close(); + + } + std::cout << "aaa" << std::endl; +} + +Bool_t MakeVertexSX3::Process(Long64_t entry) +{ + hitPos.Clear(); + qqqenergy = -1; + qqqtimestamp=-1; + 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(); + + std::vector sx3Events; + if(sx3.multi>1) { + std::array Fsx3; + //std::cout << "-----" << std::endl; + for(int i=0; i=12) continue; + int id = sx3.id[i]; + if(sx3.ch[i]>=8) { + int sx3ch=sx3.ch[i]-8; + sx3ch=(sx3ch+3)%4; + if(sx3ch==0 || sx3ch==3) continue; + float value=sx3.e[i]; + int gch = sx3.id[i]*4+(sx3.ch[i]-8); + Fsx3.at(id).fillevent("BACK",sx3ch,value); + Fsx3.at(id).ts = static_cast(sx3.t[i]); + plotter->Fill2D("sx3backs_raw",100,0,100,800,0,4096,gch,sx3.e[i]); + } else { + int sx3ch=sx3.ch[i]/2; + double value=sx3.e[i]; + if(sx3.ch[i]%2==0) { + Fsx3.at(id).fillevent("FRONT_L",sx3ch,value*sx3RightGain[id][sx3ch]); + } else { + Fsx3.at(id).fillevent("FRONT_R",sx3ch,value); + } + } + } + for(int id=0; id<12; id++) { + Fsx3.at(id).validate(); + auto det = Fsx3.at(id); + bool no_charge_sharing_strict = det.valid_front_chans.size()==1 && det.valid_back_chans.size()==1; + if(det.valid) { + //std::cout << det.frontEL << " " << det.frontEL*sx3RightGain[id][det.stripF] << std::endl; + plotter->Fill2D("be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_b"+std::to_string(det.stripB),200,-1,1,800,0,8192, + det.frontX,det.backE,"evsx"); + //std::cout << sx3BackGain[id][det.stripF][det.stripB] << " " << sx3FrontGain[id][det.stripF] << std::endl; + plotter->Fill2D("matched_be_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),200,-30,30,800,0,8192, + det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF],det.backE*sx3BackGain[id][det.stripF][det.stripB],"evsx_matched"); + //plotter->Fill2D("fe_vs_x_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF)+"_"+std::to_string(det.stripB),200,-1,1,800,0,4096,det.frontX,det.backE,"evsx"); + plotter->Fill2D("l_vs_r_sx3_id_"+std::to_string(id)+"_f"+std::to_string(det.stripF),800,0,4096,800,0,4096,det.frontEL,det.frontER,"l_vs_r"); + } + if(det.valid && (id ==9 || id==7 || id == 1 || id==3) && det.stripF!=DEFAULT_NULL && det.stripB!=DEFAULT_NULL) { + double z = det.frontX*sx3FrontGain[id][det.stripF]+sx3FrontOffset[id][det.stripF]; + double backE = det.backE*sx3BackGain[id][det.stripF][det.stripB]; + Event sx3ev(TVector3(0,0,z),backE,-1,det.ts,-1,det.stripB+4*id,det.stripF+4*id); + sx3Events.push_back(sx3ev); + } + } + } + //return kTRUE; + // 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) + if (qqq.id[i] == 1 && qqq.ch[i] < 16) //for run 12, 26Al + { + 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 QQQ_Events, PC_Events; + std::vector QQQ_Events_Raw, PC_Events_Raw; + std::vector QQQ_Events2; //clustering done + + std::unordered_map> qvecr[4], qvecw[4]; + if(qqq.multi>1) { + if(qqq.multi>=3) std::cout << "-----" << std::endl; + for(int i=0; i=3) std::cout << std::setprecision(16) << "qqq"<< qqq.id[i] << " " << std::string(qqq.ch[i]/16?"ring":"wedge") << qqq.ch[i]%16 << " " << qqq.e[i] << " " << qqq.t[i] - qqq.t[0] << std::endl; + if(qqq.ch[i]/16) { + if(qvecr[qqq.id[i]].find(qqq.ch[i])!=qvecr[qqq.id[i]].end()) std::cout << "mayday!" << std::endl; + qvecr[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i],qqq.ch[i],qqq.e[i],qqq.t[i]); + } else { + if(qvecw[qqq.id[i]].find(qqq.ch[i])!=qvecw[qqq.id[i]].end()) std::cout << "mayday!" << std::endl; + qvecw[qqq.id[i]][qqq.ch[i]] = std::tuple(qqq.id[i],qqq.ch[i],qqq.e[i],qqq.t[i]); + } + } + } + + +/* std::tuple maxRevent, maxWevent; + for(int qqqid=0; qqqid<4; qqqid) { + for(int i=0; i<16; i++) { + if(qvecr[qqqid].find(i)==qvecr[qqqid].end()) + ;//do nothing + else if(std::get<2>(qvecr[qqqid][i])>std::get<2>(maxRevent)) { + maxRevent = qvecr[qqqid][i]; + } + if(qvecw[qqqid].find(i)==qvecw[qqqid].end()) + ;//do nothing + else if(std::get<2>(qvecw[qqqid][i])>std::get<2>(maxWevent)) { + maxWevent = qvecw[qqqid][i]; + } + } + if(qvecr) + } + + int qcount=0; + while(qcount< 16) { + if(qvecr[qqqid].find(qcount)==qvecr[qqqid].end()) { + qcount++; + continue; + } + qrCluster.clear(); + std::tuple maxE_Event; + int ctr2=qcount; + do { + qrCluster.emplace_back(qvecr[qqqid][ctr2]); + if(std::get<2>(qvecr[qqqid][ctr2])>maxE) { + maxE_Event = qvecr[qqqid][ctr2]; + } + ctr2+=1; + } while(qvecr[qqqid].find(ctr2)!=qvecr[qqqid].end()); + + if(qvecr[qqqid].find(maxch-1)!=qvecr[qqqid].end()) { + std::get<2>(maxE_Event) += std::get<2>(qvecr[qqqid][maxch-1]); + } else if(qvecr[qqqid].find(maxch+1)!=qvecr[qqqid].end()) { + std::get<2>(maxE_Event) += std::get<2>(qvecr[qqqid][maxch+1]); + } + + qrClusters.push_back(std::move(qrCluster)); + qcount = ctr2; //we already dealt with segments until the last value of ctr2 + } + + int ch = 0; + while(ch < 16) { + if(qvecr[qqqid].find(ch)==qvecr[qqqid].end()) { + ch++; + continue; + } else { + if(qvecr[qqqid].find(ch+1)==qvecr[qqqid].end()) { + } + } + ch+=1; + } + + qcount=0; + while(qcount< 16) { + if(qvecw[qqqid].find(v)==qvecw[qqqid].end()) { + qcount++; + continue; + } + qwCluster.clear(); + int ctr2=qcount; + do { + qwCluster.emplace_back(qvecw[qqqid][ctr2]); + ctr2+=1; + } while(qvecw[qqqid].find(ctr2)!=qvecw[qqqid].end()); + qwClusters.push_back(std::move(qwCluster)); + qcount = ctr2; //we already dealt with segments until the last value of ctr2 + } + + + for(auto qrs: qrClusters) { + for(auto qr: qrs) { + + } + } + }*/ + + bool PCQQQTimeCut = false; + for (int i = 0; i < qqq.multi; i++) { + plotter->Fill2D("QQQ_Index_Vs_Energy", 16 * 8, 0, 16 * 8, 2000, 0, 16000, qqq.index[i], qqq.e[i], "hRawQQQ"); + + for (int j = 0; j < qqq.multi; j++) { + if (j == i) + continue; + plotter->Fill2D("QQQ_Coincidence_Matrix", 16 * 8, 0, 16 * 8, 16 * 8, 0, 16 * 8, qqq.index[i], qqq.index[j], "hRawQQQ"); + } + + for (int k = 0; k < pc.multi; k++) { + if (pc.index[k] < 24 && pc.e[k] > 50) { + plotter->Fill2D("QQQ_Vs_Anode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + plotter->Fill2D("QQQ_Vs_PC_Index", 16 * 8, 0, 16 * 8, 24, 0, 24, qqq.index[i], pc.index[k], "hRawQQQ"); + } + else if (pc.index[k] >= 24 && pc.e[k] > 50) { + plotter->Fill2D("QQQ_Vs_Cathode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + } + } + + 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(qqq.t[j]); + tWedge = static_cast(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(qqq.t[i]); + tWedge = static_cast(qqq.t[j]); + } + else + continue; + + plotter->Fill1D("Wedgetime_Vs_Ringtime", 100, -1000, 1000, tWedge - tRing, "hTiming"); + plotter->Fill2D("RingE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chRing + qqq.id[i] * 16, eRing, "hRawQQQ"); + plotter->Fill2D("WedgeE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chWedge + qqq.id[i] * 16, eWedge, "hRawQQQ"); + + 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; + + if(eRingMeV/eWedgeMeV > 3.0 || eRingMeV/eWedgeMeV<1.0/3.0) continue; + //if(eRingMeV<4.0 || eWedgeMeV<4.0) continue; + + double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + + Event qqqevent(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),23+75+30), eRingMeV, eWedgeMeV, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + Event qqqeventr(TVector3(rho*TMath::Cos(theta),rho*TMath::Sin(theta),23+75+30), eRing, eWedge, tRing, tWedge,chRing+qqq.id[i]*16, chWedge+qqq.id[i]*16); + QQQ_Events.push_back(qqqevent); + QQQ_Events_Raw.push_back(qqqeventr); + plotter->Fill2D("QQQCartesianPlot", 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + plotter->Fill2D("QQQCartesianPlot" + std::to_string(qqq.id[i]), 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + if (PCQQQTimeCut) { + plotter->Fill2D("PC_XY_Projection_QQQ_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + else + continue; + + plotter->Fill2D("WedgeE_Vs_RingECal", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + plotter->Fill2D("WedgeE_Vs_RingECal_selected", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + + for (int k = 0; k < pc.multi; k++) + { + plotter->Fill2D("RingCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index" + std::to_string(qqq.id[i]), 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k]); + plotter->Fill2D("RingCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + + if (pc.index[k] < 24 && pc.e[k] > 50) + { + plotter->Fill2D("Timing_Difference_QQQ_PC", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + plotter->Fill2D("DelT_Vs_QQQRingECal", 500, -2000, 2000, 1000, 0, 10, tRing - static_cast(pc.t[k]), eRingMeV, "hTiming"); + plotter->Fill2D("CalibratedQQQEvsPCE_R", 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQEvsPCE_W", 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + if (tRing - static_cast(pc.t[k]) < -150) // proton tests, 27Al + //if (tRing - static_cast(pc.t[k]) < -150 && tRing - static_cast(pc.t[k]) > -450) // 27Al + //if (tRing - static_cast(pc.t[k]) < -70 && tRing - static_cast(pc.t[k]) > -150) // 17F + { + PCQQQTimeCut = true; + } + } + + if (pc.index[k] >= 24 && pc.e[k] > 50) { + plotter->Fill2D("Timing_Difference_QQQ_PC_Cathode", 500, -2000, 2000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + } + } //end of pc k loop + + if (!HitNonZero) { + double theta = -TMath::Pi() / 2 + 2 * TMath::Pi() / 16 / 4. * (qqq.id[i] * 16 + chWedge + 0.5); + double rho = 50. + (50. / 16.) * (chRing + 0.5); //"?" + double x = rho * TMath::Cos(theta); + double y = rho * TMath::Sin(theta); + hitPos.SetXYZ(x, y, (23 + 75 + 30)); + qqqenergy = eRingMeV; + qqqtimestamp = tRing; + HitNonZero = true; + } + } // if j==i + } //j loop end + } //i loop end + + plotter->Fill1D("QQQ_Multiplicity", 10, 0, 10, qqqCount, "hRawQQQ"); + + /*if(QQQ_Events.size()>=1) { + std::cout<< " ---->" << std::endl; + for(auto qe: QQQ_Events) { + std::cout << qe.ch1/16 << " " <> WireEvent; //this stores nearest neighbour wire events, or a 'cluster' + WireEvent aWireEvents, cWireEvents; //naming for book keeping + aWireEvents.clear(); + aWireEvents.reserve(24); + + // PC Gain Matching and Filling + double anodeT = -99999; + double cathodeT = 99999; + int anodeIndex = -1; + int cathodeIndex = -1; + for (int i = 0; i < pc.multi; i++) + { + if (pc.e[i] > 50) + { + plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast(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(pc.t[i]); + anodeIndex = pc.index[i]; + aWireEvents[pc.index[i]] = std::tuple(pc.index[i],pc.e[i],static_cast(pc.t[i])); + } + else + { + cathodeT = static_cast(pc.t[i]); + cathodeIndex = pc.index[i] - 24; + cWireEvents[pc.index[i]-24] = std::tuple(pc.index[i]-24,pc.e[i],static_cast(pc.t[i])); + } + + if (anodeT != -99999 && cathodeT != 99999) + { + for (int j = 0; j < qqq.multi; j++) + { + plotter->Fill1D("PC_Time_qqq", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + plotter->Fill2D("PC_Time_Vs_QQQ_ch", 200, -2000, 2000, 16 * 8, 0, 16 * 8, anodeT - cathodeT, qqq.ch[j], "hTiming"); + plotter->Fill2D("PC_Time_vs_AIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, anodeIndex, "hTiming"); + plotter->Fill2D("PC_Time_vs_CIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, cathodeIndex, "hTiming"); + // plotter->Fill1D("PC_Time_A" + std::to_string(anodeIndex) + "_C" + std::to_string(cathodeIndex), 200, -1000, 1000, anodeT - cathodeT, "TimingPC"); + } + + for (int j = 0; j < sx3.multi; j++) + { + plotter->Fill1D("PC_Time_sx3", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + plotter->Fill1D("PC_Time", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + for (int j = i + 1; j < pc.multi; j++) + { + plotter->Fill2D("PC_Coincidence_Matrix", 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("PC_Coincidence_Matrix_anodeMinusCathode_lt_-200_" + std::to_string(anodeT - cathodeT < -200), 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("Anode_V_Anode", 24, 0, 24, 24, 0, 24, pc.index[i], pc.index[j], "hGMPC"); + } + } + + anodeHits.clear(); + cathodeHits.clear(); + corrcatMax.clear(); + + int aID = 0; + int cID = 0; + double aE = 0; + double cE = 0; + double aESum = 0; + double cESum = 0; + double aEMax = 0; + int aIDMax = 0; + + + + for (int i = 0; i < pc.multi; i++) { + // if (pc.e[i] > 100) + { + if (pc.index[i] < 24) { + anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); + } + else if (pc.index[i] >= 24) { + cathodeHits.push_back(std::pair(pc.index[i] - 24, pc.e[i])); + } + } + } + + std::sort(anodeHits.begin(),anodeHits.end(),[](std::pair a, std::pair b){ return a.first < b.first;}); + std::sort(cathodeHits.begin(),cathodeHits.end(),[](std::pair a, std::pair b){ return a.first < b.first;}); + + //clusters = collection of (collection of wires) where each wire is (index, energy, timestamp) + std::vector>> aClusters = pwinstance.Make_Clusters(aWireEvents); + std::vector>> cClusters = pwinstance.Make_Clusters(cWireEvents); + + std::vector> sumE_AC; + for(auto aCluster: aClusters) { + for(auto cCluster: cClusters) { + if(aCluster.size()<=1 && cCluster.size()<=1) continue; + auto [crossover,alpha,apSumE,cpSumE,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE] = pwinstance.FindCrossoverProperties(aCluster, cCluster); + if(alpha!=9999999 && apSumE!=-1) { + //Event PCEvent(crossover,apMaxE,cpMaxE,apTSMaxE,cpTSMaxE); + //Event PCEvent(crossover,apSumE,cpSumE,apTSMaxE,cpTSMaxE); + Event PCEvent(crossover,apSumE,cpMaxE,apTSMaxE,cpTSMaxE); //run12 shows cathode-max and anode-sum provide best dE signals. + //std::cout << apSumE << " " << crossover.Perp() << " " << apMaxE << " " << apTSMaxE << std::endl; + PC_Events.push_back(PCEvent); + sumE_AC.push_back(std::pair(apSumE,cpSumE)); + } + } + } + if(QQQ_Events.size() && PC_Events.size()) + plotter->Fill2D("PCEv_vs_QQQEv",20,0,20,20,0,20,QQQ_Events.size(),PC_Events.size()); + + for(auto pcevent:PC_Events) { + for(auto sx3event:sx3Events) { + plotter->Fill1D("dt_pcA_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_sx3B"+std::to_string(sx3event.ch2),640,-2000,2000,sx3event.Time1 - pcevent.Time2); + plotter->Fill2D("dE_E_Anodesx3B",400,0,10,800,0,40000,sx3event.Energy1*0.001,pcevent.Energy1); + + plotter->Fill2D("dE_E_Cathodesx3B",400,0,10,800,0,10000,sx3event.Energy1*0.001,pcevent.Energy2); + double sx3z = sx3event.pos.Z()+(75.0/2.0)+23.0-90.0; //w.r.t target origin at 90 for run12 + double sx3rho = 88.0; + double sx3theta = TMath::ATan2(sx3rho,sx3z); + double pczguess = 40.0/TMath::Tan(sx3theta) + 90.0; + plotter->Fill2D("pcz_vs_sx3z",300,0,200,150,0,200,pczguess,pcevent.pos.Z()+25.); + plotter->Fill2D("pcz_vs_sx3z"+std::to_string(sx3event.ch2),300,0,200,150,0,200,pczguess,pcevent.pos.Z()+25); + } + } + + for(auto pcevent: PC_Events) { + for(auto qqqevent: QQQ_Events) { + plotter->Fill1D("dt_pcA_qqqR",640,-2000,2000,qqqevent.Time1 - pcevent.Time1); + plotter->Fill1D("dt_pcC_qqqW",640,-2000,2000,qqqevent.Time2 - pcevent.Time2); + plotter->Fill2D("dE_E_AnodeQQQR",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1); + plotter->Fill2D("dE_E_CathodeQQQR",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2); + double sinTheta = TMath::Sin((qqqevent.pos - TVector3(0,0,90)).Theta())/TMath::Sin((TVector3(51.5,0,128.) - TVector3(0,0,90)).Theta()); + plotter->Fill2D("dE2_E_AnodeQQQR",400,0,10,800,0,40000,qqqevent.Energy1,pcevent.Energy1*sinTheta); + plotter->Fill2D("dE2_E_CathodeQQQR",400,0,10,800,0,10000,qqqevent.Energy2,pcevent.Energy2*sinTheta); + + if(qqqevent.pos.Phi() <= pcevent.pos.Phi()+TMath::Pi()/4. && qqqevent.pos.Phi() >= pcevent.pos.Phi()-TMath::Pi()/4.) { + plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + double pcz_guess = 40.0/TMath::Tan((qqqevent.pos-TVector3(0,0,90)).Theta()) + 90; //this is ideally kept to be all QQQ+userinput for calibration of pcz + plotter->Fill2D("pczguess_vs_pc",300,0,200,150,0,200,pcz_guess,pcevent.pos.Z()+25.,"phicut"); + plotter->Fill2D("pczguess_vs_pc_phi="+std::to_string(qqqevent.pos.Phi()*180./M_PI),300,0,200,150,0,200,pcz_guess,pcevent.pos.Z()+25.,"phicut"); + //plotter->Fill1D("PCZ",800,-200,200,pcevent.pos.Z(),"phicut"); + } + } + } + //HALFTIME! Can stop here in future versions + //return kTRUE; + + 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; + plotter->Fill2D("AnodeMax_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aIDMax, cID, "hRawPC"); + plotter->Fill2D("Anode_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aID, cID, "hRawPC"); + plotter->Fill2D("Anode_vs_CathodeE", 2000, 0, 30000, 2000, 0, 30000, aE, cE, "hGMPC"); + plotter->Fill2D("CathodeMult_V_CathodeE", 6, 0, 6, 2000, 0, 30000, cathodeHits.size(), cE, "hGMPC"); + for (int j = -4; j < 3; j++) + { + if ((aIDMax + 24 + j) % 24 == 23 - cID) + { + corrcatMax.push_back(std::pair(cID, cE)); + cESum += cE; + } + } + } + } + } + + TVector3 anodeIntersection,vector_closest_to_z; + anodeIntersection.Clear(); + vector_closest_to_z.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); + // << "Anode Intersection: " << anodeIntersection.X() << ", " << anodeIntersection.Y() << ", " << anodeIntersection.Z() << std::endl; + } + 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; + } + + for (double Tz = 60; Tz <= 100; Tz += 1.0) + { + TVector3 TargetPos(0, 0, Tz); + if(PCQQQPhiCut && anodeIntersection.Perp()>0 && anodeIntersection.Z()!=0 && cathodeHits.size()>=2) { + plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 400, 0, 180, 90, 0, 90, (anodeIntersection - TargetPos).Theta() * 180. / TMath::Pi(), (hitPos - TargetPos).Theta() * 180. / TMath::Pi(), "TPosVariation"); + //plotter->Fill2D("R_ratio_to_Z_ratio" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 100, -2, 2, 100, -2, 2, (anodeIntersection - TargetPos).Z()/(hitPos-TargetPos).Z(), ((anodeIntersection - TargetPos).Perp()+2.5)/(hitPos-TargetPos).Perp(), "TPosVariation"); + } + } + + if (anodeIntersection.Z() != 0 && anodeIntersection.Perp()>0 && HitNonZero) + { + 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)+ "_PC"+std::to_string(PCQQQPhiCut), 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, -1300, 1300, pw_contr.GetZ0()); + plotter->Fill1D("VertexRecon_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + if (cathodeHits.size() == 2) + plotter->Fill1D("VertexRecon_2c_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, pw_contr.GetZ0()); + + TVector3 x2(anodeIntersection), x1(hitPos); + + TVector3 v = x2-x1; + double t_minimum = -1.0*(x1.X()*v.X()+x1.Y()*v.Y())/(v.X()*v.X()+v.Y()*v.Y()); + vector_closest_to_z = x1 + t_minimum*v; + + plotter->Fill1D("VertexRecon_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + } + + plotter->Fill2D("VertexRecon_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y() ,"customVertex"); + if(cathodeHits.size()==2) { + plotter->Fill1D("VertexRecon2C_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + if(vector_closest_to_z.Perp() < 20) { + plotter->Fill1D("VertexRecon2C_RadialCut_Z_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, vector_closest_to_z.Z() ,"customVertex"); + } + plotter->Fill2D("VertexRecon2C_XY_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 100,-100,100, vector_closest_to_z.X(), vector_closest_to_z.Y() ,"customVertex"); + plotter->Fill2D("VertexRecon2C_RhoZ_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 100, -100, 100, 600,-1300,1300, vector_closest_to_z.Perp(), vector_closest_to_z.Z() ,"customVertex"); + plotter->Fill2D("VertexRecon2C_Z_vs_QQQE_TC"+std::to_string(PCQQQTimeCut)+"_PhiC"+std::to_string(PCQQQPhiCut), 600, -1300, 1300, 800,0,20000, vector_closest_to_z.Z(), qqqenergy ,"customVertex"); + } + + } + + for (int i = 0; i < qqq.multi; i++) + { + if(anodeIntersection.Perp() > 0) { //suppress x,y=0,0 events + 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(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(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("VertexRecon_QQQRingTC" + std::to_string(PCQQQTimeCut) + "PhiC" + std::to_string(PCQQQPhiCut), 600, -1300, 1300, 16, 0, 16, vector_closest_to_z.Z(), 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-vector_closest_to_z).Theta()); + double sinTheta = TMath::Sin((anodeIntersection-TVector3(0,0,90.0)).Theta()); +// double sinTheta = TMath::Sin((anodeIntersection-vector_closest_to_z).Theta()); +// double sinTheta = TMath::Sin((hitPos-TVector3(0,0,30.0)).Theta()); +// double sinTheta = TMath::Sin(hitPos.Theta()); + + if(cathodeHits.size()==2 && PCQQQPhiCut) { + plotter->Fill2D("CalibratedQQQE_RvsCPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsCPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k]*sinTheta, "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_RvsPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQE_WvsPCE_TC" + std::to_string(PCQQQTimeCut) , 400, 0, 10, 400, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("PCQQQ_dTimevsdPhi", 200, -2000, 2000, 80, -200, 200, tRing - static_cast(pc.t[k]), (hitPos.Phi()-anodeIntersection.Phi()) * 180. / TMath::Pi(), "hTiming"); + } + + } + }///qqq i==j case end + } //j loop end + } // qqq i loop end + + TVector3 guessVertex(0,0,90.); //for run12, subtract anodeIntersection.Z() by ~74.0 seems to work + //rho=40.0 mm is halfway between the cathodes(rho=42) and anodes(rho=37) + double pcz_guess = 42.0/TMath::Tan((hitPos-guessVertex).Theta()) + guessVertex.Z(); //this is ideally kept to be all QQQ+userinput for calibration of pcz + if(PCQQQTimeCut && PCQQQPhiCut && hitPos.Perp()>0 && anodeIntersection.Perp()>0 && cathodeHits.size()>=2) { + plotter->Fill2D("pczguess_vs_qqqE",100,0,200,800,0,20,pcz_guess,qqqenergy,"pczguess"); + double pczoffset=30.0; + //plotter->Fill2D("pczguess_vs_pcz_rad="+std::to_string(hitPos.Perp()),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z(),"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz_phi="+std::to_string(hitPos.Phi()*180./M_PI),100,0,200,150,0,200,pcz_guess,anodeIntersection.Z()+pczoffset,"pczguess"); //entirely qqq-derived position vs entirely PC derived position + plotter->Fill2D("pczguess_vs_pcz",100,0,200,150,0,200,pcz_guess,anodeIntersection.Z()+pczoffset); + plotter->Fill2D("pcz_vs_pcPhi_rad="+std::to_string(hitPos.Perp()),360,0,360,150,0,200,anodeIntersection.Phi()*180./M_PI,anodeIntersection.Z()+pczoffset,"pczguess"); + } + for (int i = 0; i < sx3.multi; i++) + { + // plotting sx3 strip hits vs anode phi + if (sx3.ch[i] < 8 && anodeIntersection.Perp()>0) + plotter->Fill2D("PCPhi_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 MakeVertexSX3::Terminate() +{ + /* + // -------------------------------------------------------- + // Section 2 : Gainmatcher minimizer code begins now + std::string minName = "Minuit2"; + std::string algoName = "migrad"; + double defval = 1.0; + + ROOT::Math::Minimizer* minimum = ROOT::Math::Factory::CreateMinimizer(minName, algoName); + if (!minimum) { + std::cerr << "Error: cannot create minimizer \"" << minName + << "\". Maybe the required library was not built?" << std::endl; + return; + } + + // set tolerance , etc... + minimum->SetMaxFunctionCalls(1000000000); // for Minuit/Minuit2 + minimum->SetMaxIterations(10000000); // for GSL + minimum->SetTolerance(0.1); + minimum->SetPrintLevel(1); + + ROOT::Math::Functor f(matcher,&intgm_sx3::eval,24); + matcher->print(); + minimum->SetFunction(f); + + std::vector inparams; + for(int i=0; i<24; i++) { + if(i<16) { + minimum->SetVariable(i,Form("bg%d_%d",i/4,i%4),4.0,0.1); + inparams.emplace_back(4.0); + } else if(i<20) { + minimum->SetVariable(i,Form("r%d",i-20),1.0,0.1); + inparams.emplace_back(1.0); + } else if(i<24) { + minimum->SetVariable(i,Form("stretch%d",i-24),1.0,0.1); + inparams.emplace_back(1.0); + } + minimum->SetVariableLowerLimit(i, 0.0); + } + //minimum->SetFixedVariable(2,"bg2",defval); + + std::ofstream ofile("scratch/results.txt"); + auto oldbuf = std::cerr.rdbuf(); + std::cerr.rdbuf(ofile.rdbuf()); + matcher->plot("before",inparams.data()); + minimum->Minimize(); // do the minimization + + const double *xs = minimum->X(); + std::vector outparams(xs, xs+24); + //outparams[2] = defval; + matcher->plot("after",outparams.data()); + + std::cerr << "#Minval:" << minimum->MinValue() << " status: " << minimum->Status() << std::endl; + for(int i=0; i<24; i++) { + std::cerr << Form("p%02d %g\n",i,outparams.at(i)); + } + + std::cerr.rdbuf(oldbuf); + ofile.close(); + */ + plotter->FlushToDisk(); + delete matcher; +} diff --git a/MakeVertexSX3.h b/MakeVertexSX3.h new file mode 100644 index 0000000..ed02cb7 --- /dev/null +++ b/MakeVertexSX3.h @@ -0,0 +1,132 @@ +#ifndef MakeVertexSX3_h +#define MakeVertexSX3_h + +#include +#include +#include +#include +#include +#include +#include // Required for vectors +#include // Required for std::pair + +#include "Armory/ClassDet.h" +#include "Armory/ClassPW.h" // YOU ADDED THIS (Correct! Defines Coord) + +class MakeVertexSX3 : public TSelector { +public : + TTree *fChain; //!pointer to the analyzed TTree or TChain + + // Declaration of leaf types + Det sx3; + Det qqq; + Det pc ; + Det misc; + + ULong64_t evID; + UInt_t run; + + // List of branches + TBranch *b_eventID; //! + TBranch *b_run; //! + TBranch *b_sx3Multi; //! + TBranch *b_sx3ID; //! + TBranch *b_sx3Ch; //! + TBranch *b_sx3E; //! + TBranch *b_sx3T; //! + TBranch *b_qqqMulti; //! + TBranch *b_qqqID; //! + TBranch *b_qqqCh; //! + TBranch *b_qqqE; //! + TBranch *b_qqqT; //! + TBranch *b_pcMulti; //! + TBranch *b_pcID; //! + TBranch *b_pcCh; //! + TBranch *b_pcE; //! + TBranch *b_pcT; //! + TBranch *b_miscMulti; //! + TBranch *b_miscID; //! + TBranch *b_miscCh; //! + TBranch *b_miscE; //! + TBranch *b_miscT; //! + TBranch *b_miscTf; //! + + // 1. Geometry Cache + Coord Crossover[24][24][2]; + + // 2. Persistent Vectors (REQUIRED for the optimized .cxx to work) + std::vector> anodeHits; + std::vector> cathodeHits; + std::vector> corrcatMax; + std::vector> corranoMax; + std::vector cathodeTimes; + std::vector anodeTimes; + + MakeVertexSX3(TTree * /*tree*/ =0) : fChain(0) { } + virtual ~MakeVertexSX3() { } + virtual Int_t Version() const { return 2; } + virtual void Begin(TTree *tree); + virtual void SlaveBegin(TTree *tree); + virtual void Init(TTree *tree); + virtual Bool_t Notify(); + virtual Bool_t Process(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; } + virtual void SetOption(const char *option) { fOption = option; } + virtual void SetObject(TObject *obj) { fObject = obj; } + virtual void SetInputList(TList *input) { fInput = input; } + virtual TList *GetOutputList() const { return fOutput; } + virtual void SlaveTerminate(); + virtual void Terminate(); + + ClassDef(MakeVertexSX3,0); +}; + +#endif + +#ifdef MakeVertexSX3_cxx +void MakeVertexSX3::Init(TTree *tree){ + + if (!tree) return; + fChain = tree; + fChain->SetMakeClass(1); + + fChain->SetBranchAddress("evID", &evID, &b_eventID); + fChain->SetBranchAddress("run", &run, &b_run); + + sx3.SetDetDimension(24,12); + qqq.SetDetDimension(4,32); + pc.SetDetDimension(2,24); + + fChain->SetBranchAddress("sx3Multi", &sx3.multi, &b_sx3Multi); + fChain->SetBranchAddress("sx3ID", &sx3.id, &b_sx3ID); + fChain->SetBranchAddress("sx3Ch", &sx3.ch, &b_sx3Ch); + fChain->SetBranchAddress("sx3E", &sx3.e, &b_sx3E); + fChain->SetBranchAddress("sx3T", &sx3.t, &b_sx3T); + fChain->SetBranchAddress("qqqMulti", &qqq.multi, &b_qqqMulti); + fChain->SetBranchAddress("qqqID", &qqq.id, &b_qqqID); + fChain->SetBranchAddress("qqqCh", &qqq.ch, &b_qqqCh); + fChain->SetBranchAddress("qqqE", &qqq.e, &b_qqqE); + fChain->SetBranchAddress("qqqT", &qqq.t, &b_qqqT); + fChain->SetBranchAddress("pcMulti", &pc.multi, &b_pcMulti); + fChain->SetBranchAddress("pcID", &pc.id, &b_pcID); + fChain->SetBranchAddress("pcCh", &pc.ch, &b_pcCh); + fChain->SetBranchAddress("pcE", &pc.e, &b_pcE); + fChain->SetBranchAddress("pcT", &pc.t, &b_pcT); + fChain->SetBranchAddress("miscMulti", &misc.multi, &b_miscMulti); + fChain->SetBranchAddress("miscID", &misc.id, &b_miscID); + fChain->SetBranchAddress("miscCh", &misc.ch, &b_miscCh); + fChain->SetBranchAddress("miscE", &misc.e, &b_miscE); + fChain->SetBranchAddress("miscT", &misc.t, &b_miscT); +} + +Bool_t MakeVertexSX3::Notify(){ + return kTRUE; +} + +void MakeVertexSX3::SlaveBegin(TTree * /*tree*/){ + // TString option = GetOption(); +} + +void MakeVertexSX3::SlaveTerminate(){ +} +#endif // #ifdef MakeVertexSX3_cxx diff --git a/ProcessRun.sh b/ProcessRun.sh index 33f9df2..64ce829 100755 --- a/ProcessRun.sh +++ b/ProcessRun.sh @@ -7,22 +7,22 @@ if [ "$#" -ne 3 ]; then exit 1 fi -runID=$(printf "%03d" $1) +runID=$1 timeWindow=$2 option=$3 # rawFolder=/home/tandem/data1/2024_09_17Fap/data -rawFolder=/mnt/d/17F -rootFolder=/mnt/d/Remapped_files/17F_data/root_data +rawFolder=../Raw_data +rootFolder=../root_data if [ $option -eq 0 ]; then # rsync -auh --info=progress2 splitpole@128.186.111.223:/media/nvmeData/2024_09_17Fap/*.fsu /home/tandem/data1/2024_09_17Fap/data - fileList=`\ls -1 ${rawFolder}/*SourceRun_${runID}_*.fsu` + fileList=`\ls -1 ${rawFolder}/*Run_${runID}_*.fsu` - ./EventBuilder ${timeWindow} 0 0 100000000 ${fileList} + # ./EventBuilder ${timeWindow} 0 0 100000000 ${fileList} outFile=${rawFolder}/*${runID}*${timeWindow}.root @@ -31,4 +31,4 @@ if [ $option -eq 0 ]; then ./Mapper ${rootFolder}/*${runID}*${timeWindow}.root fi -# root "processRun.C(\"${rootFolder}/Run_${runID}_mapped.root\")" +root "processRun.C(\"${rootFolder}/Run_${runID}_mapped.root\")" diff --git a/TrackRecon.C.backup b/TrackRecon.C.backup new file mode 100644 index 0000000..c5e169a --- /dev/null +++ b/TrackRecon.C.backup @@ -0,0 +1,742 @@ +#define TrackRecon_cxx + +#include "TrackRecon.h" +#include "Armory/ClassPW.h" +#include "Armory/HistPlotter.h" + +#include +#include +#include +#include +#include +#include "TVector3.h" + +#include +#include +#include +#include +#include +#include + +// Global instances +PW pw_contr; +PW pwinstance; +TVector3 hitPos; + +struct Event { + TVector3 pos; + double Energy1=-1; //Front for QQQ, Anode for PC + double Energy2=-1; //Back for QQQ, Cathode for PC + double Time1=-1; + double Time2=-1; +}; + +// 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 TrackRecon::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 Cuts from file + // { + // std::string filename = "QQQ_PCCut.root"; + // TFile *cutFile = TFile::Open(filename.c_str(), "READ"); + // if (cutFile && !cutFile->IsZombie()) + // { + // cutQQQ = (TCutg *)cutFile->Get("cutQQQPC"); + // if (cutQQQ) + // { + // std::cout << "Loaded QQQ PC cut from " << filename << std::endl; + // } + // else + // { + // std::cerr << "Error: cutQQQPC not found in " << filename << std::endl; + // } + // cutFile->Close(); + // } + // } + + // ... (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); + // std::cout << "QQQ Gain Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " GainW " << gainw << " GainR " << gainr << std::endl; + } + 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); + // std::cout << "QQQ Calib Loaded: Det " << det << " Ring " << ring << " Wedge " << wedge << " Slope " << slope << std::endl; + } + infile.close(); + } + } +} + +Bool_t TrackRecon::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 QQQ_Events, PC_Events; + std::vector QQQ_Events_Raw, PC_Events_Raw; + + + bool PCQQQTimeCut = false; + for (int i = 0; i < qqq.multi; i++) + { + + plotter->Fill2D("QQQ_Index_Vs_Energy", 16 * 8, 0, 16 * 8, 2000, 0, 16000, qqq.index[i], qqq.e[i], "hRawQQQ"); + + for (int j = 0; j < qqq.multi; j++) + { + if (j == i) + continue; + plotter->Fill2D("QQQ_Coincidence_Matrix", 16 * 8, 0, 16 * 8, 16 * 8, 0, 16 * 8, qqq.index[i], qqq.index[j], "hRawQQQ"); + } + + for (int k = 0; k < pc.multi; k++) + { + if (pc.index[k] < 24 && pc.e[k] > 50) + { + plotter->Fill2D("QQQ_Vs_Anode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + plotter->Fill2D("QQQ_Vs_PC_Index", 16 * 8, 0, 16 * 8, 24, 0, 24, qqq.index[i], pc.index[k], "hRawQQQ"); + } + else if (pc.index[k] >= 24 && pc.e[k] > 50) + { + plotter->Fill2D("QQQ_Vs_Cathode_Energy", 400, 0, 4000, 1000, 0, 16000, qqq.e[i], pc.e[k], "hRawQQQ"); + } + } + + 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(qqq.t[j]); + tWedge = static_cast(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(qqq.t[i]); + tWedge = static_cast(qqq.t[j]); + } + else + continue; + + plotter->Fill1D("Wedgetime_Vs_Ringtime", 100, -1000, 1000, tWedge - tRing, "hTiming"); + plotter->Fill2D("RingE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chRing + qqq.id[i] * 16, eRing, "hRawQQQ"); + plotter->Fill2D("WedgeE_vs_Index", 16 * 4, 0, 16 * 4, 1000, 0, 16000, chWedge + qqq.id[i] * 16, eWedge, "hRawQQQ"); + + 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; + + plotter->Fill2D("WedgeE_Vs_RingECal", 1000, 0, 10, 1000, 0, 10, eWedgeMeV, eRingMeV, "hCalQQQ"); + + for (int k = 0; k < pc.multi; k++) + { + plotter->Fill2D("RingCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index", 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Anode_Index" + std::to_string(qqq.id[i]), 16 * 4, 0, 16 * 4, 24, 0, 24, chWedge + qqq.id[i] * 16, pc.index[k]); + plotter->Fill2D("RingCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chRing + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + plotter->Fill2D("WedgeCh_vs_Cathode_Index", 16 * 4, 0, 16 * 4, 24, 24, 48, chWedge + qqq.id[i] * 16, pc.index[k], "hRawQQQ"); + + if (pc.index[k] < 24 && pc.e[k] > 50) + { + // plotter->Fill2D("QQQ_CalibW_Vs_PC_Energy", 1000, 0, 16, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hCalQQQ"); + // plotter->Fill2D("QQQ_CalibR_Vs_PC_Energy", 1000, 0, 16, 2000, 0, 30000, eRingMeV, pc.e[k], "hCalQQQ"); + + // if (tRing - static_cast(pc.t[k]) < 0 && tRing - static_cast(pc.t[k]) > -600) + // // { + // // plotter->Fill2D("QQQ_CalibW_Vs_PC_Energy_Tight", 1000, 0, 16, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hCalQQQ"); + // // plotter->Fill2D("QQQ_CalibR_Vs_PC_Energy_Tight", 1000, 0, 16, 2000, 0, 30000, eRingMeV, pc.e[k], "hCalQQQ"); + // // } + // // else + // // { + // // plotter->Fill2D("QQQ_CalibW_Vs_PC_Energy_OffTime", 1000, 0, 16, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hCalQQQ"); + // // plotter->Fill2D("QQQ_CalibR_Vs_PC_Energy_OffTime", 1000, 0, 16, 2000, 0, 30000, eRingMeV, pc.e[k], "hCalQQQ"); + // // } + plotter->Fill2D("Timing_Difference_QQQ_PC", 500, -1000, 1000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + plotter->Fill2D("DelT_Vs_QQQRingECal", 500, -1000, 1000, 1000, 0, 10, tRing - static_cast(pc.t[k]), eRingMeV, "hTiming"); + plotter->Fill2D("CalibratedQQQEvsPCE_R", 1000, 0, 10, 2000, 0, 30000, eRingMeV, pc.e[k], "hPCQQQ"); + plotter->Fill2D("CalibratedQQQEvsPCE_W", 1000, 0, 10, 2000, 0, 30000, eWedgeMeV, pc.e[k], "hPCQQQ"); + if (tRing - static_cast(pc.t[k]) < -150 && tRing - static_cast(pc.t[k]) > -450) // 27Al + //if (tRing - static_cast(pc.t[k]) < -70 && tRing - static_cast(pc.t[k]) > -150) // 17F + { + PCQQQTimeCut = true; + } + } + + if (pc.index[k] >= 24 && pc.e[k] > 50) { + plotter->Fill2D("Timing_Difference_QQQ_PC_Cathode", 500, -1000, 1000, 16, 0, 16, tRing - static_cast(pc.t[k]), chRing, "hTiming"); + } + } //end of pc loop + + 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); + plotter->Fill2D("QQQPolarPlot", 16 * 4, -TMath::Pi(), TMath::Pi(), 32, 40, 100, theta, rho, "hCalQQQ"); + plotter->Fill2D("QQQCartesianPlot", 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + plotter->Fill2D("QQQCartesianPlot" + std::to_string(qqq.id[i]), 200, -100, 100, 200, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hCalQQQ"); + if (PCQQQTimeCut) + { + plotter->Fill2D("PC_XY_Projection_QQQ_TimeCut" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + } + plotter->Fill2D("PC_XY_Projection_QQQ" + std::to_string(qqq.id[i]), 400, -100, 100, 400, -100, 100, rho * TMath::Cos(theta), rho * TMath::Sin(theta), "hPCQQQ"); + + if (!HitNonZero) + { + double x = rho * TMath::Cos(theta); + double y = rho * TMath::Sin(theta); + hitPos.SetXYZ(x, y, 23 + 75 + 30); + HitNonZero = true; + } + } + } + } + + plotter->Fill1D("QQQ_Multiplicity", 10, 0, 10, qqqCount, "hRawQQQ"); + + // PC Gain Matching and Filling + double anodeT = -99999; + double cathodeT = 99999; + int anodeIndex = -1; + int cathodeIndex = -1; + for (int i = 0; i < pc.multi; i++) + { + if (pc.e[i] > 10) + { + plotter->Fill2D("PC_Index_Vs_Energy", 48, 0, 48, 2000, 0, 30000, pc.index[i], static_cast(pc.e[i]), "hRawPC"); + } + + 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(pc.t[i]); + anodeIndex = pc.index[i]; + } + else + { + cathodeT = static_cast(pc.t[i]); + cathodeIndex = pc.index[i] - 24; + } + + if (anodeT != -99999 && cathodeT != 99999) + { + for (int j = 0; j < qqq.multi; j++) + { + plotter->Fill1D("PC_Time_qqq", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + plotter->Fill2D("PC_Time_Vs_QQQ_ch", 200, -2000, 2000, 16 * 8, 0, 16 * 8, anodeT - cathodeT, qqq.ch[j], "hTiming"); + plotter->Fill2D("PC_Time_vs_AIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, anodeIndex, "hTiming"); + plotter->Fill2D("PC_Time_vs_CIndex", 200, -2000, 2000, 24, 0, 24, anodeT - cathodeT, cathodeIndex, "hTiming"); + // plotter->Fill1D("PC_Time_A" + std::to_string(anodeIndex) + "_C" + std::to_string(cathodeIndex), 200, -1000, 1000, anodeT - cathodeT, "TimingPC"); + } + + for (int j = 0; j < sx3.multi; j++) + { + plotter->Fill1D("PC_Time_sx3", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + plotter->Fill1D("PC_Time", 200, -2000, 2000, anodeT - cathodeT, "hTiming"); + } + + for (int j = i + 1; j < pc.multi; j++) + { + plotter->Fill2D("PC_Coincidence_Matrix", 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("PC_Coincidence_Matrix_anodeMinusCathode_lt_-200_" + std::to_string(anodeT - cathodeT < -200), 48, 0, 48, 48, 0, 48, pc.index[i], pc.index[j], "hRawPC"); + plotter->Fill2D("Anode_V_Anode", 24, 0, 24, 24, 0, 24, pc.index[i], pc.index[j], "hGMPC"); + } + } + + anodeHits.clear(); + cathodeHits.clear(); + corrcatMax.clear(); + + int aID = 0; + int cID = 0; + double aE = 0; + double cE = 0; + double aESum = 0; + double cESum = 0; + double aEMax = 0; + int aIDMax = 0; + + for (int i = 0; i < pc.multi; i++) + { + // if (pc.e[i] > 100) + { + if (pc.index[i] < 24) + anodeHits.push_back(std::pair(pc.index[i], pc.e[i])); + else if (pc.index[i] >= 24) + cathodeHits.push_back(std::pair(pc.index[i] - 24, pc.e[i])); + } + } + + // std::sort(anodeHits.begin(), anodeHits.end(), [](const std::pair &a, const std::pair &b) + // { return a.second > b.second; }); + // std::sort(cathodeHits.begin(), cathodeHits.end(), [](const std::pair &a, const std::pair &b) + // { return a.second > b.second; }); + + 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; + plotter->Fill2D("AnodeMax_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aIDMax, cID, "hRawPC"); + plotter->Fill2D("Anode_Vs_Cathode_Coincidence_Matrix", 24, 0, 24, 24, 0, 24, aID, cID, "hRawPC"); + plotter->Fill2D("Anode_vs_CathodeE", 2000, 0, 30000, 2000, 0, 30000, aE, cE, "hGMPC"); + plotter->Fill2D("CathodeMult_V_CathodeE", 6, 0, 6, 2000, 0, 30000, cathodeHits.size(), cE, "hGMPC"); + for (int j = -4; j < 3; j++) + { + if ((aIDMax + 24 + j) % 24 == 23 - cID) + { + corrcatMax.push_back(std::pair(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); + // std::cout << "Anode Intersection: " << anodeIntersection.X() << ", " << anodeIntersection.Y() << ", " << anodeIntersection.Z() << std::endl; + } + 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; + } + + // for (double Tz = -190; Tz <= 190; Tz += 10.0) + // { + // TVector3 TargetPos(0, 0, Tz); + // plotter->Fill2D("Inttheta_vs_QQQtheta_TC" + std::to_string(PCQQQTimeCut) + "_TZ" + std::to_string(Tz), 90, 0, 180, 120, 0, 180, (anodeIntersection - TargetPos).Theta() * 180. / TMath::Pi(), (hitPos - TargetPos).Theta() * 180. / TMath::Pi(), "TPosVariation"); + // } + + 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, -1300, 1300, 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(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(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(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 TrackRecon::Terminate() +{ + plotter->FlushToDisk(); +} diff --git a/feeder.py b/feeder.py new file mode 100644 index 0000000..768b567 --- /dev/null +++ b/feeder.py @@ -0,0 +1,24 @@ +import keyboard +import time +fi = open("/tmp/eventlist.dat","r") +lines = fi.readlines()[3:] +fo = open("/tmp/coords","w") +for line in lines: + if("--" not in line): + print(line,end='') + fo.write(line) + fo.flush() + else: + if("end" in line): + while True: + time.sleep(2) + key = "n" + #key = input() + if 'n' in key: + break + fo.seek(0) + fo.truncate(0) + print(line,end='') + +fo.close() +fi.close() diff --git a/rootlogon.C b/rootlogon.C new file mode 100644 index 0000000..1d23fdd --- /dev/null +++ b/rootlogon.C @@ -0,0 +1,3 @@ +{ + gSystem->SetBuildDir("./obj/",1); +} diff --git a/run_19_22.sh b/run_19_22.sh new file mode 100644 index 0000000..1f9d6fc --- /dev/null +++ b/run_19_22.sh @@ -0,0 +1,33 @@ +#Alpha runs at different spacer positions +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_009_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_09.root; +###root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_010_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_10.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_012_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_12.root; +#root -l -x Analyzer_QQQ_09.root Analyzer_QQQ_12.root -e "new TBrowser" + +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_009_mapped.root -e 'tree->Process("DataDump.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_09.root; + +#26Al runs +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_027_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_27.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_028_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_28.root; +# root -l -x Analyzer_QQQ_27.root Analyzer_QQQ_28.root -e "new TBrowser" + + +#Proton runs at different spacer positions 26Al +root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_019_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run19.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_021_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_21.root; +root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_022_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run22.root; +root -l -x results_run19.root results_run22.root + +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_084_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run84.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_078_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run78.root; +#root -l -x results_run84.root -e "new TBrowser" + +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/ProtonRun_032_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run32.root; +#root -l -x results_run32.root -e "new TBrowser" + + +#root -q -l -x ../ANASEN_analysis/data/17F_Data/ProtonRun_022_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_22.root; +#root -q -l -x ../ANASEN_analysis/data/17F_Data/ProtonRun_025_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_25.root; +#root -q -l -x ../ANASEN_analysis/data/17F_Data/ProtonRun_026_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_26.root; +#root -q -l -x ../ANASEN_analysis/data/17F_Data/ProtonRun_027_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_27.root; +#root -q -l -x ../ANASEN_analysis/data/17F_Data/ProtonRun_028_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_QQQ.root Analyzer_QQQ_28.root; diff --git a/run_sx3.sh b/run_sx3.sh new file mode 100644 index 0000000..b5d2463 --- /dev/null +++ b/run_sx3.sh @@ -0,0 +1,30 @@ +#Alpha runs at different spacer positions +#rm results_run*.root +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_009_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run09.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_001_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run01.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_002_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run02.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_003_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run03.root; +#root -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_004_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run04.root; + +#alpha+gas 27Al +#root -q -b -x ../ANASEN_analysis/data/27Al_Data/Run_012_mapped.root -e 'tree->Process("MakeVertex.C+O")'; mv Analyzer_SX3.root results_run12.root; + +#protons+gas, 27Al +#root -q -b -x ../ANASEN_analysis/data/27Al_Data/Run_022_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run22.root; +#root -q -b -x ../ANASEN_analysis/data/27Al_Data/Run_021_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run21.root; + +#27Al reaction data +#root -b -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_051_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run51.root; +#root -b -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_078_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run78.root; +#root -b -q -l -x ../ANASEN_analysis/data/27Al_Data/Run_081_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run81.root; + +#root -l -x results_run19.root results_run12.root -e "new TBrowser" + +#17F alpha run with gas +#root -q -l -b -x ../ANASEN_analysis/data/17F_Data/SourceRun_018_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run18.root; +root -q -l -b -x ../ANASEN_analysis/data/17F_Data/SourceRun_019_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run19.root; +#root -q -l -b -x ../ANASEN_analysis/data/17F_Data/SourceRun_020_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run20.root; +#root -q -l -b -x ../ANASEN_analysis/data/17F_Data/SourceRun_021_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run21.root; +#root -q -l -b -x ../ANASEN_analysis/data/17F_Data/Run_104_mapped.root -e 'tree->Process("MakeVertex.C+")'; mv Analyzer_SX3.root results_run104.root; +#mv Analyzer_SX3.root results_run19.root; + diff --git a/sx3cal/17F/backgains.dat b/sx3cal/17F/backgains.dat new file mode 100644 index 0000000..11f9c8e --- /dev/null +++ b/sx3cal/17F/backgains.dat @@ -0,0 +1,23 @@ +1 front 1 back 2 4.4094 +1 front 1 back 1 4.4094 +1 front 2 back 2 4.4832 +1 front 3 back 2 4.52103 +1 front 3 back 1 4.5210 +3 front 1 back 2 3.63215 +3 front 1 back 1 3.70756 +3 front 2 back 2 3.68208 +3 front 2 back 1 3.86817 +3 front 3 back 2 3.7334 +3 front 3 back 1 3.70756 +7 front 1 back 2 3.60769 +7 front 1 back 1 3.46759 +7 front 2 back 2 3.58356 +7 front 2 back 1 3.49018 +7 front 3 back 2 3.60769 +7 front 3 back 1 3.46759 +9 front 1 back 2 3.58356 +9 front 1 back 1 3.44529 +9 front 2 back 2 3.58356 +9 front 2 back 1 3.46759 +9 front 3 back 2 3.63215 +9 front 3 back 1 3.46759 diff --git a/sx3cal/17F/backgains.dat.unity b/sx3cal/17F/backgains.dat.unity new file mode 100644 index 0000000..b7b2b5f --- /dev/null +++ b/sx3cal/17F/backgains.dat.unity @@ -0,0 +1,96 @@ +1 0 0 1. +1 1 0 1. +1 2 0 1. +1 3 0 1. +1 0 1 1. +1 1 1 1. +1 2 1 1. +1 3 1 1. +1 0 2 1. +1 1 2 1. +1 2 2 1. +1 3 2 1. +1 0 3 1. +1 1 3 1. +1 2 3 1. +1 3 3 1. +7 0 0 1. +7 1 0 1. +7 2 0 1. +7 3 0 1. +7 0 1 1. +7 1 1 1. +7 2 1 1. +7 3 1 1. +7 0 2 1. +7 1 2 1. +7 2 2 1. +7 3 2 1. +7 0 3 1. +7 1 3 1. +7 2 3 1. +7 3 3 1. +0 0 0 1. +0 1 0 1. +0 2 0 1. +0 3 0 1. +0 0 1 1. +0 1 1 1. +0 2 1 1. +0 3 1 1. +0 0 2 1. +0 1 2 1. +0 2 2 1. +0 3 2 1. +0 0 3 1. +0 1 3 1. +0 2 3 1. +0 3 3 1. +2 0 0 1. +2 1 0 1. +2 2 0 1. +2 3 0 1. +2 0 1 1. +2 1 1 1. +2 2 1 1. +2 3 1 1. +2 0 2 1. +2 1 2 1. +2 2 2 1. +2 3 2 1. +2 0 3 1. +2 1 3 1. +2 2 3 1. +2 3 3 1. +9 0 0 1. +9 1 0 1. +9 2 0 1. +9 3 0 1. +9 0 1 1. +9 1 1 1. +9 2 1 1. +9 3 1 1. +9 0 2 1. +9 1 2 1. +9 2 2 1. +9 3 2 1. +9 0 3 1. +9 1 3 1. +9 2 3 1. +9 3 3 1. +3 0 0 1. +3 1 0 1. +3 2 0 1. +3 3 0 1. +3 0 1 1. +3 1 1 1. +3 2 1 1. +3 3 1 1. +3 0 2 1. +3 1 2 1. +3 2 2 1. +3 3 2 1. +3 0 3 1. +3 1 3 1. +3 2 3 1. +3 3 3 1. diff --git a/sx3cal/17F/frontgains.dat b/sx3cal/17F/frontgains.dat new file mode 100644 index 0000000..494b776 --- /dev/null +++ b/sx3cal/17F/frontgains.dat @@ -0,0 +1,12 @@ +1 lengthcal front 1 1.5121 60.4839 +1 lengthcal front 2 -1.5625 62.5 +1 lengthcal front 3 2.72177 60.4839 +3 lengthcal front 1 -0.595088 59.5088 +3 lengthcal front 2 -4.53935 58.5723 +3 lengthcal front 3 4.08107 60.4603 +7 lengthcal front 1 1.14329 45.7317 +7 lengthcal front 2 0.115661 46.2646 +7 lengthcal front 3 2.90179 44.6429 +9 lengthcal front 1 0.115732 46.2928 +9 lengthcal front 2 0.799176 45.6672 +9 lengthcal front 3 1.68159 48.0453 diff --git a/sx3cal/17F/frontgains.dat.unity b/sx3cal/17F/frontgains.dat.unity new file mode 100644 index 0000000..a6df93c --- /dev/null +++ b/sx3cal/17F/frontgains.dat.unity @@ -0,0 +1,24 @@ +9 temp temp 0 0. 1. +9 temp temp 1 0. 1. +9 temp temp 2 0. 1. +9 temp temp 3 0. 1. +7 temp temp 0 0. 1. +7 temp temp 1 0. 1. +7 temp temp 2 0. 1. +7 temp temp 3 0. 1. +1 temp temp 0 0. 1. +1 temp temp 1 0. 1. +1 temp temp 2 0. 1. +1 temp temp 3 0. 1. +2 temp temp 0 0. 1. +2 temp temp 1 0. 1. +2 temp temp 2 0. 1. +2 temp temp 3 0. 1. +0 temp temp 0 0. 1. +0 temp temp 1 0. 1. +0 temp temp 2 0. 1. +0 temp temp 3 0. 1. +3 temp temp 0 0. 1. +3 temp temp 1 0. 1. +3 temp temp 2 0. 1. +3 temp temp 3 0. 1. diff --git a/sx3cal/17F/rightgains.dat b/sx3cal/17F/rightgains.dat new file mode 100644 index 0000000..1a4f5c7 --- /dev/null +++ b/sx3cal/17F/rightgains.dat @@ -0,0 +1,16 @@ +1 0 1678.38 1.0 +1 1 1678.38 1.07163 +1 2 1693.99 1.1035 +1 3 1667.9 0.975015 +3 0 1597.96 1.0 +3 1 1597.96 1.02536 +3 2 1821.48 1.29182 +3 3 1607.52 0.928543 +7 0 1773.34 1. +7 1 1773.34 1.14263 +7 2 1573.79 1.06715 +7 3 1542.41 0.956475 +9 0 1555.08 1. +9 1 1555.08 0.998252 +9 2 1559.36 1.00299 +9 3 1585.79 1.01582 diff --git a/sx3cal/17F/rightgains.dat.unity b/sx3cal/17F/rightgains.dat.unity new file mode 100644 index 0000000..2f7a305 --- /dev/null +++ b/sx3cal/17F/rightgains.dat.unity @@ -0,0 +1,24 @@ +9 0 1000 1.0 +9 1 1000 1.0 +9 2 1000 1.0 +9 3 1000 1.0 +7 0 1000 1.0 +7 1 1000 1.0 +7 2 1000 1.0 +7 3 1000 1.0 +2 0 1000 1.0 +2 1 1000 1.0 +2 2 1000 1.0 +2 3 1000 1.0 +0 0 1000 1.0 +0 1 1000 1.0 +0 2 1000 1.0 +0 3 1000 1.0 +1 0 1000 1.0 +1 1 1000 1.0 +1 2 1000 1.0 +1 3 1000 1.0 +3 0 1000 1.0 +3 1 1000 1.0 +3 2 1000 1.0 +3 3 1000 1.0 diff --git a/sx3cal/26Al/backgains.dat b/sx3cal/26Al/backgains.dat new file mode 100644 index 0000000..d1af840 --- /dev/null +++ b/sx3cal/26Al/backgains.dat @@ -0,0 +1,28 @@ +1 front 0 back 2 4.03168 +1 front 1 back 2 4.03168 +1 front 2 back 2 4.11533 +1 front 3 back 2 4.17315 +7 front 0 back 2 4.26886 +7 front 0 back 1 3.44529 +7 front 1 back 2 4.26886 +7 front 1 back 1 3.44529 +7 front 2 back 2 4.26886 +7 front 2 back 1 3.46759 +7 front 3 back 2 4.26886 +7 front 3 back 1 3.44529 +9 front 0 back 2 3.63215 +9 front 0 back 1 3.42327 +9 front 1 back 2 3.63215 +9 front 1 back 1 3.42327 +9 front 2 back 2 3.65694 +9 front 2 back 1 3.46759 +9 front 3 back 2 3.68208 +9 front 3 back 1 3.42327 +3 front 0 back 2 3. +3 front 0 back 1 3. +3 front 1 back 2 3.65694 +3 front 1 back 1 3.68208 +3 front 2 back 2 3.70756 +3 front 2 back 1 3.78616 +3 front 3 back 2 3.7334 +3 front 3 back 1 3.68208 diff --git a/sx3cal/26Al/backgains.dat.unity b/sx3cal/26Al/backgains.dat.unity new file mode 100644 index 0000000..b7b2b5f --- /dev/null +++ b/sx3cal/26Al/backgains.dat.unity @@ -0,0 +1,96 @@ +1 0 0 1. +1 1 0 1. +1 2 0 1. +1 3 0 1. +1 0 1 1. +1 1 1 1. +1 2 1 1. +1 3 1 1. +1 0 2 1. +1 1 2 1. +1 2 2 1. +1 3 2 1. +1 0 3 1. +1 1 3 1. +1 2 3 1. +1 3 3 1. +7 0 0 1. +7 1 0 1. +7 2 0 1. +7 3 0 1. +7 0 1 1. +7 1 1 1. +7 2 1 1. +7 3 1 1. +7 0 2 1. +7 1 2 1. +7 2 2 1. +7 3 2 1. +7 0 3 1. +7 1 3 1. +7 2 3 1. +7 3 3 1. +0 0 0 1. +0 1 0 1. +0 2 0 1. +0 3 0 1. +0 0 1 1. +0 1 1 1. +0 2 1 1. +0 3 1 1. +0 0 2 1. +0 1 2 1. +0 2 2 1. +0 3 2 1. +0 0 3 1. +0 1 3 1. +0 2 3 1. +0 3 3 1. +2 0 0 1. +2 1 0 1. +2 2 0 1. +2 3 0 1. +2 0 1 1. +2 1 1 1. +2 2 1 1. +2 3 1 1. +2 0 2 1. +2 1 2 1. +2 2 2 1. +2 3 2 1. +2 0 3 1. +2 1 3 1. +2 2 3 1. +2 3 3 1. +9 0 0 1. +9 1 0 1. +9 2 0 1. +9 3 0 1. +9 0 1 1. +9 1 1 1. +9 2 1 1. +9 3 1 1. +9 0 2 1. +9 1 2 1. +9 2 2 1. +9 3 2 1. +9 0 3 1. +9 1 3 1. +9 2 3 1. +9 3 3 1. +3 0 0 1. +3 1 0 1. +3 2 0 1. +3 3 0 1. +3 0 1 1. +3 1 1 1. +3 2 1 1. +3 3 1 1. +3 0 2 1. +3 1 2 1. +3 2 2 1. +3 3 2 1. +3 0 3 1. +3 1 3 1. +3 2 3 1. +3 3 3 1. diff --git a/sx3cal/26Al/frontgains.dat b/sx3cal/26Al/frontgains.dat new file mode 100644 index 0000000..e1519c5 --- /dev/null +++ b/sx3cal/26Al/frontgains.dat @@ -0,0 +1,16 @@ +1 lengthcal front 0 0.878906 58.5938 +1 lengthcal front 1 1.42045 56.8182 +1 lengthcal front 2 -2.55682 56.8182 +1 lengthcal front 3 2.55682 56.8182 +7 lengthcal front 0 0.425806 42.5806 +7 lengthcal front 1 1.92004 45.1774 +7 lengthcal front 2 1.11607 44.6429 +7 lengthcal front 3 3.45909 44.6334 +9 lengthcal front 0 1.82872 45.7181 +9 lengthcal front 1 1.01649 45.1774 +9 lengthcal front 2 1.46827 45.1774 +9 lengthcal front 3 2.54513 46.2751 +3 lengthcal front 0 0. 50. +3 lengthcal front 1 1.1713 58.5652 +3 lengthcal front 2 -3.07505 58.5723 +3 lengthcal front 3 4.0726 60.3348 diff --git a/sx3cal/26Al/frontgains.dat.unity b/sx3cal/26Al/frontgains.dat.unity new file mode 100644 index 0000000..7f21ff5 --- /dev/null +++ b/sx3cal/26Al/frontgains.dat.unity @@ -0,0 +1,20 @@ +9 temp temp 0 0. 1. +9 temp temp 1 0. 1. +9 temp temp 2 0. 1. +9 temp temp 3 0. 1. +7 temp temp 0 0. 1. +7 temp temp 1 0. 1. +7 temp temp 2 0. 1. +7 temp temp 3 0. 1. +1 temp temp 0 0. 1. +1 temp temp 1 0. 1. +1 temp temp 2 0. 1. +1 temp temp 3 0. 1. +2 temp temp 0 0. 1. +2 temp temp 1 0. 1. +2 temp temp 2 0. 1. +2 temp temp 3 0. 1. +0 temp temp 0 0. 1. +0 temp temp 1 0. 1. +0 temp temp 2 0. 1. +0 temp temp 3 0. 1. diff --git a/sx3cal/26Al/rightgains.dat b/sx3cal/26Al/rightgains.dat new file mode 100644 index 0000000..374c899 --- /dev/null +++ b/sx3cal/26Al/rightgains.dat @@ -0,0 +1,16 @@ +1 0 1221.23 0.648782 +1 1 1819.66 1.06196 +1 2 1860.02 1.11979 +1 3 1825.44 0.964989 +7 0 1609.63 1.04668 +7 1 1734.45 1.12285 +7 2 1538.97 1.0486 +7 3 1524.57 0.951587 +9 0 1672.38 1.11321 +9 1 1542.13 1.01442 +9 2 1540.38 0.967847 +9 3 1560.42 0.969022 +3 0 1000.0 1. +3 1 1539.42 1.0422 +3 2 1720.12 1.31534 +3 3 1562.16 1.00415 diff --git a/sx3cal/26Al/rightgains.dat.unity b/sx3cal/26Al/rightgains.dat.unity new file mode 100644 index 0000000..2f7a305 --- /dev/null +++ b/sx3cal/26Al/rightgains.dat.unity @@ -0,0 +1,24 @@ +9 0 1000 1.0 +9 1 1000 1.0 +9 2 1000 1.0 +9 3 1000 1.0 +7 0 1000 1.0 +7 1 1000 1.0 +7 2 1000 1.0 +7 3 1000 1.0 +2 0 1000 1.0 +2 1 1000 1.0 +2 2 1000 1.0 +2 3 1000 1.0 +0 0 1000 1.0 +0 1 1000 1.0 +0 2 1000 1.0 +0 3 1000 1.0 +1 0 1000 1.0 +1 1 1000 1.0 +1 2 1000 1.0 +1 3 1000 1.0 +3 0 1000 1.0 +3 1 1000 1.0 +3 2 1000 1.0 +3 3 1000 1.0 diff --git a/sx3cal/EXFit.C b/sx3cal/EXFit.C index f5ff855..c673b76 100755 --- a/sx3cal/EXFit.C +++ b/sx3cal/EXFit.C @@ -1,6 +1,6 @@ { - int index = 3; - TFile *f = new TFile("../results_SX3_run12.root"); + int index = 1; + TFile *f = new TFile("../results_run19.root"); TH2F *h2=NULL; TH1F *h1x=NULL, *h1y=NULL; //f->cd("evsx"); @@ -17,8 +17,8 @@ h2 = (TH2F*)(f->Get(Form("evsx/be_vs_x_sx3_id_%d_f%d_b%d",index,i,backnum))); auto macro = [&]() { h1x = (TH1F*)(h2->ProjectionX("_px")); - double xleft = h1x->GetBinCenter(h1x->FindFirstBinAbove(h1x->GetMaximum()*0.25)); - double xright = h1x->GetBinCenter(h1x->FindLastBinAbove(h1x->GetMaximum()*0.25)); + double xleft = h1x->GetBinCenter(h1x->FindFirstBinAbove(h1x->GetMaximum()*0.4)); + double xright = h1x->GetBinCenter(h1x->FindLastBinAbove(h1x->GetMaximum()*0.4)); //h1x->GetXaxis()->SetRangeUser(4*xleft, xright*4); h1x->Draw(); TLine L1(xleft,0,xleft,h1x->GetMaximum()); L1.SetLineColor(kRed); L1.Draw("SAME"); diff --git a/sx3cal/LRFit.C b/sx3cal/LRFit.C index c034eb2..3ec36e1 100755 --- a/sx3cal/LRFit.C +++ b/sx3cal/LRFit.C @@ -1,8 +1,8 @@ { - TFile *f = new TFile("../results_SX3_run12.root"); + TFile *f = new TFile("../results_run19.root"); f->cd("l_vs_r"); - f->ls(); - int clkpos = 3; + gDirectory->ls(); + int clkpos = 13; std::ofstream ofile(Form("rightgains%d.dat",clkpos)); for(int i=1; i<4; i++) { TH2F h2(*(TH2F*)(f->Get(Form("l_vs_r/l_vs_r_sx3_id_%d_f%d",clkpos,i)))); @@ -14,7 +14,7 @@ gPad->Update(); while(gPad->WaitPrimitive());*/ - int leftbin = hproj.FindFirstBinAbove(hproj.GetMaximum()*0.1); + int leftbin = hproj.FindFirstBinAbove(hproj.GetMaximum()*0.4); int rightbin = hproj.FindLastBinAbove(hproj.GetMaximum()*0.1); TH1F h1(*(TH1F*)(h2.ProfileX("_pfx",leftbin,rightbin))); diff --git a/sx3cal/backgains1.dat b/sx3cal/backgains1.dat new file mode 100644 index 0000000..bdd8d85 --- /dev/null +++ b/sx3cal/backgains1.dat @@ -0,0 +1,3 @@ +1 front 1 back 2 4.4094 +1 front 2 back 2 4.4832 +1 front 3 back 2 4.52103 diff --git a/sx3cal/backgains9.dat b/sx3cal/backgains9.dat new file mode 100644 index 0000000..a062ce0 --- /dev/null +++ b/sx3cal/backgains9.dat @@ -0,0 +1,6 @@ +9 front 1 back 2 3.58356 +9 front 1 back 1 3.44529 +9 front 2 back 2 3.58356 +9 front 2 back 1 3.46759 +9 front 3 back 2 3.63215 +9 front 3 back 1 3.46759 diff --git a/sx3cal/frontgains1.dat b/sx3cal/frontgains1.dat new file mode 100644 index 0000000..ec327e5 --- /dev/null +++ b/sx3cal/frontgains1.dat @@ -0,0 +1,3 @@ +1 lengthcal front 1 1.5121 60.4839 +1 lengthcal front 2 -1.5625 62.5 +1 lengthcal front 3 2.72177 60.4839 diff --git a/sx3cal/frontgains9.dat b/sx3cal/frontgains9.dat new file mode 100644 index 0000000..e558d92 --- /dev/null +++ b/sx3cal/frontgains9.dat @@ -0,0 +1,3 @@ +9 lengthcal front 1 0.115732 46.2928 +9 lengthcal front 2 0.799176 45.6672 +9 lengthcal front 3 1.68159 48.0453 diff --git a/sx3cal/rightgains1.dat b/sx3cal/rightgains1.dat new file mode 100644 index 0000000..5e93f7e --- /dev/null +++ b/sx3cal/rightgains1.dat @@ -0,0 +1,3 @@ +1 1 1678.38 1.07163 +1 2 1693.99 1.1035 +1 3 1667.9 0.975015 diff --git a/sx3cal/rightgains13.dat b/sx3cal/rightgains13.dat new file mode 100644 index 0000000..4bab787 --- /dev/null +++ b/sx3cal/rightgains13.dat @@ -0,0 +1,3 @@ +13 1 1 1 +13 2 1 1 +13 3 1 1 diff --git a/sx3cal/rightgains9.dat b/sx3cal/rightgains9.dat new file mode 100644 index 0000000..93ad2b1 --- /dev/null +++ b/sx3cal/rightgains9.dat @@ -0,0 +1,3 @@ +9 1 1555.08 0.998252 +9 2 1559.36 1.00299 +9 3 1585.79 1.01582