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