All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Public Member Functions | Private Member Functions | Private Attributes | List of all members
cluster::BlurredClusteringAlg Class Reference

#include <BlurredClusteringAlg.h>

Public Member Functions

 BlurredClusteringAlg (fhicl::ParameterSet const &pset)
 
 ~BlurredClusteringAlg ()
 
void CreateDebugPDF (int run, int subrun, int event)
 Create the PDF to save debug images. More...
 
void ConvertBinsToClusters (std::vector< std::vector< double >> const &image, std::vector< std::vector< int >> const &allClusterBins, std::vector< art::PtrVector< recob::Hit >> &clusters) const
 Takes a vector of clusters (itself a vector of hits) and turns them into clusters using the initial hit selection. More...
 
std::vector< std::vector
< double > > 
ConvertRecobHitsToVector (std::vector< art::Ptr< recob::Hit >> const &hits, int readoutWindowSize)
 Takes hit map and returns a 2D vector representing wire and tick, filled with the charge. More...
 
int FindClusters (std::vector< std::vector< double >> const &image, std::vector< std::vector< int >> &allcluster) const
 Find clusters in the histogram. More...
 
int GlobalWire (geo::WireID const &wireID) const
 Find the global wire position. More...
 
std::vector< std::vector
< double > > 
GaussianBlur (std::vector< std::vector< double >> const &image) const
 Applies Gaussian blur to image. More...
 
unsigned int GetMinSize () const noexcept
 Minimum size of cluster to save. More...
 
TH2F * MakeHistogram (std::vector< std::vector< double >> const &image, TString name) const
 Converts a 2D vector in a histogram for the debug pdf. More...
 
void SaveImage (TH2F *image, std::vector< art::PtrVector< recob::Hit >> const &allClusters, int pad, int tpc, int plane)
 
void SaveImage (TH2F *image, int pad, int tpc, int plane)
 Save the images for debugging. More...
 
void SaveImage (TH2F *image, std::vector< std::vector< int >> const &allClusterBins, int pad, int tpc, int plane)
 

Private Member Functions

art::PtrVector< recob::HitConvertBinsToRecobHits (std::vector< std::vector< double >> const &image, std::vector< int > const &bins) const
 Converts a vector of bins into a hit selection - not all the hits in the bins vector are real hits. More...
 
art::Ptr< recob::HitConvertBinToRecobHit (std::vector< std::vector< double >> const &image, int bin) const
 Converts a bin into a recob::Hit (not all of these bins correspond to recob::Hits - some are fake hits created by the blurring) More...
 
int ConvertWireTickToBin (std::vector< std::vector< double >> const &image, int xbin, int ybin) const
 Converts an xbin and a ybin to a global bin number. More...
 
double ConvertBinToCharge (std::vector< std::vector< double >> const &image, int bin) const
 Returns the charge stored in the global bin value. More...
 
std::pair< int, int > DeadWireCount (int wire_bin, int width) const
 
std::array< int, 4 > FindBlurringParameters () const
 Dynamically find the blurring radii and Gaussian sigma in each dimension. More...
 
double GetTimeOfBin (std::vector< std::vector< double >> const &image, int bin) const
 Returns the hit time of a hit in a particular bin. More...
 
std::vector< std::vector
< std::vector< double > > > 
MakeKernels () const
 Makes all the kernels which could be required given the tuned parameters. More...
 
unsigned int NumNeighbours (int nx, std::vector< bool > const &used, int bin) const
 Determines the number of clustered neighbours of a hit. More...
 
bool PassesTimeCut (std::vector< double > const &times, double time) const
 Determine if a hit is within a time threshold of any other hits in a cluster. More...
 

Private Attributes

bool fDebug
 
std::string fDetector
 
int fBlurWire
 
int fBlurTick
 
double fSigmaWire
 
double fSigmaTick
 
int fMaxTickWidthBlur
 
int fClusterWireDistance
 
int fClusterTickDistance
 
unsigned int fNeighboursThreshold
 
unsigned int fMinNeighbours
 
unsigned int fMinSize
 
double fMinSeed
 
double fTimeThreshold
 
double fChargeThreshold
 
int fKernelWidth
 
int fKernelHeight
 
std::vector< std::vector
< std::vector< double > > > 
fAllKernels
 
std::vector< std::vector
< art::Ptr< recob::Hit > > > 
fHitMap
 
std::vector< bool > fDeadWires
 
int fLowerTick
 
int fUpperTick
 
int fLowerWire
 
int fUpperWire
 
TCanvas * fDebugCanvas {nullptr}
 
std::string fDebugPDFName {}
 
art::ServiceHandle
< geo::Geometry const > 
fGeom
 
lariov::ChannelStatusProvider
const & 
fChanStatus
 

Detailed Description

Definition at line 51 of file BlurredClusteringAlg.h.

Constructor & Destructor Documentation

cluster::BlurredClusteringAlg::BlurredClusteringAlg ( fhicl::ParameterSet const &  pset)

Definition at line 37 of file BlurredClusteringAlg.cxx.

38  : fDebug{pset.get<bool>("Debug", false)}
39  , fDetector{pset.get<std::string>("Detector", "dune35t")}
40  , fBlurWire{pset.get<int>("BlurWire")}
41  , fBlurTick{pset.get<int>("BlurTick")}
42  , fSigmaWire{pset.get<double>("SigmaWire")}
43  , fSigmaTick{pset.get<double>("SigmaTick")}
44  , fMaxTickWidthBlur{pset.get<int>("MaxTickWidthBlur")}
45  , fClusterWireDistance{pset.get<int>("ClusterWireDistance")}
46  , fClusterTickDistance{pset.get<int>("ClusterTickDistance")}
47  , fNeighboursThreshold{pset.get<unsigned int>("NeighboursThreshold")}
48  , fMinNeighbours{pset.get<unsigned int>("MinNeighbours")}
49  , fMinSize{pset.get<unsigned int>("MinSize")}
50  , fMinSeed{pset.get<double>("MinSeed")}
51  , fTimeThreshold{pset.get<double>("TimeThreshold")}
52  , fChargeThreshold{pset.get<double>("ChargeThreshold")}
53  , fKernelWidth{2 * fBlurWire + 1}
56 {}
std::vector< std::vector< std::vector< double > > > MakeKernels() const
Makes all the kernels which could be required given the tuned parameters.
std::vector< std::vector< std::vector< double > > > fAllKernels
cluster::BlurredClusteringAlg::~BlurredClusteringAlg ( )

Definition at line 58 of file BlurredClusteringAlg.cxx.

59 {
60  if (fDebugCanvas) {
61  std::string closeName = fDebugPDFName;
62  closeName.append("]");
63  fDebugCanvas->Print(closeName.c_str());
64  delete fDebugCanvas;
65  }
66 }

Member Function Documentation

void cluster::BlurredClusteringAlg::ConvertBinsToClusters ( std::vector< std::vector< double >> const &  image,
std::vector< std::vector< int >> const &  allClusterBins,
std::vector< art::PtrVector< recob::Hit >> &  clusters 
) const

Takes a vector of clusters (itself a vector of hits) and turns them into clusters using the initial hit selection.

Definition at line 110 of file BlurredClusteringAlg.cxx.

114 {
115  // Loop through the clusters (each a vector of bins)
116  for (auto const& bins : allClusterBins) {
117  // Convert the clusters (vectors of bins) to hits in a vector of recob::Hits
118  art::PtrVector<recob::Hit> clusHits = ConvertBinsToRecobHits(image, bins);
119 
120  mf::LogInfo("BlurredClustering") << "Cluster made from " << bins.size() << " bins, of which "
121  << clusHits.size() << " were real hits";
122 
123  // Make sure the clusters are above the minimum cluster size
124  if (clusHits.size() < fMinSize) {
125  mf::LogVerbatim("BlurredClustering")
126  << "Cluster of size " << clusHits.size()
127  << " not saved since it is smaller than the minimum cluster size, set to " << fMinSize;
128  continue;
129  }
130 
131  clusters.push_back(clusHits);
132  }
133 }
art::PtrVector< recob::Hit > ConvertBinsToRecobHits(std::vector< std::vector< double >> const &image, std::vector< int > const &bins) const
Converts a vector of bins into a hit selection - not all the hits in the bins vector are real hits...
art::PtrVector< recob::Hit > cluster::BlurredClusteringAlg::ConvertBinsToRecobHits ( std::vector< std::vector< double >> const &  image,
std::vector< int > const &  bins 
) const
private

Converts a vector of bins into a hit selection - not all the hits in the bins vector are real hits.

Definition at line 616 of file BlurredClusteringAlg.cxx.

618 {
619  // Create the vector of hits to output
620  art::PtrVector<recob::Hit> hits;
621 
622  // Look through the hits in the cluster
623  for (auto const bin : bins) {
624  // Take each hit and convert it to a recob::Hit
625  art::Ptr<recob::Hit> const hit = ConvertBinToRecobHit(image, bin);
626 
627  // If this hit was a real hit put it in the hit selection
628  if (!hit.isNull()) hits.push_back(hit);
629  }
630 
631  // Return the vector of hits to make cluster
632  return hits;
633 }
process_name hit
Definition: cheaterreco.fcl:51
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
art::Ptr< recob::Hit > ConvertBinToRecobHit(std::vector< std::vector< double >> const &image, int bin) const
Converts a bin into a recob::Hit (not all of these bins correspond to recob::Hits - some are fake hit...
double cluster::BlurredClusteringAlg::ConvertBinToCharge ( std::vector< std::vector< double >> const &  image,
int  bin 
) const
private

Returns the charge stored in the global bin value.

Definition at line 653 of file BlurredClusteringAlg.cxx.

655 {
656  int const x = bin % image.size();
657  int const y = bin / image.size();
658  return image.at(x).at(y);
659 }
process_name opflash particleana ie x
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
process_name opflash particleana ie ie y
art::Ptr< recob::Hit > cluster::BlurredClusteringAlg::ConvertBinToRecobHit ( std::vector< std::vector< double >> const &  image,
int  bin 
) const
private

Converts a bin into a recob::Hit (not all of these bins correspond to recob::Hits - some are fake hits created by the blurring)

Definition at line 636 of file BlurredClusteringAlg.cxx.

638 {
639  int const wire = bin % image.size();
640  int const tick = bin / image.size();
641  return fHitMap[wire][tick];
642 }
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
std::vector< std::vector< double > > cluster::BlurredClusteringAlg::ConvertRecobHitsToVector ( std::vector< art::Ptr< recob::Hit >> const &  hits,
int  readoutWindowSize 
)

Takes hit map and returns a 2D vector representing wire and tick, filled with the charge.

Definition at line 136 of file BlurredClusteringAlg.cxx.

139 {
140  // Define the size of this particular plane -- dynamically to avoid huge histograms
141  int lowerTick = readoutWindowSize, upperTick{}, lowerWire = fGeom->MaxWires(), upperWire{};
142  using lar::to_element;
144  for (auto const& hit : hits | transform(to_element)) {
145  int histWire = GlobalWire(hit.WireID());
146  if (hit.PeakTime() < lowerTick) lowerTick = hit.PeakTime();
147  if (hit.PeakTime() > upperTick) upperTick = hit.PeakTime();
148  if (histWire < lowerWire) lowerWire = histWire;
149  if (histWire > upperWire) upperWire = histWire;
150  }
151  fLowerTick = lowerTick - 20;
152  fUpperTick = upperTick + 20;
153  fLowerWire = lowerWire - 20;
154  fUpperWire = upperWire + 20;
155 
156  // Use a map to keep a track of the real hits and their wire/ticks
157  fHitMap.clear();
158  fHitMap.resize(fUpperWire - fLowerWire,
159  std::vector<art::Ptr<recob::Hit>>(fUpperTick - fLowerTick));
160 
161  // Create a 2D vector
162  std::vector<std::vector<double>> image(fUpperWire - fLowerWire,
163  std::vector<double>(fUpperTick - fLowerTick));
164 
165  // Look through the hits
166  for (auto const& hit : hits) {
167  int const wire = GlobalWire(hit->WireID());
168  auto const tick = static_cast<int>(hit->PeakTime());
169  float const charge = hit->Integral();
170 
171  // Fill hit map and keep a note of all real hits for later
172  if (charge > image.at(wire - fLowerWire).at(tick - fLowerTick)) {
173  image.at(wire - fLowerWire).at(tick - fLowerTick) = charge;
174  fHitMap[wire - fLowerWire][tick - fLowerTick] = hit;
175  }
176  }
177 
178  // Keep a note of dead wires
179  fDeadWires = std::vector<bool>(fUpperWire - fLowerWire, false);
180  geo::PlaneID const planeID = hits.front()->WireID().planeID();
181 
182  for (int wire = fLowerWire; wire < fUpperWire; ++wire) {
183  raw::ChannelID_t const channel =
184  fGeom->PlaneWireToChannel(planeID.Plane, wire, planeID.TPC, planeID.Cryostat);
185  fDeadWires[wire - fLowerWire] = !fChanStatus.IsGood(channel);
186  }
187 
188  return image;
189 }
constexpr to_element_t to_element
Definition: ToElement.h:24
static constexpr Sample_t transform(Sample_t sample)
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
process_name hit
Definition: cheaterreco.fcl:51
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
int GlobalWire(geo::WireID const &wireID) const
Find the global wire position.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
virtual bool IsGood(raw::ChannelID_t channel) const
Returns whether the specified channel is physical and good.
art::ServiceHandle< geo::Geometry const > fGeom
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
lariov::ChannelStatusProvider const & fChanStatus
int cluster::BlurredClusteringAlg::ConvertWireTickToBin ( std::vector< std::vector< double >> const &  image,
int  xbin,
int  ybin 
) const
private

Converts an xbin and a ybin to a global bin number.

Definition at line 645 of file BlurredClusteringAlg.cxx.

648 {
649  return ybin * image.size() + xbin;
650 }
void cluster::BlurredClusteringAlg::CreateDebugPDF ( int  run,
int  subrun,
int  event 
)

Create the PDF to save debug images.

Definition at line 69 of file BlurredClusteringAlg.cxx.

70 {
71  if (!fDebugCanvas) {
72 
73  // Create the grayscale palette for the Z axis
74  Double_t Red[2] = {1.00, 0.00};
75  Double_t Green[2] = {1.00, 0.00};
76  Double_t Blue[2] = {1.00, 0.00};
77  Double_t Length[2] = {0.00, 1.00};
78  TColor::CreateGradientColorTable(2, Length, Red, Green, Blue, 1000);
79  gStyle->SetOptStat(110000);
80 
81  // Decide what to call this PDF
82  std::ostringstream oss;
83  oss << "BlurredImages_Run" << run << "_Subrun" << subrun;
84  fDebugPDFName = oss.str();
85  fDebugCanvas = new TCanvas(fDebugPDFName.c_str(), "Image canvas", 1000, 500);
86  fDebugPDFName.append(".pdf");
87 
88  std::string openName = fDebugPDFName;
89  openName.append("[");
90  fDebugCanvas->Print(openName.c_str());
91  fDebugCanvas->Divide(2, 2);
92  fDebugCanvas->SetGrid();
93  }
94 
95  // Clear the pads on the canvas
96  for (int i = 1; i <= 4; ++i) {
97  fDebugCanvas->GetPad(i)->Clear();
98  }
99 
100  std::ostringstream oss;
101  oss << "Event " << event;
102  fDebugCanvas->cd(1);
103  TLatex l;
104  l.SetTextSize(0.15);
105  l.DrawLatex(0.1, 0.1, oss.str().c_str());
106  fDebugCanvas->Print(fDebugPDFName.c_str());
107 }
float Length(const PFPStruct &pfp)
Definition: PFPUtils.cxx:3304
std::pair< int, int > cluster::BlurredClusteringAlg::DeadWireCount ( int  wire_bin,
int  width 
) const
private

Count how many dead wires there are in the blurring region for a particular hit Returns a pair of counters representing how many dead wires there are below and above the hit respectively

Definition at line 662 of file BlurredClusteringAlg.cxx.

663 {
664  auto deadWires = std::make_pair(0, 0);
665 
666  int const lower_bin = width / 2;
667  int const upper_bin = (width + 1) / 2;
668 
669  auto const offset = wire_bin + fLowerWire;
670  for (int wire = std::max(offset - lower_bin, fLowerWire);
671  wire < std::min(offset + upper_bin, fUpperWire);
672  ++wire) {
673  if (!fDeadWires[wire - fLowerWire]) continue;
674 
675  if (wire < offset)
676  ++deadWires.first;
677  else if (wire > offset)
678  ++deadWires.second;
679  }
680 
681  return deadWires;
682 }
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
std::array< int, 4 > cluster::BlurredClusteringAlg::FindBlurringParameters ( ) const
private

Dynamically find the blurring radii and Gaussian sigma in each dimension.

Definition at line 685 of file BlurredClusteringAlg.cxx.

686 {
687  // Calculate least squares slope
688  double nhits{}, sumx{}, sumy{}, sumx2{}, sumxy{};
689  for (unsigned int wireIt = 0; wireIt < fHitMap.size(); ++wireIt) {
690  for (unsigned int tickIt = 0; tickIt < fHitMap.at(wireIt).size(); ++tickIt) {
691  if (fHitMap[wireIt][tickIt].isNull()) continue;
692  ++nhits;
693  int const x = wireIt + fLowerWire;
694  int const y = tickIt + fLowerTick;
695  sumx += x;
696  sumy += y;
697  sumx2 += x * x;
698  sumxy += x * y;
699  }
700  }
701  double const gradient = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
702 
703  // Get the rough unit vector for the trajectories, making sure to
704  // catch the vertical gradient.
705  auto const unit = std::isnan(gradient) ? TVector2{0, 1} : TVector2{1, gradient}.Unit();
706 
707  // Use this direction to scale the blurring radii and Gaussian sigma
708  int const blur_wire = std::max(std::abs(std::round(fBlurWire * unit.X())), 1.);
709  int const blur_tick = std::max(std::abs(std::round(fBlurTick * unit.Y())), 1.);
710 
711  int const sigma_wire = std::max(std::abs(std::round(fSigmaWire * unit.X())), 1.);
712  int const sigma_tick = std::max(std::abs(std::round(fSigmaTick * unit.Y())), 1.);
713  return {{blur_wire, blur_tick, sigma_wire, sigma_tick}};
714 }
process_name opflash particleana ie x
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
T abs(T value)
process_name opflash particleana ie ie y
int cluster::BlurredClusteringAlg::FindClusters ( std::vector< std::vector< double >> const &  image,
std::vector< std::vector< int >> &  allcluster 
) const

Find clusters in the histogram.

Definition at line 192 of file BlurredClusteringAlg.cxx.

194 {
195  // Size of image in x and y
196  int const nbinsx = blurred.size();
197  int const nbinsy = blurred.at(0).size();
198  int const nbins = nbinsx * nbinsy;
199 
200  // Vectors to hold hit information
201  std::vector<bool> used(nbins);
202  std::vector<std::pair<double, int>> values;
203 
204  // Place the bin number and contents as a pair in the values vector
205  for (int xbin = 0; xbin < nbinsx; ++xbin) {
206  for (int ybin = 0; ybin < nbinsy; ++ybin) {
207  int const bin = ConvertWireTickToBin(blurred, xbin, ybin);
208  values.emplace_back(ConvertBinToCharge(blurred, bin), bin);
209  }
210  }
211 
212  // Sort the values into charge order
213  std::sort(values.rbegin(), values.rend());
214 
215  // Count the number of iterations of the cluster forming loop (== number of clusters)
216  int niter = 0;
217 
218  // Clustering loops
219  // 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)
220  // 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)
221  while (true) {
222 
223  // Start a new cluster each time loop is executed
224  std::vector<int> cluster;
225  std::vector<double> times;
226 
227  // Get the highest charge bin (go no further if below seed threshold)
228  if (double const blurred_binval = values[niter].first; blurred_binval < fMinSeed) break;
229 
230  // Iterate through the bins from highest charge down
231  int const bin = values[niter++].second;
232 
233  // Put this bin in used if not already there
234  if (used[bin]) continue;
235  used[bin] = true;
236 
237  // Start a new cluster
238  cluster.push_back(bin);
239 
240  // Get the time of this hit
241  if (double const time = GetTimeOfBin(blurred, bin); time > 0) times.push_back(time);
242 
243  // Now cluster neighbouring hits to this seed
244  while (true) {
245 
246  bool added_cluster{false};
247 
248  for (unsigned int clusBin = 0; clusBin < cluster.size(); ++clusBin) {
249 
250  // Get x and y values for bin (c++ returns a%b = a if a<b)
251  int const binx = cluster[clusBin] % nbinsx;
252  int const biny = ((cluster[clusBin] - binx) / nbinsx) % nbinsy;
253 
254  // Look for hits in the neighbouring x/y bins
255  for (int x = binx - fClusterWireDistance; x <= binx + fClusterWireDistance; x++) {
256  if (x >= nbinsx or x < 0) continue;
257  for (int y = biny - fClusterTickDistance; y <= biny + fClusterTickDistance; y++) {
258  if (y >= nbinsy or y < 0) continue;
259  if (x == binx and y == biny) continue;
260 
261  // Get this bin
262  auto const bin = ConvertWireTickToBin(blurred, x, y);
263  if (bin >= nbinsx * nbinsy or bin < 0) continue;
264  if (used[bin]) continue;
265 
266  // Get the blurred value and time for this bin
267  double const blurred_binval = ConvertBinToCharge(blurred, bin);
268  double const time =
269  GetTimeOfBin(blurred, bin); // NB for 'fake' hits, time is defaulted to -10000
270 
271  // Check real hits pass time cut (ignores fake hits)
272  if (time > 0 && times.size() > 0 && !PassesTimeCut(times, time)) continue;
273 
274  // Add to cluster if bin value is above threshold
275  if (blurred_binval > fChargeThreshold) {
276  used[bin] = true;
277  cluster.push_back(bin);
278  added_cluster = true;
279  if (time > 0) { times.push_back(time); }
280  } // End of adding blurred bin to cluster
281  }
282  } // End of looking at directly neighbouring bins
283 
284  } // End of looping over bins already in this cluster
285 
286  if (!added_cluster) break;
287 
288  } // End of adding hits to this cluster
289 
290  // Check this cluster is above minimum size
291  if (cluster.size() < fMinSize) {
292  for (auto const bin : cluster) {
293  assert(bin >= 0);
294  used[bin] = false;
295  }
296  continue;
297  }
298 
299  // Fill in holes in the cluster
300  for (unsigned int clusBin = 0; clusBin < cluster.size(); clusBin++) {
301 
302  // Looks at directly neighbouring bins (and not itself)
303  for (int x = -1; x <= 1; ++x) {
304  for (int y = -1; y <= 1; ++y) {
305  if (x == 0 && y == 0) continue;
306 
307  // Look at neighbouring bins to the clustered bin which are inside the cluster
308  int neighbouringBin = cluster[clusBin] + x + (y * nbinsx);
309  if (neighbouringBin < nbinsx || neighbouringBin % nbinsx == 0 ||
310  neighbouringBin % nbinsx == nbinsx - 1 || neighbouringBin >= nbinsx * (nbinsy - 1))
311  continue;
312 
313  double const time = GetTimeOfBin(blurred, neighbouringBin);
314 
315  // If not already clustered and passes neighbour/time thresholds, add to cluster
316  if (!used[neighbouringBin] &&
317  (NumNeighbours(nbinsx, used, neighbouringBin) > fNeighboursThreshold) &&
318  PassesTimeCut(times, time)) {
319  used[neighbouringBin] = true;
320  cluster.push_back(neighbouringBin);
321 
322  if (time > 0) { times.push_back(time); }
323  } // End of clustering neighbouring bin
324  }
325  } // End of looping over neighbouring bins
326 
327  } // End of looping over bins already in cluster
328 
329  mf::LogVerbatim("Blurred Clustering")
330  << "Size of cluster after filling in holes: " << cluster.size();
331 
332  // Remove peninsulas - hits which have too few neighbouring hits in the cluster (defined by fMinNeighbours)
333  while (true) {
334  bool removed_cluster{false};
335 
336  // Loop over all the bins in the cluster
337  for (int clusBin = cluster.size() - 1; clusBin >= 0; clusBin--) {
338  auto const bin = cluster[clusBin];
339 
340  // If bin is in cluster ignore
341  if (bin < nbinsx || bin % nbinsx == 0 || bin % nbinsx == nbinsx - 1 ||
342  bin >= nbinsx * (nbinsy - 1))
343  continue;
344 
345  // Remove hit if it has too few neighbouring hits
346  if (NumNeighbours(nbinsx, used, bin) < fMinNeighbours) {
347  used[bin] = false;
348  removed_cluster = true;
349  cluster.erase(cluster.begin() + clusBin);
350  }
351  }
352 
353  if (!removed_cluster) break;
354  }
355 
356  mf::LogVerbatim("Blurred Clustering")
357  << "Size of cluster after removing peninsulas: " << cluster.size();
358 
359  // Disregard cluster if not of minimum size
360  if (cluster.size() < fMinSize) {
361  for (auto const bin : cluster) {
362  assert(bin >= 0);
363  used[bin] = false;
364  }
365  continue;
366  }
367 
368  // Put this cluster in the vector of clusters
369  allcluster.push_back(cluster);
370 
371  } // End loop over this cluster
372 
373  // Return the number of clusters found in this hit map
374  return allcluster.size();
375 }
process_name opflash particleana ie x
process_name cluster
Definition: cheaterreco.fcl:51
double GetTimeOfBin(std::vector< std::vector< double >> const &image, int bin) const
Returns the hit time of a hit in a particular bin.
bool PassesTimeCut(std::vector< double > const &times, double time) const
Determine if a hit is within a time threshold of any other hits in a cluster.
unsigned int NumNeighbours(int nx, std::vector< bool > const &used, int bin) const
Determines the number of clustered neighbours of a hit.
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
double ConvertBinToCharge(std::vector< std::vector< double >> const &image, int bin) const
Returns the charge stored in the global bin value.
process_name opflash particleana ie ie y
int ConvertWireTickToBin(std::vector< std::vector< double >> const &image, int xbin, int ybin) const
Converts an xbin and a ybin to a global bin number.
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
std::vector< std::vector< double > > cluster::BlurredClusteringAlg::GaussianBlur ( std::vector< std::vector< double >> const &  image) const

Applies Gaussian blur to image.

Definition at line 433 of file BlurredClusteringAlg.cxx.

434 {
435  if (fSigmaWire == 0 and fSigmaTick == 0) return image;
436 
437  auto const [blur_wire, blur_tick, sigma_wire, sigma_tick] = FindBlurringParameters();
438 
439  // Convolve the Gaussian
440  int width = 2 * blur_wire + 1;
441  int height = 2 * blur_tick + 1;
442  int nbinsx = image.size();
443  int nbinsy = image.at(0).size();
444 
445  // Blurred histogram and normalisation for each bin
446  std::vector<std::vector<double>> copy(nbinsx, std::vector<double>(nbinsy, 0));
447 
448  // Loop through all the bins in the histogram to blur
449  for (int x = 0; x < nbinsx; ++x) {
450  for (int y = 0; y < nbinsy; ++y) {
451 
452  if (image[x][y] == 0) continue;
453 
454  // Scale the tick blurring based on the width of the hit
455  int tick_scale =
456  std::sqrt(cet::square(fHitMap[x][y]->RMS()) + cet::square(sigma_tick)) / (double)sigma_tick;
457  tick_scale = std::max(std::min(tick_scale, fMaxTickWidthBlur), 1);
458  auto const& correct_kernel = fAllKernels[sigma_wire][sigma_tick * tick_scale];
459 
460  // Find any dead wires in the potential blurring region
461  auto const [lower_bin_dead, upper_bin_dead] = DeadWireCount(x, width);
462 
463  // Note of how many dead wires we have passed whilst blurring in the wire direction
464  // If blurring below the seed hit, need to keep a note of how many dead wires to come
465  // If blurring above, need to keep a note of how many dead wires have passed
466  auto dead_wires_passed{lower_bin_dead};
467 
468  // Loop over the blurring region around this hit
469  for (int blurx = -(width / 2 + lower_bin_dead); blurx < (width + 1) / 2 + upper_bin_dead;
470  ++blurx) {
471  if (x + blurx < 0) continue;
472  for (int blury = -height / 2 * tick_scale;
473  blury < ((((height + 1) / 2) - 1) * tick_scale) + 1;
474  ++blury) {
475  if (blurx < 0 and fDeadWires[x + blurx]) dead_wires_passed -= 1;
476 
477  // Smear the charge of this hit
478  double const weight = correct_kernel[fKernelWidth * (fKernelHeight / 2 + blury) +
479  (fKernelWidth / 2 + (blurx - dead_wires_passed))];
480  if (x + blurx >= 0 and x + blurx < nbinsx and y + blury >= 0 and y + blury < nbinsy)
481  copy[x + blurx][y + blury] += weight * image[x][y];
482 
483  if (blurx > 0 and fDeadWires[x + blurx]) dead_wires_passed += 1;
484  }
485  } // blurring region
486  }
487  } // hits to blur
488 
489  // HAVE REMOVED NOMALISATION CODE
490  // WHEN USING DIFFERENT KERNELS, THERE'S NO EASY WAY OF DOING THIS...
491  // RECONSIDER...
492 
493  // Return the blurred histogram
494  return copy;
495 }
process_name opflash particleana ie x
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
std::array< int, 4 > FindBlurringParameters() const
Dynamically find the blurring radii and Gaussian sigma in each dimension.
std::pair< int, int > DeadWireCount(int wire_bin, int width) const
process_name opflash particleana ie ie y
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
T copy(T const &v)
std::vector< std::vector< std::vector< double > > > fAllKernels
unsigned int cluster::BlurredClusteringAlg::GetMinSize ( ) const
inlinenoexcept

Minimum size of cluster to save.

Definition at line 82 of file BlurredClusteringAlg.h.

83  {
84  return fMinSize;
85  }
double cluster::BlurredClusteringAlg::GetTimeOfBin ( std::vector< std::vector< double >> const &  image,
int  bin 
) const
private

Returns the hit time of a hit in a particular bin.

Definition at line 717 of file BlurredClusteringAlg.cxx.

719 {
720  auto const hit = ConvertBinToRecobHit(image, bin);
721  return hit.isNull() ? -10000. : hit->PeakTime();
722 }
process_name hit
Definition: cheaterreco.fcl:51
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
art::Ptr< recob::Hit > ConvertBinToRecobHit(std::vector< std::vector< double >> const &image, int bin) const
Converts a bin into a recob::Hit (not all of these bins correspond to recob::Hits - some are fake hit...
int cluster::BlurredClusteringAlg::GlobalWire ( geo::WireID const &  wireID) const

Find the global wire position.

Definition at line 378 of file BlurredClusteringAlg.cxx.

379 {
380  double globalWire = -999;
381 
382  // Induction
383  if (fGeom->SignalType(wireID) == geo::kInduction) {
384  double wireCentre[3];
385  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
386  if (wireID.TPC % 2 == 0)
387  globalWire =
388  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
389  else
390  globalWire =
391  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
392  }
393 
394  // Collection
395  else {
396  // FOR COLLECTION WIRES, HARD CODE THE GEOMETRY FOR GIVEN DETECTORS
397  // THIS _SHOULD_ BE TEMPORARY. GLOBAL WIRE SUPPORT IS BEING ADDED TO THE LARSOFT GEOMETRY AND SHOULD BE AVAILABLE SOON
398  if (fDetector == "dune35t") {
399  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
400  if (wireID.TPC == 0 or wireID.TPC == 1)
401  globalWire = wireID.Wire;
402  else if (wireID.TPC == 2 or wireID.TPC == 3 or wireID.TPC == 4 or wireID.TPC == 5)
403  globalWire = nwires + wireID.Wire;
404  else if (wireID.TPC == 6 or wireID.TPC == 7)
405  globalWire = (2 * nwires) + wireID.Wire;
406  else
407  mf::LogError("BlurredClusterAlg")
408  << "Error when trying to find a global induction plane coordinate for TPC " << wireID.TPC
409  << " (geometry " << fDetector << ")";
410  }
411  else if (fDetector == "dune10kt") {
412  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
413  // Detector geometry has four TPCs, two on top of each other, repeated along z...
414  int block = wireID.TPC / 4;
415  globalWire = (nwires * block) + wireID.Wire;
416  }
417  else {
418  double wireCentre[3];
419  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
420  if (wireID.TPC % 2 == 0)
421  globalWire =
422  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
423  else
424  globalWire =
425  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
426  }
427  }
428 
429  return std::round(globalWire);
430 }
Signal from induction planes.
Definition: geo_types.h:145
art::ServiceHandle< geo::Geometry const > fGeom
TH2F * cluster::BlurredClusteringAlg::MakeHistogram ( std::vector< std::vector< double >> const &  image,
TString  name 
) const

Converts a 2D vector in a histogram for the debug pdf.

Definition at line 498 of file BlurredClusteringAlg.cxx.

500 {
501  auto hist = new TH2F(name,
502  name,
504  fLowerWire - 0.5,
505  fUpperWire - 0.5,
507  fLowerTick - 0.5,
508  fUpperTick - 0.5);
509  hist->SetXTitle("Wire number");
510  hist->SetYTitle("Tick number");
511  hist->SetZTitle("Charge");
512 
513  for (unsigned int imageWireIt = 0; imageWireIt < image.size(); ++imageWireIt) {
514  int const wire = imageWireIt + fLowerWire;
515  for (unsigned int imageTickIt = 0; imageTickIt < image.at(imageWireIt).size(); ++imageTickIt) {
516  int const tick = imageTickIt + fLowerTick;
517  hist->Fill(wire, tick, image.at(imageWireIt).at(imageTickIt));
518  }
519  }
520 
521  return hist;
522 }
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
then echo fcl name
std::vector< std::vector< std::vector< double > > > cluster::BlurredClusteringAlg::MakeKernels ( ) const
private

Makes all the kernels which could be required given the tuned parameters.

Definition at line 725 of file BlurredClusteringAlg.cxx.

726 {
727  // Kernel size is the largest possible given the hit width rescaling
728  std::vector<std::vector<std::vector<double>>> allKernels(
729  fSigmaWire + 1,
730  std::vector<std::vector<double>>(fSigmaTick * fMaxTickWidthBlur + 1,
731  std::vector<double>(fKernelWidth * fKernelHeight)));
732 
733  // Ranges of kernels to make
734  // Complete range of sigmas possible after dynamic fixing and hit width convolution
735  for (int sigma_wire = 1; sigma_wire <= fSigmaWire; ++sigma_wire) {
736  for (int sigma_tick = 1; sigma_tick <= fSigmaTick * fMaxTickWidthBlur; ++sigma_tick) {
737 
738  // New kernel
739  std::vector<double> kernel(fKernelWidth * fKernelHeight, 0);
740 
741  // Smear out according to the blur radii in each direction
742  for (int i = -fBlurWire; i <= fBlurWire; i++) {
743  for (int j = -fBlurTick * fMaxTickWidthBlur; j <= fBlurTick * fMaxTickWidthBlur; j++) {
744 
745  // Fill kernel
746  double const sig2i = 2. * sigma_wire * sigma_wire;
747  double const sig2j = 2. * sigma_tick * sigma_tick;
748 
749  int const key = (fKernelWidth * (j + fBlurTick * fMaxTickWidthBlur)) + (i + fBlurWire);
750  double const value = 1. / std::sqrt(sig2i * M_PI) * std::exp(-i * i / sig2i) * 1. /
751  std::sqrt(sig2j * M_PI) * std::exp(-j * j / sig2j);
752  kernel.at(key) = value;
753  }
754  } // End loop over blurring region
755 
756  allKernels[sigma_wire][sigma_tick] = move(kernel);
757  }
758  }
759  return allKernels;
760 }
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
temporary value
unsigned int cluster::BlurredClusteringAlg::NumNeighbours ( int  nx,
std::vector< bool > const &  used,
int  bin 
) const
private

Determines the number of clustered neighbours of a hit.

2D hists can be considered a string of bins - the equation to convert between them is [bin = x + (nbinsx * y)]

Definition at line 763 of file BlurredClusteringAlg.cxx.

766 {
767  unsigned int neighbours = 0;
768 
769  // Loop over all directly neighbouring hits (not itself)
770  for (int x = -1; x <= 1; x++) {
771  for (int y = -1; y <= 1; y++) {
772  if (x == 0 && y == 0) continue;
773 
774  // Determine bin
775  int neighbouringBin =
776  bin + x +
777  (y *
778  nbinsx); /// 2D hists can be considered a string of bins - the equation to convert between them is [bin = x + (nbinsx * y)]
779 
780  // If this bin is in the cluster, increase the neighbouring bin counter
781  if (used.at(neighbouringBin)) neighbours++;
782  }
783  }
784 
785  // Return the number of neighbours in the cluster of a particular hit
786  return neighbours;
787 }
process_name opflash particleana ie x
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
process_name opflash particleana ie ie y
bool cluster::BlurredClusteringAlg::PassesTimeCut ( std::vector< double > const &  times,
double  time 
) const
private

Determine if a hit is within a time threshold of any other hits in a cluster.

Definition at line 790 of file BlurredClusteringAlg.cxx.

792 {
793  for (auto const t : times) {
794  if (std::abs(time - t) < fTimeThreshold) return true;
795  }
796  return false;
797 }
T abs(T value)
void cluster::BlurredClusteringAlg::SaveImage ( TH2F *  image,
std::vector< art::PtrVector< recob::Hit >> const &  allClusters,
int  pad,
int  tpc,
int  plane 
)

Save the images for debugging This version takes the final clusters and overlays on the hit map

Definition at line 525 of file BlurredClusteringAlg.cxx.

530 {
531  // Make a vector of clusters
532  std::vector<std::vector<int>> allClusterBins;
533 
534  for (auto const& cluster : allClusters) {
535  if (cluster.empty()) continue;
536 
537  std::vector<int> clusterBins;
538 
539  for (auto const& hit : cluster) {
540  unsigned int const wire = GlobalWire(hit->WireID());
541  float const tick = hit->PeakTime();
542  int bin = image->GetBin((wire - fLowerWire) + 1, (tick - fLowerTick) + 1);
543  if (cluster.size() < fMinSize) bin *= -1;
544 
545  clusterBins.push_back(bin);
546  }
547 
548  allClusterBins.push_back(clusterBins);
549  }
550 
551  SaveImage(image, allClusterBins, pad, tpc, plane);
552 }
process_name cluster
Definition: cheaterreco.fcl:51
process_name hit
Definition: cheaterreco.fcl:51
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
int GlobalWire(geo::WireID const &wireID) const
Find the global wire position.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
void SaveImage(TH2F *image, std::vector< art::PtrVector< recob::Hit >> const &allClusters, int pad, int tpc, int plane)
void cluster::BlurredClusteringAlg::SaveImage ( TH2F *  image,
int  pad,
int  tpc,
int  plane 
)

Save the images for debugging.

Definition at line 555 of file BlurredClusteringAlg.cxx.

556 {
557  std::vector<std::vector<int>> allClusterBins;
558  SaveImage(image, allClusterBins, pad, tpc, plane);
559 }
void SaveImage(TH2F *image, std::vector< art::PtrVector< recob::Hit >> const &allClusters, int pad, int tpc, int plane)
void cluster::BlurredClusteringAlg::SaveImage ( TH2F *  image,
std::vector< std::vector< int >> const &  allClusterBins,
int  pad,
int  tpc,
int  plane 
)

Save the images for debugging This version takes a vector of bins and overlays the relevant bins on the hit map

Definition at line 562 of file BlurredClusteringAlg.cxx.

567 {
568  fDebugCanvas->cd(pad);
569  std::string stage;
570 
571  switch (pad) {
572  case 1: stage = "Stage 1: Unblurred"; break;
573  case 2: stage = "Stage 2: Blurred"; break;
574  case 3: stage = "Stage 3: Blurred with clusters overlaid"; break;
575  case 4: stage = "Stage 4: Output clusters"; break;
576  default: stage = "Unknown stage"; break;
577  }
578 
579  std::stringstream title;
580  title << stage << " -- TPC " << tpc << ", Plane " << plane; // << " (Event " << fEvent << ")";
581 
582  image->SetName(title.str().c_str());
583  image->SetTitle(title.str().c_str());
584  image->DrawCopy("colz");
585 
586  // Draw the clustered hits on the histograms
587  int clusterNum = 2;
588  for (auto const& bins : allClusterBins) {
589  TMarker mark(0, 0, 20);
590  mark.SetMarkerColor(clusterNum);
591  mark.SetMarkerSize(0.1);
592 
593  for (auto bin : bins) {
594  // Hit from a cluster that we aren't going to save
595  if (bin < 0) {
596  bin *= -1;
597  mark.SetMarkerStyle(24);
598  }
599 
600  int wire, tick, z;
601  image->GetBinXYZ(bin, wire, tick, z);
602  mark.DrawMarker(wire + fLowerWire - 1, tick + fLowerTick - 1);
603  mark.SetMarkerStyle(20);
604  }
605  }
606 
607  if (pad == 4) {
608  fDebugCanvas->Print(fDebugPDFName.c_str());
609  fDebugCanvas->Clear("D");
610  }
611 }
process_name opflash particleana ie ie ie z
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75

Member Data Documentation

std::vector<std::vector<std::vector<double> > > cluster::BlurredClusteringAlg::fAllKernels
private

Definition at line 163 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fBlurTick
private

Definition at line 148 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fBlurWire
private

Definition at line 147 of file BlurredClusteringAlg.h.

lariov::ChannelStatusProvider const& cluster::BlurredClusteringAlg::fChanStatus
private
Initial value:
{
art::ServiceHandle<lariov::ChannelStatusService const>()->GetProvider()}

Definition at line 178 of file BlurredClusteringAlg.h.

double cluster::BlurredClusteringAlg::fChargeThreshold
private

Definition at line 159 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fClusterTickDistance
private

Definition at line 153 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fClusterWireDistance
private

Definition at line 152 of file BlurredClusteringAlg.h.

std::vector<bool> cluster::BlurredClusteringAlg::fDeadWires
private

Definition at line 167 of file BlurredClusteringAlg.h.

bool cluster::BlurredClusteringAlg::fDebug
private

Definition at line 143 of file BlurredClusteringAlg.h.

TCanvas* cluster::BlurredClusteringAlg::fDebugCanvas {nullptr}
private

Definition at line 173 of file BlurredClusteringAlg.h.

std::string cluster::BlurredClusteringAlg::fDebugPDFName {}
private

Definition at line 174 of file BlurredClusteringAlg.h.

std::string cluster::BlurredClusteringAlg::fDetector
private

Definition at line 144 of file BlurredClusteringAlg.h.

art::ServiceHandle<geo::Geometry const> cluster::BlurredClusteringAlg::fGeom
private

Definition at line 177 of file BlurredClusteringAlg.h.

std::vector<std::vector<art::Ptr<recob::Hit> > > cluster::BlurredClusteringAlg::fHitMap
private

Definition at line 166 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fKernelHeight
private

Definition at line 162 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fKernelWidth
private

Definition at line 162 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fLowerTick
private

Definition at line 169 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fLowerWire
private

Definition at line 170 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fMaxTickWidthBlur
private

Definition at line 151 of file BlurredClusteringAlg.h.

unsigned int cluster::BlurredClusteringAlg::fMinNeighbours
private

Definition at line 155 of file BlurredClusteringAlg.h.

double cluster::BlurredClusteringAlg::fMinSeed
private

Definition at line 157 of file BlurredClusteringAlg.h.

unsigned int cluster::BlurredClusteringAlg::fMinSize
private

Definition at line 156 of file BlurredClusteringAlg.h.

unsigned int cluster::BlurredClusteringAlg::fNeighboursThreshold
private

Definition at line 154 of file BlurredClusteringAlg.h.

double cluster::BlurredClusteringAlg::fSigmaTick
private

Definition at line 150 of file BlurredClusteringAlg.h.

double cluster::BlurredClusteringAlg::fSigmaWire
private

Definition at line 149 of file BlurredClusteringAlg.h.

double cluster::BlurredClusteringAlg::fTimeThreshold
private

Definition at line 158 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fUpperTick
private

Definition at line 169 of file BlurredClusteringAlg.h.

int cluster::BlurredClusteringAlg::fUpperWire
private

Definition at line 170 of file BlurredClusteringAlg.h.


The documentation for this class was generated from the following files: