13 #include "cetlib/pow.h"
19 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "RtypesCore.h"
30 #include "TVirtualPad.h"
32 #include "range/v3/view.hpp"
38 : fDebug{pset.get<
bool>(
"Debug",
false)}
39 ,
fDetector{pset.get<std::string>(
"Detector",
"dune35t")}
49 ,
fMinSize{pset.get<
unsigned int>(
"MinSize")}
50 ,
fMinSeed{pset.get<
double>(
"MinSeed")}
62 closeName.append(
"]");
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);
82 std::ostringstream oss;
83 oss <<
"BlurredImages_Run" << run <<
"_Subrun" << subrun;
96 for (
int i = 1; i <= 4; ++i) {
100 std::ostringstream oss;
101 oss <<
"Event " << event;
105 l.DrawLatex(0.1, 0.1, oss.str().c_str());
112 std::vector<std::vector<int>>
const& allClusterBins,
113 std::vector<art::PtrVector<recob::Hit>>& clusters)
const
116 for (
auto const& bins : allClusterBins) {
120 mf::LogInfo(
"BlurredClustering") <<
"Cluster made from " << bins.size() <<
" bins, of which "
121 << clusHits.size() <<
" were real hits";
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;
131 clusters.push_back(clusHits);
135 std::vector<std::vector<double>>
138 int const readoutWindowSize)
141 int lowerTick = readoutWindowSize, upperTick{}, lowerWire =
fGeom->MaxWires(), upperWire{};
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;
166 for (
auto const&
hit : hits) {
168 auto const tick =
static_cast<int>(
hit->PeakTime());
169 float const charge =
hit->Integral();
180 geo::PlaneID const planeID = hits.front()->WireID().planeID();
182 for (
int wire = fLowerWire; wire <
fUpperWire; ++wire) {
184 fGeom->PlaneWireToChannel(planeID.Plane, wire, planeID.TPC, planeID.Cryostat);
196 int const nbinsx = blurred.size();
197 int const nbinsy = blurred.at(0).size();
198 int const nbins = nbinsx * nbinsy;
201 std::vector<bool> used(nbins);
202 std::vector<std::pair<double, int>>
values;
205 for (
int xbin = 0; xbin < nbinsx; ++xbin) {
206 for (
int ybin = 0; ybin < nbinsy; ++ybin) {
213 std::sort(values.rbegin(), values.rend());
225 std::vector<double> times;
228 if (
double const blurred_binval = values[niter].
first; blurred_binval <
fMinSeed)
break;
231 int const bin = values[niter++].second;
234 if (used[bin])
continue;
238 cluster.push_back(bin);
241 if (
double const time =
GetTimeOfBin(blurred, bin); time > 0) times.push_back(time);
246 bool added_cluster{
false};
248 for (
unsigned int clusBin = 0; clusBin < cluster.size(); ++clusBin) {
251 int const binx = cluster[clusBin] % nbinsx;
252 int const biny = ((cluster[clusBin] - binx) / nbinsx) % nbinsy;
256 if (
x >= nbinsx or
x < 0)
continue;
258 if (
y >= nbinsy or
y < 0)
continue;
259 if (
x == binx
and y == biny)
continue;
263 if (bin >= nbinsx * nbinsy or bin < 0)
continue;
264 if (used[bin])
continue;
272 if (time > 0 && times.size() > 0 && !
PassesTimeCut(times, time))
continue;
277 cluster.push_back(bin);
278 added_cluster =
true;
279 if (time > 0) { times.push_back(time); }
286 if (!added_cluster)
break;
292 for (
auto const bin : cluster) {
300 for (
unsigned int clusBin = 0; clusBin < cluster.size(); clusBin++) {
303 for (
int x = -1;
x <= 1; ++
x) {
304 for (
int y = -1;
y <= 1; ++
y) {
305 if (
x == 0 &&
y == 0)
continue;
308 int neighbouringBin = cluster[clusBin] +
x + (
y * nbinsx);
309 if (neighbouringBin < nbinsx || neighbouringBin % nbinsx == 0 ||
310 neighbouringBin % nbinsx == nbinsx - 1 || neighbouringBin >= nbinsx * (nbinsy - 1))
313 double const time =
GetTimeOfBin(blurred, neighbouringBin);
316 if (!used[neighbouringBin] &&
319 used[neighbouringBin] =
true;
320 cluster.push_back(neighbouringBin);
322 if (time > 0) { times.push_back(time); }
329 mf::LogVerbatim(
"Blurred Clustering")
330 <<
"Size of cluster after filling in holes: " << cluster.size();
334 bool removed_cluster{
false};
337 for (
int clusBin = cluster.size() - 1; clusBin >= 0; clusBin--) {
338 auto const bin = cluster[clusBin];
341 if (bin < nbinsx || bin % nbinsx == 0 || bin % nbinsx == nbinsx - 1 ||
342 bin >= nbinsx * (nbinsy - 1))
348 removed_cluster =
true;
349 cluster.erase(cluster.begin() + clusBin);
353 if (!removed_cluster)
break;
356 mf::LogVerbatim(
"Blurred Clustering")
357 <<
"Size of cluster after removing peninsulas: " << cluster.size();
361 for (
auto const bin : cluster) {
369 allcluster.push_back(cluster);
374 return allcluster.size();
380 double globalWire = -999;
384 double wireCentre[3];
385 fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
386 if (wireID.
TPC % 2 == 0)
388 fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 0, wireID.
Cryostat);
391 fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 1, 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;
407 mf::LogError(
"BlurredClusterAlg")
408 <<
"Error when trying to find a global induction plane coordinate for TPC " << wireID.
TPC
414 int block = wireID.
TPC / 4;
415 globalWire = (nwires * block) + wireID.
Wire;
418 double wireCentre[3];
419 fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
420 if (wireID.
TPC % 2 == 0)
422 fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 0, wireID.
Cryostat);
425 fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.
Plane, 1, wireID.
Cryostat);
429 return std::round(globalWire);
432 std::vector<std::vector<double>>
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();
446 std::vector<std::vector<double>>
copy(nbinsx, std::vector<double>(nbinsy, 0));
449 for (
int x = 0;
x < nbinsx; ++
x) {
450 for (
int y = 0;
y < nbinsy; ++
y) {
452 if (image[
x][
y] == 0)
continue;
456 std::sqrt(cet::square(
fHitMap[
x][
y]->RMS()) + cet::square(sigma_tick)) / (double)sigma_tick;
458 auto const& correct_kernel =
fAllKernels[sigma_wire][sigma_tick * tick_scale];
461 auto const [lower_bin_dead, upper_bin_dead] =
DeadWireCount(
x, width);
466 auto dead_wires_passed{lower_bin_dead};
469 for (
int blurx = -(width / 2 + lower_bin_dead); blurx < (width + 1) / 2 + upper_bin_dead;
471 if (
x + blurx < 0)
continue;
472 for (
int blury = -height / 2 * tick_scale;
473 blury < ((((height + 1) / 2) - 1) * tick_scale) + 1;
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];
499 TString
const name)
const
501 auto hist =
new TH2F(name,
509 hist->SetXTitle(
"Wire number");
510 hist->SetYTitle(
"Tick number");
511 hist->SetZTitle(
"Charge");
513 for (
unsigned int imageWireIt = 0; imageWireIt < image.size(); ++imageWireIt) {
515 for (
unsigned int imageTickIt = 0; imageTickIt < image.at(imageWireIt).size(); ++imageTickIt) {
517 hist->Fill(wire, tick, image.at(imageWireIt).at(imageTickIt));
526 std::vector<art::PtrVector<recob::Hit>>
const& allClusters,
532 std::vector<std::vector<int>> allClusterBins;
534 for (
auto const&
cluster : allClusters) {
537 std::vector<int> clusterBins;
541 float const tick =
hit->PeakTime();
543 if (cluster.size() <
fMinSize) bin *= -1;
545 clusterBins.push_back(bin);
548 allClusterBins.push_back(clusterBins);
551 SaveImage(image, allClusterBins, pad, tpc, plane);
557 std::vector<std::vector<int>> allClusterBins;
558 SaveImage(image, allClusterBins, pad, tpc, plane);
563 std::vector<std::vector<int>>
const& allClusterBins,
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;
579 std::stringstream title;
580 title << stage <<
" -- TPC " << tpc <<
", Plane " << plane;
582 image->SetName(title.str().c_str());
583 image->SetTitle(title.str().c_str());
584 image->DrawCopy(
"colz");
588 for (
auto const& bins : allClusterBins) {
589 TMarker mark(0, 0, 20);
590 mark.SetMarkerColor(clusterNum);
591 mark.SetMarkerSize(0.1);
593 for (
auto bin : bins) {
597 mark.SetMarkerStyle(24);
601 image->GetBinXYZ(
bin, wire, tick, z);
603 mark.SetMarkerStyle(20);
615 art::PtrVector<recob::Hit>
617 std::vector<int>
const& bins)
const
620 art::PtrVector<recob::Hit> hits;
623 for (
auto const bin : bins) {
628 if (!hit.isNull()) hits.push_back(hit);
639 int const wire = bin % image.size();
640 int const tick = bin / image.size();
647 int const ybin)
const
649 return ybin * image.size() + xbin;
656 int const x = bin % image.size();
657 int const y = bin / image.size();
658 return image.at(x).at(y);
664 auto deadWires = std::make_pair(0, 0);
666 int const lower_bin = width / 2;
667 int const upper_bin = (width + 1) / 2;
670 for (
int wire = std::max(
offset - lower_bin, fLowerWire);
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;
701 double const gradient = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
705 auto const unit = std::isnan(gradient) ? TVector2{0, 1} : TVector2{1, gradient}.Unit();
713 return {{blur_wire, blur_tick, sigma_wire, sigma_tick}};
721 return hit.isNull() ? -10000. :
hit->PeakTime();
724 std::vector<std::vector<std::vector<double>>>
728 std::vector<std::vector<std::vector<double>>> allKernels(
735 for (
int sigma_wire = 1; sigma_wire <=
fSigmaWire; ++sigma_wire) {
739 std::vector<double> kernel(
fKernelWidth * fKernelHeight, 0);
746 double const sig2i = 2. * sigma_wire * sigma_wire;
747 double const sig2j = 2. * sigma_tick * sigma_tick;
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;
756 allKernels[sigma_wire][sigma_tick] = move(kernel);
764 std::vector<bool>
const& used,
767 unsigned int neighbours = 0;
770 for (
int x = -1;
x <= 1;
x++) {
771 for (
int y = -1;
y <= 1;
y++) {
772 if (
x == 0 &&
y == 0)
continue;
775 int neighbouringBin =
781 if (used.at(neighbouringBin)) neighbours++;
791 double const time)
const
793 for (
auto const t : times) {
process_name opflash particleana ie ie ie z
float Length(const PFPStruct &pfp)
unsigned int fNeighboursThreshold
BlurredClusteringAlg(fhicl::ParameterSet const &pset)
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Utilities related to art service access.
TH2F * MakeHistogram(std::vector< std::vector< double >> const &image, TString name) const
Converts a 2D vector in a histogram for the debug pdf.
constexpr to_element_t to_element
process_name opflash particleana ie x
std::vector< std::vector< art::Ptr< recob::Hit > > > fHitMap
std::vector< std::vector< std::vector< double > > > MakeKernels() const
Makes all the kernels which could be required given the tuned parameters.
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 ×, double time) const
Determine if a hit is within a time threshold of any other hits in a cluster.
The data type to uniquely identify a Plane.
unsigned int NumNeighbours(int nx, std::vector< bool > const &used, int bin) const
Determines the number of clustered neighbours of a hit.
std::array< int, 4 > FindBlurringParameters() const
Dynamically find the blurring radii and Gaussian sigma in each dimension.
CryostatID_t Cryostat
Index of cryostat.
WireID_t Wire
Index of the wire within its plane.
std::string fDebugPDFName
std::vector< bool > fDeadWires
int FindClusters(std::vector< std::vector< double >> const &image, std::vector< std::vector< int >> &allcluster) const
Find clusters in the histogram.
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
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...
void CreateDebugPDF(int run, int subrun, int event)
Create the PDF to save debug images.
std::pair< int, int > DeadWireCount(int wire_bin, int width) const
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.
Signal from induction planes.
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 GlobalWire(geo::WireID const &wireID) const
Find the global wire position.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
virtual bool IsGood(raw::ChannelID_t channel) const
Returns whether the specified channel is physical and good.
std::vector< std::vector< double > > GaussianBlur(std::vector< std::vector< double >> const &image) const
Applies Gaussian blur to image.
void SaveImage(TH2F *image, std::vector< art::PtrVector< recob::Hit >> const &allClusters, int pad, int tpc, int plane)
unsigned int fMinNeighbours
PlaneID_t Plane
Index of the plane within its TPC.
Definition of data types for geometry description.
art::ServiceHandle< geo::Geometry const > fGeom
Encapsulate the geometry of a wire.
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 h...
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...
std::vector< std::vector< std::vector< double > > > fAllKernels
unsigned int ChannelID_t
Type representing the ID of a readout channel.
TPCID_t TPC
Index of the TPC within its cryostat.
lariov::ChannelStatusProvider const & fChanStatus