LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
BlurredClusteringAlg.cxx
Go to the documentation of this file.
1 // Implementation of the Blurred Clustering algorithm
3 //
4 // Converts a hit map into a 2D image of the hits before convoling
5 // with a Gaussian function to introduce a weighted blurring.
6 // Clustering proceeds on this blurred image to create more
7 // complete clusters.
8 //
9 // M Wallbank (m.wallbank@sheffield.ac.uk), May 2015
11 
13 
15 
16  this->reconfigure(pset);
17  this->MakeKernels();
18 
19  // For the debug PDF
20  fDebugCanvas = NULL;
21  fDebugPDFName = "";
22 
23 }
24 
26  if (fDebugCanvas) {
27  std::string closeName = fDebugPDFName;
28  closeName.append("]");
29  fDebugCanvas->Print(closeName.c_str());
30  delete fDebugCanvas;
31  }
32 }
33 
35  fBlurWire = p.get<int> ("BlurWire");
36  fBlurTick = p.get<int> ("BlurTick");
37  fSigmaWire = p.get<double>("SigmaWire");
38  fSigmaTick = p.get<double>("SigmaTick");
39  fMaxTickWidthBlur = p.get<int> ("MaxTickWidthBlur");
40  fClusterWireDistance = p.get<int> ("ClusterWireDistance");
41  fClusterTickDistance = p.get<int> ("ClusterTickDistance");
42  fNeighboursThreshold = p.get<int> ("NeighboursThreshold");
43  fMinNeighbours = p.get<int> ("MinNeighbours");
44  fMinSize = p.get<int> ("MinSize");
45  fMinSeed = p.get<double>("MinSeed");
46  fTimeThreshold = p.get<double>("TimeThreshold");
47  fChargeThreshold = p.get<double>("ChargeThreshold");
48  fDebug = p.get<bool> ("Debug",false);
49  fDetector = p.get<std::string>("Detector","dune35t");
50 
51  fKernelWidth = 2 * fBlurWire + 1;
52  fKernelHeight = 2 * fBlurTick*fMaxTickWidthBlur + 1;
53 
54  fDetProp = lar::providerFrom<detinfo::DetectorPropertiesService>();
55 }
56 
57 void cluster::BlurredClusteringAlg::CreateDebugPDF(int run, int subrun, int event) {
58 
59  if (!fDebugCanvas) {
60 
61  // Create the grayscale palette for the Z axis
62  Double_t Red[2] = { 1.00, 0.00 };
63  Double_t Green[2] = { 1.00, 0.00 };
64  Double_t Blue[2] = { 1.00, 0.00 };
65  Double_t Length[2] = { 0.00, 1.00 };
66  TColor::CreateGradientColorTable(2, Length, Red, Green, Blue, 1000);
67  gStyle->SetOptStat(110000);
68 
69  // Decide what to call this PDF
70  std::ostringstream oss;
71  oss << "BlurredImages_Run" << run << "_Subrun" << subrun;
72  fDebugPDFName = oss.str();
73  fDebugCanvas = new TCanvas(fDebugPDFName.c_str(), "Image canvas", 1000, 500);
74  fDebugPDFName.append(".pdf");
75 
76  std::string openName = fDebugPDFName;
77  openName.append("[");
78  fDebugCanvas->Print(openName.c_str());
79  fDebugCanvas->Divide(2, 2);
80  fDebugCanvas->SetGrid();
81  }
82 
83  // Clear the pads on the canvas
84  for (int i = 1; i <= 4; i++) {
85  fDebugCanvas->GetPad(i)->Clear();
86  }
87 
88  std::ostringstream oss;
89  oss << "Event " << event;
90  fDebugCanvas->cd(1);
91  TLatex l;
92  l.SetTextSize(0.15);
93  l.DrawLatex(0.1, 0.1, oss.str().c_str());
94  fDebugCanvas->Print(fDebugPDFName.c_str());
95 
96 }
97 
98 art::PtrVector<recob::Hit> cluster::BlurredClusteringAlg::ConvertBinsToRecobHits(std::vector<std::vector<double> > const& image, std::vector<int> const& bins) {
99 
100  // Create the vector of hits to output
102 
103  // Look through the hits in the cluster
104  for (std::vector<int>::const_iterator binIt = bins.begin(); binIt != bins.end(); binIt++) {
105 
106  // Take each hit and convert it to a recob::Hit
108 
109  // If this hit was a real hit put it in the hit selection
110  if (!hit.isNull())
111  hits.push_back(hit);
112  }
113 
114  // Return the vector of hits to make cluster
115  return hits;
116 }
117 
119 
120  int wire = bin % image.size();
121  int tick = bin / image.size();
122 
123  return fHitMap[wire][tick];
124 
125 }
126 
128  std::vector<std::vector<int> > const& allClusterBins,
130 
131  // Loop through the clusters (each a vector of bins)
132  for (std::vector<std::vector<int> >::const_iterator clustIt = allClusterBins.begin(); clustIt != allClusterBins.end(); clustIt++) {
133  std::vector<int> bins = *clustIt;
134 
135  // Convert the clusters (vectors of bins) to hits in a vector of recob::Hits
136  art::PtrVector<recob::Hit> clusHits = ConvertBinsToRecobHits(image, bins);
137 
138  mf::LogInfo("BlurredClustering") << "Cluster made from " << bins.size() << " bins, of which " << clusHits.size() << " were real hits";
139 
140  // Make sure the clusters are above the minimum cluster size
141  if (clusHits.size() < fMinSize) {
142  mf::LogVerbatim("BlurredClustering") << "Cluster of size " << clusHits.size() << " not saved since it is smaller than the minimum cluster size, set to " << fMinSize;
143  continue;
144  }
145 
146  clusters.push_back(clusHits);
147 
148  }
149 
150  return;
151 
152 }
153 
155 
156  // Define the size of this particular plane -- dynamically to avoid huge histograms
157  int lowerTick = fDetProp->ReadOutWindowSize(), upperTick = 0, lowerWire = fGeom->MaxWires(), upperWire = 0;
158  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt) {
159  int histWire = GlobalWire((*hitIt)->WireID());
160  if ((*hitIt)->PeakTime() < lowerTick) lowerTick = (*hitIt)->PeakTime();
161  if ((*hitIt)->PeakTime() > upperTick) upperTick = (*hitIt)->PeakTime();
162  if (histWire < lowerWire) lowerWire = histWire;
163  if (histWire > upperWire) upperWire = histWire;
164  //std::cout << "Hit at " << (*hitIt)->WireID() << " has peak time " << (*hitIt)->PeakTime() << " and RMS " << (*hitIt)->RMS() << ": lower and upper tick is " << (*hitIt)->StartTick() << " and " << (*hitIt)->EndTick() << ")" << std::endl;
165  }
166  fLowerTick = lowerTick-20;
167  fUpperTick = upperTick+20;
168  fLowerWire = lowerWire-20;
169  fUpperWire = upperWire+20;
170 
171  // Use a map to keep a track of the real hits and their wire/ticks
172  fHitMap.clear();
174 
175  // Create a 2D vector
176  std::vector<std::vector<double> > image(fUpperWire-fLowerWire, std::vector<double>(fUpperTick-fLowerTick, 0));
177 
178  // Look through the hits
179  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt) {
180 
181  int wire = GlobalWire((*hitIt)->WireID());
182  int tick = (int)(*hitIt)->PeakTime();
183  float charge = (*hitIt)->Integral();
184 
185  // Fill hit map and keep a note of all real hits for later
186  if (charge > image.at(wire-fLowerWire).at(tick-fLowerTick)) {
187  image.at(wire-fLowerWire).at(tick-fLowerTick) = charge;
188  fHitMap[wire-fLowerWire][tick-fLowerTick] = (*hitIt);
189  }
190  }
191 
192  // Keep a note of dead wires
193  fDeadWires.clear();
194  fDeadWires.resize(fUpperWire-fLowerWire,false);
195  geo::PlaneID planeID = hits.front()->WireID().planeID();
196 
197  for (int wire = fLowerWire; wire < fUpperWire; ++wire) {
198  raw::ChannelID_t channel = fGeom->PlaneWireToChannel(planeID.Plane,wire,planeID.TPC,planeID.Cryostat);
199  fDeadWires[wire-fLowerWire] = !fChanStatus.IsGood(channel);
200  }
201 
202  return image;
203 
204 }
205 
206 int cluster::BlurredClusteringAlg::ConvertWireTickToBin(std::vector<std::vector<double> > const& image, int xbin, int ybin) {
207 
208  return (ybin * image.size()) + xbin;
209 
210 }
211 
212 double cluster::BlurredClusteringAlg::ConvertBinToCharge(std::vector<std::vector<double> > const& image, int bin) {
213 
214  int x = bin % image.size();
215  int y = bin / image.size();
216 
217  return image.at(x).at(y);
218 
219 }
220 
221 std::pair<int,int> cluster::BlurredClusteringAlg::DeadWireCount(int wire_bin, int width) {
222 
223  std::pair<int,int> deadWires = std::make_pair<int,int>(0,0);
224 
225  int lower_bin = width / 2;
226  int upper_bin = (width+1) / 2;
227 
228  for (int wire = TMath::Max(wire_bin + fLowerWire - lower_bin, fLowerWire); wire < TMath::Min(wire_bin + fLowerWire + upper_bin, fUpperWire); ++wire) {
229  if (fDeadWires[wire-fLowerWire]) {
230  if (wire < wire_bin + fLowerWire)
231  ++deadWires.first;
232  else if (wire > wire_bin + fLowerWire)
233  ++deadWires.second;
234  }
235  }
236 
237  return deadWires;
238 
239 }
240 
241 void cluster::BlurredClusteringAlg::FindBlurringParameters(int& blur_wire, int& blur_tick, int& sigma_wire, int& sigma_tick) {
242 
243  // Calculate least squares slope
244  int x, y;
245  double nhits=0, sumx=0., sumy=0., sumx2=0., sumxy=0.;
246  for (unsigned int wireIt = 0; wireIt < fHitMap.size(); ++wireIt) {
247  for (unsigned int tickIt = 0; tickIt < fHitMap.at(wireIt).size(); ++tickIt) {
248  if (fHitMap[wireIt][tickIt].isNull())
249  continue;
250  ++nhits;
251  x = wireIt + fLowerWire;
252  y = tickIt + fLowerTick;
253  sumx += x;
254  sumy += y;
255  sumx2 += x*x;
256  sumxy += x*y;
257  }
258  }
259  double gradient = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
260 
261  // Get the rough unit vector for the trajectories
262  TVector2 unit = TVector2(1,gradient).Unit();
263 
264  // Catch vertical gradients
265  if (std::isnan(gradient))
266  unit = TVector2(0,1);
267 
268  // Use this direction to scale the blurring radii and Gaussian sigma
269  blur_wire = std::max(std::abs(std::round(fBlurWire * unit.X())),1.);
270  blur_tick = std::max(std::abs(std::round(fBlurTick * unit.Y())),1.);
271 
272  sigma_wire = std::max(std::abs(std::round(fSigmaWire * unit.X())),1.);
273  sigma_tick = std::max(std::abs(std::round(fSigmaTick * unit.Y())),1.);
274 
275  // std::cout << "Gradient is " << gradient << ", giving x and y components " << unit.X() << " and " << unit.Y() << std::endl;
276  // std::cout << "Blurring: wire " << blurwire << " and tick " << blurtick << "; sigma: wire " << sigmawire << " and tick " << sigmatick << std::endl;
277 
278  return;
279 
280 }
281 
282 int cluster::BlurredClusteringAlg::FindClusters(std::vector<std::vector<double> > const& blurred, std::vector<std::vector<int> >& allcluster) {
283 
284  // Vectors to hold cluster information
285  std::vector<int> cluster;
286  std::vector<double> times;
287 
288  // Size of image in x and y
289  const int nbinsx = blurred.size();
290  const int nbinsy = blurred.at(0).size();
291  const int nbins = nbinsx * nbinsy;
292 
293  // Vectors to hold hit information
294  std::vector<bool> used(nbins);
295  std::vector<std::pair<double, int> > values;//(nbins);
296 
297  // Place the bin number and contents as a pair in the values vector
298  for (int xbin = 0; xbin < nbinsx; ++xbin) {
299  for (int ybin = 0; ybin < nbinsy; ++ybin) {
300  int bin = ConvertWireTickToBin(blurred, xbin, ybin);
301  values.push_back(std::make_pair(ConvertBinToCharge(blurred, bin), bin));
302  }
303  }
304 
305  // Sort the values into charge order
306  std::sort(values.rbegin(), values.rend());
307 
308  // Count the number of iterations of the cluster forming loop (== number of clusters)
309  int niter = 0;
310 
311 
312  // Clustering loops
313  // First loop - considers highest charge hits in decreasing order, and puts them in a new cluster if they aren't already clustered (makes new cluster every iteration)
314  // Second loop - looks at the direct neighbours of this seed and clusters to this if above charge/time thresholds. Runs recursively over all hits in cluster (inc. new ones)
315  while (true) {
316 
317  // Start a new cluster each time loop is executed
318  cluster.clear();
319  times.clear();
320 
321  // Get the highest charge bin (go no further if below seed threshold)
322  double blurred_binval = values[niter].first;
323  if (blurred_binval < fMinSeed)
324  break;
325 
326  // Iterate through the bins from highest charge down
327  int bin = values[niter++].second;
328 
329  // Put this bin in used if not already there
330  if (used[bin])
331  continue;
332  used[bin] = true;
333 
334  // Start a new cluster
335  cluster.push_back(bin);
336 
337  // Get the time of this hit
338  double time = GetTimeOfBin(blurred, bin);
339  if (time > 0)
340  times.push_back(time);
341 
342 
343  // Now cluster neighbouring hits to this seed
344  while (true) {
345 
346  int nadded = 0;
347 
348  for (unsigned int clusBin = 0; clusBin < cluster.size(); ++clusBin) {
349 
350  // Get x and y values for bin (c++ returns a%b = a if a<b)
351  int binx, biny;
352  binx = cluster[clusBin] % nbinsx;
353  biny = ((cluster[clusBin] - binx) / nbinsx) % nbinsy;
354 
355  // Look for hits in the neighbouring x/y bins
356  for (int x = binx - fClusterWireDistance; x <= binx + fClusterWireDistance; x++) {
357  for (int y = biny - fClusterTickDistance; y <= biny + fClusterTickDistance; y++) {
358  if ( (x == binx and y == biny) or (x >= nbinsx or y >= nbinsy) or (x < 0 or y < 0) )
359  continue;
360 
361  // Get this bin
362  bin = ConvertWireTickToBin(blurred, x, y);
363  if (bin >= nbinsx * nbinsy or bin < 0)
364  continue;
365  if (used[bin])
366  continue;
367 
368  // Get the blurred value and time for this bin
369  blurred_binval = ConvertBinToCharge(blurred, bin);
370  time = GetTimeOfBin(blurred, bin); // NB for 'fake' hits, time is defaulted to -10000
371 
372  // Check real hits pass time cut (ignores fake hits)
373  if (time > 0 && times.size() > 0 && ! PassesTimeCut(times, time))
374  continue;
375 
376  // Add to cluster if bin value is above threshold
377  if (blurred_binval > fChargeThreshold) {
378  used[bin] = true;
379  cluster.push_back(bin);
380  nadded++;
381  if (time > 0) {
382  times.push_back(time);
383  }
384  } // End of adding blurred bin to cluster
385 
386  }
387  } // End of looking at directly neighbouring bins
388 
389  } // End of looping over bins already in this cluster
390 
391  if (nadded == 0)
392  break;
393 
394  } // End of adding hits to this cluster
395 
396  // Check this cluster is above minimum size
397  if (cluster.size() < fMinSize) {
398  for (unsigned int i = 0; i < cluster.size(); i++)
399  used[cluster[i]] = false;
400  continue;
401  }
402 
403  // Fill in holes in the cluster
404  for (unsigned int clusBin = 0; clusBin < cluster.size(); clusBin++) {
405 
406  // Looks at directly neighbouring bins (and not itself)
407  for (int x = -1; x <= 1; x++) {
408  for (int y = -1; y <= 1; y++) {
409  if (!x && !y) continue;
410 
411  // Look at neighbouring bins to the clustered bin which are inside the cluster
412  int neighbouringBin = cluster[clusBin] + x + (y * nbinsx);
413  if (neighbouringBin < nbinsx || neighbouringBin % nbinsx == 0 || neighbouringBin % nbinsx == nbinsx - 1 || neighbouringBin >= nbinsx * (nbinsy - 1))
414  continue;
415 
416  double time = GetTimeOfBin(blurred, neighbouringBin);
417 
418  // If not already clustered and passes neighbour/time thresholds, add to cluster
419  if ( !used[neighbouringBin] && (NumNeighbours(nbinsx, used, neighbouringBin) > fNeighboursThreshold) && PassesTimeCut(times, time) ) {
420  used[neighbouringBin] = true;
421  cluster.push_back(neighbouringBin);
422 
423  if (time > 0) {
424  times.push_back(time);
425  }
426  } // End of clustering neighbouring bin
427 
428  }
429  } // End of looping over neighbouring bins
430 
431  } // End of looping over bins already in cluster
432 
433  mf::LogVerbatim("Blurred Clustering") << "Size of cluster after filling in holes: " << cluster.size();
434 
435 
436  // Remove peninsulas - hits which have too few neighbouring hits in the cluster (defined by fMinNeighbours)
437  while (true) {
438  int nremoved = 0;
439 
440  // Loop over all the bins in the cluster
441  for (int clusBin = cluster.size() - 1; clusBin >= 0; clusBin--) {
442  bin = cluster[clusBin];
443 
444  // If bin is in cluster ignore
445  if (bin < nbinsx || bin % nbinsx == 0 || bin % nbinsx == nbinsx - 1 || bin >= nbinsx * (nbinsy - 1)) continue;
446 
447  // Remove hit if it has too few neighbouring hits
448  if ((int) NumNeighbours(nbinsx, used, bin) < fMinNeighbours) {
449  used[bin] = false;
450  nremoved++;
451  cluster.erase(cluster.begin() + clusBin);
452  blurred_binval = ConvertBinToCharge(blurred, bin);
453  }
454  }
455 
456  if (!nremoved)
457  break;
458  }
459 
460  mf::LogVerbatim("Blurred Clustering") << "Size of cluster after removing peninsulas: " << cluster.size();
461 
462 
463  // Disregard cluster if not of minimum size
464  if (cluster.size() < fMinSize) {
465  for (unsigned int i = 0; i < cluster.size(); i++)
466  used[cluster[i]] = false;
467  continue;
468  }
469 
470  // Put this cluster in the vector of clusters
471  allcluster.push_back(cluster);
472 
473  } // End loop over this cluster
474 
475  // Return the number of clusters found in this hit map
476  return allcluster.size();
477 
478 }
479 
481 
482  double globalWire = -999;
483 
484  // Induction
485  if (fGeom->SignalType(wireID) == geo::kInduction) {
486  double wireCentre[3];
487  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
488  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
489  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
490  }
491 
492  // Collection
493  else {
494  // FOR COLLECTION WIRES, HARD CODE THE GEOMETRY FOR GIVEN DETECTORS
495  // THIS _SHOULD_ BE TEMPORARY. GLOBAL WIRE SUPPORT IS BEING ADDED TO THE LARSOFT GEOMETRY AND SHOULD BE AVAILABLE SOON
496  if (fDetector == "dune35t") {
497  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
498  if (wireID.TPC == 0 or wireID.TPC == 1) globalWire = wireID.Wire;
499  else if (wireID.TPC == 2 or wireID.TPC == 3 or wireID.TPC == 4 or wireID.TPC == 5) globalWire = nwires + wireID.Wire;
500  else if (wireID.TPC == 6 or wireID.TPC == 7) globalWire = (2*nwires) + wireID.Wire;
501  else mf::LogError("BlurredClusterAlg") << "Error when trying to find a global induction plane coordinate for TPC " << wireID.TPC << " (geometry " << fDetector << ")";
502  }
503  else if (fDetector == "dune10kt") {
504  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
505  // Detector geometry has four TPCs, two on top of each other, repeated along z...
506  int block = wireID.TPC / 4;
507  globalWire = (nwires*block) + wireID.Wire;
508  }
509  else {
510  double wireCentre[3];
511  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
512  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
513  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
514  }
515  }
516 
517  return std::round(globalWire);
518 
519 }
520 
521 std::vector<std::vector<double> > cluster::BlurredClusteringAlg::GaussianBlur(std::vector<std::vector<double> > const& image) {
522 
523  if (fSigmaWire == 0 and fSigmaTick == 0)
524  return image;
525 
526  // Find the blurring parameters
527  int blur_wire, blur_tick, sigma_wire, sigma_tick;
528  FindBlurringParameters(blur_wire, blur_tick, sigma_wire, sigma_tick);
529 
530  // Convolve the Gaussian
531  int width = 2 * blur_wire + 1;
532  int height = 2 * blur_tick + 1;
533  int nbinsx = image.size();
534  int nbinsy = image.at(0).size();
535 
536  // Blurred histogram and normalisation for each bin
537  std::vector<std::vector<double> > copy(nbinsx, std::vector<double>(nbinsy, 0));
538 
539  // Loop through all the bins in the histogram to blur
540  for (int x = 0; x < nbinsx; ++x) {
541  for (int y = 0; y < nbinsy; ++y) {
542 
543  if (image[x][y] == 0)
544  continue;
545 
546  // Scale the tick blurring based on the width of the hit
547  int tick_scale = TMath::Sqrt(TMath::Power(fHitMap[x][y]->RMS(),2) + TMath::Power(sigma_tick,2)) / (double)sigma_tick;
548  tick_scale = TMath::Max(TMath::Min(tick_scale,fMaxTickWidthBlur),1);
549  std::vector<double> correct_kernel = fAllKernels[sigma_wire][sigma_tick*tick_scale];
550 
551  // Find any dead wires in the potential blurring region
552  std::pair<int,int> num_deadwires = DeadWireCount(x, width);
553  //num_deadwires = std::make_pair<int,int>(0,0);
554 
555  // Note of how many dead wires we have passed whilst blurring in the wire direction
556  // If blurring below the seed hit, need to keep a note of how many dead wires to come
557  // If blurring above, need to keep a note of how many dead wires have passed
558  int dead_wires_passed = num_deadwires.first;
559 
560  // bool dead = false;
561  // if (num_deadwires.first != 0 or num_deadwires.second != 0)
562  // dead = true;
563 
564  // if (dead) {
565  // std::cout << "Wire is " << x+fLowerWire << std::endl;
566  // std::cout << "Width is " << width << std::endl;
567  // }
568 
569  // Loop over the blurring region around this hit
570  for (int blurx = -(width/2+num_deadwires.first); blurx < (width+1)/2+num_deadwires.second; ++blurx) {
571  for (int blury = -height/2*tick_scale; blury < ((((height+1)/2)-1)*tick_scale)+1; ++blury) {
572 
573  // if (dead)
574  // std::cout << "Start... dead_wires_passed is " << dead_wires_passed << " and blurx is " << blurx << std::endl;
575 
576  if (blurx < 0 and fDeadWires[x+blurx])
577  dead_wires_passed -= 1;
578 
579  // Smear the charge of this hit
580  double weight = correct_kernel[fKernelWidth * (fKernelHeight / 2 + blury) + (fKernelWidth / 2 + (blurx - dead_wires_passed))];
581  if (x + blurx >= 0 and x + blurx < nbinsx and y + blury >= 0 and y + blury < nbinsy)
582  copy[x+blurx][y+blury] += weight * image[x][y];
583 
584  if (blurx > 0 and fDeadWires[x+blurx])
585  dead_wires_passed += 1;
586 
587  // if (dead)
588  // std::cout << "Start... dead_wires_passed is " << dead_wires_passed << " and blurx is " << blurx << std::endl;
589 
590  }
591  } // blurring region
592 
593  }
594  } // hits to blur
595 
596  // HAVE REMOVED NOMALISATION CODE
597  // WHEN USING DIFFERENT KERNELS, THERE'S NO EASY WAY OF DOING THIS...
598  // RECONSIDER...
599 
600  // Return the blurred histogram
601  return copy;
602 
603 }
604 
605 double cluster::BlurredClusteringAlg::GetTimeOfBin(std::vector<std::vector<double> > const& image, int bin) {
606 
607  double time = -10000;
608 
610  if (!hit.isNull())
611  time = hit->PeakTime();
612 
613  return time;
614 
615 }
616 
618 
619  // Kernel size is the largest possible given the hit width rescaling
620  fAllKernels.clear();
621  fAllKernels.resize(fSigmaWire+1,std::vector<std::vector<double> >(fSigmaTick*fMaxTickWidthBlur+1,std::vector<double>(fKernelWidth*fKernelHeight,0.)));
622 
623  // Ranges of kernels to make
624  // Complete range of sigmas possible after dynamic fixing and hit width convolution
625  for (int sigma_wire = 1; sigma_wire <= fSigmaWire; ++sigma_wire) {
626  for (int sigma_tick = 1; sigma_tick <= fSigmaTick*fMaxTickWidthBlur; ++sigma_tick) {
627 
628  // New kernel
629  std::vector<double> kernel(fKernelWidth*fKernelHeight,0);
630 
631  // Smear out according to the blur radii in each direction
632  for (int i = -fBlurWire; i <= fBlurWire; i++) {
633  for (int j = -fBlurTick*fMaxTickWidthBlur; j <= fBlurTick*fMaxTickWidthBlur; j++) {
634 
635  // Fill kernel
636  double sig2i = 2. * sigma_wire * sigma_wire;
637  double sig2j = 2. * sigma_tick * sigma_tick;
638 
639  int key = (fKernelWidth * (j + fBlurTick*fMaxTickWidthBlur)) + (i + fBlurWire);
640  double value = 1. / sqrt(sig2i * M_PI) * exp(-i * i / sig2i) * 1. / sqrt(sig2j * M_PI) * exp(-j * j / sig2j);
641  kernel.at(key) = value;
642 
643  }
644  } // End loop over blurring region
645 
646  fAllKernels[sigma_wire][sigma_tick] = kernel;
647 
648  }
649  }
650 
651  return;
652 
653 }
654 
655 TH2F* cluster::BlurredClusteringAlg::MakeHistogram(std::vector<std::vector<double> > const& image, TString name) {
656 
657  TH2F* hist = new TH2F(name,name,fUpperWire-fLowerWire,fLowerWire-0.5,fUpperWire-0.5,fUpperTick-fLowerTick,fLowerTick-0.5,fUpperTick-0.5);
658  hist->Clear();
659  hist->SetXTitle("Wire number");
660  hist->SetYTitle("Tick number");
661  hist->SetZTitle("Charge");
662 
663  for (unsigned int imageWireIt = 0; imageWireIt < image.size(); ++imageWireIt) {
664  int wire = imageWireIt + fLowerWire;
665  for (unsigned int imageTickIt = 0; imageTickIt < image.at(imageWireIt).size(); ++imageTickIt) {
666  int tick = imageTickIt + fLowerTick;
667  hist->Fill(wire, tick, image.at(imageWireIt).at(imageTickIt));
668  }
669  }
670 
671  return hist;
672 
673 }
674 
675 unsigned int cluster::BlurredClusteringAlg::NumNeighbours(int nbinsx, std::vector<bool> const& used, int bin) {
676 
677  unsigned int neighbours = 0;
678 
679  // Loop over all directly neighbouring hits (not itself)
680  for (int x = -1; x <= 1; x++) {
681  for (int y = -1; y <= 1; y++) {
682  if (!x && !y) continue;
683 
684  // Determine bin
685  int neighbouringBin = bin + x + (y * nbinsx);
686 
687  // If this bin is in the cluster, increase the neighbouring bin counter
688  if (used.at(neighbouringBin))
689  neighbours++;
690  }
691  }
692 
693  // Return the number of neighbours in the cluster of a particular hit
694  return neighbours;
695 }
696 
697 bool cluster::BlurredClusteringAlg::PassesTimeCut(std::vector<double> const& times, double time) {
698 
699  for (std::vector<double>::const_iterator timeIt = times.begin(); timeIt != times.end(); timeIt++) {
700  if (std::abs(time - *timeIt) < fTimeThreshold) return true;
701  }
702 
703  return false;
704 }
705 
706 void cluster::BlurredClusteringAlg::SaveImage(TH2F* image, std::vector<art::PtrVector<recob::Hit> > const& allClusters, int pad, int tpc, int plane) {
707 
708  // Make a vector of clusters
709  std::vector<std::vector<int> > allClusterBins;
710 
711  for (std::vector<art::PtrVector<recob::Hit> >::const_iterator clusterIt = allClusters.begin(); clusterIt != allClusters.end(); clusterIt++) {
712  art::PtrVector<recob::Hit> cluster = *clusterIt;
713 
714  if (!cluster.size())
715  continue;
716 
717  std::vector<int> clusterBins;
718 
719  for (art::PtrVector<recob::Hit>::iterator hitIt = cluster.begin(); hitIt != cluster.end(); hitIt++) {
720  art::Ptr<recob::Hit> hit = *hitIt;
721  unsigned int wire = GlobalWire(hit->WireID());
722  float tick = hit->PeakTime();
723  int bin = image->GetBin((wire-fLowerWire)+1,(tick-fLowerTick)+1);
724  if (cluster.size() < fMinSize)
725  bin *= -1;
726 
727  clusterBins.push_back(bin);
728  }
729 
730  allClusterBins.push_back(clusterBins);
731  }
732 
733  SaveImage(image, allClusterBins, pad, tpc, plane);
734 }
735 
736 void cluster::BlurredClusteringAlg::SaveImage(TH2F* image, int pad, int tpc, int plane) {
737  std::vector<std::vector<int> > allClusterBins;
738  SaveImage(image, allClusterBins, pad, tpc, plane);
739 }
740 
741 void cluster::BlurredClusteringAlg::SaveImage(TH2F* image, std::vector<std::vector<int> > const& allClusterBins, int pad, int tpc, int plane) {
742 
743  fDebugCanvas->cd(pad);
744  std::string stage;
745 
746  switch (pad) {
747  case 1:
748  stage = "Stage 1: Unblurred";
749  break;
750  case 2:
751  stage = "Stage 2: Blurred";
752  break;
753  case 3:
754  stage = "Stage 3: Blurred with clusters overlaid";
755  break;
756  case 4:
757  stage = "Stage 4: Output clusters";
758  break;
759  default:
760  stage = "Unknown stage";
761  break;
762  }
763 
764  std::stringstream title;
765  title << stage << " -- TPC " << tpc << ", Plane " << plane;// << " (Event " << fEvent << ")";
766 
767  image->SetName(title.str().c_str());
768  image->SetTitle(title.str().c_str());
769  image->DrawCopy("colz");
770 
771  // Draw the clustered hits on the histograms
772  int clusterNum = 2;
773  for (std::vector<std::vector<int> >::const_iterator it = allClusterBins.begin(); it != allClusterBins.end(); it++, clusterNum++) {
774  std::vector<int> bins = *it;
775  TMarker mark(0, 0, 20);
776  mark.SetMarkerColor(clusterNum);
777  mark.SetMarkerSize(0.1);
778 
779  for (std::vector<int>::iterator binIt = bins.begin(); binIt != bins.end(); binIt++) {
780  int bin = *binIt;
781  int wire, tick, z;
782 
783  // Hit from a cluster that we aren't going to save
784  if (bin < 0) {
785  bin *= -1;
786  mark.SetMarkerStyle(24);
787  }
788 
789  image->GetBinXYZ(bin,wire,tick,z);
790  mark.DrawMarker(wire+fLowerWire-1, tick+fLowerTick-1);
791  mark.SetMarkerStyle(20);
792  }
793  }
794 
795  if (pad == 4) {
796  fDebugCanvas->Print(fDebugPDFName.c_str());
797  fDebugCanvas->Clear("D");
798  }
799 
800 }
Float_t x
Definition: compare.C:6
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
void FindBlurringParameters(int &blurwire, int &blurtick, int &sigmawire, int &sigmatick)
Dynamically find the blurring radii and Gaussian sigma in each dimension.
void SaveImage(TH2F *image, std::vector< art::PtrVector< recob::Hit > > const &allClusters, int pad, int tpc, int plane)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
int FindClusters(std::vector< std::vector< double > > const &image, std::vector< std::vector< int > > &allcluster)
Find clusters in the histogram.
BlurredClusteringAlg(fhicl::ParameterSet const &pset)
virtual unsigned int ReadOutWindowSize() const =0
std::pair< int, int > DeadWireCount(int wire_bin, int width)
std::vector< std::vector< double > > GaussianBlur(std::vector< std::vector< double > > const &image)
Applies Gaussian blur to image.
void reconfigure(fhicl::ParameterSet const &p)
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
intermediate_table::iterator iterator
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
iterator begin()
Definition: PtrVector.h:223
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
unsigned int NumNeighbours(int nx, std::vector< bool > const &used, int bin)
Determines the number of clustered neighbours of a hit.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
unsigned int MaxWires() const
Returns the largest number of wires among all planes in this detector.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
double GetTimeOfBin(std::vector< std::vector< double > > const &image, int bin)
Returns the hit time of a hit in a particular bin.
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
Cluster finding and building.
art::ServiceHandle< geo::Geometry > fGeom
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
bool PassesTimeCut(std::vector< double > const &times, double time)
Determine if a hit is within a time threshold of any other hits in a cluster.
void CreateDebugPDF(int run, int subrun, int event)
Create the PDF to save debug images.
Int_t max
Definition: plot.C:27
void hits()
Definition: readHits.C:15
intermediate_table::const_iterator const_iterator
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
Signal from induction planes.
Definition: geo_types.h:92
int ConvertWireTickToBin(std::vector< std::vector< double > > const &image, int xbin, int ybin)
Converts an xbin and a ybin to a global bin number.
T get(std::string const &key) const
Definition: ParameterSet.h:231
iterator end()
Definition: PtrVector.h:237
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
art::PtrVector< recob::Hit > ConvertBinsToRecobHits(std::vector< std::vector< double > > const &image, std::vector< int > const &bins)
Converts a vector of bins into a hit selection - not all the hits in the bins vector are real hits...
float bin[41]
Definition: plottest35.C:14
data_t::iterator iterator
Definition: PtrVector.h:60
size_type size() const
Definition: PtrVector.h:308
Detector simulation of raw signals on wires.
double weight
Definition: plottest35.C:25
void MakeKernels()
Makes all the kernels which could be required given the tuned parameters.
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
std::string value(boost::any const &)
TH2F * MakeHistogram(std::vector< std::vector< double > > const &image, TString name)
Converts a 2D vector in a histogram for the debug pdf.
TH2F * hist
Definition: plot.C:136
art::Ptr< recob::Hit > ConvertBinToRecobHit(std::vector< std::vector< double > > const &image, int bin)
Converts a bin into a recob::Hit (not all of these bins correspond to recob::Hits - some are fake hit...
std::vector< std::vector< double > > ConvertRecobHitsToVector(std::vector< art::Ptr< recob::Hit > > const &hits)
Takes hit map and returns a 2D vector representing wire and tick, filled with the charge...
std::vector< std::vector< std::vector< double > > > fAllKernels
bool isNull() const
Definition: Ptr.h:328
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
double ConvertBinToCharge(std::vector< std::vector< double > > const &image, int bin)
Returns the charge stored in the global bin value.
lariov::ChannelStatusProvider const & fChanStatus
detinfo::DetectorProperties const * fDetProp
void ConvertBinsToClusters(std::vector< std::vector< double > > const &image, std::vector< std::vector< int > > const &allClusterBins, std::vector< art::PtrVector< recob::Hit > > &clusters)
Takes a vector of clusters (itself a vector of hits) and turns them into clusters using the initial h...
Event finding and building.
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
Returns the specified wire.
int GlobalWire(geo::WireID const &wireID)
Find the global wire position.