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

StandardHit3DBuilder class definiton. More...

Inheritance diagram for lar_cluster3d::StandardHit3DBuilder:
lar_cluster3d::IHit3DBuilder

Public Member Functions

 StandardHit3DBuilder (fhicl::ParameterSet const &pset)
 Constructor. More...
 
void produces (art::ProducesCollector &) override
 Each algorithm may have different objects it wants "produced" so use this to let the top level producer module "know" what it is outputting. More...
 
void configure (const fhicl::ParameterSet &) override
 Interface for configuring the particular algorithm tool. More...
 
void Hit3DBuilder (art::Event &, reco::HitPairList &, RecobHitToPtrMap &) override
 Given a set of recob hits, run DBscan to form 3D clusters. More...
 
float getTimeToExecute (IHit3DBuilder::TimeValues index) const override
 If monitoring, recover the time to execute a particular function. More...
 
- Public Member Functions inherited from lar_cluster3d::IHit3DBuilder
virtual ~IHit3DBuilder () noexcept=default
 Virtual Destructor. More...
 

Private Types

using PlaneHitVectorItrPairVec = std::vector< std::pair< HitVector::iterator, HitVector::iterator >>
 Given the ClusterHit2D objects, build the HitPairMap. More...
 
using HitMatchPair = std::pair< const reco::ClusterHit2D *, reco::ClusterHit3D >
 This builds a list of candidate hit pairs from lists of hits on two planes. More...
 
using HitMatchPairVec = std::vector< HitMatchPair >
 
using HitMatchPairVecMap = std::map< geo::WireID, HitMatchPairVec >
 
using ChannelStatusVec = std::vector< size_t >
 define data structure for keeping track of channel status More...
 
using ChannelStatusByPlaneVec = std::vector< ChannelStatusVec >
 

Private Member Functions

void CollectArtHits (const art::Event &evt) const
 Extract the ART hits and the ART hit-particle relationships. More...
 
void BuildHit3D (reco::HitPairList &hitPairList) const
 Given the ClusterHit2D objects, build the HitPairMap. More...
 
void CreateNewRecobHitCollection (art::Event &, reco::HitPairList &, std::vector< recob::Hit > &, RecobHitToPtrMap &)
 Create a new 2D hit collection from hits associated to 3D space points. More...
 
void makeWireAssns (const art::Event &, art::Assns< recob::Wire, recob::Hit > &, RecobHitToPtrMap &) const
 Create recob::Wire to recob::Hit associations. More...
 
void makeRawDigitAssns (const art::Event &, art::Assns< raw::RawDigit, recob::Hit > &, RecobHitToPtrMap &) const
 Create raw::RawDigit to recob::Hit associations. More...
 
size_t BuildHitPairMap (PlaneToHitVectorMap &planeToHitVectorMap, reco::HitPairList &hitPairList) const
 Given the ClusterHit2D objects, build the HitPairMap. More...
 
size_t BuildHitPairMapByTPC (PlaneHitVectorItrPairVec &planeHitVectorItrPairVec, reco::HitPairList &hitPairList) const
 
int findGoodHitPairs (const reco::ClusterHit2D *, HitVector::iterator &, HitVector::iterator &, HitMatchPairVecMap &) const
 
void findGoodTriplets (HitMatchPairVecMap &, HitMatchPairVecMap &, reco::HitPairList &, bool=false) const
 This algorithm takes lists of hit pairs and finds good triplets. More...
 
bool makeHitPair (reco::ClusterHit3D &pairOut, const reco::ClusterHit2D *hit1, const reco::ClusterHit2D *hit2, float hitWidthSclFctr=1., size_t hitPairCntr=0) const
 Make a HitPair object by checking two hits. More...
 
bool makeHitTriplet (reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pairIn, const reco::ClusterHit2D *hit2) const
 Make a 3D HitPair object by checking two hits. More...
 
bool makeDeadChannelPair (reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pair, size_t maxStatus=4, size_t minStatus=0, float minOverlap=0.2) const
 Make a 3D HitPair object from a valid pair and a dead channel in the missing plane. More...
 
const reco::ClusterHit2DFindBestMatchingHit (const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float pairDeltaTimeLimits) const
 A utility routine for finding a 2D hit closest in time to the given pair. More...
 
int FindNumberInRange (const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float range) const
 A utility routine for returning the number of 2D hits from the list in a given range. More...
 
geo::WireID NearestWireID (const Eigen::Vector3f &position, const geo::WireID &wireID) const
 Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range. More...
 
float DistanceFromPointToHitWire (const Eigen::Vector3f &position, const geo::WireID &wireID) const
 Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range. More...
 
void BuildChannelStatusVec (PlaneToWireToHitSetMap &planeToWiretoHitSetMap) const
 Create the internal channel status vector (assume will eventually be event-by-event) More...
 
float chargeIntegral (float, float, float, float, int, int) const
 Perform charge integration between limits. More...
 
void clear ()
 clear the tuple vectors before processing next event More...
 

Private Attributes

std::vector< art::InputTag > m_hitFinderTagVec
 Data members to follow. More...
 
float m_numSigmaPeakTime
 
float m_hitWidthSclFctr
 
float m_deltaPeakTimeSig
 
std::vector< int > m_invalidTPCVec
 
float m_wirePitchScaleFactor
 Scaling factor to determine max distance allowed between candidate pairs. More...
 
float m_maxHit3DChiSquare
 Provide ability to select hits based on "chi square". More...
 
bool m_outputHistograms
 Take the time to create and fill some histograms for diagnostics. More...
 
bool m_enableMonitoring
 
float m_wirePitch [3]
 
std::vector< float > m_timeVector
 
float m_zPosOffset
 
TTree * m_tupleTree
 output analysis tree More...
 
std::vector< float > m_deltaTimeVec
 
std::vector< float > m_chiSquare3DVec
 
std::vector< float > m_maxPullVec
 
std::vector< float > m_overlapFractionVec
 
std::vector< float > m_overlapRangeVec
 
std::vector< float > m_maxDeltaPeakVec
 
std::vector< float > m_maxSideVecVec
 
std::vector< float > m_pairWireDistVec
 
std::vector< float > m_smallChargeDiffVec
 
std::vector< int > m_smallIndexVec
 
std::vector< float > m_qualityMetricVec
 
std::vector< float > m_spacePointChargeVec
 
std::vector< float > m_hitAsymmetryVec
 
Hit2DList m_clusterHit2DMasterList
 
PlaneToHitVectorMap m_planeToHitVectorMap
 
PlaneToWireToHitSetMap m_planeToWireToHitSetMap
 
ChannelStatusByPlaneVec m_channelStatus
 
size_t m_numBadChannels
 
bool m_weHaveAllBeenHereBefore = false
 
const geo::Geometrym_geometry
 
const
lariov::ChannelStatusProvider
m_channelFilter
 

Additional Inherited Members

- Public Types inherited from lar_cluster3d::IHit3DBuilder
enum  TimeValues { COLLECTARTHITS = 0, BUILDTHREEDHITS = 1, BUILDNEWHITS = 2, NUMTIMEVALUES }
 enumerate the possible values for time checking if monitoring timing More...
 
using RecobHitToPtrMap = std::unordered_map< const recob::Hit *, art::Ptr< recob::Hit >>
 Defines a structure mapping art representation to internal. More...
 

Detailed Description

StandardHit3DBuilder class definiton.

Definition at line 77 of file StandardHit3DBuilder_tool.cc.

Member Typedef Documentation

Definition at line 245 of file StandardHit3DBuilder_tool.cc.

using lar_cluster3d::StandardHit3DBuilder::ChannelStatusVec = std::vector<size_t>
private

define data structure for keeping track of channel status

Definition at line 244 of file StandardHit3DBuilder_tool.cc.

This builds a list of candidate hit pairs from lists of hits on two planes.

Definition at line 164 of file StandardHit3DBuilder_tool.cc.

Definition at line 165 of file StandardHit3DBuilder_tool.cc.

Definition at line 166 of file StandardHit3DBuilder_tool.cc.

using lar_cluster3d::StandardHit3DBuilder::PlaneHitVectorItrPairVec = std::vector<std::pair<HitVector::iterator, HitVector::iterator>>
private

Given the ClusterHit2D objects, build the HitPairMap.

Definition at line 156 of file StandardHit3DBuilder_tool.cc.

Constructor & Destructor Documentation

lar_cluster3d::StandardHit3DBuilder::StandardHit3DBuilder ( fhicl::ParameterSet const &  pset)
explicit

Constructor.

Parameters
pset

Definition at line 302 of file StandardHit3DBuilder_tool.cc.

303  : m_geometry(art::ServiceHandle<geo::Geometry const>{}.get())

Member Function Documentation

void lar_cluster3d::StandardHit3DBuilder::BuildChannelStatusVec ( PlaneToWireToHitSetMap planeToWiretoHitSetMap) const
private

Create the internal channel status vector (assume will eventually be event-by-event)

Definition at line 391 of file StandardHit3DBuilder_tool.cc.

392  {
393  // This is called each event, clear out the previous version and start over
394  if (!m_channelStatus.empty()) m_channelStatus.clear();
395 
396  m_numBadChannels = 0;
398 
399  // Loop through views/planes to set the wire length vectors
400  for (size_t idx = 0; idx < m_channelStatus.size(); idx++) {
402  }
403 
404  // Loop through the channels and mark those that are "bad"
405  for (size_t channel = 0; channel < m_geometry->Nchannels(); channel++) {
406  if (!m_channelFilter->IsGood(channel)) {
407  std::vector<geo::WireID> wireIDVec = m_geometry->ChannelToWire(channel);
408  geo::WireID wireID = wireIDVec[0];
410 
411  m_channelStatus[wireID.Plane][wireID.Wire] = chanStat;
413  }
414  }
415 
416  // add quiet wires in U plane for microboone (this will done "correctly" in near term)
417  // PlaneToWireToHitSetMap::iterator plane0HitItr = planeToWireToHitSetMap.find(geo::PlaneID(0,0,0));
418 
419  // if (plane0HitItr != planeToWireToHitSetMap.end())
420  // {
421  //// WireToHitSetMap& wireToHitSetMap = uPlaneHitItr->second;
422 
423  // for(size_t idx = 2016; idx < 2096; idx++) m_channelStatus[0][idx] = 3;
424  // for(size_t idx = 2192; idx < 2304; idx++) m_channelStatus[0][idx] = 3;
425  // for(size_t idx = 2352; idx < 2384; idx++) m_channelStatus[0][idx] = 3;
426  // //for(size_t idx = 2016; idx < 2096; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
427  // //for(size_t idx = 2192; idx < 2304; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
428  // //for(size_t idx = 2352; idx < 2384; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
429  //// for(size_t idx = 2016; idx < 2384; idx++) m_channelStatus[0][idx] = 3;
430  // }
431 
432  return;
433  }
std::vector< size_t > ChannelStatusVec
define data structure for keeping track of channel status
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
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.
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
unsigned short Status_t
type representing channel status
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
virtual Status_t Status(raw::ChannelID_t channel) const
Returns a status integer with arbitrary meaning.
virtual bool IsGood(raw::ChannelID_t channel) const
Returns whether the specified channel is physical and good.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
const lariov::ChannelStatusProvider * m_channelFilter
void lar_cluster3d::StandardHit3DBuilder::BuildHit3D ( reco::HitPairList hitPairList) const
private

Given the ClusterHit2D objects, build the HitPairMap.

Driver for processing input 2D hits, transforming to 3D hits and building lists of associated 3D hits (candidate 3D clusters)

Definition at line 512 of file StandardHit3DBuilder_tool.cc.

513  {
514  /**
515  * @brief Driver for processing input 2D hits, transforming to 3D hits and building lists
516  * of associated 3D hits (candidate 3D clusters)
517  */
518  cet::cpu_timer theClockMakeHits;
519 
520  if (m_enableMonitoring) theClockMakeHits.start();
521 
522  // The first task is to take the lists of input 2D hits (a map of view to sorted lists of 2D hits)
523  // and then to build a list of 3D hits to be used in downstream processing
525 
526  size_t numHitPairs = BuildHitPairMap(m_planeToHitVectorMap, hitPairList);
527 
528  if (m_enableMonitoring) {
529  theClockMakeHits.stop();
530 
531  m_timeVector[BUILDTHREEDHITS] = theClockMakeHits.accumulated_real_time();
532  }
533 
534  mf::LogDebug("Cluster3D") << ">>>>> 3D hit building done, found " << numHitPairs << " 3D Hits"
535  << std::endl;
536 
537  return;
538  }
size_t BuildHitPairMap(PlaneToHitVectorMap &planeToHitVectorMap, reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
void BuildChannelStatusVec(PlaneToWireToHitSetMap &planeToWiretoHitSetMap) const
Create the internal channel status vector (assume will eventually be event-by-event) ...
size_t lar_cluster3d::StandardHit3DBuilder::BuildHitPairMap ( PlaneToHitVectorMap planeToHitVectorMap,
reco::HitPairList hitPairList 
) const
private

Given the ClusterHit2D objects, build the HitPairMap.

Given input 2D hits, build out the lists of possible 3D hits

   The current strategy: ideally all 3D hits would be comprised of a triplet of 2D hits, one from each view
   However, we have concern that, in particular, the v-plane may have some inefficiency which we have to be
   be prepared to deal with. The idea, then, is to first make the association of hits in the U and W planes
   and then look for the match in the V plane. In the event we don't find the match in the V plane then we
   will evaluate the situation and in some instances keep the U-W pairs in order to keep efficiency high.

Definition at line 595 of file StandardHit3DBuilder_tool.cc.

597  {
598  /**
599  * @brief Given input 2D hits, build out the lists of possible 3D hits
600  *
601  * The current strategy: ideally all 3D hits would be comprised of a triplet of 2D hits, one from each view
602  * However, we have concern that, in particular, the v-plane may have some inefficiency which we have to be
603  * be prepared to deal with. The idea, then, is to first make the association of hits in the U and W planes
604  * and then look for the match in the V plane. In the event we don't find the match in the V plane then we
605  * will evaluate the situation and in some instances keep the U-W pairs in order to keep efficiency high.
606  */
607  size_t totalNumHits(0);
608  size_t hitPairCntr(0);
609 
610  size_t nTriplets(0);
611  size_t nDeadChanHits(0);
612 
613  // Set up to loop over cryostats and tpcs...
614  for (size_t cryoIdx = 0; cryoIdx < m_geometry->Ncryostats(); cryoIdx++) {
615  for (size_t tpcIdx = 0; tpcIdx < m_geometry->NTPC(); tpcIdx++) {
616  PlaneToHitVectorMap::iterator mapItr0 =
617  planeToHitVectorMap.find(geo::PlaneID(cryoIdx, tpcIdx, 0));
618  PlaneToHitVectorMap::iterator mapItr1 =
619  planeToHitVectorMap.find(geo::PlaneID(cryoIdx, tpcIdx, 1));
620  PlaneToHitVectorMap::iterator mapItr2 =
621  planeToHitVectorMap.find(geo::PlaneID(cryoIdx, tpcIdx, 2));
622 
623  size_t nPlanesWithHits =
624  (mapItr0 != planeToHitVectorMap.end() && !mapItr0->second.empty() ? 1 : 0) +
625  (mapItr1 != planeToHitVectorMap.end() && !mapItr1->second.empty() ? 1 : 0) +
626  (mapItr2 != planeToHitVectorMap.end() && !mapItr2->second.empty() ? 1 : 0);
627 
628  if (nPlanesWithHits < 2) continue;
629 
630  HitVector& hitVector0 = mapItr0->second;
631  HitVector& hitVector1 = mapItr1->second;
632  HitVector& hitVector2 = mapItr2->second;
633 
634  // We are going to resort the hits into "start time" order...
635  std::sort(hitVector0.begin(),
636  hitVector0.end(),
637  SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
638  std::sort(hitVector1.begin(),
639  hitVector1.end(),
640  SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
641  std::sort(hitVector2.begin(),
642  hitVector2.end(),
643  SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
644 
645  PlaneHitVectorItrPairVec hitItrVec = {
646  HitVectorItrPair(hitVector0.begin(), hitVector0.end()),
647  HitVectorItrPair(hitVector1.begin(), hitVector1.end()),
648  HitVectorItrPair(hitVector2.begin(), hitVector2.end())};
649 
650  totalNumHits += BuildHitPairMapByTPC(hitItrVec, hitPairList);
651  }
652  }
653 
654  // Return the hit pair list but sorted by z and y positions (faster traversal in next steps)
655  hitPairList.sort(SetPairStartTimeOrder);
656 
657  // Where are we?
658  mf::LogDebug("Cluster3D") << "Total number hits: " << totalNumHits << std::endl;
659  mf::LogDebug("Cluster3D") << "Created a total of " << hitPairList.size()
660  << " hit pairs, counted: " << hitPairCntr << std::endl;
661  mf::LogDebug("Cluster3D") << "-- Triplets: " << nTriplets
662  << ", dead channel pairs: " << nDeadChanHits << std::endl;
663 
664  return hitPairList.size();
665  }
size_t BuildHitPairMapByTPC(PlaneHitVectorItrPairVec &planeHitVectorItrPairVec, reco::HitPairList &hitPairList) const
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::vector< const reco::ClusterHit2D * > HitVector
std::vector< std::pair< HitVector::iterator, HitVector::iterator >> PlaneHitVectorItrPairVec
Given the ClusterHit2D objects, build the HitPairMap.
bool SetPairStartTimeOrder(const reco::ClusterHit3D &left, const reco::ClusterHit3D &right)
size_t lar_cluster3d::StandardHit3DBuilder::BuildHitPairMapByTPC ( PlaneHitVectorItrPairVec planeHitVectorItrPairVec,
reco::HitPairList hitPairList 
) const
private

Given input 2D hits, build out the lists of possible 3D hits

   The current strategy: ideally all 3D hits would be comprised of a triplet of 2D hits, one from each view
   However, we have concern that, in particular, the v-plane may have some inefficiency which we have to be
   be prepared to deal with. The idea, then, is to first make the association of hits in the U and W planes
   and then look for the match in the V plane. In the event we don't find the match in the V plane then we
   will evaluate the situation and in some instances keep the U-W pairs in order to keep efficiency high.

Definition at line 668 of file StandardHit3DBuilder_tool.cc.

670  {
671  /**
672  * @brief Given input 2D hits, build out the lists of possible 3D hits
673  *
674  * The current strategy: ideally all 3D hits would be comprised of a triplet of 2D hits, one from each view
675  * However, we have concern that, in particular, the v-plane may have some inefficiency which we have to be
676  * be prepared to deal with. The idea, then, is to first make the association of hits in the U and W planes
677  * and then look for the match in the V plane. In the event we don't find the match in the V plane then we
678  * will evaluate the situation and in some instances keep the U-W pairs in order to keep efficiency high.
679  */
680 
681  // Define functions to set start/end iterators in the loop below
682  auto SetStartIterator =
683  [](HitVector::iterator startItr, HitVector::iterator endItr, float rms, float startTime) {
684  while (startItr != endItr) {
685  float numRMS(rms);
686  if ((*startItr)->getTimeTicks() + numRMS * (*startItr)->getHit()->RMS() < startTime)
687  startItr++;
688  else
689  break;
690  }
691  return startItr;
692  };
693 
694  auto SetEndIterator =
695  [](HitVector::iterator firstItr, HitVector::iterator endItr, float rms, float endTime) {
696  while (firstItr != endItr) {
697  float numRMS(rms);
698  if ((*firstItr)->getTimeTicks() - numRMS * (*firstItr)->getHit()->RMS() < endTime)
699  firstItr++;
700  else
701  break;
702  }
703  return firstItr;
704  };
705 
706  size_t nTriplets(0);
707  size_t nDeadChanHits(0);
708 
709  //*********************************************************************************
710  // Basically, we try to loop until done...
711  while (1) {
712  // Sort so that the earliest hit time will be the first element, etc.
713  std::sort(hitItrVec.begin(), hitItrVec.end(), SetStartTimeOrder(m_numSigmaPeakTime));
714 
715  // This loop iteration's golden hit
716  const reco::ClusterHit2D* goldenHit = *hitItrVec[0].first;
717 
718  // The range of history... (for this hit)
719  float goldenTimeStart = goldenHit->getTimeTicks() -
720  m_numSigmaPeakTime * goldenHit->getHit()->RMS() -
721  std::numeric_limits<float>::epsilon();
722  float goldenTimeEnd = goldenHit->getTimeTicks() +
723  m_numSigmaPeakTime * goldenHit->getHit()->RMS() +
724  std::numeric_limits<float>::epsilon();
725 
726  // Set iterators to insure we'll be in the overlap ranges
727  HitVector::iterator hitItr1Start = SetStartIterator(
728  hitItrVec[1].first, hitItrVec[1].second, m_numSigmaPeakTime, goldenTimeStart);
729  HitVector::iterator hitItr1End =
730  SetEndIterator(hitItr1Start, hitItrVec[1].second, m_numSigmaPeakTime, goldenTimeEnd);
731  HitVector::iterator hitItr2Start = SetStartIterator(
732  hitItrVec[2].first, hitItrVec[2].second, m_numSigmaPeakTime, goldenTimeStart);
733  HitVector::iterator hitItr2End =
734  SetEndIterator(hitItr2Start, hitItrVec[2].second, m_numSigmaPeakTime, goldenTimeEnd);
735 
736  // Since we'll use these many times in the internal loops, pre make the pairs for the second set of hits
737  size_t curHitListSize(hitPairList.size());
738  HitMatchPairVecMap pair12Map;
739  HitMatchPairVecMap pair13Map;
740 
741  size_t n12Pairs = findGoodHitPairs(goldenHit, hitItr1Start, hitItr1End, pair12Map);
742  size_t n13Pairs = findGoodHitPairs(goldenHit, hitItr2Start, hitItr2End, pair13Map);
743 
744  nDeadChanHits += hitPairList.size() - curHitListSize;
745  curHitListSize = hitPairList.size();
746 
747  if (n12Pairs > n13Pairs)
748  findGoodTriplets(pair12Map, pair13Map, hitPairList);
749  else
750  findGoodTriplets(pair13Map, pair12Map, hitPairList);
751 
752  nTriplets += hitPairList.size() - curHitListSize;
753 
754  hitItrVec[0].first++;
755 
756  int nPlanesWithHits(0);
757 
758  for (auto& pair : hitItrVec)
759  if (pair.first != pair.second) nPlanesWithHits++;
760 
761  if (nPlanesWithHits < 2) break;
762  }
763 
764  return hitPairList.size();
765  }
float getTimeTicks() const
Definition: Cluster3D.h:75
int findGoodHitPairs(const reco::ClusterHit2D *, HitVector::iterator &, HitVector::iterator &, HitMatchPairVecMap &) const
std::map< geo::WireID, HitMatchPairVec > HitMatchPairVecMap
void findGoodTriplets(HitMatchPairVecMap &, HitMatchPairVecMap &, reco::HitPairList &, bool=false) const
This algorithm takes lists of hit pairs and finds good triplets.
float lar_cluster3d::StandardHit3DBuilder::chargeIntegral ( float  peakMean,
float  peakAmp,
float  peakSigma,
float  areaNorm,
int  low,
int  hi 
) const
private

Perform charge integration between limits.

Definition at line 1301 of file StandardHit3DBuilder_tool.cc.

1307  {
1308  float integral(0);
1309 
1310  for (int sigPos = low; sigPos < hi; sigPos++) {
1311  float arg = (float(sigPos) - peakMean + 0.5) / peakSigma;
1312  integral += peakAmp * std::exp(-0.5 * arg * arg);
1313  }
1314 
1315  return integral;
1316  }
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
void lar_cluster3d::StandardHit3DBuilder::clear ( )
private

clear the tuple vectors before processing next event

Definition at line 371 of file StandardHit3DBuilder_tool.cc.

372  {
373  m_deltaTimeVec.clear();
374  m_chiSquare3DVec.clear();
375  m_maxPullVec.clear();
376  m_overlapFractionVec.clear();
377  m_overlapRangeVec.clear();
378  m_maxDeltaPeakVec.clear();
379  m_maxSideVecVec.clear();
380  m_pairWireDistVec.clear();
381  m_smallChargeDiffVec.clear();
382  m_smallIndexVec.clear();
383  m_qualityMetricVec.clear();
384  m_spacePointChargeVec.clear();
385  m_hitAsymmetryVec.clear();
386 
387  return;
388  }
void lar_cluster3d::StandardHit3DBuilder::CollectArtHits ( const art::Event &  evt) const
private

Extract the ART hits and the ART hit-particle relationships.

Parameters
evt- the ART event

Recover the 2D hits from art and fill out the local data structures for the 3D clustering

Definition at line 1538 of file StandardHit3DBuilder_tool.cc.

1539  {
1540  /**
1541  * @brief Recover the 2D hits from art and fill out the local data structures for the 3D clustering
1542  */
1543 
1544  // Start by getting a vector of valid, non empty hit collections to make sure we really have something to do here...
1545  // Here is a container for the hits...
1546  std::vector<const recob::Hit*> recobHitVec;
1547 
1548  auto const clock_data =
1549  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
1550  auto const det_prop =
1551  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
1552 
1553  // Loop through the list of input sources
1554  for (const auto& inputTag : m_hitFinderTagVec) {
1555  art::Handle<std::vector<recob::Hit>> recobHitHandle;
1556  evt.getByLabel(inputTag, recobHitHandle);
1557 
1558  if (!recobHitHandle.isValid() || recobHitHandle->size() == 0) continue;
1559 
1560  recobHitVec.reserve(recobHitVec.size() + recobHitHandle->size());
1561 
1562  for (const auto& hit : *recobHitHandle)
1563  recobHitVec.push_back(&hit);
1564  }
1565 
1566  // If the vector is empty there is nothing to do
1567  if (recobHitVec.empty()) return;
1568 
1569  cet::cpu_timer theClockMakeHits;
1570 
1571  if (m_enableMonitoring) theClockMakeHits.start();
1572 
1573  // We'll want to correct the hit times for the plane offsets
1574  // (note this is already taken care of when converting to position)
1575  std::map<geo::PlaneID, double> planeOffsetMap;
1576 
1577  // Try to output a formatted string
1578  std::string debugMessage("");
1579 
1580  // Initialize the plane to hit vector map
1581  for (size_t cryoIdx = 0; cryoIdx < m_geometry->Ncryostats(); cryoIdx++) {
1582  for (size_t tpcIdx = 0; tpcIdx < m_geometry->NTPC(); tpcIdx++) {
1583  m_planeToHitVectorMap[geo::PlaneID(cryoIdx, tpcIdx, 0)] = HitVector();
1584  m_planeToHitVectorMap[geo::PlaneID(cryoIdx, tpcIdx, 1)] = HitVector();
1585  m_planeToHitVectorMap[geo::PlaneID(cryoIdx, tpcIdx, 2)] = HitVector();
1586 
1587  // What we want here are the relative offsets between the planes
1588  // Note that plane 0 is assumed the "first" plane and is the reference
1589  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 0)] = 0.;
1590  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 1)] =
1591  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 1)) -
1592  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0));
1593  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 2)] =
1594  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 2)) -
1595  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0));
1596 
1597  // Should we provide output?
1599  std::ostringstream outputString;
1600 
1601  outputString << "***> plane 0 offset: "
1602  << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 0)]
1603  << ", plane 1: " << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 1)]
1604  << ", plane 2: " << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 2)]
1605  << "\n";
1606  debugMessage += outputString.str();
1607  outputString << " Det prop plane 0: "
1608  << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0))
1609  << ", plane 1: "
1610  << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 1))
1611  << ", plane 2: "
1612  << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 2))
1613  << ", Trig: " << trigger_offset(clock_data) << "\n";
1614  debugMessage += outputString.str();
1615  }
1616  }
1617  }
1618 
1620  mf::LogDebug("Cluster3D") << debugMessage << std::endl;
1621 
1623  }
1624 
1625  // Cycle through the recob hits to build ClusterHit2D objects and insert
1626  // them into the map
1627  for (const auto& recobHit : recobHitVec) {
1628  // Reject hits with negative charge, these are misreconstructed
1629  if (recobHit->Integral() < 0.) continue;
1630 
1631  // For some detectors we can have multiple wire ID's associated to a given channel.
1632  // So we recover the list of these wire IDs
1633  const std::vector<geo::WireID>& wireIDs = m_geometry->ChannelToWire(recobHit->Channel());
1634 
1635  // And then loop over all possible to build out our maps
1636  for (const auto& wireID : wireIDs) {
1637  // Check if this is an invalid TPC
1638  // (for example, in protoDUNE there are logical TPC's which see no signal)
1639  if (std::find(m_invalidTPCVec.begin(), m_invalidTPCVec.end(), wireID.TPC) !=
1640  m_invalidTPCVec.end())
1641  continue;
1642 
1643  // Note that a plane ID will define cryostat, TPC and plane
1644  const geo::PlaneID& planeID = wireID.planeID();
1645 
1646  double hitPeakTime(recobHit->PeakTime() - planeOffsetMap[planeID]);
1647  double xPosition(det_prop.ConvertTicksToX(
1648  recobHit->PeakTime(), planeID.Plane, planeID.TPC, planeID.Cryostat));
1649 
1650  m_clusterHit2DMasterList.emplace_back(0, 0., 0., xPosition, hitPeakTime, wireID, recobHit);
1651 
1652  m_planeToHitVectorMap[planeID].push_back(&m_clusterHit2DMasterList.back());
1653  m_planeToWireToHitSetMap[planeID][wireID.Wire].insert(&m_clusterHit2DMasterList.back());
1654  }
1655  }
1656 
1657  // Make a loop through to sort the recover hits in time order
1658  for (auto& hitVectorMap : m_planeToHitVectorMap)
1659  std::sort(hitVectorMap.second.begin(), hitVectorMap.second.end(), SetHitTimeOrder);
1660 
1661  if (m_enableMonitoring) {
1662  theClockMakeHits.stop();
1663 
1664  m_timeVector[COLLECTARTHITS] = theClockMakeHits.accumulated_real_time();
1665  }
1666 
1667  mf::LogDebug("Cluster3D") << ">>>>> Number of ART hits: " << m_clusterHit2DMasterList.size()
1668  << std::endl;
1669  }
bool SetHitTimeOrder(const reco::ClusterHit2D *left, const reco::ClusterHit2D *right)
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
process_name hit
Definition: cheaterreco.fcl:51
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
std::vector< art::InputTag > m_hitFinderTagVec
Data members to follow.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::vector< const reco::ClusterHit2D * > HitVector
int trigger_offset(DetectorClocksData const &data)
TCEvent evt
Definition: DataStructs.cxx:8
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
void lar_cluster3d::StandardHit3DBuilder::configure ( const fhicl::ParameterSet &  )
overridevirtual

Interface for configuring the particular algorithm tool.

Parameters
ParameterSetThe input set of parameters for configuration

Implements lar_cluster3d::IHit3DBuilder.

Definition at line 322 of file StandardHit3DBuilder_tool.cc.

323  {
324  m_hitFinderTagVec = pset.get<std::vector<art::InputTag>>(
325  "HitFinderTagVec", std::vector<art::InputTag>() = {"gaushit"});
326  m_enableMonitoring = pset.get<bool>("EnableMonitoring", true);
327  m_numSigmaPeakTime = pset.get<float>("NumSigmaPeakTime", 3.);
328  m_hitWidthSclFctr = pset.get<float>("HitWidthScaleFactor", 6.);
329  m_deltaPeakTimeSig = pset.get<float>("DeltaPeakTimeSig", 1.7);
330  m_zPosOffset = pset.get<float>("ZPosOffset", 0.0);
331  m_invalidTPCVec = pset.get<std::vector<int>>("InvalidTPCVec", std::vector<int>());
332  m_wirePitchScaleFactor = pset.get<float>("WirePitchScaleFactor", 1.9);
333  m_maxHit3DChiSquare = pset.get<float>("MaxHitChiSquare", 6.0);
334  m_outputHistograms = pset.get<bool>("OutputHistograms", false);
335 
336  m_geometry = art::ServiceHandle<geo::Geometry const>{}.get();
337 
338  // Returns the wire pitch per plane assuming they will be the same for all TPCs
342 
343  // Access ART's TFileService, which will handle creating and writing
344  // histograms and n-tuples for us.
345  art::ServiceHandle<art::TFileService> tfs;
346 
347  if (m_outputHistograms) {
348  m_tupleTree = tfs->make<TTree>("Hit3DBuilderTree", "Tree by StandardHit3DBuilder");
349 
350  clear();
351 
352  m_tupleTree->Branch("DeltaTime2D", "std::vector<float>", &m_deltaTimeVec);
353  m_tupleTree->Branch("ChiSquare3D", "std::vector<float>", &m_chiSquare3DVec);
354  m_tupleTree->Branch("MaxPullValue", "std::vector<float>", &m_maxPullVec);
355  m_tupleTree->Branch("OverlapFraction", "std::vector<float>", &m_overlapFractionVec);
356  m_tupleTree->Branch("OverlapRange", "std::vector<float>", &m_overlapRangeVec);
357  m_tupleTree->Branch("MaxDeltaPeak", "std::vector<float>", &m_maxDeltaPeakVec);
358  m_tupleTree->Branch("MaxSideVec", "std::vector<float>", &m_maxSideVecVec);
359  m_tupleTree->Branch("PairWireDistVec", "std::vector<float>", &m_pairWireDistVec);
360  m_tupleTree->Branch("SmallChargeDiff", "std::vector<float>", &m_smallChargeDiffVec);
361  m_tupleTree->Branch("SmallChargeIdx", "std::vector<int>", &m_smallIndexVec);
362  m_tupleTree->Branch("QualityMetric", "std::vector<float>", &m_qualityMetricVec);
363  m_tupleTree->Branch("SPCharge", "std::vector<float>", &m_spacePointChargeVec);
364  m_tupleTree->Branch("HitAsymmetry", "std::vector<float>", &m_hitAsymmetryVec);
365  }
366 
367  return;
368  }
float m_wirePitchScaleFactor
Scaling factor to determine max distance allowed between candidate pairs.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
float m_maxHit3DChiSquare
Provide ability to select hits based on &quot;chi square&quot;.
std::vector< art::InputTag > m_hitFinderTagVec
Data members to follow.
bool m_outputHistograms
Take the time to create and fill some histograms for diagnostics.
art::ServiceHandle< art::TFileService > tfs
void clear()
clear the tuple vectors before processing next event
void lar_cluster3d::StandardHit3DBuilder::CreateNewRecobHitCollection ( art::Event &  event,
reco::HitPairList hitPairList,
std::vector< recob::Hit > &  hitPtrVec,
RecobHitToPtrMap recobHitToPtrMap 
)
private

Create a new 2D hit collection from hits associated to 3D space points.

Definition at line 1674 of file StandardHit3DBuilder_tool.cc.

1678  {
1679  // Set up the timing
1680  cet::cpu_timer theClockBuildNewHits;
1681 
1682  if (m_enableMonitoring) theClockBuildNewHits.start();
1683 
1684  // We want to build a unique list of hits from the input 3D points which, we know, reuse 2D points frequently
1685  // At the same time we need to create a new 2D hit with the "correct" WireID and replace the old 2D hit in the
1686  // ClusterHit2D object with this new one... while keeping track of the use of the old ones. My head is spinning...
1687  // Declare a set which will allow us to keep track of those CusterHit2D objects we have seen already
1688  std::set<const reco::ClusterHit2D*> visitedHit2DSet;
1689 
1690  // Use this handy art utility to make art::Ptr objects to the new recob::Hits for use in the output phase
1691  art::PtrMaker<recob::Hit> ptrMaker(event);
1692 
1693  // Reserve enough memory to replace every recob::Hit we have considered (this is upper limit)
1694  hitPtrVec.reserve(m_clusterHit2DMasterList.size());
1695 
1696  // Scheme is to loop through all 3D hits, then through each associated ClusterHit2D object
1697  for (reco::ClusterHit3D& hit3D : hitPairList) {
1698  reco::ClusterHit2DVec& hit2DVec = hit3D.getHits();
1699 
1700  // The loop is over the index so we can recover the correct WireID to associate to the new hit when made
1701  for (size_t idx = 0; idx < hit3D.getHits().size(); idx++) {
1702  const reco::ClusterHit2D* hit2D = hit2DVec[idx];
1703 
1704  // Have we seen this 2D hit already?
1705  if (visitedHit2DSet.find(hit2D) == visitedHit2DSet.end()) {
1706  visitedHit2DSet.insert(hit2D);
1707 
1708  // Create and save the new recob::Hit with the correct WireID
1709  hitPtrVec.emplace_back(
1710  recob::HitCreator(*hit2D->getHit(), hit3D.getWireIDs()[idx]).copy());
1711 
1712  // Recover a pointer to it...
1713  recob::Hit* newHit = &hitPtrVec.back();
1714 
1715  // Create a mapping from this hit to an art Ptr representing it
1716  recobHitToPtrMap[newHit] = ptrMaker(hitPtrVec.size() - 1);
1717 
1718  // And set the pointer to this hit in the ClusterHit2D object
1719  const_cast<reco::ClusterHit2D*>(hit2D)->setHit(newHit);
1720  }
1721  }
1722  }
1723 
1724  size_t numNewHits = hitPtrVec.size();
1725 
1726  if (m_enableMonitoring) {
1727  theClockBuildNewHits.stop();
1728 
1729  m_timeVector[BUILDNEWHITS] = theClockBuildNewHits.accumulated_real_time();
1730  }
1731 
1732  mf::LogDebug("Cluster3D") << ">>>>> New output recob::Hit size: " << numNewHits << " (vs "
1733  << m_clusterHit2DMasterList.size() << " input)" << std::endl;
1734 
1735  return;
1736  }
const recob::Hit * getHit() const
Definition: Cluster3D.h:77
Class managing the creation of a new recob::Hit object.
Definition: HitCreator.h:83
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
Definition: Cluster3D.h:91
T copy(T const &v)
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
float lar_cluster3d::StandardHit3DBuilder::DistanceFromPointToHitWire ( const Eigen::Vector3f &  position,
const geo::WireID wireID 
) const
private

Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range.

Definition at line 1482 of file StandardHit3DBuilder_tool.cc.

1484  {
1485  float distance;
1486 
1487  // Embed the call to the geometry's services nearest wire id method in a try-catch block
1488  try {
1489  // Get the wire endpoints
1490  Eigen::Vector3d wireStart;
1491  Eigen::Vector3d wireEnd;
1492 
1493  m_geometry->WireEndPoints(wireIDIn, &wireStart[0], &wireEnd[0]);
1494 
1495  // Want the hit position to have same x value as wire coordinates
1496  Eigen::Vector3d hitPosition(wireStart[0], position[1], position[2]);
1497 
1498  // Want the wire direction
1499  Eigen::Vector3d wireDir = wireEnd - wireStart;
1500 
1501  wireDir.normalize();
1502 
1503  // Get arc length to doca
1504  double arcLen = (hitPosition - wireStart).dot(wireDir);
1505 
1506  Eigen::Vector3d docaVec = hitPosition - (wireStart + arcLen * wireDir);
1507 
1508  distance = docaVec.norm();
1509  }
1510  catch (std::exception& exc) {
1511  // This can happen, almost always because the coordinates are **just** out of range
1512  mf::LogWarning("Cluster3D") << "Exception caught finding nearest wire, position - "
1513  << exc.what() << std::endl;
1514 
1515  // Assume extremum for wire number depending on z coordinate
1516  distance = 0.;
1517  }
1518 
1519  return distance;
1520  }
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
const reco::ClusterHit2D * lar_cluster3d::StandardHit3DBuilder::FindBestMatchingHit ( const Hit2DSet hit2DSet,
const reco::ClusterHit3D pair,
float  pairDeltaTimeLimits 
) const
private

A utility routine for finding a 2D hit closest in time to the given pair.

Definition at line 1398 of file StandardHit3DBuilder_tool.cc.

1401  {
1402  static const float minCharge(0.);
1403 
1404  const reco::ClusterHit2D* bestVHit(0);
1405 
1406  float pairAvePeakTime(pair.getAvePeakTime());
1407 
1408  // Idea is to loop through the input set of hits and look for the best combination
1409  for (const auto& hit2D : hit2DSet) {
1410  if (hit2D->getHit()->Integral() < minCharge) continue;
1411 
1412  float hitVPeakTime(hit2D->getTimeTicks());
1413  float deltaPeakTime(pairAvePeakTime - hitVPeakTime);
1414 
1415  if (deltaPeakTime > pairDeltaTimeLimits) continue;
1416 
1417  if (deltaPeakTime < -pairDeltaTimeLimits) break;
1418 
1419  pairDeltaTimeLimits = fabs(deltaPeakTime);
1420  bestVHit = hit2D;
1421  }
1422 
1423  return bestVHit;
1424  }
float getAvePeakTime() const
Definition: Cluster3D.h:162
int lar_cluster3d::StandardHit3DBuilder::findGoodHitPairs ( const reco::ClusterHit2D goldenHit,
HitVector::iterator &  startItr,
HitVector::iterator &  endItr,
HitMatchPairVecMap hitMatchMap 
) const
private

Definition at line 768 of file StandardHit3DBuilder_tool.cc.

772  {
773  int numPairs(0);
774 
775  // Loop through the input secon hits and make pairs
776  while (startItr != endItr) {
777  const reco::ClusterHit2D* hit = *startItr++;
778  reco::ClusterHit3D pair;
779 
780  // pair returned with a negative ave time is signal of failure
781  if (!makeHitPair(pair, goldenHit, hit, m_hitWidthSclFctr)) continue;
782 
783  geo::WireID wireID = hit->WireID();
784 
785  hitMatchMap[wireID].emplace_back(hit, pair);
786 
787  numPairs++;
788  }
789 
790  return numPairs;
791  }
const geo::WireID & WireID() const
Definition: Cluster3D.h:76
bool makeHitPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit2D *hit1, const reco::ClusterHit2D *hit2, float hitWidthSclFctr=1., size_t hitPairCntr=0) const
Make a HitPair object by checking two hits.
process_name hit
Definition: cheaterreco.fcl:51
void lar_cluster3d::StandardHit3DBuilder::findGoodTriplets ( HitMatchPairVecMap pair12Map,
HitMatchPairVecMap pair13Map,
reco::HitPairList hitPairList,
bool  tagged = false 
) const
private

This algorithm takes lists of hit pairs and finds good triplets.

Definition at line 794 of file StandardHit3DBuilder_tool.cc.

798  {
799  // Build triplets from the two lists of hit pairs
800  if (!pair12Map.empty()) {
801  // temporary container for dead channel hits
802  std::vector<reco::ClusterHit3D> tempDeadChanVec;
803  reco::ClusterHit3D deadChanPair;
804 
805  // Keep track of which third plane hits have been used
806  std::map<const reco::ClusterHit3D*, bool> usedPairMap;
807 
808  // Initial population of this map with the pair13Map hits
809  for (const auto& pair13 : pair13Map) {
810  for (const auto& hit2Dhit3DPair : pair13.second)
811  usedPairMap[&hit2Dhit3DPair.second] = false;
812  }
813 
814  // The outer loop is over all hit pairs made from the first two plane combinations
815  for (const auto& pair12 : pair12Map) {
816  if (pair12.second.empty()) continue;
817 
818  // This loop is over hit pairs that share the same first two plane wires but may have different
819  // hit times on those wires
820  for (const auto& hit2Dhit3DPair12 : pair12.second) {
821  const reco::ClusterHit3D& pair1 = hit2Dhit3DPair12.second;
822 
823  // populate the map with initial value
824  usedPairMap[&pair1] = false;
825 
826  // The simplest approach here is to loop over all possibilities and let the triplet builder weed out the weak candidates
827  for (const auto& pair13 : pair13Map) {
828  if (pair13.second.empty()) continue;
829 
830  for (const auto& hit2Dhit3DPair13 : pair13.second) {
831  const reco::ClusterHit2D* hit2 = hit2Dhit3DPair13.first;
832  const reco::ClusterHit3D& pair2 = hit2Dhit3DPair13.second;
833 
834  // If success try for the triplet
835  reco::ClusterHit3D triplet;
836 
837  if (makeHitTriplet(triplet, pair1, hit2)) {
838  triplet.setID(hitPairList.size());
839  hitPairList.emplace_back(triplet);
840  usedPairMap[&pair1] = true;
841  usedPairMap[&pair2] = true;
842  }
843  }
844  }
845  }
846  }
847 
848  // One more loop through the other pairs to check for sick channels
849  if (m_numBadChannels > 0) {
850  for (const auto& pairMapPair : usedPairMap) {
851  if (pairMapPair.second) continue;
852 
853  const reco::ClusterHit3D* pair = pairMapPair.first;
854 
855  // Here we look to see if we failed to make a triplet because the partner wire was dead/noisy/sick
856  if (makeDeadChannelPair(deadChanPair, *pair, 4, 0, 0.))
857  tempDeadChanVec.emplace_back(deadChanPair);
858  }
859 
860  // Handle the dead wire triplets
861  if (!tempDeadChanVec.empty()) {
862  // If we have many then see if we can trim down a bit by keeping those with time significance
863  if (tempDeadChanVec.size() > 1) {
864  // Sort by "significance" of agreement
865  std::sort(tempDeadChanVec.begin(),
866  tempDeadChanVec.end(),
867  [](const auto& left, const auto& right) {
868  return left.getDeltaPeakTime() / left.getSigmaPeakTime() <
869  right.getDeltaPeakTime() / right.getSigmaPeakTime();
870  });
871 
872  // What is the range of "significance" from first to last?
873  float firstSig = tempDeadChanVec.front().getDeltaPeakTime() /
874  tempDeadChanVec.front().getSigmaPeakTime();
875  float lastSig =
876  tempDeadChanVec.back().getDeltaPeakTime() / tempDeadChanVec.back().getSigmaPeakTime();
877  float sigRange = lastSig - firstSig;
878 
879  if (lastSig > 0.5 * m_deltaPeakTimeSig && sigRange > 0.5) {
880  // Declare a maximum of 1.5 * the average of the first and last pairs...
881  float maxSignificance = std::max(0.75 * (firstSig + lastSig), 1.0);
882 
883  std::vector<reco::ClusterHit3D>::iterator firstBadElem = std::find_if(
884  tempDeadChanVec.begin(),
885  tempDeadChanVec.end(),
886  [&maxSignificance](const auto& pair) {
887  return pair.getDeltaPeakTime() / pair.getSigmaPeakTime() > maxSignificance;
888  });
889 
890  // But only keep the best 10?
891  if (std::distance(tempDeadChanVec.begin(), firstBadElem) > 20)
892  firstBadElem = tempDeadChanVec.begin() + 20;
893  // Keep at least one hit...
894  else if (firstBadElem == tempDeadChanVec.begin())
895  firstBadElem++;
896 
897  tempDeadChanVec.resize(std::distance(tempDeadChanVec.begin(), firstBadElem));
898  }
899  }
900 
901  for (auto& pair : tempDeadChanVec) {
902  pair.setID(hitPairList.size());
903  hitPairList.emplace_back(pair);
904  }
905  }
906  }
907  }
908 
909  return;
910  }
bool makeHitTriplet(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pairIn, const reco::ClusterHit2D *hit2) const
Make a 3D HitPair object by checking two hits.
walls no right
Definition: selectors.fcl:105
float getSigmaPeakTime() const
Definition: Cluster3D.h:164
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
walls no left
Definition: selectors.fcl:105
void setID(const size_t &id) const
Definition: Cluster3D.h:178
float getDeltaPeakTime() const
Definition: Cluster3D.h:163
bool makeDeadChannelPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pair, size_t maxStatus=4, size_t minStatus=0, float minOverlap=0.2) const
Make a 3D HitPair object from a valid pair and a dead channel in the missing plane.
int lar_cluster3d::StandardHit3DBuilder::FindNumberInRange ( const Hit2DSet hit2DSet,
const reco::ClusterHit3D pair,
float  range 
) const
private

A utility routine for returning the number of 2D hits from the list in a given range.

Definition at line 1427 of file StandardHit3DBuilder_tool.cc.

1430  {
1431  static const float minCharge(0.);
1432 
1433  int numberInRange(0);
1434  float pairAvePeakTime(pair.getAvePeakTime());
1435 
1436  // Idea is to loop through the input set of hits and look for the best combination
1437  for (const auto& hit2D : hit2DSet) {
1438  if (hit2D->getHit()->Integral() < minCharge) continue;
1439 
1440  float hitVPeakTime(hit2D->getTimeTicks());
1441  float deltaPeakTime(pairAvePeakTime - hitVPeakTime);
1442 
1443  if (deltaPeakTime > range) continue;
1444 
1445  if (deltaPeakTime < -range) break;
1446 
1447  numberInRange++;
1448  }
1449 
1450  return numberInRange;
1451  }
float getAvePeakTime() const
Definition: Cluster3D.h:162
float lar_cluster3d::StandardHit3DBuilder::getTimeToExecute ( IHit3DBuilder::TimeValues  index) const
inlineoverridevirtual

If monitoring, recover the time to execute a particular function.

Implements lar_cluster3d::IHit3DBuilder.

Definition at line 106 of file StandardHit3DBuilder_tool.cc.

107  {
108  return m_timeVector[index];
109  }
void lar_cluster3d::StandardHit3DBuilder::Hit3DBuilder ( art::Event &  evt,
reco::HitPairList hitPairList,
RecobHitToPtrMap clusterHitToArtPtrMap 
)
overridevirtual

Given a set of recob hits, run DBscan to form 3D clusters.

Parameters
hitPairListThe input list of 3D hits to run clustering on
clusterParametersListA list of cluster objects (parameters from associated hits)

Associations with wires.

Associations with raw digits.

Implements lar_cluster3d::IHit3DBuilder.

Definition at line 455 of file StandardHit3DBuilder_tool.cc.

458  {
459  // Clear the internal data structures
460  m_clusterHit2DMasterList.clear();
461  m_planeToHitVectorMap.clear();
462  m_planeToWireToHitSetMap.clear();
463 
464  m_timeVector.resize(NUMTIMEVALUES, 0.);
465 
466  // Get a hit refiner
467  std::unique_ptr<std::vector<recob::Hit>> outputHitPtrVec(new std::vector<recob::Hit>);
468 
469  // Recover the 2D hits and then organize them into data structures which will be used in the
470  // DBscan algorithm for building the 3D clusters
471  this->CollectArtHits(evt);
472 
473  // If there are no hits in our view/wire data structure then do not proceed with the full analysis
474  if (!m_planeToWireToHitSetMap.empty()) {
475  // Call the algorithm that builds 3D hits
476  this->BuildHit3D(hitPairList);
477 
478  // If we built 3D points then attempt to output a new hit list as well
479  if (!hitPairList.empty())
480  CreateNewRecobHitCollection(evt, hitPairList, *outputHitPtrVec, clusterHitToArtPtrMap);
481  }
482 
483  // Set up to make the associations (if desired)
484  /// Associations with wires.
485  std::unique_ptr<art::Assns<recob::Wire, recob::Hit>> wireAssns(
486  new art::Assns<recob::Wire, recob::Hit>);
487 
488  makeWireAssns(evt, *wireAssns, clusterHitToArtPtrMap);
489 
490  /// Associations with raw digits.
491  std::unique_ptr<art::Assns<raw::RawDigit, recob::Hit>> rawDigitAssns(
492  new art::Assns<raw::RawDigit, recob::Hit>);
493 
494  makeRawDigitAssns(evt, *rawDigitAssns, clusterHitToArtPtrMap);
495 
496  // Move everything into the event
497  evt.put(std::move(outputHitPtrVec));
498  evt.put(std::move(wireAssns));
499  evt.put(std::move(rawDigitAssns));
500 
501  // Handle tree output too
502  if (m_outputHistograms) {
503  m_tupleTree->Fill();
504 
505  clear();
506  }
507 
508  return;
509  }
void CreateNewRecobHitCollection(art::Event &, reco::HitPairList &, std::vector< recob::Hit > &, RecobHitToPtrMap &)
Create a new 2D hit collection from hits associated to 3D space points.
void BuildHit3D(reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
void makeWireAssns(const art::Event &, art::Assns< recob::Wire, recob::Hit > &, RecobHitToPtrMap &) const
Create recob::Wire to recob::Hit associations.
bool m_outputHistograms
Take the time to create and fill some histograms for diagnostics.
void CollectArtHits(const art::Event &evt) const
Extract the ART hits and the ART hit-particle relationships.
void makeRawDigitAssns(const art::Event &, art::Assns< raw::RawDigit, recob::Hit > &, RecobHitToPtrMap &) const
Create raw::RawDigit to recob::Hit associations.
TCEvent evt
Definition: DataStructs.cxx:8
void clear()
clear the tuple vectors before processing next event
bool lar_cluster3d::StandardHit3DBuilder::makeDeadChannelPair ( reco::ClusterHit3D pairOut,
const reco::ClusterHit3D pair,
size_t  maxStatus = 4,
size_t  minStatus = 0,
float  minOverlap = 0.2 
) const
private

Make a 3D HitPair object from a valid pair and a dead channel in the missing plane.

Definition at line 1319 of file StandardHit3DBuilder_tool.cc.

1324  {
1325  // Assume failure (most common result)
1326  bool result(false);
1327 
1328  const reco::ClusterHit2D* hit0 = pair.getHits()[0];
1329  const reco::ClusterHit2D* hit1 = pair.getHits()[1];
1330 
1331  size_t missPlane(2);
1332 
1333  // u plane hit is missing
1334  if (!hit0) {
1335  hit0 = pair.getHits()[2];
1336  missPlane = 0;
1337  }
1338  // v plane hit is missing
1339  else if (!hit1) {
1340  hit1 = pair.getHits()[2];
1341  missPlane = 1;
1342  }
1343 
1344  // Which plane is missing?
1345  geo::WireID wireID0 = hit0->WireID();
1346  geo::WireID wireID1 = hit1->WireID();
1347 
1348  // Ok, recover the wireID expected in the third plane...
1349  geo::WireID wireIn(wireID0.Cryostat, wireID0.TPC, missPlane, 0);
1350  geo::WireID wireID = NearestWireID(pair.getPosition(), wireIn);
1351 
1352  // There can be a round off issue so check the next wire as well
1353  bool wireStatus = m_channelStatus[wireID.Plane][wireID.Wire] < maxChanStatus &&
1354  m_channelStatus[wireID.Plane][wireID.Wire] >= minChanStatus;
1355  bool wireOneStatus = m_channelStatus[wireID.Plane][wireID.Wire + 1] < maxChanStatus &&
1356  m_channelStatus[wireID.Plane][wireID.Wire + 1] >= minChanStatus;
1357 
1358  // Make sure they are of at least the minimum status
1359  if (wireStatus || wireOneStatus) {
1360  // Sort out which is the wire we're dealing with
1361  if (!wireStatus) wireID.Wire += 1;
1362 
1363  // Want to refine position since we "know" the missing wire
1364  geo::WireIDIntersection widIntersect0;
1365 
1366  if (m_geometry->WireIDsIntersect(wireID0, wireID, widIntersect0)) {
1367  geo::WireIDIntersection widIntersect1;
1368 
1369  if (m_geometry->WireIDsIntersect(wireID1, wireID, widIntersect1)) {
1370  Eigen::Vector3f newPosition(
1371  pair.getPosition()[0], pair.getPosition()[1], pair.getPosition()[2]);
1372 
1373  newPosition[1] = (newPosition[1] + widIntersect0.y + widIntersect1.y) / 3.;
1374  newPosition[2] =
1375  (newPosition[2] + widIntersect0.z + widIntersect1.z - 2. * m_zPosOffset) / 3.;
1376 
1377  pairOut = pair;
1378  pairOut.setWireID(wireID);
1379  pairOut.setPosition(newPosition);
1380 
1385 
1388 
1389  result = true;
1390  }
1391  }
1392  }
1393 
1394  return result;
1395  }
void setWireID(const geo::WireID &wid) const
Definition: Cluster3D.cxx:172
double z
z position of intersection
Definition: geo_types.h:805
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:157
const geo::WireID & WireID() const
Definition: Cluster3D.h:76
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
geo::WireID NearestWireID(const Eigen::Vector3f &position, const geo::WireID &wireID) const
Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range...
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
double y
y position of intersection
Definition: geo_types.h:804
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:170
void setPosition(const Eigen::Vector3f &pos) const
Definition: Cluster3D.h:185
unsigned getStatusBits() const
Definition: Cluster3D.h:71
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:79
bool lar_cluster3d::StandardHit3DBuilder::makeHitPair ( reco::ClusterHit3D pairOut,
const reco::ClusterHit2D hit1,
const reco::ClusterHit2D hit2,
float  hitWidthSclFctr = 1.,
size_t  hitPairCntr = 0 
) const
private

Make a HitPair object by checking two hits.

Definition at line 913 of file StandardHit3DBuilder_tool.cc.

918  {
919  // Assume failure
920  bool result(false);
921 
922  // We assume in this routine that we are looking at hits in different views
923  // The first mission is to check that the wires intersect
924  const geo::WireID& hit1WireID = hit1->WireID();
925  const geo::WireID& hit2WireID = hit2->WireID();
926 
927  geo::WireIDIntersection widIntersect;
928 
929  if (m_geometry->WireIDsIntersect(hit1WireID, hit2WireID, widIntersect)) {
930  // Wires intersect so now we can check the timing
931  float hit1Peak = hit1->getTimeTicks();
932  float hit1Sigma = hit1->getHit()->RMS();
933 
934  float hit2Peak = hit2->getTimeTicks();
935  float hit2Sigma = hit2->getHit()->RMS();
936 
937  // "Long hits" are an issue... so we deal with these differently
938  int hit1NDF = hit1->getHit()->DegreesOfFreedom();
939  int hit2NDF = hit2->getHit()->DegreesOfFreedom();
940 
941  // Basically, allow the range to extend to the nearest end of the snippet
942  if (hit1NDF < 2)
943  hit1Sigma = std::min(hit1Peak - float(hit1->getHit()->StartTick()),
944  float(hit1->getHit()->EndTick()) - hit1Peak);
945  if (hit2NDF < 2)
946  hit2Sigma = std::min(hit2Peak - float(hit2->getHit()->StartTick()),
947  float(hit2->getHit()->EndTick()) - hit2Peak);
948 
949  // The "hit sigma" is the gaussian fit sigma of the hit, we need to expand a bit to allow hit overlap efficiency
950  float hit1Width = hitWidthSclFctr * hit1Sigma;
951  float hit2Width = hitWidthSclFctr * hit2Sigma;
952 
953  // Coarse check hit times are "in range"
954  if (fabs(hit1Peak - hit2Peak) <= (hit1Width + hit2Width)) {
955  // Check to see that hit peak times are consistent with each other
956  float hit1SigSq = hit1Sigma * hit1Sigma;
957  float hit2SigSq = hit2Sigma * hit2Sigma;
958  float deltaPeakTime = std::fabs(hit1Peak - hit2Peak);
959  float sigmaPeakTime = std::sqrt(hit1SigSq + hit2SigSq);
960 
961  // delta peak time consistency check here
962  if (deltaPeakTime < m_deltaPeakTimeSig *
963  sigmaPeakTime) // 2 sigma consistency? (do this way to avoid divide)
964  {
965  float oneOverWghts = hit1SigSq * hit2SigSq / (hit1SigSq + hit2SigSq);
966  float avePeakTime = (hit1Peak / hit1SigSq + hit2Peak / hit2SigSq) * oneOverWghts;
967  float totalCharge = hit1->getHit()->Integral() + hit2->getHit()->Integral();
968  float hitChiSquare = std::pow((hit1Peak - avePeakTime), 2) / hit1SigSq +
969  std::pow((hit2Peak - avePeakTime), 2) / hit2SigSq;
970 
971  float xPositionHit1(hit1->getXPosition());
972  float xPositionHit2(hit2->getXPosition());
973  float xPosition = (xPositionHit1 / hit1SigSq + xPositionHit2 / hit2SigSq) * hit1SigSq *
974  hit2SigSq / (hit1SigSq + hit2SigSq);
975 
976  Eigen::Vector3f position(
977  xPosition, float(widIntersect.y), float(widIntersect.z) - m_zPosOffset);
978 
979  // If to here then we need to sort out the hit pair code telling what views are used
980  unsigned statusBits = 1 << hit1->WireID().Plane | 1 << hit2->WireID().Plane;
981 
982  // handle status bits for the 2D hits
987 
990 
991  reco::ClusterHit2DVec hitVector;
992 
993  hitVector.resize(3, NULL);
994 
995  hitVector[hit1->WireID().Plane] = hit1;
996  hitVector[hit2->WireID().Plane] = hit2;
997 
998  unsigned int cryostatIdx = hit1->WireID().Cryostat;
999  unsigned int tpcIdx = hit1->WireID().TPC;
1000 
1001  // Initialize the wireIdVec
1002  std::vector<geo::WireID> wireIDVec = {geo::WireID(cryostatIdx, tpcIdx, 0, 0),
1003  geo::WireID(cryostatIdx, tpcIdx, 1, 0),
1004  geo::WireID(cryostatIdx, tpcIdx, 2, 0)};
1005 
1006  wireIDVec[hit1->WireID().Plane] = hit1->WireID();
1007  wireIDVec[hit2->WireID().Plane] = hit2->WireID();
1008 
1009  // For compiling at the moment
1010  std::vector<float> hitDelTSigVec = {0., 0., 0.};
1011 
1012  hitDelTSigVec[hit1->WireID().Plane] = deltaPeakTime / sigmaPeakTime;
1013  hitDelTSigVec[hit2->WireID().Plane] = deltaPeakTime / sigmaPeakTime;
1014 
1015  // Create the 3D cluster hit
1016  hitPair.initialize(hitPairCntr,
1017  statusBits,
1018  position,
1019  totalCharge,
1020  avePeakTime,
1021  deltaPeakTime,
1022  sigmaPeakTime,
1023  hitChiSquare,
1024  0.,
1025  0.,
1026  0.,
1027  0.,
1028  hitVector,
1029  hitDelTSigVec,
1030  wireIDVec);
1031 
1032  result = true;
1033  }
1034  }
1035  }
1036 
1037  // Send it back
1038  return result;
1039  }
double z
z position of intersection
Definition: geo_types.h:805
float getTimeTicks() const
Definition: Cluster3D.h:75
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:220
const geo::WireID & WireID() const
Definition: Cluster3D.h:76
int DegreesOfFreedom() const
Definition: Hit.h:229
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:224
const recob::Hit * getHit() const
Definition: Cluster3D.h:77
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
float getXPosition() const
Definition: Cluster3D.h:74
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:216
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
Definition: Cluster3D.h:91
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:217
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
double y
y position of intersection
Definition: geo_types.h:804
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
unsigned getStatusBits() const
Definition: Cluster3D.h:71
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:79
bool lar_cluster3d::StandardHit3DBuilder::makeHitTriplet ( reco::ClusterHit3D pairOut,
const reco::ClusterHit3D pairIn,
const reco::ClusterHit2D hit2 
) const
private

Make a 3D HitPair object by checking two hits.

Definition at line 1042 of file StandardHit3DBuilder_tool.cc.

1045  {
1046  // Assume failure
1047  bool result(false);
1048 
1049  // We are going to force the wire pitch here, some time in the future we need to fix
1050  static const double wirePitch =
1051  0.5 * m_wirePitchScaleFactor * *std::max_element(m_wirePitch, m_wirePitch + 3);
1052 
1053  // Recover hit info
1054  float hitTimeTicks = hit->getTimeTicks();
1055  float hitSigma = hit->getHit()->RMS();
1056 
1057  // Special case check
1058  if (hitSigma > 2. * hit->getHit()->PeakAmplitude())
1059  hitSigma = 2. * hit->getHit()->PeakAmplitude();
1060 
1061  // Let's do a quick consistency check on the input hits to make sure we are in range...
1062  // Require the W hit to be "in range" with the UV Pair
1063  if (fabs(hitTimeTicks - pair.getAvePeakTime()) <
1064  m_hitWidthSclFctr * (pair.getSigmaPeakTime() + hitSigma)) {
1065  // Check the distance from the point to the wire the hit is on
1066  float hitWireDist = DistanceFromPointToHitWire(pair.getPosition(), hit->WireID());
1067 
1068  if (m_outputHistograms) m_maxSideVecVec.push_back(hitWireDist);
1069 
1070  // Reject hits that are not within range
1071  if (hitWireDist < wirePitch) {
1072  if (m_outputHistograms) m_pairWireDistVec.push_back(hitWireDist);
1073 
1074  // Use the existing code to see the U and W hits are willing to pair with the V hit
1075  reco::ClusterHit3D pair0h;
1076  reco::ClusterHit3D pair1h;
1077 
1078  // Recover all the hits involved
1079  const reco::ClusterHit2DVec& pairHitVec = pair.getHits();
1080  const reco::ClusterHit2D* hit0 = pairHitVec[0];
1081  const reco::ClusterHit2D* hit1 = pairHitVec[1];
1082 
1083  if (!hit0)
1084  hit0 = pairHitVec[2];
1085  else if (!hit1)
1086  hit1 = pairHitVec[2];
1087 
1088  // If good pairs made here then we can try to make a triplet
1089  if (makeHitPair(pair0h, hit0, hit, m_hitWidthSclFctr) &&
1090  makeHitPair(pair1h, hit1, hit, m_hitWidthSclFctr)) {
1091  // Get a copy of the input hit vector (note the order is by plane - by definition)
1092  reco::ClusterHit2DVec hitVector = pair.getHits();
1093 
1094  // include the new hit
1095  hitVector[hit->WireID().Plane] = hit;
1096 
1097  // Set up to get average peak time, hitChiSquare, etc.
1098  unsigned int statusBits(0x7);
1099  float avePeakTime(0.);
1100  float weightSum(0.);
1101  float xPosition(0.);
1102 
1103  // And get the wire IDs
1104  std::vector<geo::WireID> wireIDVec = {geo::WireID(), geo::WireID(), geo::WireID()};
1105 
1106  // First loop through the hits to get WireIDs and calculate the averages
1107  for (size_t planeIdx = 0; planeIdx < 3; planeIdx++) {
1108  const reco::ClusterHit2D* hit2D = hitVector[planeIdx];
1109 
1110  wireIDVec[planeIdx] = hit2D->WireID();
1111 
1114 
1116 
1117  float hitRMS = hit2D->getHit()->RMS();
1118  float peakTime = hit2D->getTimeTicks();
1119 
1120  // Basically, allow the range to extend to the nearest end of the snippet
1121  if (hit2D->getHit()->DegreesOfFreedom() < 2)
1122  hitRMS = std::min(hit2D->getTimeTicks() - float(hit2D->getHit()->StartTick()),
1123  float(hit2D->getHit()->EndTick()) - hit2D->getTimeTicks());
1124 
1125  float weight = 1. / (hitRMS * hitRMS);
1126 
1127  avePeakTime += peakTime * weight;
1128  xPosition += hit2D->getXPosition() * weight;
1129  weightSum += weight;
1130  }
1131 
1132  avePeakTime /= weightSum;
1133  xPosition /= weightSum;
1134 
1135  Eigen::Vector2f pair0hYZVec(pair0h.getPosition()[1], pair0h.getPosition()[2]);
1136  Eigen::Vector2f pair1hYZVec(pair1h.getPosition()[1], pair1h.getPosition()[2]);
1137  Eigen::Vector2f pairYZVec(pair.getPosition()[1], pair.getPosition()[2]);
1138  Eigen::Vector3f position(xPosition,
1139  float((pairYZVec[0] + pair0hYZVec[0] + pair1hYZVec[0]) / 3.),
1140  float((pairYZVec[1] + pair0hYZVec[1] + pair1hYZVec[1]) / 3.));
1141 
1142  // Armed with the average peak time, now get hitChiSquare and the sig vec
1143  float hitChiSquare(0.);
1144  float sigmaPeakTime(std::sqrt(1. / weightSum));
1145  std::vector<float> hitDelTSigVec;
1146 
1147  for (const auto& hit2D : hitVector) {
1148  float hitRMS = hit2D->getHit()->RMS();
1149 
1150  // Basically, allow the range to extend to the nearest end of the snippet
1151  if (hit2D->getHit()->DegreesOfFreedom() < 2)
1152  hitRMS = std::min(hit2D->getTimeTicks() - float(hit2D->getHit()->StartTick()),
1153  float(hit2D->getHit()->EndTick()) - hit2D->getTimeTicks());
1154 
1155  float combRMS = std::sqrt(hitRMS * hitRMS - sigmaPeakTime * sigmaPeakTime);
1156  float peakTime = hit2D->getTimeTicks();
1157  float deltaTime = peakTime - avePeakTime;
1158  float hitSig = deltaTime / combRMS;
1159 
1160  hitChiSquare += hitSig * hitSig;
1161 
1162  hitDelTSigVec.emplace_back(std::fabs(hitSig));
1163  }
1164 
1165  if (m_outputHistograms) m_chiSquare3DVec.push_back(hitChiSquare);
1166 
1167  int lowMinIndex(std::numeric_limits<int>::max());
1168  int lowMaxIndex(std::numeric_limits<int>::min());
1169  int hiMinIndex(std::numeric_limits<int>::max());
1170  int hiMaxIndex(std::numeric_limits<int>::min());
1171 
1172  // First task is to get the min/max values for the common overlap region
1173  for (const auto& hit2D : hitVector) {
1174  float range = 2. * hit2D->getHit()->RMS();
1175 
1176  // Basically, allow the range to extend to the nearest end of the snippet
1177  if (hit2D->getHit()->DegreesOfFreedom() < 2)
1178  range = std::min(hit2D->getTimeTicks() - float(hit2D->getHit()->StartTick()),
1179  float(hit2D->getHit()->EndTick()) - hit2D->getTimeTicks());
1180 
1181  int hitStart = hit2D->getHit()->PeakTime() - range - 0.5;
1182  int hitStop = hit2D->getHit()->PeakTime() + range + 0.5;
1183 
1184  lowMinIndex = std::min(hitStart, lowMinIndex);
1185  lowMaxIndex = std::max(hitStart, lowMaxIndex);
1186  hiMinIndex = std::min(hitStop + 1, hiMinIndex);
1187  hiMaxIndex = std::max(hitStop + 1, hiMaxIndex);
1188  }
1189 
1190  // Keep only "good" hits...
1191  if (hitChiSquare < m_maxHit3DChiSquare && hiMinIndex > lowMaxIndex) {
1192  // One more pass through hits to get charge
1193  std::vector<float> chargeVec;
1194 
1195  for (const auto& hit2D : hitVector)
1196  chargeVec.push_back(chargeIntegral(hit2D->getHit()->PeakTime(),
1197  hit2D->getHit()->PeakAmplitude(),
1198  hit2D->getHit()->RMS(),
1199  1.,
1200  lowMaxIndex,
1201  hiMinIndex));
1202 
1203  float totalCharge =
1204  std::accumulate(chargeVec.begin(), chargeVec.end(), 0.) / float(chargeVec.size());
1205  float overlapRange = float(hiMinIndex - lowMaxIndex);
1206  float overlapFraction = overlapRange / float(hiMaxIndex - lowMinIndex);
1207 
1208  // Set up to compute the charge asymmetry
1209  std::vector<float> smallestChargeDiffVec;
1210  std::vector<float> chargeAveVec;
1211  float smallestDiff(std::numeric_limits<float>::max());
1212  float maxDeltaPeak(0.);
1213  size_t chargeIndex(0);
1214 
1215  for (size_t idx = 0; idx < 3; idx++) {
1216  size_t leftIdx = (idx + 2) % 3;
1217  size_t rightIdx = (idx + 1) % 3;
1218 
1219  smallestChargeDiffVec.push_back(std::abs(chargeVec[leftIdx] - chargeVec[rightIdx]));
1220  chargeAveVec.push_back(float(0.5 * (chargeVec[leftIdx] + chargeVec[rightIdx])));
1221 
1222  if (smallestChargeDiffVec.back() < smallestDiff) {
1223  smallestDiff = smallestChargeDiffVec.back();
1224  chargeIndex = idx;
1225  }
1226 
1227  // Take opportunity to look at peak time diff
1228  float deltaPeakTime =
1229  hitVector[leftIdx]->getTimeTicks() - hitVector[rightIdx]->getTimeTicks();
1230 
1231  if (std::abs(deltaPeakTime) > maxDeltaPeak) maxDeltaPeak = std::abs(deltaPeakTime);
1232 
1233  if (m_outputHistograms) m_deltaTimeVec.push_back(deltaPeakTime);
1234  }
1235 
1236  float chargeAsymmetry = (chargeAveVec[chargeIndex] - chargeVec[chargeIndex]) /
1237  (chargeAveVec[chargeIndex] + chargeVec[chargeIndex]);
1238 
1239  // If this is true there has to be a negative charge that snuck in somehow
1240  if (chargeAsymmetry < -1. || chargeAsymmetry > 1.) {
1241  const geo::WireID& hitWireID = hitVector[chargeIndex]->WireID();
1242 
1243  std::cout << "============> Charge asymmetry out of range: " << chargeAsymmetry
1244  << " <============" << std::endl;
1245  std::cout << " hit C: " << hitWireID.Cryostat << ", TPC: " << hitWireID.TPC
1246  << ", Plane: " << hitWireID.Plane << ", Wire: " << hitWireID.Wire
1247  << std::endl;
1248  std::cout << " charge: " << chargeVec[0] << ", " << chargeVec[1] << ", "
1249  << chargeVec[2] << std::endl;
1250  std::cout << " index: " << chargeIndex << ", smallest diff: " << smallestDiff
1251  << std::endl;
1252  return result;
1253  }
1254 
1255  // Usurping "deltaPeakTime" to be the maximum pull
1256  float deltaPeakTime = *std::max_element(hitDelTSigVec.begin(), hitDelTSigVec.end());
1257 
1258  if (m_outputHistograms) {
1259  m_smallChargeDiffVec.push_back(smallestDiff);
1260  m_smallIndexVec.push_back(chargeIndex);
1261  m_maxPullVec.push_back(deltaPeakTime);
1262  m_qualityMetricVec.push_back(hitChiSquare);
1263  m_spacePointChargeVec.push_back(totalCharge);
1264  m_overlapFractionVec.push_back(overlapFraction);
1265  m_overlapRangeVec.push_back(overlapRange);
1266  m_maxDeltaPeakVec.push_back(maxDeltaPeak);
1267  m_hitAsymmetryVec.push_back(chargeAsymmetry);
1268  }
1269 
1270  // Try to weed out cases where overlap doesn't match peak separation
1271  if (maxDeltaPeak > overlapRange) return result;
1272 
1273  // Create the 3D cluster hit
1274  hitTriplet.initialize(0,
1275  statusBits,
1276  position,
1277  totalCharge,
1278  avePeakTime,
1279  deltaPeakTime,
1280  sigmaPeakTime,
1281  hitChiSquare,
1282  overlapFraction,
1283  chargeAsymmetry,
1284  0.,
1285  0.,
1286  hitVector,
1287  hitDelTSigVec,
1288  wireIDVec);
1289 
1290  result = true;
1291  }
1292  }
1293  }
1294  }
1295 
1296  // return success/fail
1297  return result;
1298  }
float m_wirePitchScaleFactor
Scaling factor to determine max distance allowed between candidate pairs.
float getTimeTicks() const
Definition: Cluster3D.h:75
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:157
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:220
const geo::WireID & WireID() const
Definition: Cluster3D.h:76
int DegreesOfFreedom() const
Definition: Hit.h:229
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
bool makeHitPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit2D *hit1, const reco::ClusterHit2D *hit2, float hitWidthSclFctr=1., size_t hitPairCntr=0) const
Make a HitPair object by checking two hits.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
process_name hit
Definition: cheaterreco.fcl:51
const recob::Hit * getHit() const
Definition: Cluster3D.h:77
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:221
T abs(T value)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
bool m_outputHistograms
Take the time to create and fill some histograms for diagnostics.
float getXPosition() const
Definition: Cluster3D.h:74
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:216
float chargeIntegral(float, float, float, float, int, int) const
Perform charge integration between limits.
float DistanceFromPointToHitWire(const Eigen::Vector3f &position, const geo::WireID &wireID) const
Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range...
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
Definition: Cluster3D.h:91
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:217
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
constexpr WireID()=default
Default constructor: an invalid TPC ID.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:170
BEGIN_PROLOG could also be cout
unsigned getStatusBits() const
Definition: Cluster3D.h:71
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:79
void lar_cluster3d::StandardHit3DBuilder::makeRawDigitAssns ( const art::Event &  evt,
art::Assns< raw::RawDigit, recob::Hit > &  rawDigitAssns,
RecobHitToPtrMap recobHitPtrMap 
) const
private

Create raw::RawDigit to recob::Hit associations.

Definition at line 1786 of file StandardHit3DBuilder_tool.cc.

1789  {
1790  // Let's make sure the input associations container is empty
1791  rawDigitAssns = art::Assns<raw::RawDigit, recob::Hit>();
1792 
1793  // First task is to recover all of the previous wire <--> hit associations and map them by channel number
1794  // Create the temporary container
1795  std::unordered_map<raw::ChannelID_t, art::Ptr<raw::RawDigit>> channelToRawDigitMap;
1796 
1797  // Go through the list of input sources and fill out the map
1798  for (const auto& inputTag : m_hitFinderTagVec) {
1799  art::ValidHandle<std::vector<recob::Hit>> hitHandle =
1800  evt.getValidHandle<std::vector<recob::Hit>>(inputTag);
1801 
1802  art::FindOneP<raw::RawDigit> hitToRawDigitAssns(hitHandle, evt, inputTag);
1803 
1804  if (hitToRawDigitAssns.isValid()) {
1805  for (size_t rawDigitIdx = 0; rawDigitIdx < hitToRawDigitAssns.size(); rawDigitIdx++) {
1806  art::Ptr<raw::RawDigit> rawDigit = hitToRawDigitAssns.at(rawDigitIdx);
1807 
1808  channelToRawDigitMap[rawDigit->Channel()] = rawDigit;
1809  }
1810  }
1811  }
1812 
1813  // Now fill the container
1814  for (const auto& hitPtrPair : recobHitPtrMap) {
1815  raw::ChannelID_t channel = hitPtrPair.first->Channel();
1816 
1817  std::unordered_map<raw::ChannelID_t, art::Ptr<raw::RawDigit>>::iterator chanRawDigitItr =
1818  channelToRawDigitMap.find(channel);
1819 
1820  if (!(chanRawDigitItr != channelToRawDigitMap.end())) {
1821  mf::LogDebug("Cluster3D") << "** Did not find channel to wire match! Skipping..."
1822  << std::endl;
1823  continue;
1824  }
1825 
1826  rawDigitAssns.addSingle(chanRawDigitItr->second, hitPtrPair.second);
1827  }
1828 
1829  return;
1830  }
std::vector< art::InputTag > m_hitFinderTagVec
Data members to follow.
TCEvent evt
Definition: DataStructs.cxx:8
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
void lar_cluster3d::StandardHit3DBuilder::makeWireAssns ( const art::Event &  evt,
art::Assns< recob::Wire, recob::Hit > &  wireAssns,
RecobHitToPtrMap recobHitPtrMap 
) const
private

Create recob::Wire to recob::Hit associations.

Definition at line 1739 of file StandardHit3DBuilder_tool.cc.

1742  {
1743  // Let's make sure the input associations container is empty
1744  wireAssns = art::Assns<recob::Wire, recob::Hit>();
1745 
1746  // First task is to recover all of the previous wire <--> hit associations and map them by channel number
1747  // Create the temporary container
1748  std::unordered_map<raw::ChannelID_t, art::Ptr<recob::Wire>> channelToWireMap;
1749 
1750  // Go through the list of input sources and fill out the map
1751  for (const auto& inputTag : m_hitFinderTagVec) {
1752  art::ValidHandle<std::vector<recob::Hit>> hitHandle =
1753  evt.getValidHandle<std::vector<recob::Hit>>(inputTag);
1754 
1755  art::FindOneP<recob::Wire> hitToWireAssns(hitHandle, evt, inputTag);
1756 
1757  if (hitToWireAssns.isValid()) {
1758  for (size_t wireIdx = 0; wireIdx < hitToWireAssns.size(); wireIdx++) {
1759  art::Ptr<recob::Wire> wire = hitToWireAssns.at(wireIdx);
1760 
1761  channelToWireMap[wire->Channel()] = wire;
1762  }
1763  }
1764  }
1765 
1766  // Now fill the container
1767  for (const auto& hitPtrPair : recobHitPtrMap) {
1768  raw::ChannelID_t channel = hitPtrPair.first->Channel();
1769 
1770  std::unordered_map<raw::ChannelID_t, art::Ptr<recob::Wire>>::iterator chanWireItr =
1771  channelToWireMap.find(channel);
1772 
1773  if (!(chanWireItr != channelToWireMap.end())) {
1774  mf::LogDebug("Cluster3D") << "** Did not find channel to wire match! Skipping..."
1775  << std::endl;
1776  continue;
1777  }
1778 
1779  wireAssns.addSingle(chanWireItr->second, hitPtrPair.second);
1780  }
1781 
1782  return;
1783  }
std::vector< art::InputTag > m_hitFinderTagVec
Data members to follow.
TCEvent evt
Definition: DataStructs.cxx:8
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
geo::WireID lar_cluster3d::StandardHit3DBuilder::NearestWireID ( const Eigen::Vector3f &  position,
const geo::WireID wireID 
) const
private

Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range.

Definition at line 1454 of file StandardHit3DBuilder_tool.cc.

1456  {
1457  geo::WireID wireID = wireIDIn;
1458 
1459  // Embed the call to the geometry's services nearest wire id method in a try-catch block
1460  try {
1461  // Switch from NearestWireID to this method to avoid the roundoff error issues...
1462  double distanceToWire = m_geometry->Plane(wireIDIn).WireCoordinate(position.data());
1463 
1464  wireID.Wire = int(distanceToWire);
1465  }
1466  catch (std::exception& exc) {
1467  // This can happen, almost always because the coordinates are **just** out of range
1468  mf::LogWarning("Cluster3D") << "Exception caught finding nearest wire, position - "
1469  << exc.what() << std::endl;
1470 
1471  // Assume extremum for wire number depending on z coordinate
1472  if (position[2] < 0.5 * m_geometry->DetLength())
1473  wireID.Wire = 0;
1474  else
1475  wireID.Wire = m_geometry->Nwires(wireIDIn.Plane) - 1;
1476  }
1477 
1478  return wireID;
1479  }
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
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.
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:882
void lar_cluster3d::StandardHit3DBuilder::produces ( art::ProducesCollector &  collector)
overridevirtual

Each algorithm may have different objects it wants "produced" so use this to let the top level producer module "know" what it is outputting.

Implements lar_cluster3d::IHit3DBuilder.

Definition at line 312 of file StandardHit3DBuilder_tool.cc.

313  {
314  collector.produces<std::vector<recob::Hit>>();
315  collector.produces<art::Assns<recob::Wire, recob::Hit>>();
316  collector.produces<art::Assns<raw::RawDigit, recob::Hit>>();
317  }

Member Data Documentation

const lariov::ChannelStatusProvider* lar_cluster3d::StandardHit3DBuilder::m_channelFilter
private

Definition at line 299 of file StandardHit3DBuilder_tool.cc.

ChannelStatusByPlaneVec lar_cluster3d::StandardHit3DBuilder::m_channelStatus
mutableprivate

Definition at line 293 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_chiSquare3DVec
mutableprivate

Definition at line 275 of file StandardHit3DBuilder_tool.cc.

Hit2DList lar_cluster3d::StandardHit3DBuilder::m_clusterHit2DMasterList
mutableprivate

Definition at line 289 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_deltaPeakTimeSig
private

Definition at line 258 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_deltaTimeVec
mutableprivate

Definition at line 274 of file StandardHit3DBuilder_tool.cc.

bool lar_cluster3d::StandardHit3DBuilder::m_enableMonitoring
private

Definition at line 265 of file StandardHit3DBuilder_tool.cc.

const geo::Geometry* lar_cluster3d::StandardHit3DBuilder::m_geometry
private

Definition at line 298 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_hitAsymmetryVec
mutableprivate

Definition at line 286 of file StandardHit3DBuilder_tool.cc.

std::vector<art::InputTag> lar_cluster3d::StandardHit3DBuilder::m_hitFinderTagVec
private

Data members to follow.

Definition at line 255 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_hitWidthSclFctr
private

Definition at line 257 of file StandardHit3DBuilder_tool.cc.

std::vector<int> lar_cluster3d::StandardHit3DBuilder::m_invalidTPCVec
private

Definition at line 259 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_maxDeltaPeakVec
mutableprivate

Definition at line 279 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_maxHit3DChiSquare
private

Provide ability to select hits based on "chi square".

Definition at line 262 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_maxPullVec
mutableprivate

Definition at line 276 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_maxSideVecVec
mutableprivate

Definition at line 280 of file StandardHit3DBuilder_tool.cc.

size_t lar_cluster3d::StandardHit3DBuilder::m_numBadChannels
mutableprivate

Definition at line 294 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_numSigmaPeakTime
private

Definition at line 256 of file StandardHit3DBuilder_tool.cc.

bool lar_cluster3d::StandardHit3DBuilder::m_outputHistograms
private

Take the time to create and fill some histograms for diagnostics.

Definition at line 263 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_overlapFractionVec
mutableprivate

Definition at line 277 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_overlapRangeVec
mutableprivate

Definition at line 278 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_pairWireDistVec
mutableprivate

Definition at line 281 of file StandardHit3DBuilder_tool.cc.

PlaneToHitVectorMap lar_cluster3d::StandardHit3DBuilder::m_planeToHitVectorMap
mutableprivate

Definition at line 290 of file StandardHit3DBuilder_tool.cc.

PlaneToWireToHitSetMap lar_cluster3d::StandardHit3DBuilder::m_planeToWireToHitSetMap
mutableprivate

Definition at line 291 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_qualityMetricVec
mutableprivate

Definition at line 284 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_smallChargeDiffVec
mutableprivate

Definition at line 282 of file StandardHit3DBuilder_tool.cc.

std::vector<int> lar_cluster3d::StandardHit3DBuilder::m_smallIndexVec
mutableprivate

Definition at line 283 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_spacePointChargeVec
mutableprivate

Definition at line 285 of file StandardHit3DBuilder_tool.cc.

std::vector<float> lar_cluster3d::StandardHit3DBuilder::m_timeVector
mutableprivate

Definition at line 267 of file StandardHit3DBuilder_tool.cc.

TTree* lar_cluster3d::StandardHit3DBuilder::m_tupleTree
private

output analysis tree

Definition at line 272 of file StandardHit3DBuilder_tool.cc.

bool lar_cluster3d::StandardHit3DBuilder::m_weHaveAllBeenHereBefore = false
mutableprivate

Definition at line 296 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_wirePitch[3]
private

Definition at line 266 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_wirePitchScaleFactor
private

Scaling factor to determine max distance allowed between candidate pairs.

Definition at line 261 of file StandardHit3DBuilder_tool.cc.

float lar_cluster3d::StandardHit3DBuilder::m_zPosOffset
private

Definition at line 269 of file StandardHit3DBuilder_tool.cc.


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