LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
HarrisVertexFinder_module.cc
Go to the documentation of this file.
1 //
3 // HarrisVertexFinder class
4 //
5 // joshua.spitz@yale.edu
6 //
7 // This algorithm is designed to find (weak) vertices from hits after deconvolution and hit finding.
8 // A weak vertex is a vertex that has been found using a dedicated vertex finding algorithm only. A
9 // strong vertex is a vertex that has been found using a dedicated vertex finding algorithm and matched
10 // to a crossing of two or more HoughLineFinder lines. The VertexMatch module finds strong vertices.
17 //Thanks to B. Morgan of U. of Warwick for comments and suggestions
18 #ifndef HarrisVertexFinder_H
19 #define HarrisVertexFinder_H
20 
21 // Framework includes
26 #include "fhiclcpp/ParameterSet.h"
34 
35 extern "C" {
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 }
39 
40 #include <sstream>
41 #include <fstream>
42 #include <math.h>
43 #include <algorithm>
44 #include <iostream>
45 #include <vector>
46 #include <string>
47 
57 
58 #include "TMath.h"
59 #include "TH2.h"
60 
62 namespace vertex {
63 
65 
66  public:
67 
68  explicit HarrisVertexFinder(fhicl::ParameterSet const& pset);
69  virtual ~HarrisVertexFinder();
70  void beginJob();
71 
72  void produce(art::Event& evt);
73 
74  private:
75 
76  double Gaussian(int x, int y, double sigma);
77  double GaussianDerivativeX(int x, int y);
78  double GaussianDerivativeY(int x, int y);
79  void SaveBMPFile(const char *fileName, unsigned char *pix, int dx, int dy);
80 
81  std::string fDBScanModuleLabel;
82  int fTimeBins;
84  double fGsigma;
85  int fWindow;
86  double fThreshold;
88  TH2F* fNoVertices;
89 
90  };
91 
92 }
93 
94 //-----------------------------------------------------------------------------
96  : fDBScanModuleLabel (pset.get< std::string >("DBScanModuleLabel"))
97  , fTimeBins (pset.get< int >("TimeBins") )
98  , fMaxCorners (pset.get< int >("MaxCorners") )
99  , fGsigma (pset.get< double >("Gsigma") )
100  , fWindow (pset.get< int >("Window") )
101  , fThreshold (pset.get< double >("Threshold") )
102  , fSaveVertexMap (pset.get< int >("SaveVertexMap") )
103 {
104  produces< std::vector<recob::EndPoint2D> >();
105  produces< art::Assns<recob::EndPoint2D, recob::Hit> >();
106 }
107 
108 //-----------------------------------------------------------------------------
110 {
111 }
112 
114  // get access to the TFile service
116 
117  fNoVertices= tfs->make<TH2F>("fNoVertices", ";Event No; No of vertices", 100,0, 100, 30, 0, 30);
118 
119 }
120 
121 //-----------------------------------------------------------------------------
122 double vertex::HarrisVertexFinder::Gaussian(int x, int y, double sigma)
123 {
124  double Norm = 1./std::sqrt(2*TMath::Pi()*pow(sigma,2));
125  double value = Norm*exp(-(pow(x,2)+pow(y,2))/(2*pow(sigma,2)));
126  return value;
127 }
128 
129 //-----------------------------------------------------------------------------
131 {
132  double Norm = 1./(std::sqrt(2*TMath::Pi())*pow(fGsigma,3));
133  double value = Norm*(-x)*exp(-(pow(x,2)+pow(y,2))/(2*pow(fGsigma,2)));
134  return value;
135 }
136 
137 //-----------------------------------------------------------------------------
139 {
140  double Norm = 1./(std::sqrt(2*TMath::Pi())*pow(fGsigma,3));
141  double value = Norm*(-y)*exp(-(pow(x,2)+pow(y,2))/(2*pow(fGsigma,2)));
142  return value;
143 }
144 
145 //-----------------------------------------------------------------------------
147 {
148 
150 
151  art::Handle< std::vector<recob::Cluster> > clusterListHandle;
152  evt.getByLabel(fDBScanModuleLabel, clusterListHandle);
153 
154  //Point to a collection of vertices to output and the associations with the hits
155  std::unique_ptr<std::vector<recob::EndPoint2D> > vtxcol(new std::vector<recob::EndPoint2D>);
156  std::unique_ptr< art::Assns<recob::EndPoint2D, recob::Hit> > assn(new art::Assns<recob::EndPoint2D, recob::Hit>);
157 
158  std::vector< art::Ptr<recob::Hit> > cHits;
160 
162  for(unsigned int ii = 0; ii < clusterListHandle->size(); ++ii){
163  art::Ptr<recob::Cluster> cluster(clusterListHandle, ii);
164  clusIn.push_back(cluster);
165  }
166 
167  art::FindManyP<recob::Hit> fmh(clusterListHandle, evt, fDBScanModuleLabel);
168 
169  int flag = 0;
170  int n = 0; //index of window cell. There are 49 cells in the 7X7 Gaussian and Gaussian derivative windows
171  unsigned int numberwires = 0;
172  double MatrixAAsum = 0.;
173  double MatrixBBsum = 0.;
174  double MatrixCCsum = 0.;
175  std::vector<double> Cornerness2;
176  //gaussian window definitions. The cell weights are calculated here to help the algorithm's speed
177  double w[49] = {0.};
178  double wx[49] = {0.};
179  double wy[49] = {0.};
180  int ctr = 0;
181  for(int i = -3; i < 4; ++i){
182  for(int j = 3; j > -4; --j){
183  w[ctr] = Gaussian(i, j, fGsigma);
184  wx[ctr] = GaussianDerivativeX(i,j);
185  wy[ctr] = GaussianDerivativeY(i,j);
186  ++ctr;
187  }
188  }
189 
190  const unsigned int numbertimesamples
191  = lar::providerFrom<detinfo::DetectorPropertiesService>()->ReadOutWindowSize();
192 
193  const float BinsPerTick = fTimeBins / numbertimesamples;
194  const float TicksPerBin = numbertimesamples / fTimeBins;
195 
196  for(auto pid : geom->IteratePlaneIDs()){
198  geo::View_t view = geom->View(pid);
199  hit.clear();
200  cHits.clear();
201  for(size_t ci = 0; ci < clusIn.size(); ++ci) {
202  cHits = fmh.at(ci);
203  if(cHits.size() > 0)
204  for(unsigned int i = 0; i < cHits.size(); ++i) hit.push_back(cHits[i]);
205 
206  }
207  if(hit.size() == 0) continue;
208 
209  numberwires = geom->Cryostat(pid.Cryostat).TPC(pid.TPC).Plane(pid.Plane).Nwires();
210  std::vector< std::vector<double> > MatrixAsum(numberwires);
211  std::vector< std::vector<double> > MatrixBsum(numberwires);
212  std::vector< std::vector<double> > hit_map(numberwires);//the map of hits
213  std::vector< std::vector<int> > hit_loc(numberwires);//the index of the hit that corresponds to the potential corner
214  std::vector< std::vector<double> > Cornerness(numberwires);//the "weight" of a corner
215 
216  for(unsigned int wi = 0; wi < numberwires; ++wi){
217  MatrixAsum[wi].resize(fTimeBins);
218  MatrixBsum[wi].resize(fTimeBins);
219  hit_map[wi].resize(fTimeBins);
220  hit_loc[wi].resize(fTimeBins);
221  Cornerness[wi].resize(fTimeBins);
222  for(int timebin = 0; timebin < fTimeBins; ++timebin){
223  hit_map[wi][timebin] = 0.;
224  hit_loc[wi][timebin] = -1;
225  Cornerness[wi][timebin] = 0.;
226  MatrixAsum[wi][timebin] = 0.;
227  MatrixBsum[wi][timebin] = 0.;
228  }
229  }
230 
231  for(unsigned int i = 0; i < hit.size(); ++i){
232  unsigned int wire = hit[i]->WireID().Wire;
233  // pixelization using a Gaussian (3 sigmas around peak)
234  const float center = hit[i]->PeakTime(), sigma = hit[i]->RMS();
235  const int iFirstBin = int((center - 3*sigma) / TicksPerBin),
236  iLastBin = int((center + 3*sigma) / TicksPerBin);
237  for (int iBin = iFirstBin; iBin <= iLastBin; ++iBin) {
238  const float bin_center = iBin * TicksPerBin;
239  hit_map[wire][iBin] += Gaussian(bin_center, center, sigma);
240  }
241  }
242 
243  // Gaussian derivative convolution
244  for(unsigned int wire = 1;wire < numberwires-1; ++wire){
245  for(int timebin = 1;timebin < fTimeBins-1; ++timebin){
246  MatrixAsum[wire][timebin] = 0.;
247  MatrixBsum[wire][timebin] = 0.;
248  n = 0;
249  for(int i = -3; i <= 3; ++i) {
250  unsigned int windex = ((int)wire < -i)? 0: wire + i;
251  if (windex >= numberwires) windex = numberwires - 1;
252  for(int j = -3; j <= 3; ++j) {
253  unsigned int tindex = (unsigned int) std::min(std::max(timebin +j, 0), fTimeBins - 1);
254 
255  MatrixAsum[wire][timebin] += wx[n]*hit_map[windex][tindex];
256  MatrixBsum[wire][timebin] += wy[n]*hit_map[windex][tindex];
257  ++n;
258  }// end loop over j
259  }// end loop over i
260  }// end loop over time bins
261  }// end loop over wires
262 
263  //calculate the cornerness of each pixel while making sure not to fall off the hit map.
264  for(unsigned int wire = 1; wire < numberwires-1; ++wire){
265  for(int timebin = 1; timebin < fTimeBins-1; ++timebin){
266  MatrixAAsum = 0.;
267  MatrixBBsum = 0.;
268  MatrixCCsum = 0.;
269  //Gaussian smoothing convolution
270  n = 0;
271 
272  for(int i = -3; i <= 3; i++) {
273  unsigned int windex = ((int)wire < -i)? 0: wire + i;
274  if (windex >= numberwires) windex = numberwires - 1;
275  for(int j = -3; j <= 3; j++) {
276  unsigned int tindex = (unsigned int) std::min(std::max(timebin +j, 0), fTimeBins - 1);
277  MatrixAAsum += w[n]*pow(MatrixAsum[windex][tindex],2);
278  MatrixBBsum += w[n]*pow(MatrixBsum[windex][tindex],2);
279  MatrixCCsum += w[n]*MatrixAsum[windex][tindex]*MatrixBsum[windex][tindex];
280  ++n;
281  }// end loop over j
282  }// end loop over i
283 
284  if((MatrixAAsum+MatrixBBsum) > 0)
285  Cornerness[wire][timebin] = (MatrixAAsum*MatrixBBsum-pow(MatrixCCsum,2))/(MatrixAAsum+MatrixBBsum);
286  else
287  Cornerness[wire][timebin] = 0;
288 
289  if(Cornerness[wire][timebin]>0){
290  for(unsigned int i = 0;i < hit.size(); ++i){
291  unsigned int wire2 = hit[i]->WireID().Wire;
292  // make sure the vertex candidate coincides with an actual hit
293  // (time within one RMS from the center of the hit)
294  const float time = timebin / TicksPerBin;
295  if(wire == wire2 && std::abs(hit[i]->TimeDistanceAsRMS(time)) < 1.){
296  //this index keeps track of the hit number
297  hit_loc[wire][timebin] = i;
298  Cornerness2.push_back(Cornerness[wire][timebin]);
299  break;
300  }
301  }// end loop over hits
302  }// end if cornerness > 0
303  }// end loop over time bins
304  }// end loop over wires
305 
306  std::sort(Cornerness2.rbegin(),Cornerness2.rend());
307 
308  for(int vertexnum = 0; vertexnum < fMaxCorners; ++vertexnum){
309  flag = 0;
310  for(unsigned int wire = 0;wire < numberwires && flag == 0; ++wire){
311  for(int timebin = 0;timebin < fTimeBins && flag == 0; ++timebin){
312  if(Cornerness2.size() > (unsigned int)vertexnum)
313  if(Cornerness[wire][timebin] == Cornerness2[vertexnum]
314  && Cornerness[wire][timebin] > 0.
315  && hit_loc[wire][timebin]>-1){
316  ++flag;
317  //thresholding
318  if(Cornerness2.size())
319  if(Cornerness[wire][timebin] < (fThreshold*Cornerness2[0]))
320  vertexnum = fMaxCorners;
321 
322  vHits.push_back(hit[hit_loc[wire][timebin]]);
323  // get the total charge from the associated hits
324  double totalQ = 0.;
325  for(size_t vh = 0; vh < vHits.size(); ++vh) totalQ += vHits[vh]->Integral();
326 
327  recob::EndPoint2D vertex(hit[hit_loc[wire][timebin]]->PeakTime(),
328  hit[hit_loc[wire][timebin]]->WireID(), //for update to EndPoint2D ... WK 4/22/13
329  Cornerness[wire][timebin],
330  vtxcol->size(),
331  view,
332  totalQ);
333  vtxcol->push_back(vertex);
334 
335  util::CreateAssn(*this, evt, *(vtxcol.get()), vHits, *(assn.get()));
336 
337  vHits.clear();
338  // non-maximal suppression on a square window. The wire coordinate units are
339  // converted to time ticks so that the window is truly square.
340  // Note that there are 1/0.0743=13.46 time samples per 4.0 mm (wire pitch in ArgoNeuT),
341  // assuming a 1.5 mm/us drift velocity for a 500 V/cm E-field
342 
344 
345  for(unsigned int wireout=wire-(int)((fWindow*BinsPerTick*.0743)+.5);
346  wireout <= wire+(int)((fWindow*BinsPerTick*.0743)+.5) ; wireout++)
347  for(int timebinout=timebin-fWindow;timebinout <= timebin+fWindow; timebinout++)
348  if(std::sqrt(pow(wire-wireout,2)+pow(timebin-timebinout,2))<fWindow)//circular window
349  Cornerness[wireout][timebinout]=0;
350  }
351  }// end loop over time bins
352  }// end loop over wires
353  }// end loop over vertices
354  Cornerness2.clear();
355  hit.clear();
356 
357  if(pid.Plane == (unsigned int)fSaveVertexMap){
358  unsigned char *outPix = new unsigned char [fTimeBins*numberwires];
359  //finds the maximum cell in the map for image scaling
360  int cell, pix=0, maxCell=0;
361  for (int y = 0; y < fTimeBins; ++y){
362  for (unsigned int x = 0; x < numberwires; ++x){
363  cell = (int)(hit_map[x][y]*1000);
364  if (cell > maxCell){
365  maxCell = cell;
366  }
367  }
368  }
369 
370  for (unsigned int y = 0; y < (unsigned int)fTimeBins; ++y){
371  for (unsigned int x = 0; x < numberwires; ++x){
372  //scales the pixel weights based on the maximum cell value
373  if(maxCell>0)
374  pix = (int)((1500000*hit_map[x][y])/maxCell);
375  outPix[y*numberwires + x] = pix;
376  }
377  }
378  SaveBMPFile("harrisvertexmap.bmp", outPix, numberwires, fTimeBins);
379  delete [] outPix;
380  }
381  }// end loop over planes
382 
383  mf::LogInfo("HarrisVertexFinder") << "Size of vtxcol= " << vtxcol->size();
384  fNoVertices->Fill(evt.id().event(),vtxcol->size());
385 
386  evt.put(std::move(vtxcol));
387 }
388 
389 //-----------------------------------------------------------------------------
390 //this method saves a BMP image of the vertex map space, which can be viewed with gimp
391 void vertex::HarrisVertexFinder::SaveBMPFile(const char *fileName, unsigned char *pix, int dx, int dy)
392 {
393  std::ofstream bmpFile(fileName, std::ios::binary);
394  bmpFile.write("B", 1);
395  bmpFile.write("M", 1);
396  int bitsOffset = 54 +256*4;
397  int size = bitsOffset + dx*dy; //header plus 256 entry LUT plus pixels
398  bmpFile.write((const char *)&size, 4);
399  int reserved = 0;
400  bmpFile.write((const char *)&reserved, 4);
401  bmpFile.write((const char *)&bitsOffset, 4);
402  int bmiSize = 40;
403  bmpFile.write((const char *)&bmiSize, 4);
404  bmpFile.write((const char *)&dx, 4);
405  bmpFile.write((const char *)&dy, 4);
406  short planes = 1;
407  bmpFile.write((const char *)&planes, 2);
408  short bitCount = 8;
409  bmpFile.write((const char *)&bitCount, 2);
410  int i, temp = 0;
411  for (i=0; i<6; i++)
412  bmpFile.write((const char *)&temp, 4); // zero out optional color info
413  // write a linear LUT
414  char lutEntry[4]; // blue,green,red
415  lutEntry[3] = 0; // reserved part
416  for (i=0; i<256; i++)
417  {
418  lutEntry[0] = lutEntry[1] = lutEntry[2] = i;
419  bmpFile.write(lutEntry, sizeof lutEntry);
420  }
421  // write the actual pixels
422  bmpFile.write((const char *)pix, dx*dy);
423 }
424 
425 namespace vertex{
426 
428 
429 } // end of vertex namespace
430 
431 #endif // HarrisVertexFinder_H
Float_t x
Definition: compare.C:6
Encapsulate the construction of a single cyostat.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Declaration of signal hit object.
Float_t y
Definition: compare.C:6
void SaveBMPFile(const char *fileName, unsigned char *pix, int dx, int dy)
STL namespace.
Cluster finding and building.
IteratorBox< plane_id_iterator,&GeometryCore::begin_plane_id,&GeometryCore::end_plane_id > IteratePlaneIDs() const
Enables ranged-for loops on all plane IDs of the detector.
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
double Gaussian(int x, int y, double sigma)
Int_t max
Definition: plot.C:27
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
bool CreateAssn(PRODUCER const &prod, art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t indx=UINT_MAX)
Creates a single one-to-one association.
Declaration of cluster object.
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
HarrisVertexFinder(fhicl::ParameterSet const &pset)
size_type size() const
Definition: PtrVector.h:308
Detector simulation of raw signals on wires.
T * make(ARGS...args) const
std::string value(boost::any const &)
Utility object to perform functions of association.
Encapsulate the construction of a single detector plane.
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Int_t min
Definition: plot.C:26
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:250
EventNumber_t event() const
Definition: EventID.h:117
Char_t n[5]
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:299
TCEvent evt
Definition: DataStructs.cxx:5
void clear()
Definition: PtrVector.h:537
Float_t w
Definition: plot.C:23
EventID id() const
Definition: Event.h:56
art framework interface to geometry description
Encapsulate the construction of a single detector plane.
vertex reconstruction