15 #include "TPrincipal.h"
20 fTree =
tfs->make<TTree>(
"MatchingVariables",
"MatchingVariables");
39 std::map<double,TVector2> hitProjection;
42 for (
auto &
hit : cluster) {
43 pos = HitCoordinates(
hit) - centre;
44 hitProjection[direction*pos] = pos;
48 start = hitProjection.begin()->second.Proj(direction) + centre;
49 end = hitProjection.rbegin()->second.Proj(direction) + centre;
59 double clusterOverlap = 0;
62 double s1 = (start1-centre)*direction;
63 double e1 = (end1-centre)*direction;
64 double s2 = (start2-centre)*direction;
65 double e2 = (end2-centre)*direction;
69 std::cout <<
"s1>e1: " << s1 <<
" and " << e1 << std::endl;
75 std::cout <<
"s1>e1: " << s1 <<
" and " << e1 << std::endl;
82 if ((e1 > s2) && (e2 > s1))
83 clusterOverlap = std::min((e1 - s2), (e2 - s1));
85 return clusterOverlap;
94 double dcross = (direction1.X() * direction2.Y()) - (direction1.Y() * direction2.X());
95 TVector2
p = centre2 - centre1;
96 double pcrossd = (p.X() * direction2.Y()) - (p.Y() * direction2.X());
97 TVector2 crossing = centre1 + ((pcrossd/dcross) * direction1);
100 double crossingDistance = std::min((centre1-crossing).Mod(),(centre2-crossing).Mod());
102 return crossingDistance;
110 double minDistance = 99999.;
113 for (
auto const& hit1 : cluster1) {
114 for (
auto const& hit2 : cluster2) {
116 TVector2 pos1 = HitCoordinates(hit1);
117 TVector2 pos2 = HitCoordinates(hit2);
119 double distance = (pos1 - pos2).Mod();
121 if (distance < minDistance) minDistance =
distance;
135 TVector2 parallel = (centre2 - centre1).Unit();
136 TVector2 perpendicular = parallel.Rotate(TMath::Pi()/2);
139 double s1 = (start1-centre1)*perpendicular;
140 double e1 = (end1-centre1)*perpendicular;
141 double s2 = (start2-centre2)*perpendicular;
142 double e2 = (end2-centre2)*perpendicular;
145 double projectionStart = std::max(TMath::Abs(s1), TMath::Abs(s2));
146 double projectionEnd = std::max(TMath::Abs(e1), TMath::Abs(e2));
148 double projectionWidth = projectionStart + projectionEnd;
150 return projectionWidth;
158 double wireCentre[3];
159 fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
163 if (wireID.
TPC % 2 == 0) globalWire =
fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 0, wireID.
Cryostat);
164 else globalWire =
fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 1, wireID.
Cryostat);
179 return TVector2(GlobalWire(hit->WireID()), hit->PeakTime());
303 std::vector<unsigned int> mergedClusters;
305 std::vector<art::PtrVector<recob::Hit> > oldClusters = planeClusters;
308 std::sort(oldClusters.begin(), oldClusters.end(), [](
const art::PtrVector<recob::Hit> &
a,
const art::PtrVector<recob::Hit> &b) {
return a.size() > b.size();} );
311 unsigned int nclusters = 0;
312 for (
auto &
cluster : oldClusters)
313 if (
cluster.size() >= fMinMergeClusterSize) ++nclusters;
316 bool mergedAllClusters =
false;
317 while (!mergedAllClusters) {
320 art::PtrVector<recob::Hit>
cluster;
323 for (
unsigned int initCluster = 0; initCluster < oldClusters.size(); ++initCluster) {
324 if (oldClusters.at(initCluster).size() < fMinMergeClusterSize or std::find(mergedClusters.begin(), mergedClusters.end(), initCluster) != mergedClusters.end())
continue;
325 cluster = oldClusters.at(initCluster);
326 mergedClusters.push_back(initCluster);
331 bool mergedAllToThisCluster =
false;
332 while (!mergedAllToThisCluster) {
336 for (
unsigned int trialCluster = 0; trialCluster < oldClusters.size(); ++trialCluster) {
338 if (oldClusters.at(trialCluster).size() < fMinMergeClusterSize or std::find(mergedClusters.begin(), mergedClusters.end(), trialCluster) != mergedClusters.end())
continue;
341 TPrincipal *pca1 =
new TPrincipal(2,
""), *pca2 =
new TPrincipal(2,
"");
346 TVector2 chargePoint1 = TVector2(0,0), chargePoint2 = TVector2(0,0);
347 double totalCharge1 = 0, totalCharge2 = 0;
349 for (
auto &hit1 : cluster) {
350 pos = HitCoordinates(hit1);
354 chargePoint1 += hit1->Integral() * pos;
355 totalCharge1 += hit1->Integral();
357 for (
auto &hit2 : oldClusters.at(trialCluster)) {
358 pos = HitCoordinates(hit2);
362 chargePoint2 += hit2->Integral() * pos;
363 totalCharge2 += hit2->Integral();
366 pca1->MakePrincipals();
367 pca2->MakePrincipals();
370 TVector2 direction1 = TVector2( (*pca1->GetEigenVectors())[0][0], (*pca1->GetEigenVectors())[1][0] ).Unit();
371 TVector2 direction2 = TVector2( (*pca2->GetEigenVectors())[0][0], (*pca2->GetEigenVectors())[1][0] ).Unit();
372 TVector2 direction = ((direction1+direction2)/2).Unit();
373 TVector2 centre1 = chargePoint1 / totalCharge1;
374 TVector2 centre2 = chargePoint2 / totalCharge2;
375 TVector2 centre = (centre1+centre2)/2;
376 TVector2 start1, end1;
377 TVector2 start2, end2;
378 FindClusterEndPoints(cluster, centre1, direction1, start1, end1);
379 FindClusterEndPoints(oldClusters.at(trialCluster), centre2, direction2, start2, end2);
380 double length1 = (end1-start1).Mod();
381 double length2 = (end2-start2).Mod();
384 double crossingDistance = FindCrossingDistance(direction1, centre1, direction2, centre2);
385 double projectedWidth = FindProjectedWidth(centre1, start1, end1, centre2, start2, end2);
386 double angle = direction1.DeltaPhi(direction2);
387 if (angle > 1.57) angle = 3.14159 -
angle;
388 double overlap = FindClusterOverlap(direction, centre, start1, end1, start2, end2);
389 double separation = FindMinSeparation(cluster, oldClusters.at(trialCluster));
391 if (separation > fMaxMergeSeparation)
393 if (PassCuts(angle, crossingDistance, projectedWidth, separation, overlap,
TMath::Max(length1, length2))) {
395 for (
auto &
hit : oldClusters.at(trialCluster))
396 cluster.push_back(
hit);
398 mergedClusters.push_back(trialCluster);
408 if (nadded == 0) mergedAllToThisCluster =
true;
412 clusters.push_back(cluster);
413 if (mergedClusters.size() == nclusters) mergedAllClusters =
true;
417 return clusters.size();
425 bool passCrossingDistanceAngle =
false;
426 if (crossingDistance < (-2 + (5 / (1 * TMath::Abs(angle)) - 0) ) )
427 passCrossingDistanceAngle =
true;
429 bool passSeparationAngle =
false;
430 if (separation < (200 * TMath::Abs(angle) + 40))
431 passSeparationAngle =
true;
433 bool passProjectedWidth =
false;
434 if (((
double)projectedWidth/(
double)longLength) < fProjWidthThreshold)
435 passProjectedWidth =
true;
437 return passCrossingDistanceAngle
and passSeparationAngle
and passProjectedWidth;
442 fMinMergeClusterSize = p.get<
int> (
"MinMergeClusterSize");
443 fMaxMergeSeparation = p.get<
double>(
"MaxMergeSeparation");
444 fProjWidthThreshold = p.get<
double>(
"ProjWidthThreshold");
MergeClusterAlg(fhicl::ParameterSet const &pset)
void FindClusterEndPoints(art::PtrVector< recob::Hit > const &cluster, TVector2 const ¢re, TVector2 const &direction, TVector2 &start, TVector2 &end) const
art::ServiceHandle< art::TFileService const > tfs
CryostatID_t Cryostat
Index of cryostat.
WireID_t Wire
Index of the wire within its plane.
void reconfigure(fhicl::ParameterSet const &p)
double FindClusterOverlap(TVector2 const &direction, TVector2 const ¢re, TVector2 const &start1, TVector2 const &end1, TVector2 const &start2, TVector2 const &end2) const
int MergeClusters(std::vector< art::PtrVector< recob::Hit > > const &planeClusters, std::vector< art::PtrVector< recob::Hit > > &clusters) const
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Signal from induction planes.
bool PassCuts(double const &angle, double const &crossingDistance, double const &projectedWidth, double const &separation, double const &overlap, double const &longLength) const
auto end(FixedBins< T, C > const &) noexcept
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
PlaneID_t Plane
Index of the plane within its TPC.
TVector2 HitCoordinates(art::Ptr< recob::Hit > const &hit) const
double FindMinSeparation(art::PtrVector< recob::Hit > const &cluster1, art::PtrVector< recob::Hit > const &cluster2) const
double FindCrossingDistance(TVector2 const &direction1, TVector2 const ¢re1, TVector2 const &direction2, TVector2 const ¢re2) const
finds tracks best matching by angle
double GlobalWire(geo::WireID const &wireID) const
TPCID_t TPC
Index of the TPC within its cryostat.
double FindProjectedWidth(TVector2 const ¢re1, TVector2 const &start1, TVector2 const &end1, TVector2 const ¢re2, TVector2 const &start2, TVector2 const &end2) const
BEGIN_PROLOG could also be cout