ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
AtPRA.cxx
Go to the documentation of this file.
1 #include "AtPRA.h"
2 
3 #include "AtContainerManip.h"
4 #include "AtHit.h" // for AtHit, XYZPoint
5 #include "AtPattern.h" // for AtPattern
6 #include "AtPatternCircle2D.h"
7 #include "AtPatternEvent.h"
8 #include "AtPatternLine.h"
9 #include "AtPatternTypes.h" // for PatternType, PatternTy...
10 #include "AtSampleConsensus.h"
11 #include "AtTrack.h" // for XYZPoint, AtTrack
12 
13 #include <FairLogger.h>
14 
15 #include <Math/Point3D.h> // for PositionVector3D, Cart...
16 #include <Math/Vector2D.h> // for PositionVector3D, Cart...
17 #include <Math/Vector2Dfwd.h> // for XYVector
18 #include <Math/Vector3D.h> // for DisplacementVector3D
19 #include <TGraph.h> // for TGraph
20 #include <TMath.h> // for Power, Sqrt, ATan2, Pi
21 
22 #include <algorithm> // for max, for_each, copy_if
23 #include <cmath> // for fabs, acos
24 #include <cstddef> // for size_t
25 #include <exception> // for exception
26 #include <iostream> // for operator<<, basic_ostream
27 #include <memory> // for shared_ptr, __shared_p...
29 
36 {
37 
38  /*
39 std::cout << " Processing track with " << track.GetHitArray().size() << " points."
40  << "\n";
41  for (auto &hit : track.GetHitArray())
42  std::cout << hit.GetTimeStamp() << " ";
43  std::cout << std::endl;
44  */
45 
46  SampleConsensus::AtSampleConsensus RansacSmoothRadius;
48  RansacSmoothRadius.SetMinHitsPattern(0.1 * track.GetHitArray().size());
49  RansacSmoothRadius.SetDistanceThreshold(6.0);
50  RansacSmoothRadius.SetNumIterations(1000);
51  auto circularTracks = RansacSmoothRadius.Solve(ContainerManip::GetConstPointerVector(track.GetHitArray()))
52  .GetTrackCand(); // Only part of the spiral is used
53  // This function also sets the coefficients
54  // i.e. radius of curvature and center
55 
56  if (!circularTracks.empty()) {
57 
58  auto &hits = circularTracks.at(0).GetHitArray();
59 
60  auto circle = dynamic_cast<const AtPatterns::AtPatternCircle2D *>(circularTracks.at(0).GetPattern());
61 
62  auto center = circle->GetCenter();
63  auto radius = circle->GetRadius();
64 
65  track.SetGeoCenter({center.X(), center.Y()});
66  track.SetGeoRadius(radius);
67  track.SetPattern(circle->Clone());
68 
69  // std::vector<double> wpca;
70  std::vector<double> whit;
71  std::vector<double> arclength;
72 
73  auto arclengthGraph = std::make_unique<TGraph>();
74 
75  auto posPCA = hits.at(0)->GetPosition();
76  auto refPosOnCircle = posPCA - center;
77  auto refAng = refPosOnCircle.Phi(); // Bounded between (-Pi,Pi]
78 
79  std::vector<AtHit> thetaHits;
80 
81  // The number of times we have crossed the -Y axis.
82  // Increase by 1 when moving from +y to -y
83  // Decrease by 1 when moving from -y to +y
84  int numYCross = 0;
85  int lastYSign = GetSign(refPosOnCircle.Y());
86 
87  for (size_t i = 0; i < hits.size(); ++i) {
88 
89  auto pos = hits.at(i)->GetPosition();
90  auto posOnCircle = pos - center;
91  auto angleHit = posOnCircle.Phi();
92 
93  // Check for a move over -Y axis
94  int currYSign = GetSign(posOnCircle.Y());
95 
96  // If we have moved over the Y axis in some direction
97  // last = (0 or -1) and current = 1 -> numCross--
98  // last = (0 or 1) and current = -1 -> numCross++
99  if (posOnCircle.X() < 0 && lastYSign != currYSign) {
100  numYCross -= currYSign;
101  }
102  lastYSign = currYSign;
103  angleHit += 2 * M_PI * numYCross;
104 
105  whit.push_back(angleHit);
106  arclength.push_back((radius * (refAng - whit.at(i))));
107 
108  arclengthGraph->SetPoint(arclengthGraph->GetN(), arclength.at(i), pos.Z());
109 
110  if (track.GetTrackID() > -1)
111  LOG(debug2) << posOnCircle.X() << " " << posOnCircle.Y() << " " << pos.Z() << " "
112  << hits.at(i)->GetTimeStamp() << " " << arclength.back() << "\n";
113 
114  // Add a hit in the Arc legnth - Z plane
115  Double_t xPos = arclength.at(i);
116  Double_t yPos = pos.Z();
117  Double_t zPos = i * 1E-19;
118 
119  thetaHits.emplace_back(i, hits.at(i)->GetPadNum(), XYZPoint(xPos, yPos, zPos), hits.at(i)->GetCharge());
120  }
121 
122  // TF1 *f1 = new TF1("f1", "pol1", -500, 500);
123  // TF1 * f1 = new TF1("f1",[](double *x, double *p) { return (p[0]+p[1]*x[0]); },-500,500,2);
124  // TF1 * f1 = new TF1("f1","[0]+[1]*x",-500,500);
125  // TF1 *f1 = new TF1("f1", fitf, -500, 500, 2);
126  // arclengthGraph->Fit(f1, "R");
127  // auto slope = ROOT::Math::XYVector(1, f1->GetParameter(1)).Unit();
128  // std::cout << " Slope " << slope << "\n";
129 
130  Double_t angle = 0.0;
131  Double_t phi0 = 0.0;
132 
133  try {
134 
135  if (thetaHits.size() > 0) {
136  // std::cout<<" RANSAC Theta "<<"\n";
137  std::vector<AtTrack> thetaTracks;
138 
141  RansacTheta.SetMinHitsPattern(0.1 * thetaHits.size());
142  RansacTheta.SetDistanceThreshold(6.0);
143  RansacTheta.SetFitPattern(true);
144  thetaTracks = RansacTheta.Solve(thetaHits).GetTrackCand();
145 
146  if (thetaTracks.size() > 0) {
147 
148  // NB: Only the most intense line is taken, if any
149  auto line = dynamic_cast<const AtPatterns::AtPatternLine *>(thetaTracks.at(0).GetPattern());
150  LOG(info) << "Track ID: " << track.GetTrackID() << " with " << track.GetHitArray().size()
151  << " hits. Fit " << thetaTracks[0].GetHitArray().size() << "/" << thetaHits.size()
152  << " hits in first of " << thetaTracks.size() << " tracks";
153 
154  auto dirTheta = line->GetDirection();
155  auto dir2D = ROOT::Math::XYVector(dirTheta.X(), dirTheta.Y()).Unit();
156 
157  int sign = 0;
158 
159  if (dir2D.X() * dir2D.Y() < 0)
160  sign = -1;
161  else
162  sign = 1;
163 
164  if (dir2D.X() != 0) {
165  angle = acos(sign * fabs(dir2D.Y())) * TMath::RadToDeg();
166  }
167 
168  LOG(info) << "Setting theta geo to: " << angle << " with ransac direction: " << dir2D;
169  for (int i = 1; i < thetaTracks.size(); ++i) {
170  auto ranLine = dynamic_cast<const AtPatterns::AtPatternLine *>(thetaTracks.at(i).GetPattern());
171  auto ranDir = ROOT::Math::XYVector(ranLine->GetDirection().X(), ranLine->GetDirection().Y()).Unit();
172  LOG(info) << "RANSAC direction " << i << " with " << thetaTracks[i].GetHitArray().size() << "/"
173  << thetaHits.size() << ": " << ranDir;
174  }
175 
176  auto temp2 = posPCA - center;
177  phi0 = TMath::ATan2(temp2.Y(), temp2.X());
178 
179  } // thetaTracks
180  track.SetGeoTheta(angle * TMath::Pi() / 180.0);
181  track.SetGeoPhi(phi0);
182 
183  } // if
184  else {
185  LOG(info) << "Track ID: " << track.GetTrackID() << " with " << track.GetHitArray().size()
186  << " hits does not have enough theta hits to get angle";
187  }
188 
189  } catch (std::exception &e) {
190 
191  std::cout << " AtPRA::SetTrackInitialParameters - Exception caught : " << e.what() << "\n";
192  }
193 
194  } // end if (!circularTracks->empty())
195 }
196 
197 Double_t fitf(Double_t *x, Double_t *par)
198 {
199 
200  return par[0] + par[1] * x[0];
201 }
202 
204 {
205  auto &hitArray = track.GetHitArray();
206 
207  std::cout << " === Prunning track : " << track.GetTrackID() << "\n";
208  std::cout << " = Hit Array size : " << hitArray.size() << "\n";
209 
210  for (auto iHit = 0; iHit < hitArray.size(); ++iHit) {
211 
212  try {
213  bool isNoise = kNN(hitArray, *hitArray.at(iHit), fKNN); // Returns true if hit is an outlier
214 
215  if (isNoise) {
216  // std::cout<<" Hit "<<iHit<<" flagged as outlier. "<<"\n";
217  hitArray.erase(hitArray.begin() + iHit);
218  }
219  } catch (std::exception &e) {
220 
221  std::cout << " AtPRA::PruneTrack - Exception caught : " << e.what() << "\n";
222  }
223  }
224 
225  std::cout << " = Hit Array size after prunning : " << hitArray.size() << "\n";
226 }
227 
228 bool AtPATTERN::AtPRA::kNN(const std::vector<std::unique_ptr<AtHit>> &hits, AtHit &hitRef, int k)
229 {
230 
231  std::vector<Double_t> distances;
232  distances.reserve(hits.size());
233 
234  std::for_each(hits.begin(), hits.end(), [&distances, &hitRef](const std::unique_ptr<AtHit> &hit) {
235  distances.push_back(TMath::Sqrt((hitRef.GetPosition() - hit->GetPosition()).Mag2()));
236  });
237 
238  std::sort(distances.begin(), distances.end(), [](Double_t a, Double_t b) { return a < b; });
239 
240  Double_t mean = 0.0;
241  Double_t stdDev = 0.0;
242 
243  if (k > hits.size())
244  k = hits.size();
245 
246  // Compute mean distance of kNN
247  for (auto i = 0; i < k; ++i)
248  mean += distances.at(i);
249 
250  mean /= k;
251 
252  // Compute std dev
253  for (auto i = 0; i < k; ++i)
254  stdDev += TMath::Power((distances.at(i) - mean), 2);
255 
256  stdDev = TMath::Sqrt(stdDev / k);
257 
258  // Compute threshold
259  Double_t T = mean + stdDev * fStdDevMulkNN;
260 
261  return (T < fkNNDist) ? false : true;
262 }
263 
264 /*
265 void AtPATTERN::AtPRA::SetTrackCurvature(AtTrack &track)
266 {
267  std::cout << " new track "
268  << "\n";
269  std::vector<double> radius_vec;
270  std::vector<AtHit> hitArray = track.GetHitArray();
271  int nstep = 0.60 * hitArray.size(); // 20% of the hits to calculate the radius of curvature with less fluctuations
272 
273  for (Int_t iHit = 0; iHit < (hitArray.size() - nstep); iHit++) {
274 
275  AtHit hitA = hitArray.at(iHit);
276  AtHit hitB = hitArray.at((int)(iHit + (nstep / 2.0)));
277  AtHit hitC = hitArray.at((int)(iHit + nstep));
278 
279  // std::cout<<nstep<<" "<<iHit<<" "<<(int)(iHit+(nstep/2.0))<<" "<<(int)(iHit+nstep)<<"\n";
280 
281  auto posA = hitA.GetPosition();
282  auto posB = hitB.GetPosition();
283  auto posC = hitC.GetPosition();
284 
285  double slopeAB = (posB.Y() - posA.Y()) / (posB.X() - posA.X()); // m1
286  double slopeBC = (posC.Y() - posB.Y()) / (posC.X() - posB.X()); // m2
287 
288  double centerX = (slopeAB * slopeBC * (posA.Y() - posC.Y()) + slopeBC * (posB.X() + posA.X()) -
289  slopeAB * (posB.X() + posC.X())) /
290  (2.0 * (slopeBC - slopeAB));
291 
292  double centerY = (-1 / slopeAB) * (centerX - (posB.X() + posA.X()) / 2.0) + (posB.Y() + posA.Y()) / 2.0;
293 
294  // std::cout<<" Center "<<centerX<<" - "<<centerY<<"\n";
295 
296  double radiusA = TMath::Sqrt(TMath::Power(posA.X() - centerX, 2) + TMath::Power(posA.Y() - centerY, 2));
297  radius_vec.push_back(radiusA);
298  double radiusB = TMath::Sqrt(TMath::Power(posB.X() - centerX, 2) + TMath::Power(posB.Y() - centerY, 2));
299  radius_vec.push_back(radiusB);
300  double radiusC = TMath::Sqrt(TMath::Power(posC.X() - centerX, 2) + TMath::Power(posC.Y() - centerY, 2));
301  radius_vec.push_back(radiusC);
302  }
303 }
304 */
SampleConsensus::AtSampleConsensus::SetDistanceThreshold
void SetDistanceThreshold(Float_t threshold)
Definition: AtSampleConsensus.h:87
AtPATTERN::AtPRA::kNN
bool kNN(const std::vector< std::unique_ptr< AtHit >> &hits, AtHit &hit, int k)
Definition: AtPRA.cxx:228
XYVector
ROOT::Math::XYVector XYVector
Definition: AtEDistortionModel.cxx:23
AtTrack::SetPattern
void SetPattern(std::unique_ptr< AtPatterns::AtPattern > pat)
Definition: AtTrack.h:99
SampleConsensus::AtSampleConsensus::Solve
AtPatternEvent Solve(AtEvent *event)
See Solve(const std::vector<const AtHit *> &hitArray)
Definition: AtSampleConsensus.cxx:60
SampleConsensus::AtSampleConsensus
Perform a sample consensus on a cloud of AtHits.
Definition: AtSampleConsensus.h:46
AtTrack::SetGeoTheta
void SetGeoTheta(Double_t angle)
Definition: AtTrack.h:101
AtPRA.h
SampleConsensus::AtSampleConsensus::SetNumIterations
void SetNumIterations(Int_t niterations)
Definition: AtSampleConsensus.h:85
AtPattern.h
AtPatterns::AtPatternLine
Describes a linear track.
Definition: AtPatternLine.h:28
SampleConsensus::AtSampleConsensus::SetFitPattern
void SetFitPattern(bool val)
Definition: AtSampleConsensus.h:89
AtPatterns::PatternType::kCircle2D
@ kCircle2D
AtPATTERN::AtPRA
Find patterns in hit clouds.
Definition: AtPRA.h:32
ContainerManip::GetConstPointerVector
std::vector< const T * > GetConstPointerVector(const std::vector< T > &vec)
Definition: AtContainerManip.h:85
AtTrack::SetGeoRadius
void SetGeoRadius(Double_t radius)
Definition: AtTrack.h:103
fitf
Double_t fitf(Double_t *x, Double_t *par)
Definition: AtPRA.cxx:197
AtPATTERN::AtPRA::GetSign
constexpr int GetSign(T num, std::true_type is_signed)
Definition: AtPRA.h:84
XYZPoint
ROOT::Math::XYZPoint XYZPoint
Definition: AtPatternCircle2D.h:18
AtPatternLine.h
SampleConsensus::AtSampleConsensus::SetPatternType
void SetPatternType(PatternType type)
Definition: AtSampleConsensus.h:82
AtTrack::SetGeoPhi
void SetGeoPhi(Double_t angle)
Definition: AtTrack.h:102
AtHit.h
AtPatternEvent::GetTrackCand
std::vector< AtTrack > & GetTrackCand()
Definition: AtPatternEvent.h:56
AtSampleConsensus.h
AtTrack
Definition: AtTrack.h:25
AtPATTERN::AtPRA::SetTrackInitialParameters
void SetTrackInitialParameters(AtTrack &track)
Set initial parameters for HC.
Definition: AtPRA.cxx:35
AtTrack.h
AtPatternEvent.h
AtPatterns::AtPatternCircle2D::GetCenter
XYZPoint GetCenter() const
Definition: AtPatternCircle2D.h:30
AtTrack::GetTrackID
Int_t GetTrackID() const
Definition: AtTrack.h:78
AtTrack::SetGeoCenter
void SetGeoCenter(std::pair< Double_t, Double_t > center)
Definition: AtTrack.h:104
AtContainerManip.h
AtPatternTypes.h
ClassImp
ClassImp(AtPATTERN::AtPRA)
sign
Double_t sign(Double_t num)
Definition: AtTPC_d2He.cxx:39
AtPATTERN::AtPRA::PruneTrack
void PruneTrack(AtTrack &track)
Definition: AtPRA.cxx:203
AtPatterns::PatternType::kLine
@ kLine
AtPatternCircle2D.h
SampleConsensus::AtSampleConsensus::SetMinHitsPattern
void SetMinHitsPattern(Int_t nhits)
Definition: AtSampleConsensus.h:86
AtTrack::GetHitArray
HitVector & GetHitArray()
Definition: AtTrack.h:79
AtHit
Point in space with charge.
Definition: AtHit.h:27
mean
double mean(const double *a, size_t m)
Definition: cluster.cxx:26
AtPatterns::AtPatternCircle2D
Describes a circle track projected to the XY plane.
Definition: AtPatternCircle2D.h:26