LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SmallClusterFinderAlg.cxx
Go to the documentation of this file.
1 //
3 // \file SmallClusterFinderAlg.cxx
4 //
5 // \author corey.adams@yale.edu
6 //
7 // This algorithm is designed to find small clusters that could correspond to gammas
8 // or low energy electrons.
9 //
10 /* There are two parameters that matter from the fcl file:
11  fNHitsInClust is the number of hits that should be in these small clusters
12  ^-- Gamma events seem to rarely have more than 4 hits in the cluster
13  ^-- SN events are unclear. Should this even be used for SN?
14  fRadiusSizePar is the distance (in cm) between the small clusters and any other hits.
15 
16  This algorithm sorts the hits by plane, and then looks at each hit individually. If
17  there is a hit within RadiusSizePar, it gets added to a local list. All other hits
18  are ignored. Then, if the number of hits that got added to the local list is greater
19  then NHitsInClust, the original hit is ignored. If it's less, the original hit is
20  presumed to be part of a very small (or single hit) cluster. So its added to the list
21  of hits in the small cluster.
22 
23  All of the small clusters are then split apart into groups in the way you would expect.
24  Each cluster is assigned an ID number to distinguish it, and the hits that aren't
25  identified as small clusters all end up in the "leftover" cluster. The numbering scheme
26  is ID = 100*iPlane + Cluster on that plane, and the leftover hits are the first (0th)
27  cluster written out.
28 
29  -Corey
30 */
31 //
32 //
34 
35 #include <iostream>
36 
37 // Framework includes
39 #include "fhiclcpp/ParameterSet.h"
47 
48 // LArSoft includes
49 //#include "Simulation/sim.h"
50 //#include "Simulation/SimListUtils.h"
55 //#include "SimulationBase/simbase.h"
56 //#include "RawData/RawDigit.h"
57 //#include "SummaryData/summary.h"
58 //#include "CLHEP/Random/JamesRandom.h"
59 //#include "Utilities/SeedCreator.h"
60 
61 // ***************** //
62 
63 //default constructor:
65 
67 
68  fNPlanes = geom -> Nplanes();
69 
71 
72 }
73 
74 //constructor with parameters:
76 
77  fNPlanes = geom -> Nplanes();
78  //call reconfigure to grab all the good
79  this -> reconfigure(pset);
81 
82 }
83 
84 //Ability to update the .fcl parameter set:
86 {
87  fRadiusSizePar =pset.get< double > ("RadiusSizePar");
88  fNHitsInClust =pset.get< double > ("NHitsInClust");
89  verbose =pset.get< bool > ("Verbose");
90 
91  //fRadiusSizePar is used to exclude hits from a cluster outside of a certain size
92  //fNHitsInClust ensures the clusters don't get too big
93  //verbose determines the number of printouts - all or nothing, really.
94  }
95 
96 // ***************** //
97 // This method actually makes the clusters.
99 {
100  const detinfo::DetectorProperties* detp = lar::providerFrom<detinfo::DetectorPropertiesService>();
101 
103  fDriftVelocity=detp->DriftVelocity(detp->Efield(),detp->Temperature());
104  fWirePitch = geom -> WirePitch();
105  fTimeTick=detp->SamplingRate()/1000.;
109 
111 
112  //A vector to hold hits, not yet filled:
113  //std::vector< art::Ptr<recob::Hit> > hitlist;
114 
115  //Catch the case were there are no hits in the event:
116  if(allHits.size() ==0 )
117  {
118  if (verbose) std::cout << " no hits received! exiting " << std::endl;
119  return;
120  }
121 
122  //std::cout << "Received " << allHits.size() << " hits from the art::producer." << std::endl;
123 
124  art::Ptr< recob::Hit> theHit;
125 
126  //sort the hits into hits by plane
127  for(std::vector<art::Ptr<recob::Hit> >::iterator HitIter = allHits.begin();
128  HitIter != allHits.end(); HitIter ++){
129  theHit = *HitIter;
130  unsigned int p(0),w(0), t(0),cs(0); //c=channel, p=plane, w=wire, but what is t?
131  GetPlaneAndTPC(*HitIter,p,cs,t,w); //Find out what plane this hit is on.
132  //add this hit to the list specific to this plane
133  hitlistbyplane[p].push_back(theHit);
134  //std::cout << "Added a hit to plane " << p << std::endl;
135  } // End loop on hits.
136 
137  //Want to check that the wires are OK for each event, and by each wire.
138  //This could be done in HitFinder, but I'm doing it here because I want to do some things
139  //specifically for Small Clusters...
140  //Flags to look for:
141  // Does this wire have more hits that the other wires that also have hits? Significantly more?
142  // Does the RMS of this hit lie well below the peak of the hit? Significantly below?
143  // More?
144  // If a bad wire is found, remove all of it's from the hitlists so they aren't clustered.
145 
146  //Start by looping over planes:
147  for (unsigned int ip=0; ip< fNPlanes; ip++){
148  //Need to sort the hits into which are on the wires...
149  //Of course, larsoft doesn't allow the wires to know which hits are on them.
150  //So I guess we'll circumvent that by just making up our own struct for this.
151  }
152 
153 
154  //make the refined hit list for each plane.
155  for(unsigned int ip=0;ip<fNPlanes;ip++) {
156  //std::cout << "Before refining, " << hitlistbyplane[ip].size() << " hits on plane " << ip << std::endl;
158 
159  //Check that the lists are populated correctly:
160  if (verbose) std::cout << "At plane " << ip << ", found " << hitlistrefined[ip].size() << " hits with " << hitlistleftover[ip].size() << " leftover" << std::endl;
161  //add the leftover hits to the correct object:
162  }
163 
164  //Now we have all of the gammas. This is good!
165  //Want to split all of the gammas up into individual clusters.
166 
167  //I was going to use lists instead of vectors to do this, because lists are more efficient
168  //at insertion and removal at arbitrary places. But, the number of gammas is so small that
169  //it just doesn't seem worth it
170  //
171  //Also, larsoft is so slow on its own that i think the difference is undetectable
172 
173  // The method to split the gammas into individual clusters that I want is:
174  // Use the existing method below to find all the hits within a certain distance from a given hit
175  // Take ALL of those hits and write them to a cluster.
176  // Then, remove those hits from the list of gammas.
177 
178  // Repeat, until the list of gammas is empty.
179 
180  // There is an issue of knowing which hits to remove from the total gamma hit list.
181  // To solve this, I'm going to overload SelectLocalHitList to take a reference to a vector
182  // of ints as an argument. When a hit is added to the local hit list,
183  // it's index will be added to a vector that is returned by reference.
184  // It's important to remove these hits in reverse order. This is because removing a hit
185  // changes the index of all of the hits after it
186 
187 
188 
189 
190  // make an art::PtrVector of the clusters
191  //std::auto_ptr<std::vector<recob::Cluster> > SmallClusterFinder(new std::vector<recob::Cluster>);
192  //std::auto_ptr< art::Assns<recob::Cluster, recob::Hit> > assn(new art::Assns<recob::Cluster, recob::Hit>);
193 
194  //Now we need to take the lists of small clusters and sort it into the individual spots
195  //going to end up with smallClustList[plane][iClust][Hit]
196  //loop over planes of hits:
197 
198  for(unsigned int iplane=0;iplane<fNPlanes;iplane++){
199 
200 
201  if (hitlistrefined[iplane].size() == 0 ) continue;
202 
203  //write the rest of the gammas one by one, in clusters:
204  int i = 1;
205 
206  std::vector<art::Ptr<recob::Hit> > splittingVector = hitlistrefined[iplane];
207 
208  while (splittingVector.size() != 0){
209 
210  // std::cout << "\nThe hits remaining to be spilt are:" << std::endl;
211  //for (unsigned int j = 0; j < splittingVector.size();j++){
212  // std::cout << *splittingVector[j] << std::endl;
213  //}
214 
215  //find the first small cluster of gammas:
216  std::vector<int> index;
217  std::vector< art::Ptr<recob::Hit> > thiscluster;
218  thiscluster.clear();
219  index.clear();
220 
221  //Just use the first hit in the list of gammas:
222 
223  art::Ptr<recob::Hit> theHit = splittingVector.front(); //grab a hit from the list
224 
225  double time = theHit->PeakTime() ;
226  unsigned int plane(0),cstat(0),tpc(0),wire(0);
227  //std::cout << "The hit is " << (*theHit) << std::endl;
228  GetPlaneAndTPC(theHit,plane,cstat,tpc,wire);
229 
230  // std::cout << "The time of the seed hit is " << time << std::endl;
231 
232  SelectLocalHitlist(splittingVector, thiscluster, wire, time, fRadiusSizePar,index);
233 
234  if (verbose) std::cout << "Done writing " << thiscluster.size() << " hits to cluster with ID " << plane *100 + i << std::endl;
235  //make sure to add these hits to the object that stores them:
236  smallClustList[plane].push_back(thiscluster);
237 
238  //Lastly, remove the gammas just clustered from the refinded hit list
239  while (index.size() != 0){
240  //for (int j = 0; j < index.size();j++) std::cout << index[j] << " ";
241  //std::cout << "\nSize of index is " << index.size() << std::endl;
242  //std::cout << "Size of hitlistrefined is " << splittingVector.size() << std::endl;
243  //std::cout << "Erasing element at " << index.back() << std::endl;
244  splittingVector.erase( splittingVector.begin() + ( index.back() ) );
245  index.pop_back();
246  }
247  i++;
248  }
249  }
250  return;
251 }
252 
253 // ************************************* //
254 // Clear and resize - exactly what it sounds like
256  smallClustList.clear();
257  hitlistbyplane.clear();
258  hitlistrefined.clear();
259  hitlistleftover.clear();
260  smallClustList.resize(fNPlanes);
261  hitlistbyplane.resize(fNPlanes);
262  hitlistrefined.resize(fNPlanes);
263  hitlistleftover.resize(fNPlanes);
264  return;
265 }
266 
267 
268 
269 /* This is the method takes a list of hits ("hitlist") and compares each hit to a 2D
270  location that is specified by a wire ("wire_start") and time ("time_start"). If the
271  hit being examined is farther away than a specified distance ("radlimit", in cm) then
272  the hit is excluded. If the hit is within that distance, it's added.
273 */
275  std::vector < art::Ptr<recob::Hit> > &hitlistlocal,
276  double wire_start,
277  double time_start,
278  double radlimit)
279 {
280  //loop over the hits in "hitlist", which should contain the hits we're selecting from
281  for(std::vector < art::Ptr < recob::Hit > >::const_iterator hitIter = hitlist.begin(); hitIter != hitlist.end(); hitIter++){
282  art::Ptr<recob::Hit> theHit = (*hitIter);
283  double time = theHit->PeakTime() ;
284  unsigned int plane,cstat,tpc,wire;
285  GetPlaneAndTPC(theHit,plane,cstat,tpc,wire);
286  //we now know which wire and what time this hit occurred on
287 
288 
289  //calculate linear distance from start point and orthogonal distance from axis
290  double linear_dist=gser.Get2DDistance(wire,time,wire_start,time_start);
291 
292  if ( linear_dist < radlimit ) hitlistlocal.push_back(theHit);
293  }
294  return;
295 }
296 
297 //This method is identical to the other method by the same name except that
298 //it keeps track of the location of the hits selected. That is, index is filled with
299 //the indices of the selected hits in the hitlist vector (the input vector)
301  std::vector < art::Ptr<recob::Hit> > &hitlistlocal,
302  double wire_start,
303  double time_start,
304  double radlimit,
305  std::vector<int> &index)
306 {
307  //loop over the hits in "hitlist", which should contain the hits we're selecting from
308  int i = 0; //i keeps track of the index of the hit.
309  for(std::vector < art::Ptr < recob::Hit > >::const_iterator hitIter = hitlist.begin(); hitIter != hitlist.end(); hitIter++){
310  art::Ptr<recob::Hit> theHit = (*hitIter);
311  double time = theHit->PeakTime() ;
312  unsigned int plane,cstat,tpc,wire;
313  GetPlaneAndTPC(theHit,plane,cstat,tpc,wire);
314  //we now know which wire and what time this hit occurred on
315 
316 
317  //calculate linear distance from start point and orthogonal distance from axis
318  double linear_dist=gser.Get2DDistance(wire,time,wire_start,time_start);
319 
320  if ( linear_dist<radlimit ) {
321  hitlistlocal.push_back(theHit);
322  index.push_back(i);
323  }
324  i++;
325  }
326  //std::cout << "in select local hit list, index is:" << std::endl;
327  //for (int j = 0; j < index.size();j++) std::cout << index[j] << " ";
328 
329  //need to make sure the index array is in order. Sort it!
330  std::sort (index.begin(), index.end());
331 
332  return;
333 }
334 
335 
336 /* This method sorts this hitlist (which should only be on a single plane)
337 
338 */
340 {
341 
342  std::vector< art::Ptr<recob::Hit> > hitlist_total; //This is the final result, a list of hits that are small clusters
343 
344  std::vector < art::Ptr<recob::Hit> > hitlistlocal;
345  //std::cout << "The hitlist size is " << hitlist.size() << std::endl;
346  //for (unsigned int iHit =0; iHit < hitlist.size();iHit++) std::cout << (*hitlist[iHit]) << std::endl;
347 
348 
349  for(unsigned int ix = 0; ix< hitlist.size(); ix++){
350 
351  art::Ptr<recob::Hit> theHit = hitlist[ix]; //grab a hit from the list
352 
353  double time = theHit->PeakTime() ;
354  unsigned int plane(0),cstat(0),tpc(0),wire(0);
355  //std::cout << "The hit is " << (*theHit) << std::endl;
356  GetPlaneAndTPC(theHit,plane,cstat,tpc,wire);
357  //use the wire and time of this hit as a seed.
358  // ^^^^^ This could probably be optimized?
359 
360  //get ALL of the hits from hitlist that are within the distance fRadiusSizePar of the seed hit.
361  SelectLocalHitlist(hitlist, hitlistlocal, (double)wire,time,fRadiusSizePar);
362 
363 
364  if(hitlistlocal.size()<fNHitsInClust ){
365  hitlist_total.push_back(theHit); //Add this hit if there are less than fNHitsInClust nearby.
366  if (verbose) std::cout << " adding hit @ w,t " << wire << " "<< time << " on plane " << plane << std::endl;
367  }
368  else{
369  //Add this hit to the leftover pile
370  leftovers.push_back(theHit);
371  }
372 
373  hitlistlocal.clear(); //clear the local hit list, and look at the next hit.
374  }
375 
376 /*
377  This method could definitely be optimized. It creates a local hit list for each particle,
378  while if there is a local hit list that is sufficiently separated from all others it should be OK to
379  add them all at once. This is a task for future coders!
380 */
381 
382 
383  return hitlist_total;
384 
385 }
386 
387 // ******************************* //
389  unsigned int &p, //plane
390  unsigned int &/*cs*/, //cryostat
391  unsigned int &t, //time
392  unsigned int &w) //wire
393 {
395  unsigned int channel = a->Channel();
396  geom->ChannelToWire(channel);
397  p = a -> WireID().Plane;
398  t = a -> PeakTime();
399  w = a -> WireID().Wire;
400 
401 
402  return 0;
403 }
404 
405 //Function to return the small clusters by plane
406 std::vector< std::vector <art::Ptr< recob::Hit> > > cluster::SmallClusterFinderAlg::GetSmallClustersByPlane(unsigned int iPlane){
407  //Check the plane number:
408  if (/* iPlane >= 0 && */ iPlane < fNPlanes)
409  return smallClustList[iPlane];
410  else {
411  std::vector< std::vector <art::Ptr< recob::Hit> > > vec;
412  return vec;
413  }
414 }
415 
416 std::vector< art::Ptr<recob::Hit> > cluster::SmallClusterFinderAlg::GetLeftoversByPlane(unsigned int iPlane){
417  //Check the plane number:
418  if (/* iPlane >= 0 && */ iPlane < fNPlanes)
419  return hitlistleftover[iPlane];
420  else {
421  std::vector <art::Ptr< recob::Hit> > vec;
422  return vec;
423  }
424 }
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistbyplane
Double_t Get2DDistance(Double_t wire1, Double_t time1, Double_t wire2, Double_t time2) const
Collect all the geometry header files together.
virtual double SamplingRate() const =0
Returns the period of the TPC readout electronics clock.
void FindSmallClusters(std::vector< art::Ptr< recob::Hit > > allHits)
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistleftover
virtual double Temperature() const =0
std::vector< art::Ptr< recob::Hit > > GetLeftoversByPlane(unsigned int iPlane)
T get(std::string const &key) const
Definition: ParameterSet.h:231
void SelectLocalHitlist(std::vector< art::Ptr< recob::Hit > > hitlist, std::vector< art::Ptr< recob::Hit > > &hitlistlocal, double wire_start, double time_start, double radlimit)
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistrefined
std::vector< art::Ptr< recob::Hit > > CreateHighHitlist(std::vector< art::Ptr< recob::Hit > > hitlist, std::vector< art::Ptr< recob::Hit > > &hitlistleftover)
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
Utility object to perform functions of association.
void reconfigure(fhicl::ParameterSet const &pset)
std::vector< std::vector< art::Ptr< recob::Hit > > > GetSmallClustersByPlane(unsigned int iPlane)
virtual double DriftVelocity(double efield=0., double temperature=0.) const =0
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
art::ServiceHandle< geo::Geometry > geom
int GetPlaneAndTPC(art::Ptr< recob::Hit > a, unsigned int &p, unsigned int &cs, unsigned int &t, unsigned int &w)
Float_t w
Definition: plot.C:23
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
std::vector< std::vector< std::vector< art::Ptr< recob::Hit > > > > smallClustList