LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
ClusterMatchTQ.cxx
Go to the documentation of this file.
12 
16 
17 #include "TH1D.h"
18 
19 struct CluLen{
20  int index;
21  float length;
22 };
23 
24 bool SortByLength (CluLen const&c1, CluLen const& c2) {
25  return (c1.length>c2.length);
26 }
27 
29  return h1->WireID().Wire < h2->WireID().Wire;
30 }
31 
32 namespace cluster{
33 
34  ClusterMatchTQ::ClusterMatchTQ(fhicl::ParameterSet const& pset){
35  this->reconfigure(pset);
36  }
37 
38  //---------------------------------------------------------------------
39  void ClusterMatchTQ::reconfigure(fhicl::ParameterSet const& pset){
40  fKSCut = pset.get< double >("KSCut");
41  fEnableU = pset.get< bool >("EnableU");
42  fEnableV = pset.get< bool >("EnableV");
43  fEnableZ = pset.get< bool >("EnableZ");
44  }
45 
46  //---------------------------------------------------------------------
47  void ClusterMatchTQ::ClusterMatch(const std::vector<art::Ptr<recob::Cluster> > &clusterlist, const art::FindManyP<recob::Hit> &fm){
48 
49  matchedclusters.clear();
50 
51  // get services
53  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
54 
55  int nplanes = geom->Nplanes();
56  int nts = detprop->NumberTimeSamples();
57 
58  std::vector< std::vector<TH1D*> > signals(nplanes);
59 
60  std::vector< std::vector<unsigned int> > Cls(nplanes);
61  std::vector< std::vector<CluLen> > clulens(nplanes);
62 
63  for (size_t iclu = 0; iclu<clusterlist.size(); ++iclu){
64 
65  float wire_pitch = geom->WirePitch(clusterlist[iclu]->Plane());
66 
67  float w0 = clusterlist[iclu]->StartWire();
68  float w1 = clusterlist[iclu]->EndWire();
69  float t0 = clusterlist[iclu]->StartTick();
70  float t1 = clusterlist[iclu]->EndTick();
71 
72  CluLen clulen;
73  clulen.index = iclu;
74  clulen.length = sqrt(pow((w0-w1)*wire_pitch,2)+pow(detprop->ConvertTicksToX(t0,clusterlist[iclu]->Plane().Plane,clusterlist[iclu]->Plane().TPC,clusterlist[iclu]->Plane().Cryostat)-detprop->ConvertTicksToX(t1,clusterlist[iclu]->Plane().Plane,clusterlist[iclu]->Plane().TPC,clusterlist[iclu]->Plane().Cryostat),2));
75 
76  switch(clusterlist[iclu]->View()){
77  case geo::kU :
78  if (fEnableU) clulens[0].push_back(clulen);
79  break;
80  case geo::kV :
81  if (fEnableV) clulens[1].push_back(clulen);
82  break;
83  case geo::kZ :
84  if (fEnableZ) clulens[2].push_back(clulen);
85  break;
86  default :
87  break;
88  }
89  }
90 
91  //sort clusters based on 2D length
92  for (size_t i = 0; i<clulens.size(); ++i){
93  std::sort (clulens[i].begin(),clulens[i].end(), SortByLength);
94  for (size_t j = 0; j<clulens[i].size(); ++j){
95  Cls[i].push_back(clulens[i][j].index);
96  }
97  }
98 
99  for (int i = 0; i<nplanes; ++i){
100  for (size_t ic = 0; ic < Cls[i].size(); ++ic){
101  TH1D sig(Form("sig_%d_%d",i,int(ic)),Form("sig_%d_%d",i,int(ic)),nts+100,-100,nts);
102  TH1D sigint(Form("sigint_%d_%d",i,int(ic)),Form("sigint_%d_%d",i,int(ic)),nts+100,-100,nts);
103  std::vector< art::Ptr<recob::Hit> > hitlist = fm.at(Cls[i][ic]);
104  std::sort(hitlist.begin(), hitlist.end(), SortByWire);
105 
106  for(auto theHit = hitlist.begin(); theHit != hitlist.end(); theHit++){
107 
108  double time = (*theHit)->PeakTime();
109  time -= detprop->GetXTicksOffset((*theHit)->WireID().Plane,
110  (*theHit)->WireID().TPC,
111  (*theHit)->WireID().Cryostat);
112 
113  double charge = (*theHit)->Integral();
114  int bin = sig.FindBin(time);
115  sig.SetBinContent(bin,sig.GetBinContent(bin)+charge);
116  for (int j = bin; j<=sig.GetNbinsX(); ++j){
117  sigint.SetBinContent(j,sigint.GetBinContent(j)+charge);
118  }
119  }
120  if (sigint.Integral()) sigint.Scale(1./sigint.GetBinContent(sigint.GetNbinsX()));
121  signals[i].push_back(new TH1D(sigint));
122  }
123  }
124 
125  //matching clusters between different views
126  std::vector<int> matched(clusterlist.size());
127  for (size_t i = 0; i<clusterlist.size(); ++i) matched[i] = 0;
128 
129  for (int i = 0; i<nplanes-1; ++i){
130  for (int j = i+1; j<nplanes; ++j){
131  for (size_t c1 = 0; c1<Cls[i].size(); ++c1){
132  for (size_t c2 = 0; c2<Cls[j].size(); ++c2){
133 
134  // check if both are the same view
135  if (clusterlist[Cls[i][c1]]->View()==
136  clusterlist[Cls[j][c2]]->View()) continue;
137  // check if both are in the same cryostat and tpc
138  if (clusterlist[Cls[i][c1]]->Plane().Cryostat!=
139  clusterlist[Cls[j][c2]]->Plane().Cryostat) continue;
140  if (clusterlist[Cls[i][c1]]->Plane().TPC!=
141  clusterlist[Cls[j][c2]]->Plane().TPC) continue;
142  // check if both are already in the matched list
143  if (matched[Cls[i][c1]]==1&&matched[Cls[j][c2]]==1) continue;
144  // KS test between two views in time
145  double ks = 0;
146  if (signals[i][c1]->Integral()
147  &&signals[j][c2]->Integral())
148  ks = signals[i][c1]->KolmogorovTest(signals[j][c2]);
149  else{
150  mf::LogWarning("ClusterMatchTQ") <<"One of the two clusters appears to be empty: "<<clusterlist[Cls[i][c1]]->ID()<<" "<<clusterlist[Cls[j][c2]]->ID()<<" "<<i<<" "<<j<<" "<<c1<<" "<<c2<<" "<<signals[i][c1]->Integral()<<" "<<signals[j][c2]->Integral();
151  }
152  //hks->Fill(ks);
153  int imatch = -1; //track candidate index
154  int iadd = -1; //cluster index to be inserted
155  if (ks>fKSCut){//pass KS test
156  // check both clusters with all matched clusters
157  // if one is already matched,
158  // check if need to add the other to the same track candidate
159  for (size_t l = 0; l<matchedclusters.size(); ++l){
160  for (size_t m = 0; m<matchedclusters[l].size(); ++m){
161  if (matchedclusters[l][m]==Cls[i][c1]){
162  imatch = l; //track candidate
163  iadd = j; //consider the other cluster
164  }
165  else if (matchedclusters[l][m]==Cls[j][c2]){
166  imatch = l; //track candidate
167  iadd = i; //consider the other cluster
168  }
169  }
170  }
171  if (imatch>=0){
172  if (iadd == i){
173  bool matchview = false;
174  // check if one matched cluster has the same view
175  for (size_t ii = 0; ii<matchedclusters[imatch].size(); ++ii){
176  if (clusterlist[matchedclusters[imatch][ii]]->View()==
177  clusterlist[Cls[i][c1]]->View()){
178  matchview = true;
179  //replace if the new cluster has more hits
180  if (fm.at(Cls[i][c1]).size()>fm.at(matchedclusters[imatch][ii]).size()){
181  matched[matchedclusters[imatch][ii]] = 0;
182  matchedclusters[imatch][ii] = Cls[i][c1];
183  matched[Cls[i][c1]] = 1;
184  }
185  }
186  }
187  if (!matchview){//not matched view found, just add
188  matchedclusters[imatch].push_back(Cls[i][c1]);
189  matched[Cls[i][c1]] = 1;
190  }
191  }
192  else {
193  bool matchview = false;
194  for (size_t jj = 0; jj<matchedclusters[imatch].size(); ++jj){
195  if (clusterlist[matchedclusters[imatch][jj]]->View()==
196  clusterlist[Cls[j][c2]]->View()){
197  matchview = true;
198  //replace if it has more hits
199  if (fm.at(Cls[j][c2]).size()>fm.at(matchedclusters[imatch][jj]).size()){
200  matched[matchedclusters[imatch][jj]] = 0;
201  matchedclusters[imatch][jj] = Cls[j][c2];
202  matched[Cls[j][c2]] = 1;
203  }
204  }
205  }
206  if (!matchview){
207  matchedclusters[imatch].push_back(Cls[j][c2]);
208  matched[Cls[j][c2]] = 1;
209  }
210  }
211  }
212  else{
213  std::vector<unsigned int> tmp;
214  tmp.push_back(Cls[i][c1]);
215  tmp.push_back(Cls[j][c2]);
216  matchedclusters.push_back(tmp);
217  matched[Cls[i][c1]]=1;
218  matched[Cls[j][c2]]=1;
219  }
220  }//pass KS test
221  }//c2
222  }//c1
223  }//j
224  }//i
225 
226  for (size_t i = 0; i<matchedclusters.size(); ++i){
227  if (matchedclusters[i].size()) mf::LogVerbatim("ClusterMatchTQ")<<"Cluster group "<<i<<":";
228  for (size_t j = 0; j<matchedclusters[i].size(); ++j){
229  mf::LogVerbatim("ClusterMatchTQ")<<matchedclusters[i][j];
230  }
231  }
232 
233 
234  for (int i = 0; i<nplanes; ++i){
235  for (size_t j = 0; j<signals[i].size(); ++j){
236  delete signals[i][j];
237  }
238  }
239 
240  }//ClusterMatch
241 }//namespace cluster
code to link reconstructed objects back to the MC truth information
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
TTree * t1
Definition: plottest35.C:26
Planes which measure V.
Definition: geo_types.h:77
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
Plane(const Point_t &planePos, const Vector_t &planeDir)
Constructor from reference position on the plane and direction orthogonal to the plane.
Definition: TrackingPlane.h:61
Planes which measure Z direction.
Definition: geo_types.h:79
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
Float_t tmp
Definition: plot.C:37
Cluster finding and building.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Planes which measure U.
Definition: geo_types.h:76
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
TCanvas * c1
Definition: plotHisto.C:7
TCanvas * c2
Definition: plot_hist.C:75
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
virtual unsigned int NumberTimeSamples() const =0
float bin[41]
Definition: plottest35.C:14
bool SortByWire(art::Ptr< recob::Hit > const &h1, art::Ptr< recob::Hit > const &h2)
TH1F * h2
Definition: plot.C:46
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
float length
bool SortByLength(CluLen const &c1, CluLen const &c2)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
TH1F * h1
Definition: plot.C:43
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
recob::tracking::Plane Plane
Definition: TrackState.h:17
art framework interface to geometry description
virtual double GetXTicksOffset(int p, int t, int c) const =0