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.