LArSoft  v10_04_05
Liquid Argon Software toolkit - https://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
40 #include "fhiclcpp/ParameterSet.h"
41 
42 // LArSoft includes
52 
53 // ***************** //
54 
55 //constructor with parameters:
57 {
59  fRadiusSizePar = pset.get<double>("RadiusSizePar");
60  fNHitsInClust = pset.get<double>("NHitsInClust");
61  verbose = pset.get<bool>("Verbose");
63 }
64 
65 // ***************** //
66 // This method actually makes the clusters.
68  util::GeometryUtilities const& gser,
69  detinfo::DetectorClocksData const& clockData,
70  detinfo::DetectorPropertiesData const& detProp,
72 {
74  fDriftVelocity = detProp.DriftVelocity(detProp.Efield(), detProp.Temperature());
75  fWirePitch = wireReadoutGeom->Plane({0, 0, 0}).WirePitch();
76  fTimeTick = sampling_rate(clockData) / 1000.;
80 
82 
83  // Catch the case were there are no hits in the event:
84  if (allHits.size() == 0) {
85  if (verbose) std::cout << " no hits received! exiting " << std::endl;
86  return;
87  }
88 
89  //sort the hits into hits by plane
90  for (auto const& theHit : allHits) {
91  unsigned int p(0), w(0), t(0), cs(0); //c=channel, p=plane, w=wire, but what is t?
92  GetPlaneAndTPC(theHit, p, cs, t, w); //Find out what plane this hit is on.
93  //add this hit to the list specific to this plane
94  hitlistbyplane[p].push_back(theHit);
95  } // End loop on hits.
96 
97  // Want to check that the wires are OK for each event, and by each wire.
98  // This could be done in HitFinder, but I'm doing it here because I want to do
99  // some things specifically for Small Clusters... Flags to look for: Does
100  // this
101  // wire have more hits that the other wires that also have hits? Significantly
102  // more? Does the RMS of this hit lie well below the peak of the hit?
103  // Significantly below? More? If a bad wire is found, remove all of
104  // it's from the hitlists so they aren't clustered.
105 
106  //make the refined hit list for each plane.
107  for (unsigned int ip = 0; ip < fNPlanes; ip++) {
109 
110  //Check that the lists are populated correctly:
111  if (verbose)
112  std::cout << "At plane " << ip << ", found " << hitlistrefined[ip].size() << " hits with "
113  << hitlistleftover[ip].size() << " leftover" << std::endl;
114  //add the leftover hits to the correct object:
115  }
116 
117  //Now we have all of the gammas. This is good!
118  //Want to split all of the gammas up into individual clusters.
119 
120  //I was going to use lists instead of vectors to do this, because lists are more efficient
121  //at insertion and removal at arbitrary places. But, the number of gammas is so small that
122  //it just doesn't seem worth it
123 
124  // The method to split the gammas into individual clusters that I want is:
125  // Use the existing method below to find all the hits within a certain distance from a given hit
126  // Take ALL of those hits and write them to a cluster.
127  // Then, remove those hits from the list of gammas.
128 
129  // Repeat, until the list of gammas is empty.
130 
131  // There is an issue of knowing which hits to remove from the total gamma hit list.
132  // To solve this, I'm going to overload SelectLocalHitList to take a reference to a vector
133  // of ints as an argument. When a hit is added to the local hit list,
134  // it's index will be added to a vector that is returned by reference.
135  // It's important to remove these hits in reverse order. This is because removing a hit
136  // changes the index of all of the hits after it
137 
138  //Now we need to take the lists of small clusters and sort it into the individual spots
139  //going to end up with smallClustList[plane][iClust][Hit]
140  //loop over planes of hits:
141 
142  for (unsigned int iplane = 0; iplane < fNPlanes; iplane++) {
143 
144  if (hitlistrefined[iplane].size() == 0) continue;
145 
146  //write the rest of the gammas one by one, in clusters:
147  int i = 1;
148 
149  std::vector<art::Ptr<recob::Hit>> splittingVector = hitlistrefined[iplane];
150 
151  while (splittingVector.size() != 0) {
152 
153  //find the first small cluster of gammas:
154  std::vector<int> index;
155  std::vector<art::Ptr<recob::Hit>> thiscluster;
156  thiscluster.clear();
157  index.clear();
158 
159  //Just use the first hit in the list of gammas:
160 
161  art::Ptr<recob::Hit> theHit = splittingVector.front(); //grab a hit from the list
162 
163  double time = theHit->PeakTime();
164  unsigned int plane(0), cstat(0), tpc(0), wire(0);
165  GetPlaneAndTPC(theHit, plane, cstat, tpc, wire);
166 
167  SelectLocalHitlist(gser, splittingVector, thiscluster, wire, time, fRadiusSizePar, index);
168 
169  if (verbose)
170  std::cout << "Done writing " << thiscluster.size() << " hits to cluster with ID "
171  << plane * 100 + i << std::endl;
172  //make sure to add these hits to the object that stores them:
173  smallClustList[plane].push_back(thiscluster);
174 
175  //Lastly, remove the gammas just clustered from the refinded hit list
176  while (index.size() != 0) {
177  splittingVector.erase(splittingVector.begin() + (index.back()));
178  index.pop_back();
179  }
180  i++;
181  }
182  }
183 }
184 
185 // ************************************* //
186 // Clear and resize - exactly what it sounds like
188 {
189  smallClustList.clear();
190  hitlistbyplane.clear();
191  hitlistrefined.clear();
192  hitlistleftover.clear();
193  smallClustList.resize(fNPlanes);
194  hitlistbyplane.resize(fNPlanes);
195  hitlistrefined.resize(fNPlanes);
196  hitlistleftover.resize(fNPlanes);
197 }
198 
199 /*
200  This is the method takes a list of hits ("hitlist") and compares each hit to a 2D
201  location that is specified by a wire ("wire_start") and time ("time_start"). If the
202  hit being examined is farther away than a specified distance ("radlimit", in cm) then
203  the hit is excluded. If the hit is within that distance, it's added.
204 */
206  util::GeometryUtilities const& gser,
208  std::vector<art::Ptr<recob::Hit>>& hitlistlocal,
209  double wire_start,
210  double time_start,
211  double radlimit) const
212 {
213  //loop over the hits in "hitlist", which should contain the hits we're selecting from
214  for (auto const& theHit : hitlist) {
215  double time = theHit->PeakTime();
216  unsigned int plane, cstat, tpc, wire;
217  GetPlaneAndTPC(theHit, plane, cstat, tpc, wire);
218  //we now know which wire and what time this hit occurred on
219 
220  //calculate linear distance from start point and orthogonal distance from axis
221  double linear_dist = gser.Get2DDistance(wire, time, wire_start, time_start);
222 
223  if (linear_dist < radlimit) hitlistlocal.push_back(theHit);
224  }
225 }
226 
227 // This method is identical to the other method by the same name except that
228 // it keeps track of the location of the hits selected. That is, index is filled with
229 // the indices of the selected hits in the hitlist vector (the input vector)
231  util::GeometryUtilities const& gser,
233  std::vector<art::Ptr<recob::Hit>>& hitlistlocal,
234  double wire_start,
235  double time_start,
236  double radlimit,
237  std::vector<int>& index) const
238 {
239  // loop over the hits in "hitlist", which should contain the hits we're selecting from
240  int i = 0; //i keeps track of the index of the hit.
241  for (auto const& theHit : hitlist) {
242  double time = theHit->PeakTime();
243  unsigned int plane, cstat, tpc, wire;
244  GetPlaneAndTPC(theHit, plane, cstat, tpc, wire);
245  //we now know which wire and what time this hit occurred on
246 
247  //calculate linear distance from start point and orthogonal distance from axis
248  double linear_dist = gser.Get2DDistance(wire, time, wire_start, time_start);
249 
250  if (linear_dist < radlimit) {
251  hitlistlocal.push_back(theHit);
252  index.push_back(i);
253  }
254  i++;
255  }
256 
257  //need to make sure the index array is in order. Sort it!
258  std::sort(index.begin(), index.end());
259 }
260 
261 // This method sorts this hitlist (which should only be on a single plane)
262 std::vector<art::Ptr<recob::Hit>> cluster::SmallClusterFinderAlg::CreateHighHitlist(
263  util::GeometryUtilities const& gser,
264  std::vector<art::Ptr<recob::Hit>> const& hitlist,
265  std::vector<art::Ptr<recob::Hit>>& leftovers) const
266 {
267 
268  std::vector<art::Ptr<recob::Hit>>
269  hitlist_total; //This is the final result, a list of hits that are small clusters
270 
271  std::vector<art::Ptr<recob::Hit>> hitlistlocal;
272 
273  for (unsigned int ix = 0; ix < hitlist.size(); ix++) {
274 
275  art::Ptr<recob::Hit> const& theHit = hitlist[ix]; //grab a hit from the list
276 
277  double time = theHit->PeakTime();
278  unsigned int plane(0), cstat(0), tpc(0), wire(0);
279  GetPlaneAndTPC(theHit, plane, cstat, tpc, wire);
280  //use the wire and time of this hit as a seed.
281  // ^^^^^ This could probably be optimized?
282 
283  //get ALL of the hits from hitlist that are within the distance fRadiusSizePar of the seed hit.
284  SelectLocalHitlist(gser, hitlist, hitlistlocal, (double)wire, time, fRadiusSizePar);
285 
286  if (hitlistlocal.size() < fNHitsInClust) {
287  hitlist_total.push_back(theHit); //Add this hit if there are less than fNHitsInClust nearby.
288  if (verbose)
289  std::cout << " adding hit @ w,t " << wire << " " << time << " on plane " << plane
290  << std::endl;
291  }
292  else {
293  //Add this hit to the leftover pile
294  leftovers.push_back(theHit);
295  }
296 
297  hitlistlocal.clear(); //clear the local hit list, and look at the next hit.
298  }
299 
300  /*
301  This method could definitely be optimized. It creates a local hit list for each particle,
302  while if there is a local hit list that is sufficiently separated from all others it should be OK to
303  add them all at once. This is a task for future coders!
304  */
305 
306  return hitlist_total;
307 }
308 
309 // ******************************* //
311  unsigned int& p, //plane
312  unsigned int& /*cs*/, //cryostat
313  unsigned int& t, //time
314  unsigned int& w) const //wire
315 {
316  p = a->WireID().Plane;
317  t = a->PeakTime();
318  w = a->WireID().Wire;
319 
320  return 0;
321 }
322 
323 //Function to return the small clusters by plane
324 std::vector<std::vector<art::Ptr<recob::Hit>>>
326 {
327  if (iPlane < fNPlanes) return smallClustList[iPlane];
328  return {};
329 }
330 
331 std::vector<art::Ptr<recob::Hit>> cluster::SmallClusterFinderAlg::GetLeftoversByPlane(
332  unsigned int iPlane)
333 {
334  if (iPlane < fNPlanes) return hitlistleftover[iPlane];
335  return {};
336 }
std::vector< art::Ptr< recob::Hit > > CreateHighHitlist(util::GeometryUtilities const &gser, std::vector< art::Ptr< recob::Hit >> const &hitlist, std::vector< art::Ptr< recob::Hit >> &hitlistleftover) const
double Get2DDistance(double wire1, double time1, double wire2, double time2) const
Utilities related to art service access.
geo::WireReadoutGeom const * wireReadoutGeom
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistbyplane
std::vector< std::vector< std::vector< art::Ptr< recob::Hit > > > > smallClustList
Declaration of signal hit object.
double Temperature() const
In kelvin.
void FindSmallClusters(util::GeometryUtilities const &gser, detinfo::DetectorClocksData const &dataClocks, detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> allHits)
int GetPlaneAndTPC(art::Ptr< recob::Hit > a, unsigned int &plane, unsigned int &cryostat, unsigned int &time, unsigned int &wire) const
void SelectLocalHitlist(util::GeometryUtilities const &gser, std::vector< art::Ptr< recob::Hit >> hitlist, std::vector< art::Ptr< recob::Hit >> &hitlistlocal, double wire_start, double time_start, double radlimit) const
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistleftover
double Efield(unsigned int planegap=0) const
kV/cm
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
std::vector< art::Ptr< recob::Hit > > GetLeftoversByPlane(unsigned int iPlane)
T get(std::string const &key) const
Definition: ParameterSet.h:314
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
std::vector< std::vector< art::Ptr< recob::Hit > > > hitlistrefined
Definition of data types for geometry description.
unsigned int Nplanes(TPCID const &tpcid=details::tpc_zero) const
Returns the total number of planes in the specified TPC.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
Contains all timing reference information for the detector.
std::vector< std::vector< art::Ptr< recob::Hit > > > GetSmallClustersByPlane(unsigned int iPlane)
SmallClusterFinderAlg(fhicl::ParameterSet const &pset)
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
Float_t w
Definition: plot.C:20
art framework interface to geometry description