33 #include "art/Framework/Core/ModuleMacros.h"
34 #include "art/Framework/Core/SharedProducer.h"
35 #include "art/Framework/Principal/Event.h"
36 #include "art/Framework/Services/Registry/ServiceHandle.h"
37 #include "art/Utilities/Globals.h"
38 #include "art/Utilities/make_tool.h"
39 #include "art_root_io/TFileService.h"
40 #include "canvas/Persistency/Common/FindOneP.h"
41 #include "fhiclcpp/ParameterSet.h"
58 #include "tbb/concurrent_vector.h"
59 #include "tbb/parallel_for.h"
64 explicit GausHitFinder(fhicl::ParameterSet
const& pset, art::ProcessingFrame
const&);
67 void produce(art::Event&
evt, art::ProcessingFrame
const&)
override;
68 void beginJob(art::ProcessingFrame
const&)
override;
83 const std::vector<double>
94 std::vector<std::unique_ptr<reco_tool::ICandidateHitFinder>>
110 : SharedProducer{pset}
111 , fFilterHits(pset.get<
bool>(
"FilterHits",
false))
112 , fFillHists(pset.get<
bool>(
"FillHists",
false))
113 , fCalDataModuleLabel(pset.get<std::string>(
"CalDataModuleLabel"))
114 , fAllHitsInstanceName(pset.get<std::string>(
"AllHitsInstanceName",
""))
115 , fLongMaxHitsVec(pset.get<std::vector<int>>(
"LongMaxHits", std::vector<int>() = {25, 25, 25}))
117 pset.get<std::vector<int>>(
"LongPulseWidth", std::vector<int>() = {16, 16, 16}))
120 ,
fAreaNormsVec(FillOutHitParameterVector(pset.get<std::vector<double>>(
"AreaNorms")))
121 ,
fChi2NDF(pset.get<
double>(
"Chi2NDF"))
123 pset.get<std::vector<float>>(
"PulseHeightCuts", std::vector<float>() = {3.0, 3.0, 3.0}))
125 pset.get<std::vector<float>>(
"PulseWidthCuts", std::vector<float>() = {2.0, 1.5, 1.0}))
127 pset.get<std::vector<float>>(
"PulseRatioCuts", std::vector<float>() = {0.35, 0.40, 0.20}))
130 throw art::Exception(art::errors::Configuration)
131 <<
"Cannot fill histograms when multiple threads configured, please set fFillHists to "
132 "false or change number of threads to 1\n";
134 async<art::InEvent>();
136 fHitFilterAlg = std::make_unique<HitFilterAlg>(pset.get<fhicl::ParameterSet>(
"HitFilterAlg"));
141 const fhicl::ParameterSet& hitFinderTools = pset.get<fhicl::ParameterSet>(
"HitFinderToolVec");
143 fHitFinderToolVec.resize(hitFinderTools.get_pset_names().size());
145 for (
const std::string& hitFinderTool : hitFinderTools.get_pset_names()) {
146 const fhicl::ParameterSet& hitFinderToolParamSet =
147 hitFinderTools.get<fhicl::ParameterSet>(hitFinderTool);
148 size_t planeIdx = hitFinderToolParamSet.get<
size_t>(
"Plane");
150 fHitFinderToolVec.at(planeIdx) =
151 art::make_tool<reco_tool::ICandidateHitFinder>(hitFinderToolParamSet);
156 art::make_tool<reco_tool::IPeakFitter>(pset.get<fhicl::ParameterSet>(
"PeakFitter"));
165 producesCollector(), fAllHitsInstanceName,
true,
false);
168 if (fAllHitsInstanceName !=
"")
170 producesCollector(),
"",
true,
false);
178 GausHitFinder::FillOutHitParameterVector(
const std::vector<double>& input)
180 if (input.size() == 0)
181 throw std::runtime_error(
182 "GausHitFinder::FillOutHitParameterVector ERROR! Input config vector has zero size.");
184 std::vector<double>
output;
185 art::ServiceHandle<geo::Geometry const> geom;
186 const unsigned int N_PLANES = geom->Nplanes();
188 if (input.size() == 1)
189 output.resize(N_PLANES, input[0]);
190 else if (input.size() == N_PLANES)
193 throw std::runtime_error(
"GausHitFinder::FillOutHitParameterVector ERROR! Input config "
194 "vector size !=1 and !=N_PLANES.");
201 GausHitFinder::beginJob(art::ProcessingFrame
const&)
204 art::ServiceHandle<art::TFileService const>
tfs;
209 fFirstChi2 = tfs->make<TH1F>(
"fFirstChi2",
"#chi^{2}", 10000, 0, 5000);
210 fChi2 = tfs->make<TH1F>(
"fChi2",
"#chi^{2}", 10000, 0, 5000);
219 GausHitFinder::produce(art::Event&
evt, art::ProcessingFrame
const&)
221 unsigned int count = fEventCount.fetch_add(1);
224 TH1::AddDirectory(kFALSE);
233 art::ServiceHandle<geo::Geometry const> geom;
246 if (fFilterHits) filteredHitCol = &hcol;
251 art::Ptr<recob::Wire> wire_tbb;
254 tbb::concurrent_vector<hitstruct> hitstruct_vec;
255 tbb::concurrent_vector<hitstruct> filthitstruct_vec;
262 art::Handle<std::vector<recob::Wire>> wireVecHandle;
263 evt.getByLabel(fCalDataModuleLabel, wireVecHandle);
269 std::function<double(double, double, double, double, int, int)> chargeFunc =
270 [](
double peakMean,
double peakAmp,
double peakWidth,
double areaNorm,
int low,
int hi) {
271 return std::sqrt(2 * TMath::Pi()) * peakAmp * peakWidth / areaNorm;
279 [](
double peakMean,
double peakAmp,
double peakWidth,
double areaNorm,
int low,
int hi) {
281 for (
int sigPos = low; sigPos < hi; sigPos++)
282 charge += peakAmp * TMath::Gaus(sigPos, peakMean, peakWidth);
292 static_cast<std::size_t>(0),
293 wireVecHandle->size(),
294 [&](
size_t& wireIter) {
298 art::Ptr<recob::Wire> wire(wireVecHandle, wireIter);
305 std::vector<geo::WireID> wids = geom->ChannelToWire(channel);
322 tbb::parallel_for(static_cast<std::size_t>(0),signalROI.
n_ranges(),
323 [&](
size_t& rangeIter){
324 const auto& range = signalROI.
range(rangeIter);
335 fHitFinderToolVec.at(plane)->findHitCandidates(range, 0, channel, count, hitCandidateVec);
336 fHitFinderToolVec.at(plane)->MergeHitCandidates(
337 range, hitCandidateVec, mergedCandidateHitVec);
343 for (
auto& mergedCands : mergedCandidateHitVec) {
344 int startT = mergedCands.front().startTick;
345 int endT = mergedCands.back().stopTick;
350 if (endT - startT < 5)
continue;
357 int nGausForFit = mergedCands.size();
362 double chi2PerNDF(0.);
373 fPeakFitterTool->findPeakParameters(
374 range.data(), mergedCands, peakParamsVec, chi2PerNDF, NDF);
377 if (!(chi2PerNDF < std::numeric_limits<double>::infinity())) {
382 if (fFillHists) fFirstChi2->Fill(chi2PerNDF);
393 int nHitsThisPulse = (endT - startT) / longPulseWidth;
395 if (nHitsThisPulse > fLongMaxHitsVec.at(plane)) {
396 nHitsThisPulse = fLongMaxHitsVec.at(plane);
397 longPulseWidth = (endT - startT) / nHitsThisPulse;
400 if (nHitsThisPulse * longPulseWidth < endT - startT) nHitsThisPulse++;
402 int firstTick = startT;
403 int lastTick = std::min(firstTick + longPulseWidth, endT);
405 peakParamsVec.clear();
406 nGausForFit = nHitsThisPulse;
408 chi2PerNDF = chi2PerNDF >
fChi2NDF ? chi2PerNDF : -1.;
410 for (
int hitIdx = 0; hitIdx < nHitsThisPulse; hitIdx++) {
413 std::accumulate(range.begin() + firstTick, range.begin() + lastTick, 0.);
414 double peakSigma = (lastTick - firstTick) / 3.;
415 double peakAmp = 0.3989 * sumADC / peakSigma;
416 double peakMean = (firstTick + lastTick) / 2.;
428 peakParamsVec.push_back(peakParams);
431 firstTick = lastTick;
432 lastTick = std::min(lastTick + longPulseWidth, endT);
443 std::vector<recob::Hit> filteredHitVec;
445 for (
const auto& peakParams : peakParamsVec) {
447 float peakAmp = peakParams.peakAmplitude;
448 float peakMean = peakParams.peakCenter;
449 float peakWidth = peakParams.peakSigma;
452 if (std::isnan(peakAmp)) {
453 std::cout <<
"**** hit peak amplitude is a nan! Channel: " << channel
454 <<
", start tick: " << startT << std::endl;
459 float peakAmpErr = peakParams.peakAmplitudeError;
460 float peakMeanErr = peakParams.peakCenterError;
461 float peakWidthErr = peakParams.peakSigmaError;
465 chargeFunc(peakMean, peakAmp, peakWidth,
fAreaNormsVec[plane], startT, endT);
468 std::sqrt(TMath::Pi()) * (peakAmpErr * peakWidthErr + peakWidthErr * peakAmpErr);
471 std::vector<float>::const_iterator sumStartItr = range.begin() + startT;
472 std::vector<float>::const_iterator sumEndItr = range.begin() + endT;
475 double sumADC = std::accumulate(sumStartItr, sumEndItr, 0.);
481 startT + roiFirstBinTick,
482 endT + roiFirstBinTick,
484 peakMean + roiFirstBinTick,
497 if (filteredHitCol) filteredHitVec.push_back(hitcreator.
copy());
502 hitstruct tmp{std::move(
hit), wire};
503 hitstruct_vec.push_back(std::move(tmp));
509 if (filteredHitCol && !filteredHitVec.empty()) {
518 std::sort(filteredHitVec.begin(),
519 filteredHitVec.end(),
520 [](
const auto&
left,
const auto&
right) {
521 return left.PeakAmplitude() >
right.PeakAmplitude();
527 filteredHitVec.clear();
530 if (filteredHitVec.size() > 1) {
532 float largestPH = filteredHitVec.front().PeakAmplitude();
537 std::vector<recob::Hit>::iterator smallHitItr = std::find_if(
538 filteredHitVec.begin(),
539 filteredHitVec.end(),
540 [largestPH, threshold](
const auto&
hit) {
541 return hit.PeakAmplitude() < 8. &&
hit.PeakAmplitude() / largestPH < threshold;
545 if (smallHitItr != filteredHitVec.end())
546 filteredHitVec.resize(
std::distance(filteredHitVec.begin(), smallHitItr));
549 std::sort(filteredHitVec.begin(),
550 filteredHitVec.end(),
551 [](
const auto&
left,
const auto&
right) {
552 return left.PeakTime() <
right.PeakTime();
557 for (
const auto& filteredHit : filteredHitVec)
558 if (!fHitFilterAlg || fHitFilterAlg->IsGoodHit(filteredHit)) {
559 hitstruct tmp{std::move(filteredHit), wire};
560 filthitstruct_vec.push_back(std::move(tmp));
563 if (fFillHists) fChi2->Fill(chi2PerNDF);
573 for (
size_t i = 0; i < hitstruct_vec.size(); i++) {
574 allHitCol.
emplace_back(hitstruct_vec[i].hit_tbb, hitstruct_vec[i].wire_tbb);
577 for (
size_t j = 0; j < filthitstruct_vec.size(); j++) {
578 filteredHitCol->
emplace_back(filthitstruct_vec[j].hit_tbb, filthitstruct_vec[j].wire_tbb);
584 if (filteredHitCol) {
589 if (fAllHitsInstanceName ==
"") {
const datarange_t & range(size_t i) const
Returns the i-th non-void range (zero-based)
size_type n_ranges() const
Returns the internal list of non-void ranges.
recob::Hit const & copy() const
Returns the constructed wire.
std::unique_ptr< HitFilterAlg > fHitFilterAlg
algorithm used to filter out noise hits
fMaxMultiHit(pset.get< int >("MaxMultiHit"))
Declaration of signal hit object.
void produce(art::Event &evt, art::ProcessingFrame const &) override
GausHitFinder(fhicl::ParameterSet const &pset, art::ProcessingFrame const &)
unsigned int PlaneID_t
Type for the ID number.
fPulseHeightCuts(pset.get< std::vector< float >>("PulseHeightCuts", std::vector< float >()={3.0, 3.0, 3.0}))
fPulseRatioCuts(pset.get< std::vector< float >>("PulseRatioCuts", std::vector< float >()={0.35, 0.40, 0.20}))
const std::string instance
const std::vector< int > fLongPulseWidthVec
Sets width of hits used to describe long pulses.
static void declare_products(art::ProducesCollector &collector, std::string instance_name="", bool doWireAssns=true, bool doRawDigitAssns=true)
Declares the hit products we are going to fill.
std::unique_ptr< reco_tool::IPeakFitter > fPeakFitterTool
Perform fit to candidate peaks.
const int fAreaMethod
Type of area calculation.
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
const std::string fCalDataModuleLabel
const std::vector< float > fPulseWidthCuts
int TDCtick_t
Type representing a TDC tick.
Class managing the creation of a new recob::Hit object.
Helper functions to create a hit.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
A class handling a collection of hits and its associations.
std::vector< double > FillOutHitParameterVector(const std::vector< double > &input)
std::atomic< size_t > fEventCount
const size_t fMaxMultiHit
maximum hits for multi fit
const std::vector< int > fLongMaxHitsVec
Maximum number hits on a really long pulse train.
fLongPulseWidthVec(pset.get< std::vector< int >>("LongPulseWidth", std::vector< int >()={16, 16, 16}))
void beginJob(art::ProcessingFrame const &) override
void emplace_back(recob::Hit &&hit, art::Ptr< recob::Wire > const &wire=art::Ptr< recob::Wire >(), art::Ptr< raw::RawDigit > const &digits=art::Ptr< raw::RawDigit >())
Adds the specified hit to the data collection.
PlaneID_t Plane
Index of the plane within its TPC.
void put_into(art::Event &)
Moves the data into an event.
fPulseWidthCuts(pset.get< std::vector< float >>("PulseWidthCuts", std::vector< float >()={2.0, 1.5, 1.0}))
BEGIN_PROLOG sequence::SlidingWindowTriggerPatternsOppositeWindows END_PROLOG simSlidingORM6O6 effSlidingORW output
const std::vector< float > fPulseRatioCuts
This provides an interface for tools which are tasked with finding candidate hits on input waveforms...
const std::vector< float > fPulseHeightCuts
maximum Chisquared / NDF allowed for a hit to be saved
Declaration of basic channel signal object.
const std::string fAllHitsInstanceName
fAreaMethod(pset.get< int >("AreaMethod"))
2D representation of charge deposited in the TDC/wire plane
art::ServiceHandle< art::TFileService > tfs
fAreaNormsVec(FillOutHitParameterVector(pset.get< std::vector< double >>("AreaNorms")))
const std::vector< double > fAreaNormsVec
factors for converting area to same units as peak height
std::size_t count(Cont const &cont)
unsigned int ChannelID_t
Type representing the ID of a readout channel.
fChi2NDF(pset.get< double >("Chi2NDF"))
recob::Hit && move()
Prepares the constructed hit to be moved away.
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::vector< std::unique_ptr< reco_tool::ICandidateHitFinder > > fHitFinderToolVec
For finding candidate hits.