LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
cluster::ClusterCrawlerAlg Class Reference

#include "ClusterCrawlerAlg.h"

Classes

struct  ClusterStore
 struct of temporary clusters More...
 
struct  Vtx3Store
 struct of temporary 3D vertices More...
 
struct  VtxStore
 struct of temporary 2D vertices (end points) More...
 

Public Types

typedef unsigned int CTP_t
 

Public Member Functions

Data structures for the reconstruction results
 ClusterCrawlerAlg (fhicl::ParameterSet const &pset)
 
void RunCrawler (detinfo::DetectorClocksData const &clock_data, detinfo::DetectorPropertiesData const &det_prop, std::vector< recob::Hit > const &srchits)
 
Result retrieval
std::vector< short > const & GetinClus () const
 Returns (and loses) the collection of reconstructed hits. More...
 
std::vector< recob::Hit > && YieldHits ()
 Returns (and loses) the collection of reconstructed hits. More...
 
std::vector< recob::HitGetHits ()
 Returns the collection of reconstructed hits. More...
 
std::vector< ClusterStore > const & GetClusters () const
 Returns a constant reference to the clusters found. More...
 
std::vector< VtxStore > const & GetEndPoints () const
 Returns a constant reference to the 2D end points found. More...
 
std::vector< Vtx3Store > const & GetVertices () const
 Returns a constant reference to the 3D vertices found. More...
 
void ClearResults ()
 

Static Public Member Functions

static CTP_t EncodeCTP (unsigned int cryo, unsigned int tpc, unsigned int plane)
 
static CTP_t EncodeCTP (const geo::PlaneID &planeID)
 
static geo::PlaneID DecodeCTP (CTP_t CTP)
 
static bool SortByMultiplet (recob::Hit const &a, recob::Hit const &b)
 Comparison for sorting hits by wire and hit multiplet. More...
 

Static Public Attributes

static constexpr unsigned int CTPpad = 1000
 

Private Member Functions

void ClusterLoop ()
 
bool ClusterHitsOK (short nHitChk)
 
void AddHit (unsigned int kwire, bool &HitOK, bool &SigOK)
 
void AddLAHit (unsigned int kwire, bool &ChkCharge, bool &HitOK, bool &SigOK)
 
void FitCluster ()
 
void FitClusterChg ()
 
void FitClusterMid (unsigned short it1, unsigned int iht, short nhit)
 
void FitClusterMid (std::vector< unsigned int > &hitVec, unsigned int iht, short nhit)
 
void CrawlUS ()
 
void LACrawlUS ()
 
void KillGarbageClusters ()
 
void ChkMerge ()
 
void ChkMerge12 (unsigned short it1, unsigned short it2, bool &didit)
 
void DoMerge (unsigned short it1, unsigned short it2, short ProcCode)
 
void ChkClusterNearbyHits (bool prt)
 
void MergeHits (const unsigned int theHit, bool &didMerge)
 
void FixMultipletLocalIndices (size_t begin, size_t end, short int multiplicity=-1)
 Resets the local index and multiplicity of all the hits in [begin;end[. More...
 
void CheckClusterHitFrac (bool prt)
 
void ChkClusterDS ()
 
void MergeOverlap ()
 
void MakeClusterObsolete (unsigned short icl)
 Marks the cluster as obsolete and frees hits still associated with it. More...
 
void RestoreObsoleteCluster (unsigned short icl)
 Restores an obsolete cluster. More...
 
void RemoveObsoleteHits ()
 Removes obsolete hits from hits, updating the indices. More...
 
void FindVertices ()
 
void FindStarVertices ()
 
void ChkVertex (float fvw, float fvt, unsigned short it1, unsigned short it2, short topo)
 
void ClusterVertex (unsigned short it2)
 
void VertexCluster (unsigned short ivx)
 
void RefineVertexClusters (unsigned short ivx)
 
bool VtxClusterSplit ()
 
bool CrawlVtxChk (unsigned int kwire)
 
bool CrawlVtxChk2 ()
 
void VtxConstraint (unsigned int iwire, unsigned int ihit, unsigned int jwire, unsigned int &useHit, bool &doConstrain)
 
void FitVtx (unsigned short iv)
 
void FitAllVtx (CTP_t inCTP)
 
void VtxMatch (detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
 
void Vtx3ClusterMatch (detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
 
void Vtx3ClusterSplit (detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
 
void FindHammerClusters (detinfo::DetectorPropertiesData const &det_prop)
 
void CrawlInit ()
 
void ClusterInit ()
 
void GetHitRange (CTP_t CTP)
 
bool TmpStore ()
 
void TmpGet (unsigned short it1)
 
void CalculateAveHitWidth ()
 
void FclTrimUS (unsigned short nTrim)
 
bool SplitCluster (unsigned short icl, unsigned short pos, unsigned short ivx)
 
unsigned int DeadWireCount ()
 
unsigned int DeadWireCount (unsigned int inWire1, unsigned int inWire2)
 
bool ChkMergedClusterHitFrac (unsigned short it1, unsigned short it2)
 
void PrintClusters ()
 
void PrintVertices ()
 
bool ChkSignal (unsigned int iht, unsigned int jht)
 
bool ChkSignal (unsigned int wire1, float time1, unsigned int wire2, float time2)
 
float AngleFactor (float slope)
 
float EndKinkAngle ()
 
bool CheckHitDuplicates (std::string location, std::string marker="") const
 Returns true if there are no duplicates in the hit list for next cluster. More...
 
float DoCA (short icl, unsigned short end, float vwire, float vtick)
 
float ClusterVertexChi (short icl, unsigned short end, unsigned short ivx)
 
float PointVertexChi (float wire, float tick, unsigned short ivx)
 
std::string PrintHit (unsigned int iht)
 
std::pair< size_t, size_t > FindHitMultiplet (size_t iHit) const
 
void CheckHitClusterAssociations ()
 

Static Private Member Functions

static bool areInSameMultiplet (recob::Hit const &first_hit, recob::Hit const &second_hit)
 Returns whether the two hits belong to the same multiplet. More...
 

Private Attributes

unsigned short fNumPass
 number of passes over the hit collection More...
 
std::vector< unsigned short > fMaxHitsFit
 Max number of hits fitted. More...
 
std::vector< unsigned short > fMinHits
 Min number of hits to make a cluster. More...
 
std::vector< unsigned short > fNHitsAve
 
std::vector< float > fChiCut
 stop adding hits to clusters if chisq too high More...
 
std::vector< float > fKinkChiRat
 
std::vector< float > fKinkAngCut
 kink angle cut made after fKinkChiRat More...
 
std::vector< float > fChgCut
 charge difference cut for adding a hit to a cluster More...
 
std::vector< unsigned short > fMaxWirSkip
 max number of wires that can be skipped while crawling More...
 
std::vector< unsigned short > fMinWirAfterSkip
 
std::vector< bool > fDoMerge
 try to merge clusters? More...
 
std::vector< float > fTimeDelta
 max time difference for matching More...
 
std::vector< float > fMergeChgCut
 max charge ratio for matching More...
 
std::vector< bool > fFindVertices
 run vertexing code after clustering? More...
 
std::vector< bool > fLACrawl
 Crawl Large Angle clusters on pass? More...
 
bool fFindHammerClusters
 look for hammer type clusters More...
 
bool fRefineVertexClusters
 
std::vector< float > fMinAmp
 expected minimum signal in each wire plane More...
 
float fKillGarbageClusters
 
bool fChkClusterDS
 
bool fVtxClusterSplit
 
bool fFindStarVertices
 
float fHitErrFac
 hit time error = fHitErrFac * hit RMS used for cluster fit More...
 
float fHitMinAmp
 < ignore hits with Amp < this value More...
 
float fClProjErrFac
 cluster projection error factor More...
 
float fMinHitFrac
 
float fLAClusAngleCut
 call Large Angle Clustering code if > 0 More...
 
unsigned short fLAClusMaxHitsFit
 max hits fitted on a Large Angle cluster More...
 
float fLAClusSlopeCut
 
bool fMergeAllHits
 
float fHitMergeChiCut
 
float fMergeOverlapAngCut
 angle cut for merging overlapping clusters More...
 
unsigned short fAllowNoHitWire
 
float fVertex2DCut
 2D vtx -> cluster matching cut (chisq/dof) More...
 
float fVertex2DWireErrCut
 
float fVertex3DCut
 2D vtx -> 3D vtx matching cut (chisq/dof) More...
 
int fDebugPlane
 
int fDebugWire
 set to the Begin Wire and Hit of a cluster to print More...
 
int fDebugHit
 out detailed information while crawling More...
 
std::vector< geo::WireIDfFilteredWires
 
float clpar [3]
 
float clparerr [2]
 cluster parameter errors More...
 
float clChisq
 chisq of the current fit More...
 
float fAveChg
 average charge at leading edge of cluster More...
 
float fChgSlp
 slope of the charge vs wire More...
 
float fAveHitWidth
 average width (EndTick - StartTick) of hits More...
 
bool prt
 
bool vtxprt
 
unsigned short NClusters
 
art::ServiceHandle< geo::Geometry const > geom
 
geo::WireReadoutGeom const * wireReadoutGeom
 
std::vector< recob::HitfHits
 our version of the hits More...
 
std::vector< short > inClus
 Hit used in cluster (-1 = obsolete, 0 = free) More...
 
std::vector< bool > mergeAvailable
 set true if hit is with HitMergeChiCut of a neighbor hit More...
 
std::vector< ClusterStoretcl
 the clusters we are creating More...
 
std::vector< VtxStorevtx
 the endpoints we are reconstructing More...
 
std::vector< Vtx3Storevtx3
 the 3D vertices we are reconstructing More...
 
trkf::LinFitAlg fLinFitAlg
 
float clBeginSlp
 begin slope (= DS end = high wire number) More...
 
float clBeginAng
 
float clBeginSlpErr
 
unsigned int clBeginWir
 begin wire More...
 
float clBeginTim
 begin time More...
 
float clBeginChg
 begin average charge More...
 
float clBeginChgNear
 nearby charge More...
 
float clEndSlp
 slope at the end (= US end = low wire number) More...
 
float clEndAng
 
float clEndSlpErr
 
unsigned int clEndWir
 begin wire More...
 
float clEndTim
 begin time More...
 
float clEndChg
 end average charge More...
 
float clEndChgNear
 nearby charge More...
 
short clStopCode
 
short clProcCode
 
CTP_t clCTP
 Cryostat/TPC/Plane code. More...
 
bool clLA
 using Large Angle crawling code More...
 
unsigned int fFirstWire
 the first wire with a hit More...
 
unsigned int fFirstHit
 first hit used More...
 
unsigned int fLastWire
 the last wire with a hit More...
 
unsigned int cstat
 
unsigned int tpc
 
unsigned int plane
 
unsigned int fNumWires
 
unsigned int fMaxTime
 
float fScaleF
 scale factor from Tick/Wire to dx/du More...
 
unsigned short pass
 
std::vector< std::pair< int, int > > WireHitRange
 
std::vector< unsigned int > fcl2hits
 vector of hits used in the cluster More...
 
std::vector< float > chifits
 fit chisq for monitoring kinks, etc More...
 
std::vector< short > hitNear
 
std::vector< float > chgNear
 charge near a cluster on each wire More...
 
float fChgNearWindow
 window (ticks) for finding nearby charge More...
 
float fChgNearCut
 
std::string fhitsModuleLabel
 

Detailed Description

Definition at line 33 of file ClusterCrawlerAlg.h.

Member Typedef Documentation

typedef unsigned int cluster::ClusterCrawlerAlg::CTP_t

Definition at line 36 of file ClusterCrawlerAlg.h.

Constructor & Destructor Documentation

cluster::ClusterCrawlerAlg::ClusterCrawlerAlg ( fhicl::ParameterSet const &  pset)
explicit

Definition at line 55 of file ClusterCrawlerAlg.cxx.

References art::errors::Configuration, fhicl::ParameterSet::get(), and fhicl::ParameterSet::has_key().

56  {
57  fNumPass = pset.get<unsigned short>("NumPass", 0);
58  fMaxHitsFit = pset.get<std::vector<unsigned short>>("MaxHitsFit");
59  fMinHits = pset.get<std::vector<unsigned short>>("MinHits");
60  fNHitsAve = pset.get<std::vector<unsigned short>>("NHitsAve");
61  fChgCut = pset.get<std::vector<float>>("ChgCut");
62  fChiCut = pset.get<std::vector<float>>("ChiCut");
63  fMaxWirSkip = pset.get<std::vector<unsigned short>>("MaxWirSkip");
64  fMinWirAfterSkip = pset.get<std::vector<unsigned short>>("MinWirAfterSkip");
65  fKinkChiRat = pset.get<std::vector<float>>("KinkChiRat");
66  fKinkAngCut = pset.get<std::vector<float>>("KinkAngCut");
67  fDoMerge = pset.get<std::vector<bool>>("DoMerge");
68  fTimeDelta = pset.get<std::vector<float>>("TimeDelta");
69  fMergeChgCut = pset.get<std::vector<float>>("MergeChgCut");
70  fFindVertices = pset.get<std::vector<bool>>("FindVertices");
71  fLACrawl = pset.get<std::vector<bool>>("LACrawl");
72  fMinAmp = pset.get<std::vector<float>>("MinAmp", {5, 5, 5});
73  fChgNearWindow = pset.get<float>("ChgNearWindow");
74  fChgNearCut = pset.get<float>("ChgNearCut");
75 
76  fChkClusterDS = pset.get<bool>("ChkClusterDS", false);
77  fVtxClusterSplit = pset.get<bool>("VtxClusterSplit", false);
78  fFindStarVertices = pset.get<bool>("FindStarVertices", false);
79  if (pset.has_key("HammerCluster")) {
80  mf::LogWarning("CC")
81  << "fcl setting HammerCluster is replaced by FindHammerClusters. Ignoring...";
82  }
83  fFindHammerClusters = pset.get<bool>("FindHammerClusters", false);
84  fKillGarbageClusters = pset.get<float>("KillGarbageClusters", 0);
85  fRefineVertexClusters = pset.get<bool>("RefineVertexClusters", false);
86  fHitErrFac = pset.get<float>("HitErrFac", 0.2);
87  fHitMinAmp = pset.get<float>("HitMinAmp", 0.2);
88  fClProjErrFac = pset.get<float>("ClProjErrFac", 4);
89  fMinHitFrac = pset.get<float>("MinHitFrac", 0.6);
90 
91  fLAClusAngleCut = pset.get<float>("LAClusAngleCut", 45);
92  fLAClusMaxHitsFit = pset.get<unsigned short>("LAClusMaxHitsFit");
93  fMergeAllHits = pset.get<bool>("MergeAllHits", false);
94  fHitMergeChiCut = pset.get<float>("HitMergeChiCut", 2.5);
95  fMergeOverlapAngCut = pset.get<float>("MergeOverlapAngCut");
96  fAllowNoHitWire = pset.get<unsigned short>("AllowNoHitWire", 0);
97  fVertex2DCut = pset.get<float>("Vertex2DCut", 5);
98  fVertex2DWireErrCut = pset.get<float>("Vertex2DWireErrCut", 5);
99  fVertex3DCut = pset.get<float>("Vertex3DCut", 5);
100 
101  fDebugPlane = pset.get<int>("DebugPlane", -1);
102  fDebugWire = pset.get<int>("DebugWire", -1);
103  fDebugHit = pset.get<int>("DebugHit", -1);
104 
105  // some error checking
106  bool badinput = false;
107  if (fNumPass > fMaxHitsFit.size()) badinput = true;
108  if (fNumPass > fMinHits.size()) badinput = true;
109  if (fNumPass > fNHitsAve.size()) badinput = true;
110  if (fNumPass > fChgCut.size()) badinput = true;
111  if (fNumPass > fChiCut.size()) badinput = true;
112  if (fNumPass > fMaxWirSkip.size()) badinput = true;
113  if (fNumPass > fMinWirAfterSkip.size()) badinput = true;
114  if (fNumPass > fKinkChiRat.size()) badinput = true;
115  if (fNumPass > fKinkAngCut.size()) badinput = true;
116  if (fNumPass > fDoMerge.size()) badinput = true;
117  if (fNumPass > fTimeDelta.size()) badinput = true;
118  if (fNumPass > fMergeChgCut.size()) badinput = true;
119  if (fNumPass > fFindVertices.size()) badinput = true;
120  if (fNumPass > fLACrawl.size()) badinput = true;
121 
122  if (badinput)
124  << "ClusterCrawlerAlg: Bad input from fcl file";
125 
126  } // reconfigure
std::vector< float > fTimeDelta
max time difference for matching
std::vector< float > fChgCut
charge difference cut for adding a hit to a cluster
std::vector< unsigned short > fMinWirAfterSkip
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
std::vector< unsigned short > fMaxWirSkip
max number of wires that can be skipped while crawling
std::vector< float > fMinAmp
expected minimum signal in each wire plane
std::vector< float > fMergeChgCut
max charge ratio for matching
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
float fHitMinAmp
< ignore hits with Amp < this value
int fDebugHit
out detailed information while crawling
std::vector< bool > fLACrawl
Crawl Large Angle clusters on pass?
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
float fChgNearWindow
window (ticks) for finding nearby charge
unsigned short fNumPass
number of passes over the hit collection
float fMergeOverlapAngCut
angle cut for merging overlapping clusters
float fVertex2DCut
2D vtx -> cluster matching cut (chisq/dof)
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
unsigned short fLAClusMaxHitsFit
max hits fitted on a Large Angle cluster
std::vector< float > fKinkChiRat
std::vector< bool > fFindVertices
run vertexing code after clustering?
std::vector< unsigned short > fMaxHitsFit
Max number of hits fitted.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< unsigned short > fMinHits
Min number of hits to make a cluster.
float fLAClusAngleCut
call Large Angle Clustering code if > 0
float fClProjErrFac
cluster projection error factor
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
bool fFindHammerClusters
look for hammer type clusters
std::vector< unsigned short > fNHitsAve
std::vector< bool > fDoMerge
try to merge clusters?

Member Function Documentation

void cluster::ClusterCrawlerAlg::AddHit ( unsigned int  kwire,
bool &  HitOK,
bool &  SigOK 
)
private

Definition at line 4725 of file ClusterCrawlerAlg.cxx.

References util::abs(), lar::util::absDiff(), recob::Hit::Integral(), recob::Hit::LocalIndex(), recob::Hit::Multiplicity(), recob::Hit::PeakTime(), tca::PrintHit(), recob::Hit::RMS(), and cluster::SortByLowHit().

4726  {
4727  // Add a hit to the cluster if it meets several criteria:
4728  // similar pulse height to the cluster (if fAveChg is defined)
4729  // closest hit to the project cluster position.
4730  // Return SigOK if there is a nearby hit that was missed due to the cuts
4731 
4732  SigOK = false;
4733  HitOK = false;
4734 
4735  // not in the range of wires with hits
4736  if (kwire < fFirstWire || kwire > fLastWire) return;
4737 
4738  unsigned int lastClHit = UINT_MAX;
4739  if (fcl2hits.size() > 0) lastClHit = fcl2hits[fcl2hits.size() - 1];
4740 
4741  // the last hit added to the cluster
4742  unsigned int wire0 = clpar[2];
4743 
4744  // return if no signal and no hit
4745  if (fAllowNoHitWire == 0) {
4746  if (WireHitRange[kwire].first == -2) return;
4747  }
4748  else {
4749  // allow a number of wires with no hits
4750  if (WireHitRange[kwire].first == -2 && (wire0 - kwire) > fAllowNoHitWire) {
4751  SigOK = true;
4752  return;
4753  }
4754  }
4755  // skip bad wire, but assume the track was there
4756  if (WireHitRange[kwire].first == -1) {
4757  SigOK = true;
4758  return;
4759  }
4760 
4761  unsigned int firsthit = WireHitRange[kwire].first;
4762  unsigned int lasthit = WireHitRange[kwire].second;
4763 
4764  // the projected time of the cluster on this wire
4765  float dw = (float)kwire - (float)wire0;
4766  float prtime = clpar[0] + dw * clpar[1];
4767  if (prtime < 0 || (unsigned int)prtime > fMaxTime) return;
4768  // Find the projected time error including the projection error and the
4769  // error from the last hit added
4770  float prtimerr2 = std::abs(dw) * clparerr[1] * clparerr[1];
4771 
4772  // apply an angle dependent scale factor to the hit error. Default is very large error
4773  float hiterr = 10;
4774  if (lastClHit != UINT_MAX) hiterr = 3 * fHitErrFac * fHits[lastClHit].RMS();
4775  float err = std::sqrt(prtimerr2 + hiterr * hiterr);
4776  // Time window for accepting a hit.
4777  float hitWin = fClProjErrFac * err;
4778 
4779  float prtimeLo = prtime - hitWin;
4780  float prtimeHi = prtime + hitWin;
4781  float chgWinLo = prtime - fChgNearWindow;
4782  float chgWinHi = prtime + fChgNearWindow;
4783  if (prt) {
4784  mf::LogVerbatim("CC") << "AddHit: wire " << kwire << " prtime Lo " << (int)prtimeLo
4785  << " prtime " << (int)prtime << " Hi " << (int)prtimeHi << " prtimerr "
4786  << sqrt(prtimerr2) << " hiterr " << hiterr << " fAveChg "
4787  << (int)fAveChg << " fAveHitWidth " << std::setprecision(3)
4788  << fAveHitWidth;
4789  }
4790  // loop through the hits
4791  unsigned int imbest = INT_MAX;
4792  float best = 9999., dtime;
4793  float cnear = 0;
4794  float hitTime, hitChg, hitStartTick, hitEndTick;
4795  for (unsigned int khit = firsthit; khit < lasthit; ++khit) {
4796  // obsolete hit?
4797  if (inClus[khit] < 0) continue;
4798  hitTime = fHits[khit].PeakTime();
4799  dtime = std::abs(hitTime - prtime);
4800  if (dtime > 1000) continue;
4801  hitStartTick = fHits[khit].StartTick();
4802  hitEndTick = fHits[khit].EndTick();
4803  // weight by the charge difference
4804  if (fAveChg > 0) dtime *= std::abs(fHits[khit].Integral() - fAveChg) / fAveChg;
4805  if (prt && std::abs(dtime) < 100) {
4806  mf::LogVerbatim("CC") << " Chk W:T " << PrintHit(khit) << " dT " << std::fixed
4807  << std::setprecision(1) << (hitTime - prtime) << " InClus "
4808  << inClus[khit] << " mult " << fHits[khit].Multiplicity() << " RMS "
4809  << std::fixed << std::setprecision(1) << fHits[khit].RMS() << " Chi2 "
4810  << std::fixed << std::setprecision(1) << fHits[khit].GoodnessOfFit()
4811  << " Charge " << (int)fHits[khit].Integral() << " Peak " << std::fixed
4812  << std::setprecision(1) << fHits[khit].PeakAmplitude() << " LoT "
4813  << (int)hitStartTick << " HiT " << (int)hitEndTick << " index "
4814  << khit;
4815  }
4816  // count charge in the window
4817  if (fHits[khit].StartTick() > chgWinLo && fHits[khit].EndTick() < chgWinHi)
4818  cnear += fHits[khit].Integral();
4819  // check for signal
4820  if (prtimeHi < hitStartTick) continue;
4821  if (prtimeLo > hitEndTick) continue;
4822  SigOK = true;
4823  // check for good hit
4824  if (hitTime < prtimeLo) continue;
4825  if (hitTime > prtimeHi) continue;
4826  // hit used?
4827  if (inClus[khit] > 0) continue;
4828  if (dtime < best) {
4829  best = dtime;
4830  imbest = khit;
4831  }
4832  } // khit
4833 
4834  if (!SigOK) {
4835  if (fAllowNoHitWire == 0) return;
4836  if (prt)
4837  mf::LogVerbatim("CC") << " wire0 " << wire0 << " kwire " << kwire << " max "
4838  << fAllowNoHitWire << " imbest " << imbest;
4839  if ((wire0 - kwire) > fAllowNoHitWire) return;
4840  SigOK = true;
4841  }
4842 
4843  if (imbest == INT_MAX) return;
4844 
4845  recob::Hit const& hit = fHits[imbest];
4846  hitChg = hit.Integral();
4847 
4848  if (prt) mf::LogVerbatim("CC") << " Best hit time " << (int)hit.PeakTime();
4849 
4850  short hnear = 0;
4851  // merge hits in a doublet?
4852  bool didMerge = false;
4853  if (lastClHit != UINT_MAX && fAveHitWidth > 0 && fHitMergeChiCut > 0 &&
4854  hit.Multiplicity() == 2) {
4855  bool doMerge = true;
4856  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4857  if (std::abs(kwire - vtx[ivx].Wire) < 10 &&
4858  std::abs(int(hit.PeakTime() - vtx[ivx].Time)) < 20) {
4859  doMerge = false;
4860  break;
4861  }
4862  } // ivx
4863  // quit if localindex does not make sense.
4864  if (hit.LocalIndex() != 0 && imbest == 0) doMerge = false;
4865  if (doMerge) {
4866  // find the neighbor hit
4867  unsigned int oht;
4868  if (hit.LocalIndex() == 0) { oht = imbest + 1; }
4869  else {
4870  oht = imbest - 1;
4871  } // hit.LocalIndex() == 0
4872  // check the hit time separation
4873  recob::Hit const& other_hit = fHits[oht];
4874  float hitSep = std::abs(hit.PeakTime() - other_hit.PeakTime());
4875  hitSep /= hit.RMS();
4876  // check the the charge similarity
4877  float totChg = hitChg + other_hit.Integral();
4878  float lastHitChg = fAveChg;
4879  if (lastHitChg < 0) lastHitChg = fHits[lastClHit].Integral();
4880  hnear = 1;
4881  if (prt)
4882  mf::LogVerbatim("CC") << " Chk hit merge hitsep " << hitSep << " dChg "
4883  << std::abs(totChg - lastHitChg) << " Cut "
4884  << std::abs(hit.Integral() - lastHitChg);
4885  if (inClus[oht] == 0 && hitSep < fHitMergeChiCut) {
4886  if (prt) mf::LogVerbatim("CC") << " Merging hit doublet " << imbest;
4887  MergeHits(imbest, didMerge);
4888  if (prt && !didMerge) mf::LogVerbatim("CC") << " Hit merge failed ";
4889  } // not in a cluster, hitSep OK, total charge OK
4890  } // doMerge
4891  } // fHitMergeChiCut > 0 && hit.Multiplicity() == 2
4892 
4893  // Make a charge similarity cut if the average charge is defined
4894  bool fitChg = true;
4895  if (fAveChg > 0.) {
4896 
4897  float chgrat = (hitChg - fAveChg) / fAveChg;
4898  if (prt) mf::LogVerbatim("CC") << " Chgrat " << std::setprecision(2) << chgrat;
4899 
4900  // charge is way too high?
4901  if (chgrat > 3 * fChgCut[pass]) {
4902  if (prt)
4903  mf::LogVerbatim("CC") << " fails 3 x high charge cut " << fChgCut[pass] << " on pass "
4904  << pass;
4905  return;
4906  }
4907 
4908  // Determine if the last hit added was a large (low) charge hit
4909  // This will be used to prevent adding large (low) charge hits on two
4910  // consecutive fits. This cut is only applied to hits on adjacent wires
4911  float bigchgcut = 1.5 * fChgCut[pass];
4912  bool lasthitbig = false;
4913  bool lasthitlow = false;
4914  if (lastClHit != UINT_MAX && lar::util::absDiff(wire0, kwire) == 1) {
4915  float lastchgrat = (fHits[lastClHit].Integral() - fAveChg) / fAveChg;
4916  lasthitbig = (lastchgrat > bigchgcut);
4917  lasthitlow = (lastchgrat < -fChgCut[pass]);
4918  }
4919 
4920  // the last hit added was low charge and this one is as well
4921  if (lasthitlow && chgrat < -fChgCut[pass]) {
4922  if (prt) mf::LogVerbatim("CC") << " fails low charge cut. Stop crawling.";
4923  SigOK = false;
4924  return;
4925  } // lasthitlow
4926 
4927  // the last hit was high charge and this one is also
4928  if (lasthitbig && chgrat > fChgCut[pass]) {
4929  if (prt)
4930  mf::LogVerbatim("CC") << " fails 2nd hit high charge cut. Last hit was high also. ";
4931  return;
4932  } // lasthitbig
4933 
4934  // require that large charge hits have a very good projection error
4935  if (chgrat > fChgCut[pass]) {
4936  if (best > 2 * err) {
4937  if (prt) mf::LogVerbatim("CC") << " high charge && bad dT= " << best << " err= " << err;
4938  return;
4939  }
4940  } // chgrat > fChgCut[pass]
4941 
4942  // decide whether to fit the charge
4943  fitChg = (chgrat < std::abs(fChgCut[pass]));
4944  } // fAveChg > 0
4945 
4946  // we now have a hit that meets all the criteria. Fit it
4947  fcl2hits.push_back(imbest);
4948  // This is strictly only necessary when calling AddHit for seed clusters
4949  if (fcl2hits.size() == 3) std::sort(fcl2hits.begin(), fcl2hits.end(), SortByLowHit);
4950  FitCluster();
4951  chifits.push_back(clChisq);
4952  hitNear.push_back(hnear);
4953  // remove the charge of the just added hit
4954  cnear -= fHits[imbest].Integral();
4955  if (cnear < 0) cnear = 0;
4956  // divide by the just added hit charge
4957  cnear /= fHits[imbest].Integral();
4958  chgNear.push_back(cnear);
4959  // nearby hit check
4960  // ChkClusterNearbyHits(prt);
4961  HitOK = true;
4962 
4963  if (chgNear.size() != fcl2hits.size()) {
4964  mf::LogError("CC") << "AddHit: Bad length";
4965  return;
4966  }
4967 
4968  if (prt)
4969  mf::LogVerbatim("CC") << " >>ADD" << pass << " W:T " << PrintHit(imbest) << " dT " << best
4970  << " clChisq " << clChisq << " Chg " << (int)fHits[imbest].Integral()
4971  << " AveChg " << (int)fAveChg << " fcl2hits size " << fcl2hits.size();
4972 
4973  if (!fitChg) return;
4974  if (prt) mf::LogVerbatim("CC") << " Fit charge ";
4975  FitClusterChg();
4976  } // AddHit()
short int LocalIndex() const
How well do we believe we know this hit?
Definition: Hit.h:266
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< std::pair< int, int > > WireHitRange
float clparerr[2]
cluster parameter errors
std::vector< float > fChgCut
charge difference cut for adding a hit to a cluster
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:234
constexpr auto abs(T v)
Returns the absolute value of the argument.
for(Int_t i=0;i< nentries;i++)
Definition: comparison.C:30
STL namespace.
void MergeHits(const unsigned int theHit, bool &didMerge)
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:254
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:262
float fAveHitWidth
average width (EndTick - StartTick) of hits
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
float fChgNearWindow
window (ticks) for finding nearby charge
bool SortByLowHit(unsigned int i, unsigned int j)
std::string PrintHit(unsigned int iht)
Detector simulation of raw signals on wires.
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
std::vector< float > chifits
fit chisq for monitoring kinks, etc
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:69
float fClProjErrFac
cluster projection error factor
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< VtxStore > vtx
the endpoints we are reconstructing
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::AddLAHit ( unsigned int  kwire,
bool &  ChkCharge,
bool &  HitOK,
bool &  SigOK 
)
private

Definition at line 4475 of file ClusterCrawlerAlg.cxx.

References util::abs(), and tca::PrintHit().

4476  {
4477  // A variant of AddHit for large angle clusters
4478 
4479  SigOK = false;
4480  HitOK = false;
4481 
4482  // not in the range of wires with hits
4483  if (kwire < fFirstWire || kwire > fLastWire) return;
4484 
4485  if (fcl2hits.size() == 0) return;
4486 
4487  // skip bad wire and assume the track was there
4488  if (WireHitRange[kwire].first == -1) {
4489  SigOK = true;
4490  return;
4491  }
4492  // return SigOK false if no hit on a good wire
4493  if (WireHitRange[kwire].first == -2) return;
4494 
4495  unsigned int firsthit = WireHitRange[kwire].first;
4496  unsigned int lasthit = WireHitRange[kwire].second;
4497 
4498  // max allowable time difference between projected cluster and a hit
4499  float timeDiff = 40 * AngleFactor(clpar[1]);
4500  float dtime;
4501 
4502  // the last hit added to the cluster
4503  unsigned int lastClHit = UINT_MAX;
4504  if (fcl2hits.size() > 0) {
4505  lastClHit = fcl2hits[fcl2hits.size() - 1];
4506  if (lastClHit == 0) {
4507  fAveChg = fHits[lastClHit].Integral();
4508  fAveHitWidth = fHits[lastClHit].EndTick() - fHits[lastClHit].StartTick();
4509  }
4510  } // fcl2hits.size() > 0
4511 
4512  // the projected time of the cluster on this wire
4513  float prtime = clpar[0] + ((float)kwire - clpar[2]) * clpar[1];
4514  float chgWinLo = prtime - fChgNearWindow;
4515  float chgWinHi = prtime + fChgNearWindow;
4516  float chgrat, hitWidth;
4517  float hitWidthCut = 0.5 * fAveHitWidth;
4518  float cnear = 0;
4519  // float fom;
4520  if (prt)
4521  mf::LogVerbatim("CC") << "AddLAHit: wire " << kwire << " prtime " << prtime
4522  << " max timeDiff " << timeDiff << " fAveChg " << fAveChg;
4523  unsigned int imbest = 0;
4524  unsigned int khit;
4525  for (khit = firsthit; khit < lasthit; ++khit) {
4526  // obsolete hit?
4527  if (inClus[khit] < 0) continue;
4528  dtime = std::abs(fHits[khit].PeakTime() - prtime);
4529  hitWidth = fHits[khit].EndTick() - fHits[khit].StartTick();
4530  chgrat = 1;
4531  if (ChkCharge && fAveChg > 0) { chgrat = fHits[khit].Integral() / fAveChg; }
4532  if (prt)
4533  mf::LogVerbatim("CC") << " Chk W:T " << kwire << ":" << (short)fHits[khit].PeakTime()
4534  << " dT " << std::fixed << std::setprecision(1) << dtime << " InClus "
4535  << inClus[khit] << " mult " << fHits[khit].Multiplicity() << " width "
4536  << (int)hitWidth << " MergeAvail " << mergeAvailable[khit] << " Chi2 "
4537  << std::fixed << std::setprecision(2) << fHits[khit].GoodnessOfFit()
4538  << " Charge " << (int)fHits[khit].Integral() << " chgrat "
4539  << std::fixed << std::setprecision(1) << chgrat << " index " << khit;
4540  // count charge in the window
4541  if (fHits[khit].PeakTime() > chgWinLo && fHits[khit].PeakTime() < chgWinHi)
4542  cnear += fHits[khit].Integral();
4543  // projected time outside the Signal time window?
4544  if (prtime < fHits[khit].StartTick() - timeDiff) continue;
4545  if (prtime > fHits[khit].EndTick() + timeDiff) continue;
4546  SigOK = true;
4547  // hit used?
4548  if (inClus[khit] > 0) continue;
4549  // ignore narrow width hits
4550  if (hitWidth < hitWidthCut) continue;
4551  // ignore very low charge hits
4552  if (chgrat < 0.1) continue;
4553  if (dtime < timeDiff) {
4554  HitOK = true;
4555  imbest = khit;
4556  timeDiff = dtime;
4557  }
4558  } // khit
4559 
4560  if (prt && !HitOK) mf::LogVerbatim("CC") << " no hit found ";
4561 
4562  if (!HitOK) return;
4563 
4564  if (prt)
4565  mf::LogVerbatim("CC") << " Pick hit time " << (int)fHits[imbest].PeakTime() << " hit index "
4566  << imbest;
4567 
4568  // merge hits in a multiplet?
4569  short hnear = 0;
4570  if (lastClHit != UINT_MAX && fHits[imbest].Multiplicity() > 1) {
4571  bool doMerge = true;
4572  // Standard code
4573  // don't merge if we are close to a vertex
4574  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4575  if (vtx[ivx].CTP != clCTP) continue;
4576  if (prt)
4577  mf::LogVerbatim("CC") << " close vtx chk W:T " << vtx[ivx].Wire << ":"
4578  << (int)vtx[ivx].Time;
4579  if (std::abs(kwire - vtx[ivx].Wire) < 5 &&
4580  std::abs(int(fHits[imbest].PeakTime() - vtx[ivx].Time)) < 20) {
4581  if (prt) mf::LogVerbatim("CC") << " Close to a vertex. Don't merge hits";
4582  doMerge = false;
4583  }
4584  } // ivx
4585  // Decide which hits in the multiplet to merge. Hits that are well
4586  // separated from each other should not be merged
4587  if (doMerge) {
4588  unsigned short nused = 0;
4589  // the total charge of the hit multiplet
4590  float multipletChg = 0.;
4591  float chicut = AngleFactor(clpar[1]) * fHitMergeChiCut * fHits[lastClHit].RMS();
4592  // look for a big separation between adjacent hits
4593  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(imbest);
4594  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
4595  if (inClus[jht] < 0) continue;
4596  if (inClus[jht] == 0)
4597  multipletChg += fHits[jht].Integral();
4598  else
4599  ++nused;
4600  // check the neighbor hit separation
4601  if (jht > MultipletRange.first) {
4602  // pick the larger RMS of the two hits
4603  float hitRMS = fHits[jht].RMS();
4604  if (fHits[jht - 1].RMS() > hitRMS) hitRMS = fHits[jht - 1].RMS();
4605  const float tdiff =
4606  std::abs(fHits[jht].PeakTime() - fHits[jht - 1].PeakTime()) / hitRMS;
4607  if (prt) mf::LogVerbatim("CC") << " Hit RMS chisq " << tdiff << " chicut " << chicut;
4608  if (tdiff > chicut) doMerge = false;
4609  } // jht > 0
4610  } // jht
4611  if (prt) {
4612  if (!doMerge) mf::LogVerbatim("CC") << " Hits are well separated. Don't merge them ";
4613  }
4614  if (doMerge && nused == 0) {
4615  // compare the charge with the last hit added?
4616  if (ChkCharge) {
4617  // there is a nearby hit
4618  hnear = 1;
4619  float chgrat = multipletChg / fHits[lastClHit].Integral();
4620  if (prt)
4621  mf::LogVerbatim("CC") << " merge hits charge check " << (int)multipletChg
4622  << " Previous hit charge " << (int)fHits[lastClHit].Integral();
4623  if (chgrat > 2) doMerge = false;
4624  }
4625  } // doMerge && nused == 0
4626  } // doMerge true
4627  if (doMerge) {
4628  // there is a nearby hit and it will be merged
4629  hnear = -1;
4630  bool didMerge;
4631  MergeHits(imbest, didMerge);
4632  } // doMerge
4633  } // Hits[imbest].Multiplicity() > 1
4634 
4635  // attach to the cluster and fit
4636  fcl2hits.push_back(imbest);
4637  FitCluster();
4638  FitClusterChg();
4639  chifits.push_back(clChisq);
4640  hitNear.push_back(hnear);
4641  // remove the charge of the just added hit
4642  cnear -= fHits[imbest].Integral();
4643  if (cnear < 0) cnear = 0;
4644  // divide by the just added hit charge
4645  cnear /= fHits[imbest].Integral();
4646  chgNear.push_back(cnear);
4647  if (prt) {
4648  hitWidth = fHits[imbest].EndTick() - fHits[imbest].StartTick();
4649  mf::LogVerbatim("CC") << " >>LADD" << pass << " W:T " << PrintHit(imbest) << " dT "
4650  << timeDiff << " clChisq " << clChisq << " Chg "
4651  << (int)fHits[imbest].Integral() << " AveChg " << (int)fAveChg
4652  << " width " << (int)hitWidth << " AveWidth " << (int)fAveHitWidth
4653  << " fcl2hits size " << fcl2hits.size();
4654  } // prt
4655  // decide what to do with a bad fit
4656  if (clChisq > fChiCut[pass]) {
4657  FclTrimUS(1);
4658  FitCluster();
4659  HitOK = false;
4660  SigOK = false;
4661  if (prt) mf::LogVerbatim("CC") << " LADD- Removed bad hit. Stopped tracking";
4662  }
4663  } // AddLAHit()
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< std::pair< int, int > > WireHitRange
constexpr auto abs(T v)
Returns the absolute value of the argument.
void MergeHits(const unsigned int theHit, bool &didMerge)
CTP_t clCTP
Cryostat/TPC/Plane code.
float fAveHitWidth
average width (EndTick - StartTick) of hits
void FclTrimUS(unsigned short nTrim)
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
float fChgNearWindow
window (ticks) for finding nearby charge
std::pair< size_t, size_t > FindHitMultiplet(size_t iHit) const
std::string PrintHit(unsigned int iht)
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
std::vector< float > chifits
fit chisq for monitoring kinks, etc
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
float cluster::ClusterCrawlerAlg::AngleFactor ( float  slope)
private

Definition at line 4333 of file ClusterCrawlerAlg.cxx.

References util::abs().

4334  {
4335  // returns an angle dependent cluster projection error factor for fitting
4336  // and hit finding
4337 
4338  float slp = std::abs(slope);
4339  if (slp > 15) slp = 15;
4340  // return a value between 1 and 4
4341  float angfac = 1 + 0.03 * slp * slp;
4342  return angfac;
4343  }
constexpr auto abs(T v)
Returns the absolute value of the argument.
bool cluster::ClusterCrawlerAlg::areInSameMultiplet ( recob::Hit const &  first_hit,
recob::Hit const &  second_hit 
)
staticprivate

Returns whether the two hits belong to the same multiplet.

Definition at line 6088 of file ClusterCrawlerAlg.cxx.

References recob::Hit::StartTick(), and recob::Hit::WireID().

6090  {
6091  return (first_hit.StartTick() == second_hit.StartTick()) &&
6092  (first_hit.WireID() == second_hit.WireID());
6093  } // ClusterCrawlerAlg::areInSameMultiplet()
void cluster::ClusterCrawlerAlg::CalculateAveHitWidth ( )
private

Definition at line 4346 of file ClusterCrawlerAlg.cxx.

4347  {
4348  fAveHitWidth = 0;
4349  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii)
4350  fAveHitWidth += fHits[fcl2hits[ii]].EndTick() - fHits[fcl2hits[ii]].StartTick();
4351  fAveHitWidth /= (float)fcl2hits.size();
4352  } // CalculateAveHitWidth
float fAveHitWidth
average width (EndTick - StartTick) of hits
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::CheckClusterHitFrac ( bool  prt)
private

Definition at line 4058 of file ClusterCrawlerAlg.cxx.

References tca::DeadWireCount().

4059  {
4060 
4061  // Find the fraction of the wires on the cluster that have
4062  // hits.
4063  unsigned int iht = fcl2hits[fcl2hits.size() - 1];
4064  clEndWir = fHits[iht].WireID().Wire;
4065  clBeginWir = fHits[fcl2hits[0]].WireID().Wire;
4066  float hitFrac = (float)(fcl2hits.size() + DeadWireCount()) / (float)(clBeginWir - clEndWir + 1);
4067 
4068  if (hitFrac < fMinHitFrac) {
4069  if (prt)
4070  mf::LogVerbatim("CC") << "CheckClusterHitFrac: Poor hit fraction " << hitFrac
4071  << " clBeginWir " << clBeginWir << " clEndWir " << clEndWir
4072  << " size " << fcl2hits.size() << " DeadWireCount "
4073  << DeadWireCount();
4074  fcl2hits.clear();
4075  return;
4076  } // hitFrac
4077 
4078  /* TODO: Does this make sense?
4079  // lop off the last hit if it is part of a hit multiplet
4080  if(fHits[iht].Multiplicity() > 1) {
4081  fcl2hits.resize(fcl2hits.size() - 1);
4082  }
4083 */
4084  // check for short track ghosts
4085  if (fcl2hits.size() < 5) {
4086  unsigned short nsing = 0;
4087  for (unsigned short iht = 0; iht < fcl2hits.size(); ++iht)
4088  if (fHits[fcl2hits[iht]].Multiplicity() == 1) ++nsing;
4089  hitFrac = (float)nsing / (float)fcl2hits.size();
4090  if (hitFrac < fMinHitFrac) {
4091  fcl2hits.clear();
4092  if (prt)
4093  mf::LogVerbatim("CC") << "CheckClusterHitFrac: Poor short track hit fraction " << hitFrac;
4094  return;
4095  } // hitFrac
4096  } // short ghost track check
4097 
4098  // analyze the pattern of nearby charge
4099  // will need the cluster charge so calculate it here if it isn't defined yet
4100  if (clBeginChg <= 0) {
4101  unsigned int iht, nht = 0;
4102  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
4103  iht = fcl2hits[ii];
4104  clBeginChg += fHits[iht].Integral();
4105  ++nht;
4106  if (nht == 8) break;
4107  }
4108  clBeginChg /= (float)nht;
4109  } // clBeginChg == 0
4110  // handle short vs long clusters
4111  unsigned short cnt = chgNear.size() / 2;
4112  // get the average charge from <= 30 hits at each end
4113  if (chgNear.size() > 60) cnt = 30;
4114  clBeginChgNear = 0;
4115  clEndChgNear = 0;
4116  for (unsigned short ids = 0; ids < cnt; ++ids) {
4117  clBeginChgNear += chgNear[ids];
4118  clEndChgNear += chgNear[chgNear.size() - 1 - ids];
4119  }
4120  clBeginChgNear /= (float)cnt;
4121  clEndChgNear /= (float)cnt;
4122 
4123  } // CheckClusterHitFrac()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
float clBeginChg
begin average charge
unsigned int clEndWir
begin wire
std::vector< recob::Hit > fHits
our version of the hits
unsigned int clBeginWir
begin wire
float clBeginChgNear
nearby charge
std::vector< float > chgNear
charge near a cluster on each wire
float clEndChgNear
nearby charge
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::CheckHitClusterAssociations ( )
private

Definition at line 875 of file ClusterCrawlerAlg.cxx.

876  {
877  // check hit - cluster associations
878 
879  if (fHits.size() != inClus.size()) {
880  mf::LogError("CC") << "CHCA: Sizes wrong " << fHits.size() << " " << inClus.size();
881  return;
882  }
883 
884  unsigned int iht, nErr = 0;
885  short clID;
886 
887  // check cluster -> hit association
888  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
889  if (tcl[icl].ID < 0) continue;
890  clID = tcl[icl].ID;
891  for (unsigned short ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
892  iht = tcl[icl].tclhits[ii];
893  if (iht > fHits.size() - 1) {
894  mf::LogError("CC") << "CHCA: Bad tclhits index " << iht << " fHits size " << fHits.size();
895  return;
896  } // iht > fHits.size() - 1
897  if (inClus[iht] != clID) {
898  mf::LogError("CC") << "CHCA: Bad cluster -> hit association. clID " << clID
899  << " hit inClus " << inClus[iht] << " ProcCode " << tcl[icl].ProcCode
900  << " CTP " << tcl[icl].CTP;
901  ++nErr;
902  if (nErr > 10) return;
903  }
904  } // ii
905  } // icl
906 
907  // check hit -> cluster association
908  unsigned short icl;
909  for (iht = 0; iht < fHits.size(); ++iht) {
910  if (inClus[iht] <= 0) continue;
911  icl = inClus[iht] - 1;
912  // see if the cluster is obsolete
913  if (tcl[icl].ID < 0) {
914  mf::LogError("CC") << "CHCA: Hit associated with an obsolete cluster. hit W:T "
915  << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime()
916  << " tcl[icl].ID " << tcl[icl].ID;
917  ++nErr;
918  if (nErr > 10) return;
919  }
920  if (std::find(tcl[icl].tclhits.begin(), tcl[icl].tclhits.end(), iht) ==
921  tcl[icl].tclhits.end()) {
922  mf::LogError("CC") << "CHCA: Bad hit -> cluster association. hit index " << iht << " W:T "
923  << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime()
924  << " inClus " << inClus[iht];
925  ++nErr;
926  if (nErr > 10) return;
927  }
928  } // iht
929 
930  } // CheckHitClusterAssociations()
std::vector< ClusterStore > tcl
the clusters we are creating
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< recob::Hit > fHits
our version of the hits
bool cluster::ClusterCrawlerAlg::CheckHitDuplicates ( std::string  location,
std::string  marker = "" 
) const
private

Returns true if there are no duplicates in the hit list for next cluster.

Definition at line 6107 of file ClusterCrawlerAlg.cxx.

References hits().

6109  {
6110  // currently unused, only for debug
6111  unsigned int nDuplicates = 0;
6112  std::set<unsigned int> hits;
6113  for (unsigned int hit : fcl2hits) {
6114  if (hits.count(hit)) {
6115  ++nDuplicates;
6116  mf::LogProblem log("CC");
6117  log << "Hit #" << hit
6118  << " being included twice in the future cluster (ID=" << (tcl.size() + 1)
6119  << "?) at location: " << location;
6120  if (!marker.empty()) log << " (marker: '" << marker << "')";
6121  }
6122  hits.insert(hit);
6123  } // for
6124  return nDuplicates > 0;
6125  } // ClusterCrawlerAlg::CheckHitDuplicates()
std::vector< ClusterStore > tcl
the clusters we are creating
void hits()
Definition: readHits.C:15
Detector simulation of raw signals on wires.
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ChkClusterDS ( )
private

Definition at line 973 of file ClusterCrawlerAlg.cxx.

References util::abs(), and cluster::SortByLowHit().

974  {
975  // Try to extend clusters DS by a few wires.
976  // DS hits may not have been included in a cluster if they have high
977  // multiplicity or high charge.
978  // Ref ClusterLoop cuts for starting a seed cluster.
979 
980  prt = (fDebugPlane == 3);
981 
982  // use the most generous kink angle cut
983  float dThCut = fKinkAngCut[fNumPass - 1];
984 
985  if (prt)
986  mf::LogVerbatim("CC") << "ChkClusterDS clCTP " << clCTP << " kink angle cut " << dThCut;
987 
988  const unsigned short tclsize = tcl.size();
989  bool didMerge, skipit;
990  unsigned short icl, ii, nhm, iv;
991  unsigned int iht;
992 
993  // first merge any hits on the DS end of clusters
994  for (icl = 0; icl < tclsize; ++icl) {
995  if (tcl[icl].ID < 0) continue;
996  if (tcl[icl].CTP != clCTP) continue;
997  // ignore clusters that have a Begin vertex
998  if (tcl[icl].BeginVtx >= 0) continue;
999  // and clusters near a vertex
1000  skipit = false;
1001  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1002  if (vtx[iv].CTP != clCTP) continue;
1003  if (std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4) continue;
1004  if (std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20) continue;
1005  skipit = true;
1006  break;
1007  }
1008  if (skipit) continue;
1009  // check the first few hits
1010  nhm = 0;
1011  for (ii = 0; ii < 3; ++ii) {
1012  iht = fcl2hits[ii];
1013  if (fHits[iht].Multiplicity() > 1) {
1014  MergeHits(iht, didMerge);
1015  if (didMerge) ++nhm;
1016  }
1017  } // ii
1018  if (nhm > 0) {
1019  // update the Begin parameters in-place
1020  FitClusterMid(icl, 0, 3);
1021  tcl[icl].BeginTim = clpar[0];
1022  tcl[icl].BeginSlp = clpar[1];
1023  tcl[icl].BeginAng = atan(fScaleF * clpar[1]);
1024  tcl[icl].BeginSlpErr = clparerr[1];
1025  tcl[icl].BeginChg = fAveChg;
1026  tcl[icl].ProcCode += 5000;
1027  if (prt) mf::LogVerbatim("CC") << "ChkClusterDS: Merge hits on cluster " << tcl[icl].ID;
1028  } // nhm > 0
1029  } // icl
1030 
1031  float thhits, prevth, hitrms, rmsrat;
1032  bool ratOK;
1033  std::vector<unsigned int> dshits;
1034  for (icl = 0; icl < tclsize; ++icl) {
1035  if (tcl[icl].ID < 0) continue;
1036  if (tcl[icl].CTP != clCTP) continue;
1037  // ignore clusters that have a Begin vertex
1038  if (tcl[icl].BeginVtx >= 0) continue;
1039  // and clusters near a vertex
1040  skipit = false;
1041  for (iv = 0; iv < vtx.size(); ++iv) {
1042  if (vtx[iv].CTP != clCTP) continue;
1043  if (std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4) continue;
1044  if (std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20) continue;
1045  skipit = true;
1046  break;
1047  }
1048  if (skipit) continue;
1049  // find the angle using the first 2 hits
1050  unsigned int ih0 = tcl[icl].tclhits[1];
1051  unsigned int ih1 = tcl[icl].tclhits[0];
1052  const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1053  (fHits[ih1].WireID().Wire - fHits[ih0].WireID().Wire);
1054  prevth = std::atan(fScaleF * slp);
1055  // move the "origin" to the first hit
1056  ih0 = ih1;
1057  unsigned int wire = fHits[ih0].WireID().Wire;
1058  hitrms = fHits[ih0].RMS();
1059  float time0 = fHits[ih0].PeakTime();
1060  float prtime;
1061  dshits.clear();
1062  // follow DS a few wires. Stop if any encountered
1063  // hit is associated with a cluster
1064  for (ii = 0; ii < 4; ++ii) {
1065  ++wire;
1066  if (wire > fLastWire) break;
1067  prtime = time0 + slp;
1068  if (prt)
1069  mf::LogVerbatim("CC") << "ChkClusterDS: Try to extend " << tcl[icl].ID << " to W:T "
1070  << wire << " hitrms " << hitrms << " prevth " << prevth
1071  << " prtime " << (int)prtime;
1072  // stop if no hits on this wire
1073  if (WireHitRange[wire].first == -2) break;
1074  unsigned int firsthit = WireHitRange[wire].first;
1075  unsigned int lasthit = WireHitRange[wire].second;
1076  bool hitAdded = false;
1077  for (ih1 = firsthit; ih1 < lasthit; ++ih1) {
1078  if (inClus[ih1] != 0) continue;
1079  if (prtime < fHits[ih1].PeakTimeMinusRMS(5)) continue;
1080  if (prtime > fHits[ih1].PeakTimePlusRMS(5)) continue;
1081  const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1082  (fHits[ih1].WireID().Wire - fHits[ih0].WireID().Wire);
1083  thhits = std::atan(fScaleF * slp);
1084  if (prt)
1085  mf::LogVerbatim("CC") << " theta " << thhits << " prevth " << prevth << " cut "
1086  << dThCut;
1087  if (std::abs(thhits - prevth) > dThCut) continue;
1088  // make a hit rms cut for small angle clusters
1089  ratOK = true;
1090  if (std::abs(slp) < fLAClusSlopeCut) {
1091  rmsrat = fHits[ih1].RMS() / hitrms;
1092  ratOK = rmsrat > 0.3 && rmsrat < 3;
1093  }
1094  else {
1095  // merge the hits
1096  bool didMerge;
1097  MergeHits(ih1, didMerge);
1098  }
1099  if (prt) mf::LogVerbatim("CC") << " rmsrat " << rmsrat << " OK? " << ratOK;
1100  // require small angle and not wildly different width compared
1101  // to the first hit in the cluster
1102  // TODO handle hit multiplets here
1103  if (ratOK) {
1104  dshits.push_back(ih1);
1105  hitAdded = true;
1106  prevth = thhits;
1107  ih0 = ih1;
1108  if (prt)
1109  mf::LogVerbatim("CC") << " Add hit " << fHits[ih1].WireID().Wire << ":"
1110  << (int)fHits[ih1].PeakTime() << " rmsrat " << rmsrat;
1111  break;
1112  }
1113  } // ih1
1114  // stop looking if no hit was added on this wire
1115  if (!hitAdded) break;
1116  } // ii
1117  // Found hits not associated with a different cluster
1118  if (dshits.size() > 0) {
1119  // put the tcl cluster into the working vectors
1120  TmpGet(icl);
1121  // clobber the hits
1122  fcl2hits.clear();
1123  // sort the DS hits
1124  if (dshits.size() > 1) std::sort(dshits.begin(), dshits.end(), SortByLowHit);
1125  // stuff them into fcl2hits
1126  fcl2hits = dshits;
1127  // Append the existing hits
1128  for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
1129  // un-assign the hits so that TmpStore will re-assign them
1130  iht = tcl[icl].tclhits[ii];
1131  inClus[iht] = 0;
1132  fcl2hits.push_back(iht);
1133  }
1134  clProcCode += 5000;
1135  pass = fNumPass - 1;
1136  FitClusterChg();
1137  clBeginChg = fAveChg;
1138  // declare the old one obsolete
1139  MakeClusterObsolete(icl);
1140  // add the new one
1141  if (!TmpStore()) {
1142  mf::LogError("CC") << "ChkClusterDS TmpStore failed while extending cluster ID "
1143  << tcl[icl].ID;
1144  continue;
1145  }
1146  const size_t newcl = tcl.size() - 1;
1147  if (prt) { mf::LogVerbatim("CC") << " Store " << newcl; }
1148  tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1149  tcl[newcl].EndVtx = tcl[icl].EndVtx;
1150  } // dshits.size() > 0
1151  } // icl
1152  } // ChkClusterDS
float fScaleF
scale factor from Tick/Wire to dx/du
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< std::pair< int, int > > WireHitRange
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
constexpr auto abs(T v)
Returns the absolute value of the argument.
void MergeHits(const unsigned int theHit, bool &didMerge)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
unsigned short fNumPass
number of passes over the hit collection
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
bool SortByLowHit(unsigned int i, unsigned int j)
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
void TmpGet(unsigned short it1)
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ChkClusterNearbyHits ( bool  prt)
private

Definition at line 4979 of file ClusterCrawlerAlg.cxx.

References util::abs(), recob::Hit::LocalIndex(), recob::Hit::Multiplicity(), recob::Hit::PeakTime(), and recob::Hit::RMS().

4980  {
4981  // analyze the hitnear vector
4982  // 0 = no nearby hit exists
4983  // 1 = a nearby hit exists but was not merged
4984  // -1 = a nearby hit was merged
4985 
4986  if (fHitMergeChiCut <= 0) return;
4987 
4988  if (hitNear.size() != fcl2hits.size()) {
4989  mf::LogWarning("CC") << "Coding error: hitNear size != fcl2hits";
4990  return;
4991  }
4992 
4993  // Analyze the last 6 hits added but don't consider the first few hits
4994  if (hitNear.size() < 12) return;
4995 
4996  // TODO move into loops
4997  unsigned short ii, indx;
4998  unsigned short merged = 0;
4999  unsigned short notmerged = 0;
5000  for (ii = 0; ii < 6; ++ii) {
5001  indx = hitNear.size() - 1 - ii;
5002  if (hitNear[indx] > 0) ++notmerged;
5003  if (hitNear[indx] < 0) ++merged;
5004  }
5005 
5006  if (prt)
5007  mf::LogVerbatim("CC") << "ChkClusterNearbyHits: nearby hits merged " << merged
5008  << " not merged " << notmerged;
5009 
5010  if (notmerged < 2) return;
5011 
5012  // a number of nearby hits were not merged while crawling, so the
5013  // average charge is probably wrong. Look at the last 6 hits added
5014  // and merge them if they are close
5015  bool didMerge;
5016  for (ii = 0; ii < 6; ++ii) {
5017  indx = fcl2hits.size() - 1 - ii;
5018  const unsigned int iht = fcl2hits[indx];
5019  recob::Hit const& hit = fHits[iht];
5020  if (hit.Multiplicity() == 2) {
5021  // quit if localindex does not make sense.
5022  if (hit.LocalIndex() != 0 && iht == 0) continue;
5023  // hit doublet. Get the index of the other hit
5024  unsigned int oht;
5025  if (hit.LocalIndex() == 0) { oht = iht + 1; }
5026  else {
5027  oht = iht - 1;
5028  } // hit.LocalIndex() == 0
5029  recob::Hit const& other_hit = fHits[oht];
5030  // TODO use Hit::TimeDistanceAsRMS()
5031  float hitSep = std::abs(hit.PeakTime() - other_hit.PeakTime());
5032  hitSep /= hit.RMS();
5033  if (hitSep < fHitMergeChiCut && inClus[oht] == 0) {
5034  if (prt)
5035  mf::LogVerbatim("CC") << "Merging hit doublet " << iht << " W:T "
5036  << fHits[iht].WireID().Wire << ":" << fHits[iht].PeakTime();
5037  MergeHits(iht, didMerge);
5038  if (didMerge) hitNear[indx] = -1;
5039  } // hitSep OK and not in a cluster
5040  } // hit doublet
5041  } // ii
5042 
5043  // now re-fit
5044  FitCluster();
5045  FitClusterChg();
5046 
5047  if (prt) mf::LogVerbatim("CC") << "ChkClusterNearbyHits refit cluster. fAveChg= " << fAveChg;
5048 
5049  } // ChkClusterHitNear()
short int LocalIndex() const
How well do we believe we know this hit?
Definition: Hit.h:266
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:234
constexpr auto abs(T v)
Returns the absolute value of the argument.
void MergeHits(const unsigned int theHit, bool &didMerge)
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:262
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
Detector simulation of raw signals on wires.
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ChkMerge ( )
private

Definition at line 2786 of file ClusterCrawlerAlg.cxx.

References util::abs(), and tca::DeadWireCount().

2787  {
2788  // Try to merge clusters. Clusters that have been subsumed in other
2789  // clusters, i.e. no longer valid, have ID < 0
2790 
2791  if (tcl.size() < 2) return;
2792  // The size of the ClusterStore vector will increase while merging
2793  // is on-going so the upper limit on it1 is fixed tcl.size() - 1
2794  // before merging starts
2795 
2796  prt = (fDebugPlane == (short)plane && fDebugWire < 0);
2797  if (prt) mf::LogVerbatim("CC") << "ChkMerge on pass " << pass;
2798 
2799  unsigned short it1, it2, nh1, pass1, pass2;
2800  float bs1, bth1, bt1, bc1, es1, eth1, et1, ec1;
2801  float bs2, bth2, bt2, bc2, es2, eth2, et2, ec2;
2802  int bw1, ew1, bw2, ew2, ndead;
2803  float dth, dw, angcut, chgrat, chgcut, dtim, timecut, bigslp;
2804  bool bothLong, NoVtx;
2805 
2806  int skipcut, tclsize = tcl.size();
2807  int maxOverlap = 3;
2808 
2809  for (it1 = 0; it1 < tclsize - 1; ++it1) {
2810  // ignore already merged clusters
2811  if (tcl[it1].ID < 0) continue;
2812  if (tcl[it1].CTP != clCTP) continue;
2813  bs1 = tcl[it1].BeginSlp;
2814  // convert slope to angle
2815  bth1 = std::atan(fScaleF * bs1);
2816  // more compact notation for begin/end, wire/time/chg/slp/theta, 1/2
2817  bw1 = tcl[it1].BeginWir;
2818  bt1 = tcl[it1].BeginTim;
2819  bc1 = tcl[it1].BeginChg;
2820  es1 = tcl[it1].EndSlp;
2821  eth1 = tcl[it1].EndAng;
2822  ew1 = tcl[it1].EndWir;
2823  et1 = tcl[it1].EndTim;
2824  ec1 = tcl[it1].EndChg;
2825  nh1 = tcl[it1].tclhits.size();
2826  pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2827  if (pass1 > fNumPass) pass1 = fNumPass;
2828  for (it2 = it1 + 1; it2 < tclsize; ++it2) {
2829  // ignore already merged clusters
2830  if (tcl[it1].ID < 0) continue;
2831  if (tcl[it2].ID < 0) continue;
2832  // only merge if they are in the right cryostat/TPC/plane
2833  if (tcl[it2].CTP != clCTP) continue;
2834  // Don't bother if these clusters, if merged, would fail the
2835  // cluster hit fraction cut
2836  if (!ChkMergedClusterHitFrac(it1, it2)) { continue; }
2837  bs2 = tcl[it2].BeginSlp;
2838  bth2 = std::atan(fScaleF * bs2);
2839  bw2 = tcl[it2].BeginWir;
2840  bt2 = tcl[it2].BeginTim;
2841  bc2 = tcl[it2].BeginChg;
2842  es2 = tcl[it2].EndSlp;
2843  eth2 = tcl[it2].EndAng;
2844  ew2 = tcl[it2].EndWir;
2845  et2 = tcl[it2].EndTim;
2846  ec2 = tcl[it2].EndChg;
2847  pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2848  if (pass2 > fNumPass) pass2 = fNumPass;
2849  // use the more promiscuous pass for cuts
2850  angcut = fKinkAngCut[pass1];
2851  if (fKinkAngCut[pass2] > angcut) angcut = fKinkAngCut[pass2];
2852  skipcut = fMaxWirSkip[pass1];
2853  if (fMaxWirSkip[pass2] > skipcut) skipcut = fMaxWirSkip[pass2];
2854  chgcut = fMergeChgCut[pass1];
2855  if (fMergeChgCut[pass2] > chgcut) chgcut = fMergeChgCut[pass2];
2856  // tweak the cuts for long straight tracks
2857  bothLong = (nh1 > 100 && tcl[it2].tclhits.size() > 100);
2858 
2859  // look for US and DS broken clusters w similar angle.
2860  // US cluster 2 merge with DS cluster 1?
2861  // This is the most likely occurrence given the order in which
2862  // clusters are created so put it first.
2863  dth = std::abs(bth2 - eth1);
2864  ndead = DeadWireCount(bw2, ew1);
2865  dw = ew1 - bw2 - ndead;
2866  // require no vertex between
2867  NoVtx = (tcl[it1].EndVtx < 0) && (tcl[it2].BeginVtx < 0);
2868  if (prt && bw2 < (ew1 + maxOverlap))
2869  mf::LogVerbatim("CC") << "Chk1 ID1-2 " << tcl[it1].ID << "-" << tcl[it2].ID << " " << ew1
2870  << ":" << (int)et1 << " " << bw2 << ":" << (int)bt2 << " dw " << dw
2871  << " ndead " << ndead << " skipcut " << skipcut << " dth " << dth
2872  << " angcut " << angcut;
2873  if (NoVtx && bw2 < (ew1 + maxOverlap) && dw < skipcut && dth < angcut) {
2874  chgrat = 2 * fabs(bc2 - ec1) / (bc2 + ec1);
2875  // ignore the charge cut for long tracks with small dth
2876  if (bothLong && dth < 0.05) chgrat = 0.;
2877  // project bw2,bt2 to ew1
2878  dtim = fabs(bt2 + (ew1 - bw2) * bs2 - et1);
2879  bigslp = std::abs(bs2);
2880  if (std::abs(es1) > bigslp) bigslp = std::abs(es1);
2881  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2882  if (prt)
2883  mf::LogVerbatim("CC") << " dtim " << dtim << " timecut " << (int)timecut << " ec1 "
2884  << ec1 << " bc2 " << bc2 << " chgrat " << chgrat << " chgcut "
2885  << chgcut << " es1 " << es1 << " ChkSignal "
2886  << ChkSignal(ew1, et1, bw2, bt2);
2887  if (chgrat < chgcut && dtim < timecut) {
2888  // ensure there is a signal between cluster ends
2889  if (ChkSignal(ew1, et1, bw2, bt2)) {
2890  DoMerge(it2, it1, 10);
2891  tclsize = tcl.size();
2892  break;
2893  }
2894  } // chgrat < chgcut ...
2895  } // US cluster 2 merge with DS cluster 1?
2896 
2897  // look for US and DS broken clusters w similar angle
2898  // US cluster 1 merge with DS cluster 2?
2899  dth = fabs(bth1 - eth2);
2900  ndead = DeadWireCount(bw1, ew2);
2901  dw = ew2 - bw1 - ndead;
2902  if (prt && bw1 < (ew2 + maxOverlap) && dw < skipcut)
2903  mf::LogVerbatim("CC") << "Chk2 ID1-2 " << tcl[it1].ID << "-" << tcl[it2].ID << " " << bw1
2904  << ":" << (int)bt1 << " " << bw2 << ":" << (int)et2 << " dw " << dw
2905  << " ndead " << ndead << " skipcut " << skipcut << " dth " << dth
2906  << " angcut " << angcut;
2907  // require no vertex between
2908  NoVtx = (tcl[it2].EndVtx < 0) && (tcl[it1].BeginVtx < 0);
2909  if (NoVtx && bw1 < (ew2 + maxOverlap) && dw < skipcut && dth < angcut) {
2910  chgrat = 2 * fabs((bc1 - ec2) / (bc1 + ec2));
2911  // ignore the charge cut for long tracks with small dth
2912  if (bothLong && dth < 0.05) chgrat = 0.;
2913  // project sw1,st1 to ew2
2914  dtim = std::abs(bt1 + (ew2 - bw1) * bs1 - et2);
2915  bigslp = std::abs(bs1);
2916  if (std::abs(bs2) > bigslp) bigslp = std::abs(bs2);
2917  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2918  if (prt)
2919  mf::LogVerbatim("CC") << " dtim " << dtim << " err " << dtim << " timecut "
2920  << (int)timecut << " chgrat " << chgrat << " chgcut " << chgcut
2921  << " ChkSignal " << ChkSignal(bw1, bt1, ew2, et2);
2922  // TODO: we should be checking for a signal here like we did above
2923  if (chgrat < chgcut && dtim < timecut) {
2924  if (ChkSignal(bw1, bt1, ew2, et2)) {
2925  DoMerge(it1, it2, 10);
2926  tclsize = tcl.size();
2927  break;
2928  }
2929  } // chgrat < chgcut ...
2930  } // US cluster 1 merge with DS cluster 2
2931 
2932  if (bw2 < bw1 && ew2 > ew1) {
2933  // look for small cl2 within the wire boundary of cl1
2934  // with similar times and slopes for both clusters
2935  dth = fabs(eth2 - eth1);
2936  dtim = fabs(et1 + (ew2 - ew1 - 1) * es1 - et2);
2937  bigslp = std::abs(es1);
2938  if (std::abs(es1) > bigslp) bigslp = std::abs(es1);
2939  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2940  // count the number of wires with no hits on cluster 1
2941  short nmiss1 = bw1 - ew1 + 1 - tcl[it1].tclhits.size();
2942  // compare with the number of hits in cluster 2
2943  short nin2 = tcl[it2].tclhits.size();
2944  if (prt)
2945  mf::LogVerbatim("CC") << "cl2: " << ew2 << ":" << (int)et2 << " - " << bw2 << ":"
2946  << (int)bt2 << " within cl1 " << ew1 << ":" << (int)et1 << " - "
2947  << bw1 << ":" << (int)bt1 << " ? dth " << dth << " dtim " << dtim
2948  << " nmissed " << nmiss1 << " timecut " << timecut
2949  << " FIX THIS CODE";
2950  // make rough cuts before calling ChkMerge12
2951  // this may not work well for long wandering clusters
2952  // TODO fix this code
2953  bool didit = false;
2954  if (dth < 1 && dtim < timecut && nmiss1 >= nin2) ChkMerge12(it1, it2, didit);
2955  if (didit) {
2956  tclsize = tcl.size();
2957  break;
2958  } //didit
2959  } // small cl2 within the wire boundary of cl1
2960 
2961  if (bw1 < bw2 && ew1 > ew2) {
2962  // look for small cl1 within the wire boundary of cl2
2963  // with similar times and slopes for both clusters
2964  dth = std::abs(eth2 - eth1);
2965  dtim = std::abs(et2 + (ew1 - ew2 - 1) * es2 - et1);
2966  bigslp = std::abs(es1);
2967  if (std::abs(es1) > bigslp) bigslp = std::abs(es1);
2968  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2969  // count the number of wires with no hits on cluster 2
2970  short nmiss2 = bw2 - ew2 + 1 - tcl[it2].tclhits.size();
2971  // compare with the number of hits in cluster 1
2972  short nin1 = tcl[it1].tclhits.size();
2973  if (prt)
2974  mf::LogVerbatim("CC") << "cl1: " << ew1 << ":" << (int)et1 << " - " << bw1 << ":"
2975  << (int)bt1 << " within cl2 " << ew2 << ":" << (int)et2 << " - "
2976  << bw2 << ":" << (int)bt2 << " ? dth " << dth << " dtim " << dtim
2977  << " nmissed " << nmiss2 << " timecut " << timecut
2978  << " FIX THIS CODE";
2979  // make rough cuts before calling ChkMerge12
2980  // this may not work well for long wandering clusters
2981  bool didit = false;
2982  if (dth < 1 && dtim < timecut && nmiss2 >= nin1) ChkMerge12(it2, it1, didit);
2983  if (didit) {
2984  tclsize = tcl.size();
2985  break;
2986  } // didit
2987  } // small cl1 within the wire boundary of cl2
2988 
2989  if (tcl[it1].ID < 0) break;
2990  } // cluster 2
2991  if (tcl[it1].ID < 0) continue;
2992  } // cluster 1
2993  }
float fScaleF
scale factor from Tick/Wire to dx/du
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
bool ChkSignal(unsigned int iht, unsigned int jht)
std::vector< float > fTimeDelta
max time difference for matching
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< unsigned short > fMaxWirSkip
max number of wires that can be skipped while crawling
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< float > fMergeChgCut
max charge ratio for matching
void DoMerge(unsigned short it1, unsigned short it2, short ProcCode)
unsigned short fNumPass
number of passes over the hit collection
if(nlines<=0)
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
void ChkMerge12(unsigned short it1, unsigned short it2, bool &didit)
bool ChkMergedClusterHitFrac(unsigned short it1, unsigned short it2)
void cluster::ClusterCrawlerAlg::ChkMerge12 ( unsigned short  it1,
unsigned short  it2,
bool &  didit 
)
private

Definition at line 2996 of file ClusterCrawlerAlg.cxx.

References util::abs(), cluster::ClusterCrawlerAlg::ClusterStore::EndWir, and cluster::ClusterCrawlerAlg::ClusterStore::tclhits.

2997  {
2998  // Calling routine has done a rough check that cluster it2 is a candidate
2999  // for merging with cluster it1. The wire range spanned by it2 lies
3000  // within the wire range of it1 and the clusters are reasonably close
3001  // together in time.
3002 
3003  // assume that no merging was done
3004  didit = false;
3005 
3006  if (prt) mf::LogVerbatim("CC") << "ChkMerge12 " << tcl[it1].ID << " " << tcl[it2].ID;
3007 
3008  ClusterStore& cl1 = tcl[it1];
3009  // fill a vector spanning the length of cluster 1 and filled with the hit
3010  // time
3011  int ew1 = tcl[it1].EndWir;
3012  int bw1 = tcl[it1].BeginWir;
3013  unsigned int iht, hit;
3014  int wire;
3015  std::vector<unsigned int> cl1hits(bw1 + 1 - ew1);
3016  // put in the hit IDs
3017  for (iht = 0; iht < cl1.tclhits.size(); ++iht) {
3018  hit = cl1.tclhits[iht];
3019  wire = fHits[hit].WireID().Wire;
3020  if (wire - ew1 < 0 || wire - ew1 > (int)cl1hits.size()) { return; }
3021  cl1hits[wire - ew1] = hit;
3022  }
3023  unsigned int ew2 = tcl[it2].EndWir;
3024  float et2 = tcl[it2].EndTim;
3025  // look for the closest wire with a hit on cluster 1
3026  unsigned int wiron1 = 0;
3027  // count the number of missing hits
3028  short nmiss = 0;
3029  for (wire = ew2 - 1; wire > ew1; --wire) {
3030  if (cl1hits[wire - ew1] > 0) {
3031  wiron1 = wire;
3032  break;
3033  }
3034  ++nmiss;
3035  } // wire
3036  if (prt) mf::LogVerbatim("CC") << "chk next US wire " << wiron1 << " missed " << nmiss;
3037  if (wiron1 == 0) return;
3038  if (nmiss > fMaxWirSkip[pass]) return;
3039 
3040  // compare the wires with hits on cluster 2 with the gap in cluster 1
3041  // the number of hit wires that fit in the gap
3042  unsigned int hiton2;
3043  int wiron2;
3044  unsigned short nfit = 0;
3045  for (iht = 0; iht < tcl[it2].tclhits.size(); ++iht) {
3046  hiton2 = tcl[it2].tclhits[iht];
3047  wiron2 = fHits[hiton2].WireID().Wire;
3048  if (wiron2 < ew1 || wiron2 > bw1) return;
3049  if (cl1hits[wiron2 - ew1] == 0) ++nfit;
3050  }
3051  // require complete filling of the gap
3052  if (nfit < tcl[it2].tclhits.size()) return;
3053 
3054  // decode the pass for both clusters and select the matching cuts
3055  unsigned short pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
3056  unsigned short pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
3057  unsigned short cpass = pass1;
3058  // use the tighter cuts
3059  if (pass2 < pass1) cpass = pass2;
3060 
3061  // ***** Check End of Cluster 2 matching with middle of cluster 1
3062  if ((int)wiron1 - ew1 < 0) return;
3063  unsigned int hiton1 = cl1hits[wiron1 - ew1];
3064  if (hiton1 > fHits.size() - 1) { return; }
3065  // check the time difference
3066  float timon1 = fHits[hiton1].PeakTime();
3067  float dtim = std::abs(et2 + (wiron1 - ew2) * tcl[it2].EndSlp - timon1);
3068  if (dtim > fTimeDelta[cpass]) return;
3069  // check the slope difference. First do a local fit on cluster 1 near
3070  // the matching point
3071  FitClusterMid(it1, hiton1, 3);
3072  if (clChisq > 20.) return;
3073  // fit parameters are now in clpar.
3074  // check for angle consistency
3075  float dth = std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].EndSlp));
3076  if (prt) mf::LogVerbatim("CC") << "US dtheta " << dth << " cut " << fKinkAngCut[cpass];
3077  if (dth > fKinkAngCut[cpass]) return;
3078  // make a charge ratio cut. fAveChg was calculated in FitClusterMid
3079  float chgrat = 2 * std::abs(fAveChg - tcl[it2].EndChg) / (fAveChg + tcl[it2].EndChg);
3080  if (prt) mf::LogVerbatim("CC") << "US chgrat " << chgrat << " cut " << fMergeChgCut[pass];
3081  // ensure that there is a signal on any missing wires at the US end of 1
3082  bool SigOK;
3083  SigOK = ChkSignal(wiron1, timon1, ew2, et2);
3084  if (prt) mf::LogVerbatim("CC") << "US SigOK? " << SigOK;
3085  if (!SigOK) return;
3086 
3087  // ***** Check Begin of Cluster 2 matching with middle of cluster 1
3088  unsigned int bw2 = tcl[it2].BeginWir;
3089  float bt2 = tcl[it2].BeginTim;
3090  nmiss = 0;
3091  wiron1 = 0;
3092  for (wire = bw2 + 1; wire < bw1; ++wire) {
3093  if (cl1hits[wire - ew1] > 0) {
3094  wiron1 = wire;
3095  break;
3096  }
3097  ++nmiss;
3098  }
3099  if (wiron1 == 0) return;
3100  if (nmiss > fMaxWirSkip[pass]) return;
3101  // fit this section of cluster 1 with 4 hits starting at the hit on the
3102  // closest wire and moving DS
3103  hiton1 = cl1hits[wiron1 - ew1];
3104  if (hiton1 > fHits.size() - 1) { return; }
3105  timon1 = fHits[hiton1].PeakTime();
3106  dtim = std::abs(bt2 - (wiron1 - bw2) * tcl[it2].BeginSlp - timon1);
3107  if (dtim > fTimeDelta[cpass]) return;
3108  FitClusterMid(it1, hiton1, -3);
3109  if (clChisq > 20.) return;
3110  // check for angle consistency
3111  dth = std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].BeginSlp));
3112  if (prt) mf::LogVerbatim("CC") << "DS dtheta " << dth << " cut " << fKinkAngCut[cpass];
3113  if (dth > fKinkAngCut[cpass]) return;
3114  // make a charge ratio cut
3115  chgrat = 2 * std::abs(fAveChg - tcl[it2].BeginChg) / (fAveChg + tcl[it2].BeginChg);
3116  if (prt) mf::LogVerbatim("CC") << "DS chgrat " << chgrat << " cut " << fMergeChgCut[pass];
3117  // ensure that there is a signal on any missing wires at the US end of 1
3118  SigOK = ChkSignal(wiron1, timon1, bw2, bt2);
3119  if (prt) mf::LogVerbatim("CC") << "DS SigOK? " << SigOK;
3120  if (!SigOK) return;
3121 
3122  if (prt) mf::LogVerbatim("CC") << "Merge em";
3123  // success. Merge them
3124  DoMerge(it1, it2, 100);
3125  didit = true;
3126  } // ChkMerge12()
float fScaleF
scale factor from Tick/Wire to dx/du
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
bool ChkSignal(unsigned int iht, unsigned int jht)
std::vector< float > fTimeDelta
max time difference for matching
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< unsigned short > fMaxWirSkip
max number of wires that can be skipped while crawling
std::vector< float > fMergeChgCut
max charge ratio for matching
void DoMerge(unsigned short it1, unsigned short it2, short ProcCode)
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
Detector simulation of raw signals on wires.
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
bool cluster::ClusterCrawlerAlg::ChkMergedClusterHitFrac ( unsigned short  it1,
unsigned short  it2 
)
private

Definition at line 4011 of file ClusterCrawlerAlg.cxx.

4012  {
4013  // This routine is called before two tcl clusters, it1 and it2, are slated to be
4014  // merged to see if they will satisfy the minimum hit fraction criterion
4015  if (it1 > tcl.size() - 1) return false;
4016  if (it2 > tcl.size() - 1) return false;
4017  unsigned int eWire = 99999;
4018  unsigned int bWire = 0, wire;
4019  if (tcl[it1].BeginWir > bWire) bWire = tcl[it1].BeginWir;
4020  if (tcl[it2].BeginWir > bWire) bWire = tcl[it2].BeginWir;
4021  if (tcl[it1].EndWir < eWire) eWire = tcl[it1].EndWir;
4022  if (tcl[it2].EndWir < eWire) eWire = tcl[it2].EndWir;
4023  unsigned int mergedClusterLength = bWire - eWire + 1;
4024  // define a vector of size = length of the wire range
4025  std::vector<bool> cHits(mergedClusterLength, false);
4026  // set the elements true if there is a hit
4027  unsigned int ii, iht, indx;
4028  for (ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
4029  iht = tcl[it1].tclhits[ii];
4030  if (iht > fHits.size() - 1) {
4031  mf::LogError("CC") << "ChkMergedClusterHitFrac bad iht ";
4032  return false;
4033  }
4034  indx = fHits[iht].WireID().Wire - eWire;
4035  cHits[indx] = true;
4036  } // ii
4037  for (ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
4038  iht = tcl[it2].tclhits[ii];
4039  if (iht > fHits.size() - 1) {
4040  mf::LogError("CC") << "ChkMergedClusterHitFrac bad iht ";
4041  return false;
4042  }
4043  indx = fHits[iht].WireID().Wire - eWire;
4044  cHits[indx] = true;
4045  } // ii
4046  // set cHits true if the wire is dead
4047  for (ii = 0; ii < cHits.size(); ++ii) {
4048  wire = eWire + ii;
4049  if (WireHitRange[wire].first == -1) cHits[ii] = true;
4050  }
4051  // count the number of wires with hits
4052  float nhits = std::count(cHits.begin(), cHits.end(), true);
4053  float hitFrac = nhits / (float)cHits.size();
4054  return (hitFrac > fMinHitFrac);
4055  } // ChkMergedClusterHitFrac
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< std::pair< int, int > > WireHitRange
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< recob::Hit > fHits
our version of the hits
bool cluster::ClusterCrawlerAlg::ChkSignal ( unsigned int  iht,
unsigned int  jht 
)
private

Definition at line 2565 of file ClusterCrawlerAlg.cxx.

2566  {
2567  if (iht > fHits.size() - 1) return false;
2568  if (jht > fHits.size() - 1) return false;
2569  unsigned int wire1 = fHits[iht].WireID().Wire;
2570  float time1 = fHits[iht].PeakTime();
2571  unsigned int wire2 = fHits[jht].WireID().Wire;
2572  float time2 = fHits[jht].PeakTime();
2573  return ChkSignal(wire1, time1, wire2, time2);
2574  } // ChkSignal
bool ChkSignal(unsigned int iht, unsigned int jht)
std::vector< recob::Hit > fHits
our version of the hits
bool cluster::ClusterCrawlerAlg::ChkSignal ( unsigned int  wire1,
float  time1,
unsigned int  wire2,
float  time2 
)
private

Definition at line 2577 of file ClusterCrawlerAlg.cxx.

References util::abs(), and bin.

2581  {
2582  // returns true if there is a signal on the line between
2583  // (wire1, time1) and (wire2, time2).
2584  // Be sure to set time1 < time2 if you are checking for signals on a single wire
2585 
2586  // Gaussian amplitude in bins of size 0.15
2587  const float gausAmp[20] = {1, 0.99, 0.96, 0.90, 0.84, 0.75, 0.67, 0.58, 0.49, 0.40,
2588  0.32, 0.26, 0.20, 0.15, 0.11, 0.08, 0.06, 0.04, 0.03, 0.02};
2589 
2590  // return true if fMinAmp is set ignore wire signal checking in this plane
2591  if (fMinAmp[plane] <= 0) return true;
2592 
2593  // get the begin and end right
2594  unsigned int wireb = wire1;
2595  float timeb = time1;
2596  unsigned int wiree = wire2;
2597  float timee = time2;
2598  // swap them?
2599  if (wiree > wireb) {
2600  wireb = wire2;
2601  timeb = time2;
2602  wiree = wire1;
2603  timee = time1;
2604  }
2605  if (wiree < fFirstWire || wiree > fLastWire) return false;
2606  if (wireb < fFirstWire || wireb > fLastWire) return false;
2607 
2608  int wire0 = wiree;
2609  // checking a single wire?
2610  float slope = 0;
2611  bool oneWire = false;
2612  float prTime, prTimeLo = 0, prTimeHi = 0;
2613  if (wireb == wiree) {
2614  oneWire = true;
2615  if (time1 < time2) {
2616  prTimeLo = time1;
2617  prTimeHi = time2;
2618  }
2619  else {
2620  prTimeLo = time2;
2621  prTimeHi = time1;
2622  }
2623  }
2624  else {
2625  slope = (timeb - timee) / (wireb - wiree);
2626  }
2627 
2628  int bin;
2629  unsigned short nmissed = 0;
2630  for (unsigned int wire = wiree; wire < wireb + 1; ++wire) {
2631  if (oneWire) { prTime = (prTimeLo + prTimeHi) / 2; }
2632  else {
2633  prTime = timee + (wire - wire0) * slope;
2634  }
2635  // skip dead wires
2636  if (WireHitRange[wire].first == -1) continue;
2637  // no hits on this wire
2638  if (WireHitRange[wire].first == -2) ++nmissed;
2639  unsigned int firsthit = WireHitRange[wire].first;
2640  unsigned int lasthit = WireHitRange[wire].second;
2641  float amp = 0;
2642  for (unsigned int khit = firsthit; khit < lasthit; ++khit) {
2643  if (oneWire) {
2644  // TODO: This sometimes doesn't work with overlapping hits
2645  // A not totally satisfactory solution
2646  if (prTime < fHits[khit].StartTick()) continue;
2647  if (prTime > fHits[khit].EndTick()) continue;
2648  return true;
2649  }
2650  else {
2651  // skip checking if we are far away from prTime on the positive side
2652  if (fHits[khit].PeakTime() - prTime > 500) continue;
2653  bin = std::abs(fHits[khit].PeakTime() - prTime) / fHits[khit].RMS();
2654  bin /= 0.15;
2655  if (bin > 19) continue;
2656  if (bin < 0) continue;
2657  // add amplitude from all hits
2658  amp += fHits[khit].PeakAmplitude() * gausAmp[bin];
2659  }
2660  } // khit
2661  if (amp < fMinAmp[plane]) ++nmissed;
2662  } // wire
2663  if (nmissed > fAllowNoHitWire) return false;
2664  return true;
2665 
2666  } // ChkSignal()
std::vector< std::pair< int, int > > WireHitRange
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< float > fMinAmp
expected minimum signal in each wire plane
unsigned int fLastWire
the last wire with a hit
float bin[41]
Definition: plottest35.C:14
std::vector< recob::Hit > fHits
our version of the hits
void cluster::ClusterCrawlerAlg::ChkVertex ( float  fvw,
float  fvt,
unsigned short  it1,
unsigned short  it2,
short  topo 
)
private

Definition at line 2365 of file ClusterCrawlerAlg.cxx.

References util::abs(), cluster::ClusterCrawlerAlg::VtxStore::CTP, cluster::ClusterCrawlerAlg::VtxStore::Fixed, cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::Topo, and cluster::ClusterCrawlerAlg::VtxStore::Wire.

2370  {
2371  // Checks the vertex (vw, fvt) against the existing set of vertices.
2372  // If there a match, clusters it1 and/or it2 are associated with it
2373  // if there is signal between the existing vertex and the start of
2374  // the cluster. The topo flag indicates the type of vertex that was
2375  // found: 1 = US of it1 && US of it2, 2 = US of it1 && DS of it2,
2376  // 3 = DS of it1 && US of it2, 4 = DS of it1 and DS of it2.
2377  // didit is set true if a cluster is attached to a (new or old) vertex
2378 
2379  if (vtxprt)
2380  mf::LogVerbatim("CC") << " ChkVertex " << tcl[it1].EndWir << ":" << (int)tcl[it1].EndTim
2381  << " - " << tcl[it1].BeginWir << ":" << (int)tcl[it1].BeginTim
2382  << " and " << tcl[it2].EndWir << ":" << (int)tcl[it2].EndTim << " - "
2383  << tcl[it2].BeginWir << ":" << (int)tcl[it2].BeginTim << " topo "
2384  << topo << " fvw " << fvw << " fvt " << fvt;
2385 
2386  unsigned int vw = (unsigned int)(0.5 + fvw);
2387  unsigned int iht;
2388 
2389  // don't make vertices using short tracks that are close to
2390  // long straight clusters. These are most likely due to numerous
2391  // short delta ray clusters
2392  if (tcl[it1].tclhits.size() < 10 && tcl[it2].tclhits.size() < 10) {
2393  for (unsigned short it = 0; it < tcl.size(); ++it) {
2394  if (it == it1 || it == it2) continue;
2395  if (tcl[it].ID < 0) continue;
2396  if (tcl[it].CTP != clCTP) continue;
2397  if (tcl[it].tclhits.size() < 100) continue;
2398  if (std::abs(tcl[it].BeginAng - tcl[it].EndAng) > 0.1) continue;
2399  // don't reject because it is near the end of a long cluster
2400  if (vw < tcl[it].EndWir + 5) continue;
2401  if (vw > tcl[it].BeginWir - 5) continue;
2402  for (unsigned short ii = 0; ii < tcl[it].tclhits.size(); ++ii) {
2403  iht = tcl[it].tclhits[ii];
2404  if (fHits[iht].WireID().Wire <= vw) {
2405  if (std::abs(fHits[iht].PeakTime() - fvt) < 60) return;
2406  } // fHits[iht].WireID().Wire <= vWire
2407  } // ii
2408  } // it
2409  }
2410 
2411  // check vertex and clusters for proximity to existing vertices
2412  unsigned short nFitOK = 0;
2413  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
2414  if (vtx[iv].CTP != clCTP) continue;
2415  // make this a really loose cut since the errors on the prospective vertex aren't known yet
2416  if (PointVertexChi(fvw, fvt, iv) > 300) continue;
2417  if (vtxprt)
2418  mf::LogVerbatim("CC") << " vtx " << iv << " PointVertexChi "
2419  << PointVertexChi(fvw, fvt, iv);
2420  // got a match. Check the appropriate cluster end and attach
2421  if ((topo == 1 || topo == 2) && tcl[it1].EndVtx < 0) {
2422  if (ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim)) {
2423  // try to fit
2424  tcl[it1].EndVtx = iv;
2425  FitVtx(iv);
2426  if (vtxprt)
2427  mf::LogVerbatim("CC") << " FitVtx " << iv << " WireErr " << vtx[iv].WireErr
2428  << " ChiDOF " << vtx[iv].ChiDOF;
2429  if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2430  else {
2431  // bad fit
2432  tcl[it1].EndVtx = -99;
2433  FitVtx(iv);
2434  } // check fit
2435  } // ChkSignal
2436  }
2437  else if ((topo == 3 || topo == 4) && tcl[it1].BeginVtx < 0) {
2438  if (ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim)) {
2439  tcl[it1].BeginVtx = iv;
2440  FitVtx(iv);
2441  if (vtxprt)
2442  mf::LogVerbatim("CC") << " FitVtx " << iv << " WireErr " << vtx[iv].WireErr
2443  << " ChiDOF " << vtx[iv].ChiDOF;
2444  if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2445  else {
2446  // bad fit
2447  tcl[it1].BeginVtx = -99;
2448  FitVtx(iv);
2449  } // bad fit
2450  } // ChkSignal
2451  } // cluster it2
2452  if ((topo == 1 || topo == 3) && tcl[it2].EndVtx < 0) {
2453  if (ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim)) {
2454  tcl[it2].EndVtx = iv;
2455  FitVtx(iv);
2456  if (vtxprt)
2457  mf::LogVerbatim("CC") << " FitVtx " << iv << " WireErr " << vtx[iv].WireErr
2458  << " ChiDOF " << vtx[iv].ChiDOF;
2459  if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2460  else {
2461  // bad fit
2462  tcl[it2].EndVtx = -99;
2463  FitVtx(iv);
2464  } // bad fit
2465  } // ChkSignal
2466  }
2467  else if ((topo == 2 || topo == 4) && tcl[it2].BeginVtx < 0) {
2468  if (ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim)) {
2469  tcl[it2].BeginVtx = iv;
2470  FitVtx(iv);
2471  if (vtxprt)
2472  mf::LogVerbatim("CC") << " FitVtx " << iv << " WireErr " << vtx[iv].WireErr
2473  << " ChiDOF " << vtx[iv].ChiDOF;
2474  if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2475  else {
2476  // bad fit
2477  tcl[it2].BeginVtx = -99;
2478  FitVtx(iv);
2479  } // bad fit
2480  } // ChkSignal
2481  } // cluster it2
2482  if (nFitOK > 0) {
2483  if (vtxprt) mf::LogVerbatim("CC") << " Attached " << nFitOK << " clusters to vertex " << iv;
2484  return;
2485  }
2486  } // iv
2487 
2488  // no match to existing vertices. Ensure that there is a wire signal between
2489  // the vertex and the appropriate ends of the clusters
2490  bool SigOK = false;
2491  if (topo == 1 || topo == 2) { SigOK = ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim); }
2492  else {
2493  SigOK = ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim);
2494  }
2495  if (!SigOK) return;
2496 
2497  if (topo == 1 || topo == 3) { SigOK = ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim); }
2498  else {
2499  SigOK = ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim);
2500  }
2501  if (!SigOK) return;
2502 
2503  VtxStore newvx;
2504  newvx.Wire = vw;
2505  newvx.Time = fvt;
2506  newvx.Topo = topo;
2507  newvx.CTP = clCTP;
2508  newvx.Fixed = false;
2509  vtx.push_back(newvx);
2510  unsigned short iv = vtx.size() - 1;
2511  if (topo == 1 || topo == 2) {
2512  if (tcl[it1].EndVtx >= 0) {
2513  vtx.pop_back();
2514  return;
2515  }
2516  tcl[it1].EndVtx = iv;
2517  }
2518  else {
2519  if (tcl[it1].BeginVtx >= 0) {
2520  vtx.pop_back();
2521  return;
2522  }
2523  tcl[it1].BeginVtx = iv;
2524  }
2525  if (topo == 1 || topo == 3) {
2526  if (tcl[it2].EndVtx >= 0) {
2527  vtx.pop_back();
2528  return;
2529  }
2530  tcl[it2].EndVtx = iv;
2531  }
2532  else {
2533  if (tcl[it2].BeginVtx >= 0) {
2534  vtx.pop_back();
2535  return;
2536  }
2537  tcl[it2].BeginVtx = iv;
2538  }
2539  // fit it
2540  FitVtx(iv);
2541  // reject it if the fit is bad
2542  if (vtx[iv].ChiDOF < 5 && vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].TimeErr < 20) {
2543  if (vtxprt)
2544  mf::LogVerbatim("CC") << " New vtx " << iv << " in plane " << plane << " topo " << topo
2545  << " cls " << tcl[it1].ID << " " << tcl[it2].ID << " W:T " << (int)vw
2546  << ":" << (int)fvt << " NClusters " << vtx[iv].NClusters;
2547  // Try to refine the cluster hits and vertex position
2549  }
2550  else {
2551  if (vtxprt)
2552  mf::LogVerbatim("CC") << " Bad vtx fit " << vtx[iv].ChiDOF << " wire err "
2553  << vtx[iv].WireErr << " TimeErr " << vtx[iv].TimeErr;
2554  // clobber the vertex and references to it
2555  vtx.pop_back();
2556  if (tcl[it1].BeginVtx == iv) tcl[it1].BeginVtx = -99;
2557  if (tcl[it1].EndVtx == iv) tcl[it1].EndVtx = -99;
2558  if (tcl[it2].BeginVtx == iv) tcl[it2].BeginVtx = -99;
2559  if (tcl[it2].EndVtx == iv) tcl[it2].EndVtx = -99;
2560  } // bad fit
2561 
2562  } // ChkVertex()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void RefineVertexClusters(unsigned short ivx)
float PointVertexChi(float wire, float tick, unsigned short ivx)
void cluster::ClusterCrawlerAlg::ClearResults ( )

Deletes all the results (might saves memory)

Note
The current implementation typically does NOT save memory.

Definition at line 142 of file ClusterCrawlerAlg.cxx.

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

143  {
144  fHits.clear();
145  tcl.clear();
146  vtx.clear();
147  vtx3.clear();
148  inClus.clear();
149  }
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
bool cluster::ClusterCrawlerAlg::ClusterHitsOK ( short  nHitChk)
private

Definition at line 4666 of file ClusterCrawlerAlg.cxx.

References lar::util::absDiff().

4667  {
4668  // Check StartTick and EndTick of hits on adjacent wires overlap as illustrated below.
4669  // >>>>>> This is OK
4670  // Wire StartTick EndTick
4671  // n |--------------|
4672  // n+1 |--------------|
4673  // n+2 |--------------|
4674  // >>>>>> This is NOT OK
4675  // n |------|
4676  // n+1 |-----|
4677  // n+2 |------|
4678 
4679  if (fcl2hits.size() == 0) return true;
4680 
4681  unsigned short nHitToChk = fcl2hits.size();
4682  if (nHitChk > 0) nHitToChk = nHitChk + 1;
4683  unsigned short ii, indx;
4684 
4685  // require that they overlap
4686  // add a tolerance to the StartTick - EndTick overlap
4687  raw::TDCtick_t tol = 30;
4688  // expand the tolerance for induction planes
4689  if (plane < wireReadoutGeom->Nplanes(geo::TPCID(cstat, tpc)) - 1) tol = 40;
4690 
4691  bool posSlope =
4692  (fHits[fcl2hits[0]].PeakTime() > fHits[fcl2hits[fcl2hits.size() - 1]].PeakTime());
4693 
4694  if (prt) {
4695  for (ii = 0; ii < nHitToChk; ++ii) {
4696  indx = fcl2hits.size() - 1 - ii;
4697  mf::LogVerbatim("CC") << "ClusterHitsOK chk " << fHits[fcl2hits[indx]].WireID().Wire
4698  << " start " << fHits[fcl2hits[indx]].StartTick() << " peak "
4699  << fHits[fcl2hits[indx]].PeakTime() << " end "
4700  << fHits[fcl2hits[indx]].EndTick() << " posSlope " << posSlope;
4701  }
4702  }
4703 
4704  raw::TDCtick_t hiStartTick, loEndTick;
4705  for (ii = 0; ii < nHitToChk - 1; ++ii) {
4706  indx = fcl2hits.size() - 1 - ii;
4707  // ignore if not on adjacent wires
4708  if (lar::util::absDiff(fHits[fcl2hits[indx]].WireID().Wire,
4709  fHits[fcl2hits[indx - 1]].WireID().Wire) > 1)
4710  continue;
4711  hiStartTick =
4712  std::max(fHits[fcl2hits[indx]].StartTick(), fHits[fcl2hits[indx - 1]].StartTick());
4713  loEndTick = std::min(fHits[fcl2hits[indx]].EndTick(), fHits[fcl2hits[indx - 1]].EndTick());
4714  if (posSlope) {
4715  if (loEndTick + tol < hiStartTick) { return false; }
4716  }
4717  else {
4718  if (loEndTick + tol < hiStartTick) { return false; }
4719  }
4720  } // ii
4721  return true;
4722  } // ClusterHitsOK
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
int TDCtick_t
Type representing a TDC tick.
Definition: RawTypes.h:25
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
The data type to uniquely identify a TPC.
Definition: geo_types.h:306
std::vector< recob::Hit > fHits
our version of the hits
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:69
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ClusterInit ( )
private

Definition at line 184 of file ClusterCrawlerAlg.cxx.

185  {
186  fcl2hits.clear();
187  chifits.clear();
188  hitNear.clear();
189  chgNear.clear();
190  fAveChg = -1.;
191  fAveHitWidth = -1;
192  clEndChg = -1.;
193  clStopCode = 0;
194  clProcCode = pass;
195  }
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
float fAveHitWidth
average width (EndTick - StartTick) of hits
float clEndChg
end average charge
std::vector< float > chifits
fit chisq for monitoring kinks, etc
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ClusterLoop ( )
private

Definition at line 288 of file ClusterCrawlerAlg.cxx.

References util::abs(), art::errors::LogicError, tca::MergeOverlap(), recob::Hit::PeakTime(), tca::PrintClusters(), tca::PrintHit(), and util::span().

289  {
290  // looks for seed clusters in a plane and crawls along a trail of hits
291 
292  unsigned int nHitsUsed = 0, iwire, jwire, kwire;
293  bool AllDone = false, SigOK = false, HitOK = false;
294  unsigned int ihit, jhit;
295  for (unsigned short thispass = 0; thispass < fNumPass; ++thispass) {
296  pass = thispass;
297  // look for a starting cluster that spans a block of wires
298  unsigned int span = 3;
299  if (fMinHits[pass] < span) span = fMinHits[pass];
300  for (iwire = fLastWire; iwire > fFirstWire + span; --iwire) {
301  // skip bad wires or no hits on the wire
302  if (WireHitRange[iwire].first < 0) continue;
303  auto ifirsthit = (unsigned int)WireHitRange[iwire].first;
304  auto ilasthit = (unsigned int)WireHitRange[iwire].second;
305  for (ihit = ifirsthit; ihit < ilasthit; ++ihit) {
306  bool ClusterAdded = false;
307  recob::Hit const& hit = fHits[ihit];
308  // skip used hits
309  if (ihit > fHits.size() - 1) {
310  mf::LogError("CC") << "ClusterLoop bad ihit " << ihit << " fHits size " << fHits.size();
311  return;
312  }
313  // skip used and obsolete hits
314  if (inClus[ihit] != 0) continue;
315  // skip narrow hits
316  if (fHits[ihit].PeakAmplitude() < fHitMinAmp) continue;
317  if ((iwire + 1) < span) continue;
318  jwire = iwire - span + 1;
319  if (prt)
320  mf::LogVerbatim("CC") << "Found debug hit " << PrintHit(ihit) << " on pass" << pass;
321  // skip if good wire and no hit
322  if (WireHitRange[jwire].first == -2) continue;
323  if (WireHitRange[jwire].first == -1) {
324  // Found a dead jwire. Keep looking upstream until we find a good wire
325  unsigned int nmissed = 0;
326  while (WireHitRange[jwire].first == -1 && jwire > 1 && nmissed < fMaxWirSkip[pass]) {
327  --jwire;
328  ++nmissed;
329  }
330  if (prt)
331  mf::LogVerbatim("CC")
332  << " new jwire " << jwire << " dead? " << WireHitRange[jwire].first;
333  if (WireHitRange[jwire].first < 0) continue;
334  } // dead jwire
335  // Find the hit on wire jwire that best matches a line between
336  // a nearby vertex and hit ihit. No constraint if useHit < 0
337  unsigned int useHit = 0;
338  bool doConstrain = false;
339  VtxConstraint(iwire, ihit, jwire, useHit, doConstrain);
340  unsigned int jfirsthit = (unsigned int)WireHitRange[jwire].first;
341  unsigned int jlasthit = (unsigned int)WireHitRange[jwire].second;
342  if (jfirsthit > fHits.size() - 1 || jfirsthit > fHits.size() - 1)
344  << "ClusterLoop jwire " << jwire << " bad firsthit " << jfirsthit << " lasthit "
345  << jlasthit << " fhits size " << fHits.size();
346  for (jhit = jfirsthit; jhit < jlasthit; ++jhit) {
347  if (jhit > fHits.size() - 1)
349  << "ClusterLoop bad jhit " << jhit << " firsthit " << jfirsthit << " lasthit "
350  << jlasthit << " fhits size" << fHits.size();
351  // Constraint?
352  if (doConstrain && jhit != useHit) continue;
353  recob::Hit const& other_hit = fHits[jhit];
354  // skip used and obsolete hits
355  if (inClus[jhit] != 0) continue;
356  // skip narrow hits
357  if (fHits[jhit].PeakAmplitude() < fHitMinAmp) continue;
358  // start a cluster with these two hits
359  ClusterInit();
360  fcl2hits.push_back(ihit);
361  chifits.push_back(0.);
362  hitNear.push_back(0);
363  chgNear.push_back(0); // These will be defined if the cluster survives the cuts
364  // enter the jhit
365  fcl2hits.push_back(jhit);
366  chifits.push_back(0.);
367  hitNear.push_back(0);
368  chgNear.push_back(0);
369  clLA = false;
370  clpar[0] = other_hit.PeakTime();
371  clpar[1] = (hit.PeakTime() - other_hit.PeakTime()) / (iwire - jwire);
372  // increase slope errors for large angle clusters
373  clparerr[1] = 0.2 * std::abs(clpar[1]);
374  clpar[2] = fHits[jhit].WireID().Wire;
375  clChisq = 0;
376  // now look for hits to add on the intervening wires
377  bool clok = false;
378  for (kwire = jwire + 1; kwire < iwire; ++kwire) {
379  // ensure this cluster doesn't cross a vertex
380  if (CrawlVtxChk(kwire)) {
381  clok = false;
382  break;
383  }
384  AddHit(kwire, HitOK, SigOK);
385  if (prt)
386  mf::LogVerbatim("CC") << " HitOK " << HitOK << " clChisq " << clChisq << " cut "
387  << fChiCut[pass] << " ClusterHitsOK " << ClusterHitsOK(-1);
388  // No hit found
389  if (!HitOK) break;
390  // This should be a really good chisq
391  if (clChisq > 2) break;
392  // hit widths & overlap not consistent
393  if (!ClusterHitsOK(-1)) continue;
394  clok = true;
395  }
396  // drop it?
397  if (!clok) continue;
398  prt = (fDebugPlane == (int)plane && (int)iwire == fDebugWire &&
399  std::abs((int)hit.PeakTime() - fDebugHit) < 20);
400  if (prt)
401  mf::LogVerbatim("CC")
402  << "ADD >>>>> Starting cluster with hits " << PrintHit(fcl2hits[0]) << " "
403  << PrintHit(fcl2hits[1]) << " " << PrintHit(fcl2hits[2]) << " on pass " << pass;
404  // save the cluster begin info
405  clBeginWir = iwire;
406  clBeginTim = hit.PeakTime();
407  clBeginSlp = clpar[1];
408  // don't do a small angle crawl if the cluster slope is too large
409  // and Large Angle crawling is NOT requested on this pass
410  if (!fLACrawl[pass] && std::abs(clBeginSlp) > fLAClusSlopeCut) continue;
411  // See if we are trying to start a cluster between a vertex
412  // and a cluster that is associated to that vertex. If so, skip it
413  if (CrawlVtxChk2()) continue;
414  clBeginSlpErr = clparerr[1];
415  clBeginChg = 0;
416  // Calculate the average width
417  fAveHitWidth = 0;
418  for (unsigned short kk = 0; kk < fcl2hits.size(); ++kk) {
419  fAveHitWidth += fHits[fcl2hits[kk]].EndTick() - fHits[fcl2hits[kk]].StartTick();
420  }
421  fAveHitWidth /= (float)fcl2hits.size();
422  // decide whether to crawl a large angle cluster. Requirements are:
423  // 1) the user has set the LACluster angle cut > 0, AND
424  // 2) the cluster slope exceeds the cut
425  // Note that if condition 1 is met, normal cluster crawling is done
426  // only if the slope is less than the cut
427  if (fLACrawl[pass] && fLAClusSlopeCut > 0) {
428  // LA cluster crawling requested
430  else {
431  CrawlUS();
432  } // std::abs(clBeginSlp) > fLAClusAngleCut
433  }
434  else {
435  // allow clusters of any angle
436  CrawlUS();
437  } // fLAClusSlopeCut > 0
438  if (fcl2hits.size() >= fMinHits[pass]) {
439  // it's long enough so save it
440  clEndSlp = clpar[1]; // save the slope at the end
441  clEndSlpErr = clparerr[1];
442  // store the cluster
443  if (!TmpStore()) {
444  mf::LogError("CC") << "Failed to store cluster in plane " << plane;
445  continue;
446  }
447  ClusterAdded = true;
448  nHitsUsed += fcl2hits.size();
449  AllDone = (nHitsUsed == fHits.size());
450  break;
451  }
452  else {
453  // abandon it
454  if (prt) mf::LogVerbatim("CC") << "ClusterLoop: dropped the cluster";
455  }
456  if (ClusterAdded || AllDone) break;
457  } // jhit
458  if (AllDone) break;
459  } // ihit
460  if (AllDone) break;
461  } // iwire
462 
463  // try to merge clusters
464  if (fDoMerge[pass]) ChkMerge();
465  // form 2D vertices
466  if (fFindVertices[pass]) FindVertices();
467 
468  if (AllDone) break;
469 
470  } // pass
471 
472  // Kill Garbage clusters
473  if (fKillGarbageClusters > 0 && !tcl.empty()) KillGarbageClusters();
474  // Merge overlapping clusters
476  // Check the DS end of clusters
478  // split clusters using vertices
479  if (fVtxClusterSplit) {
480  bool didSomething = VtxClusterSplit();
481  // iterate once to handle the case where a cluster crosses two vertices
482  if (didSomething) VtxClusterSplit();
483  }
484  // Look for 2D vertices with star topology - short, back-to-back clusters
486 
487  if (fDebugPlane == (int)plane) {
488  mf::LogVerbatim("CC") << "Clustering done in plane " << plane;
489  PrintClusters();
490  }
491 
493 
494  } // ClusterLoop()
std::vector< short > hitNear
bool ClusterHitsOK(short nHitChk)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< std::pair< int, int > > WireHitRange
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
float clEndSlp
slope at the end (= US end = low wire number)
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< unsigned short > fMaxWirSkip
max number of wires that can be skipped while crawling
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fAveHitWidth
average width (EndTick - StartTick) of hits
bool CrawlVtxChk(unsigned int kwire)
float fHitMinAmp
< ignore hits with Amp < this value
int fDebugHit
out detailed information while crawling
std::vector< bool > fLACrawl
Crawl Large Angle clusters on pass?
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< std::invoke_result_t< Adaptor, IterB >, std::invoke_result_t< Adaptor, IterE >>
unsigned int fLastWire
the last wire with a hit
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
unsigned short fNumPass
number of passes over the hit collection
float fMergeOverlapAngCut
angle cut for merging overlapping clusters
unsigned int fFirstWire
the first wire with a hit
void VtxConstraint(unsigned int iwire, unsigned int ihit, unsigned int jwire, unsigned int &useHit, bool &doConstrain)
std::vector< bool > fFindVertices
run vertexing code after clustering?
float clBeginSlp
begin slope (= DS end = high wire number)
std::string PrintHit(unsigned int iht)
Detector simulation of raw signals on wires.
float clChisq
chisq of the current fit
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool clLA
using Large Angle crawling code
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
std::vector< unsigned short > fMinHits
Min number of hits to make a cluster.
std::vector< float > chifits
fit chisq for monitoring kinks, etc
unsigned int clBeginWir
begin wire
void AddHit(unsigned int kwire, bool &HitOK, bool &SigOK)
std::vector< float > chgNear
charge near a cluster on each wire
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:82
std::vector< bool > fDoMerge
try to merge clusters?
void cluster::ClusterCrawlerAlg::ClusterVertex ( unsigned short  it2)
private

Definition at line 2268 of file ClusterCrawlerAlg.cxx.

References util::abs().

2269  {
2270  // try to attach cluster it to an existing vertex
2271 
2272  if (vtx.size() == 0) return;
2273 
2274  unsigned short iv, jv;
2275  short dwib, dwjb, dwie, dwje;
2276  bool matchEnd, matchBegin;
2277 
2278  for (iv = 0; iv < vtx.size(); ++iv) {
2279  // ignore vertices in the wrong cryostat/TPC/Plane
2280  if (vtx[iv].CTP != clCTP) continue;
2281  // ignore deleted vertices
2282  if (vtx[iv].NClusters == 0) continue;
2283  // determine which end to match - begin or end. Handle short tracks
2284  matchEnd = false;
2285  matchBegin = false;
2286  if (tcl[it].tclhits.size() < 6) {
2287  // See which end is closer to this vertex vs other vertices
2288  dwib = std::abs(vtx[iv].Wire - tcl[it].BeginWir);
2289  if (dwib > 2) dwib = 2;
2290  dwie = std::abs(vtx[iv].Wire - tcl[it].EndWir);
2291  if (dwie > 2) dwie = 2;
2292  dwjb = 999;
2293  dwje = 999;
2294  for (jv = 0; jv < vtx.size(); ++jv) {
2295  if (iv == jv) continue;
2296  if (std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50) {
2297  if (std::abs(vtx[jv].Wire - tcl[it].BeginWir) < dwjb)
2298  dwjb = std::abs(vtx[jv].Wire - tcl[it].BeginWir);
2299  } // std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50
2300  if (std::abs(vtx[jv].Time - tcl[it].EndTim) < 50) {
2301  if (std::abs(vtx[jv].Wire - tcl[it].EndWir) < dwje)
2302  dwje = std::abs(vtx[jv].Wire - tcl[it].EndWir);
2303  } // std::abs(vtx[jv].Time - tcl[it].EndTim) < 50
2304  } // jv
2305  matchEnd = tcl[it].EndVtx != iv && dwie < 3 && dwie < dwje && dwie < dwib;
2306  matchBegin = tcl[it].BeginVtx != iv && dwib < 3 && dwib < dwjb && dwib < dwie;
2307  }
2308  else {
2309  matchEnd = tcl[it].EndVtx < 0 && vtx[iv].Wire <= tcl[it].EndWir + 2;
2310  matchBegin = tcl[it].BeginVtx < 0 && vtx[iv].Wire >= tcl[it].BeginWir - 2;
2311  }
2312  if (matchEnd) {
2313  if (vtxprt)
2314  mf::LogVerbatim("CC") << " Match End chi " << ClusterVertexChi(it, 1, iv) << " to vtx "
2315  << iv << " signalOK "
2316  << ChkSignal(
2317  vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim);
2318  if (ClusterVertexChi(it, 1, iv) < fVertex2DCut &&
2319  ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim)) {
2320  // good match
2321  tcl[it].EndVtx = iv;
2322  // re-fit it
2323  FitVtx(iv);
2324  if (vtxprt)
2325  mf::LogVerbatim("CC") << " Add End " << tcl[it].ID << " to vtx " << iv << " NClusters "
2326  << vtx[iv].NClusters;
2327  if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut) return;
2328  if (vtxprt)
2329  mf::LogVerbatim("CC") << " Bad fit. ChiDOF " << vtx[iv].ChiDOF << " WireErr "
2330  << vtx[iv].WireErr << " Undo it";
2331  tcl[it].EndVtx = -99;
2332  FitVtx(iv);
2333  } // tChi < 3
2334  } // matchEnd
2335 
2336  if (matchBegin) {
2337  if (vtxprt)
2338  mf::LogVerbatim("CC") << " Match Begin chi " << ClusterVertexChi(it, 0, iv) << " to vtx "
2339  << iv << " signalOK "
2340  << ChkSignal(vtx[iv].Wire,
2341  vtx[iv].Time,
2342  tcl[it].BeginWir,
2343  tcl[it].BeginTim);
2344  if (ClusterVertexChi(it, 0, iv) < fVertex2DCut &&
2345  ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].BeginWir, tcl[it].BeginTim)) {
2346  // good match
2347  tcl[it].BeginVtx = iv;
2348  // re-fit it
2349  FitVtx(iv);
2350  if (vtxprt)
2351  mf::LogVerbatim("CC") << " Add Begin " << tcl[it].ID << " to vtx " << iv
2352  << " NClusters " << vtx[iv].NClusters;
2353  if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut) return;
2354  if (vtxprt)
2355  mf::LogVerbatim("CC") << " Bad fit. ChiDOF " << vtx[iv].ChiDOF << " WireErr "
2356  << vtx[iv].WireErr << " Undo it";
2357  tcl[it].BeginVtx = -99;
2358  FitVtx(iv);
2359  } // tChi < 3
2360  } // matchBegin
2361  } // iv
2362  } // ClusterVertex()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
float fVertex2DCut
2D vtx -> cluster matching cut (chisq/dof)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
float cluster::ClusterCrawlerAlg::ClusterVertexChi ( short  icl,
unsigned short  end,
unsigned short  ivx 
)
private

Definition at line 6174 of file ClusterCrawlerAlg.cxx.

References E.

6175  {
6176  // Returns the chisq/DOF between a cluster and a vertex
6177 
6178  if (icl > (short)tcl.size()) return 9999;
6179  if (ivx > vtx.size()) return 9999;
6180 
6181  float cwire, cslp, cslpErr, ctick;
6182  // figure out which cluster to use
6183  if (icl < 0) {
6184  if (fcl2hits.size() == 0) return 9999;
6185  // cluster under construction
6186  if (end == 0) {
6187  cwire = clBeginWir;
6188  cslp = clBeginSlp;
6189  cslpErr = clBeginSlpErr;
6190  ctick = clBeginTim;
6191  }
6192  else {
6193  cwire = clpar[2];
6194  cslp = clpar[1];
6195  cslpErr = clparerr[1];
6196  ctick = clpar[0];
6197  } // end
6198  }
6199  else {
6200  // tcl cluster
6201  if (end == 0) {
6202  cwire = tcl[icl].BeginWir;
6203  cslp = tcl[icl].BeginSlp;
6204  cslpErr = tcl[icl].BeginSlpErr;
6205  ctick = tcl[icl].BeginTim;
6206  }
6207  else {
6208  cwire = tcl[icl].EndWir;
6209  cslp = tcl[icl].EndSlp;
6210  cslpErr = tcl[icl].EndSlpErr;
6211  ctick = tcl[icl].EndTim;
6212  } // end
6213  }
6214 
6215  // Closest approach wire
6216  float docaW =
6217  (vtx[ivx].Wire + cslp * (vtx[ivx].Time - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6218  float dW = docaW - vtx[ivx].Wire;
6219  float chi = dW / vtx[ivx].WireErr;
6220  float totChi = chi * chi;
6221  dW = vtx[ivx].Wire - cwire;
6222  float dT = ctick + dW * cslp - vtx[ivx].Time;
6223  if (cslpErr < 1E-3) cslpErr = 1E-3;
6224  // increase slope error for large angle clusters
6225  cslpErr *= AngleFactor(cslp);
6226  // cluster slope projection error
6227  float dTErr = dW * cslpErr;
6228  // squared
6229  dTErr *= dTErr;
6230  // add the vertex time error^2 to the cluster projection error^2
6231  dTErr += vtx[ivx].TimeErr * vtx[ivx].TimeErr;
6232  if (dTErr < 1E-3) dTErr = 1E-3;
6233  totChi += dT * dT / dTErr;
6234  totChi /= 2;
6235 
6236  return totChi;
6237 
6238  } // ClusterVertexChi
std::vector< ClusterStore > tcl
the clusters we are creating
float clparerr[2]
cluster parameter errors
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
Float_t E
Definition: plot.C:20
float clBeginSlp
begin slope (= DS end = high wire number)
unsigned int clBeginWir
begin wire
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::CrawlInit ( )
private

Definition at line 152 of file ClusterCrawlerAlg.cxx.

153  {
154  prt = false;
155  vtxprt = false;
156  NClusters = 0;
157  clBeginSlp = 0;
158  clBeginSlpErr = 0;
159  clBeginTim = 0;
160  clBeginWir = 0;
161  clBeginChg = 0;
162  clBeginChgNear = 0;
163  clEndSlp = 0;
164  clEndSlpErr = 0;
165  clEndTim = 0;
166  clEndWir = 0;
167  clEndChg = 0;
168  clEndChgNear = 0;
169  clChisq = 0;
170  clStopCode = 0;
171  clProcCode = 0;
172  fFirstWire = 0;
173  fLastWire = 0;
174  fAveChg = 0.;
175  fChgSlp = 0.;
176  pass = 0;
177  fScaleF = 0;
178  WireHitRange.clear();
179 
180  ClearResults();
181  }
float fScaleF
scale factor from Tick/Wire to dx/du
float fAveChg
average charge at leading edge of cluster
std::vector< std::pair< int, int > > WireHitRange
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
unsigned int fLastWire
the last wire with a hit
unsigned int fFirstWire
the first wire with a hit
unsigned int clEndWir
begin wire
float clBeginSlp
begin slope (= DS end = high wire number)
float clChisq
chisq of the current fit
float clEndChg
end average charge
unsigned int clBeginWir
begin wire
float clBeginChgNear
nearby charge
float clEndChgNear
nearby charge
float fChgSlp
slope of the charge vs wire
void cluster::ClusterCrawlerAlg::CrawlUS ( )
private

Definition at line 3688 of file ClusterCrawlerAlg.cxx.

References util::abs().

3689  {
3690  // Crawl along a trail of hits moving upstream
3691 
3692  if (fcl2hits.size() < 2) return;
3693 
3694  unsigned int dhit = fcl2hits[0];
3695  int dwir = fHits[dhit].WireID().Wire;
3696  clLA = false;
3697 
3698  prt = false;
3699  if (fDebugPlane == (short)plane && dwir == fDebugWire && fDebugHit > 0)
3700  prt = std::abs(fHits[dhit].PeakTime() - fDebugHit) < 20;
3701 
3702  if (prt) {
3703  mf::LogVerbatim myprt("CC");
3704  myprt << "******************* Start CrawlUS on pass " << pass << " Hits: ";
3705  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3706  unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3707  myprt << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime() << " ";
3708  }
3709  myprt << "\n";
3710  }
3711 
3712  // SigOK = true if there is a ADC signal near the projected cluster position
3713  bool SigOK = true;
3714  bool HitOK = true;
3715  // count the number of missed hits on adjacent wires
3716  short nmissed = 0;
3717  // count the number of added hits after skipping
3718  short nHitAfterSkip = 0;
3719  bool DidaSkip = false;
3720  bool PostSkip = false;
3721  unsigned int it = fcl2hits.size() - 1;
3722  unsigned int lasthit = fcl2hits[it];
3723  if (lasthit > fHits.size() - 1) {
3724  mf::LogError("CC") << "CrawlUS bad lasthit " << lasthit;
3725  return;
3726  }
3727  unsigned int lastwire = fHits[lasthit].WireID().Wire;
3728  if (prt) mf::LogVerbatim("CC") << "CrawlUS: last wire " << lastwire << " hit " << lasthit;
3729 
3730  unsigned int lastWireWithSignal = lastwire;
3731  unsigned short nDroppedHit = 0;
3732 
3733  for (unsigned int nextwire = lastwire - 1; nextwire > fFirstWire; --nextwire) {
3734  if (prt)
3735  mf::LogVerbatim("CC") << "CrawlUS: next wire " << nextwire << " HitRange "
3736  << WireHitRange[nextwire].first;
3737  // stop crawling if there is a nearby vertex
3738  if (CrawlVtxChk(nextwire)) {
3739  if (prt) mf::LogVerbatim("CC") << "CrawlUS: stop at vertex";
3740  clStopCode = 6;
3741  break;
3742  }
3743  // Switch to large angle crawling?
3744  if (std::abs(clpar[1]) > fLAClusSlopeCut) {
3745  if (prt) mf::LogVerbatim("CC") << ">>>>> CrawlUS: Switching to LACrawlUS";
3746  LACrawlUS();
3747  return;
3748  }
3749  // add hits and check for PH and width consistency
3750  AddHit(nextwire, HitOK, SigOK);
3751  if (prt)
3752  mf::LogVerbatim("CC") << "CrawlUS: HitOK " << HitOK << " SigOK " << SigOK << " nmissed "
3753  << nmissed;
3754  if (SigOK) lastWireWithSignal = nextwire;
3755  if (!HitOK) {
3756  // no hit on this wire. Was there a signal or dead wire?
3757  if (SigOK) {
3758  // no hit on the wire but there is a signal
3759  ++nmissed;
3760  // see if we are in the PostSkip phase and missed more than 1 wire
3761  if (PostSkip && nmissed > fMinWirAfterSkip[pass]) {
3762  // cluster is really short
3763  if ((int)(fcl2hits.size() - nHitAfterSkip) < 4) {
3764  fcl2hits.clear();
3765  return;
3766  }
3767  if (prt) mf::LogVerbatim("CC") << " PostSkip && nmissed = " << nmissed;
3768  clStopCode = 2;
3769  FclTrimUS(nHitAfterSkip);
3770  FitCluster();
3771  if (clChisq > 90.) {
3772  fcl2hits.clear();
3773  return;
3774  }
3775  FitCluster();
3776  return;
3777  } // PostSkip && nmissed >
3778  if (nmissed > 1) {
3779  DidaSkip = true;
3780  PostSkip = false;
3781  }
3782  } // SigOK
3783  else {
3784  // SigOK is false
3785  clStopCode = 0;
3786  lasthit = fcl2hits[fcl2hits.size() - 1];
3787  if ((lastWireWithSignal - nextwire) > fAllowNoHitWire) {
3788  if (prt)
3789  mf::LogVerbatim("CC")
3790  << "No hit or signal on wire " << nextwire << " last wire with signal "
3791  << lastWireWithSignal << " exceeding fAllowNoHitWire " << fAllowNoHitWire
3792  << " Break!";
3793  break;
3794  }
3795  } // else SigOK false
3796  } // !HitOK
3797  else {
3798  if (prt)
3799  mf::LogVerbatim("CC") << " CrawlUS check clChisq " << clChisq << " cut " << fChiCut[pass];
3800  if (clChisq > fChiCut[pass]) {
3801  if (fcl2hits.size() < 3) {
3802  fcl2hits.clear();
3803  return;
3804  }
3805  // a fit error occurred. Lop off the leading hit and refit
3806  if (prt) mf::LogVerbatim("CC") << "ADD- Bad clChisq " << clChisq << " dropping hit";
3807  FclTrimUS(1);
3808  FitCluster();
3809  ++nDroppedHit;
3810  if (nDroppedHit > 4) {
3811  if (prt)
3812  mf::LogVerbatim("CC")
3813  << " Too many dropped hits: " << nDroppedHit << " Stop crawling";
3814  break;
3815  } // too many dropped hits
3816  if (clChisq > fChiCut[pass]) {
3817  if (prt)
3818  mf::LogVerbatim("CC")
3819  << " Bad clChisq " << clChisq << " after dropping hit. Stop crawling";
3820  break;
3821  }
3822  FitClusterChg();
3823  continue;
3824  } // clChisq > fChiCut[0]
3825  // monitor the onset of a kink. Look for a progressive increase
3826  // in chisq for the previous 0 - 2 hits.
3827  if (chifits.size() > 5 && fKinkChiRat[pass] > 0) {
3828  if (chifits.size() != fcl2hits.size()) {
3829  mf::LogError("CC") << "CrawlUS: chifits size error " << chifits.size() << " "
3830  << fcl2hits.size();
3831  return;
3832  }
3833  unsigned short chsiz = chifits.size() - 1;
3834  if (prt)
3835  mf::LogVerbatim("CC") << "Kink chk " << chifits[chsiz] << " " << chifits[chsiz - 1]
3836  << " " << chifits[chsiz - 2] << " " << chifits[chsiz - 3];
3837  if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3838  chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3839  if (fcl2hits.size() != chifits.size()) {
3840  mf::LogError("CC") << "bad kink check size " << chifits.size() << " "
3841  << fcl2hits.size() << " plane " << plane << " cluster " << dwir
3842  << ":" << dhit;
3843  continue;
3844  }
3845  if (EndKinkAngle() > fKinkAngCut[pass]) {
3846  if (prt)
3847  mf::LogVerbatim("CC")
3848  << "******************* Stopped tracking - kink angle " << EndKinkAngle() << " > "
3849  << fKinkAngCut[pass] << " Removing 3 hits";
3850  // kill the last 3 hits and refit
3851  FclTrimUS(3);
3852  FitCluster();
3853  FitClusterChg();
3854  } // kinkang check
3855  } // chifits check
3856  } // chifits.size() > 5
3857  // done with kink check
3858  // update the cluster Begin information?
3859  if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
3860  clBeginSlp = clpar[1];
3861  clBeginSlpErr = clparerr[1];
3862  }
3863  // define the begin cluster charge if it's not defined yet
3864  if (clBeginChg <= 0 && fAveChg > 0) {
3865  clBeginChg = fAveChg;
3866  if (prt) mf::LogVerbatim("CC") << " Set clBeginChg " << clBeginChg;
3867  }
3868  // reset nmissed
3869  nmissed = 0;
3870  // start counting hits added after skipping
3871  if (DidaSkip) {
3872  // start PostSkip phase
3873  PostSkip = true;
3874  DidaSkip = false;
3875  nHitAfterSkip = 0;
3876  } // DidaSkip
3877  // check for PostSkip phase
3878  if (PostSkip) {
3879  // end the PostSkip phase if there are enough hits
3880  ++nHitAfterSkip;
3881  if (nHitAfterSkip == fMinWirAfterSkip[pass]) PostSkip = false;
3882  }
3883  // check for bad chisq
3884  if (clChisq > fChiCut[pass]) {
3885  if (prt) mf::LogVerbatim("CC") << "<<ADD- Bad chisq " << clChisq;
3886  // remove the last few hits if there is a systematic increase in chisq and re-fit
3887  float chirat;
3888  unsigned short lopped = 0;
3889  for (unsigned short nlop = 0; nlop < 4; ++nlop) {
3890  unsigned short cfsize = chifits.size() - 1;
3891  chirat = chifits[cfsize] / chifits[cfsize - 1];
3892  if (prt)
3893  mf::LogVerbatim("CC")
3894  << "chirat " << chirat << " last hit " << fcl2hits[fcl2hits.size() - 1];
3895  if (chirat < 1.2) break;
3896  if (prt) mf::LogVerbatim("CC") << "<<ADD- Bad chisq. Bad chirat " << chirat;
3897  FclTrimUS(1);
3898  ++lopped;
3899  if (fcl2hits.size() < 6) break;
3900  if (chifits.size() < 6) break;
3901  } // nlop
3902  if (fcl2hits.size() < 6) {
3903  clStopCode = 4;
3904  if (prt) mf::LogVerbatim("CC") << "Bad fit chisq - short cluster. Break";
3905  break;
3906  }
3907  if (lopped == 0 && fcl2hits.size() > 5) {
3908  if (prt) mf::LogVerbatim("CC") << "<<ADD- Bad chisq. remove 1 hit";
3909  FclTrimUS(1);
3910  ++lopped;
3911  }
3912  FitCluster();
3913  FitClusterChg();
3914  if (prt)
3915  mf::LogVerbatim("CC") << "Bad fit chisq - removed " << lopped << " hits. Continue";
3916  } // clChisq > fChiCut[pass]
3917  } // !HitOK check
3918  } // nextwire
3919  if (prt)
3920  mf::LogVerbatim("CC") << "******************* CrawlUS normal stop. size " << fcl2hits.size();
3921 
3922  bool reFit = false;
3923  // end kink angle check
3924  if (fcl2hits.size() > 5) {
3925  // check for a kink at the US end
3926  if (prt)
3927  mf::LogVerbatim("CC") << "EndKinkAngle check " << EndKinkAngle() << " cut "
3928  << fKinkAngCut[pass];
3929  if (EndKinkAngle() > fKinkAngCut[pass]) {
3930  if (prt) mf::LogVerbatim("CC") << "EndKinkAngle removes 3 hits ";
3931  FclTrimUS(3);
3932  reFit = true;
3933  }
3934  } // fcl2hits.size() > 5
3935 
3936  // count the number of hits on adjacent wires at the leading edge and
3937  // ensure that the count is consistent with fMinWirAfterSkip
3938  if ((unsigned short)fcl2hits.size() > fMinWirAfterSkip[pass] + 3) {
3939  unsigned int ih0 = fcl2hits.size() - 1;
3940  unsigned int hit0 = fcl2hits[ih0];
3941  unsigned int uswir = fHits[hit0].WireID().Wire;
3942  unsigned int nxtwir;
3943  unsigned short nAdjHit = 0;
3944  for (unsigned short ii = ih0 - 1; ii > 0; --ii) {
3945  nxtwir = fHits[fcl2hits[ii]].WireID().Wire;
3946  ++nAdjHit;
3947  if (nxtwir != uswir + 1) break;
3948  // break if there are enough hits
3949  if (nAdjHit == fMinWirAfterSkip[pass]) break;
3950  uswir = nxtwir;
3951  } // ii
3952  // lop off hits?
3953  if (nAdjHit < fMinWirAfterSkip[pass]) {
3954  if (prt) mf::LogVerbatim("CC") << "fMinWirAfterSkip removes " << nAdjHit << " hits ";
3955  FclTrimUS(nAdjHit);
3956  reFit = true;
3957  }
3958  } // fcl2hits.size() > fMinWirAfterSkip[pass] + 3
3959 
3960  // check for a bad hit on the end
3961  if (!reFit && fcl2hits.size() > 3) {
3962  float chirat = chifits[chifits.size() - 1] / chifits[chifits.size() - 2];
3963  if (prt)
3964  mf::LogVerbatim("CC") << "Last hit chirat " << chirat << " cut " << fKinkChiRat[pass];
3965  if (prt)
3966  mf::LogVerbatim("CC") << "Check " << clChisq << " " << chifits[chifits.size() - 1] << " "
3967  << chifits[chifits.size() - 2];
3968  if (chirat > fKinkChiRat[pass]) {
3969  if (prt) mf::LogVerbatim("CC") << "<<ADD- at end";
3970  FclTrimUS(1);
3971  reFit = true;
3972  }
3973  } // !reFit
3974 
3975  if (reFit) {
3976  FitCluster();
3977  FitClusterChg();
3978  }
3980  if (prt)
3981  mf::LogVerbatim("CC") << "******************* CrawlUS done. Size " << fcl2hits.size()
3982  << " min length for this pass " << fMinHits[pass];
3983 
3984  prt = false;
3985  } // CrawlUS()
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< std::pair< int, int > > WireHitRange
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
std::vector< unsigned short > fMinWirAfterSkip
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
constexpr auto abs(T v)
Returns the absolute value of the argument.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
void FclTrimUS(unsigned short nTrim)
bool CrawlVtxChk(unsigned int kwire)
int fDebugHit
out detailed information while crawling
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
unsigned int fFirstWire
the first wire with a hit
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
std::vector< float > fKinkChiRat
float clBeginSlp
begin slope (= DS end = high wire number)
std::vector< unsigned short > fMaxHitsFit
Max number of hits fitted.
float clChisq
chisq of the current fit
bool clLA
using Large Angle crawling code
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned short > fMinHits
Min number of hits to make a cluster.
std::vector< float > chifits
fit chisq for monitoring kinks, etc
void AddHit(unsigned int kwire, bool &HitOK, bool &SigOK)
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
bool cluster::ClusterCrawlerAlg::CrawlVtxChk ( unsigned int  kwire)
private

Definition at line 1190 of file ClusterCrawlerAlg.cxx.

References util::abs().

1191  {
1192 
1193  // returns true if the cluster is near a vertex on wire kwire
1194  if (vtx.size() == 0) return false;
1195  unsigned int iht = fcl2hits.size() - 1;
1196  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1197  float prtime = clpar[0] + (kwire - wire0) * clpar[1];
1198  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1199  if (vtx[iv].CTP != clCTP) continue;
1200  if ((unsigned int)(0.5 + vtx[iv].Wire) != kwire) continue;
1201  if (std::abs(prtime - vtx[iv].Time) < 10) return true;
1202  }
1203  return false;
1204  } // CrawlVtxChk()
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
bool cluster::ClusterCrawlerAlg::CrawlVtxChk2 ( )
private

Definition at line 1155 of file ClusterCrawlerAlg.cxx.

References util::abs().

1156  {
1157  // returns true if the (presumably short) cluster under construction
1158  // resides between a vertex and another cluster that is associated with
1159  // that vertex
1160 
1161  if (vtx.size() == 0) return false;
1162  if (fcl2hits.size() == 0) return false;
1163 
1164  unsigned int iht = fcl2hits.size() - 1;
1165  unsigned short icl;
1166  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1167  float dt;
1168  float thclus = std::atan(fScaleF * clpar[1]);
1169 
1170  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1171  if (vtx[iv].CTP != clCTP) continue;
1172  if (wire0 < vtx[iv].Wire) continue;
1173  if (wire0 > vtx[iv].Wire + 10) continue;
1174  dt = clpar[0] + (vtx[iv].Wire - wire0) * clpar[1] - vtx[iv].Time;
1175  if (std::abs(dt) > 10) continue;
1176  // cluster points to an US vertex. See if the angle is similar to
1177  // cluster associated with this vertex
1178  for (icl = 0; icl < tcl.size(); ++icl) {
1179  if (tcl[icl].CTP != clCTP) continue;
1180  if (tcl[icl].EndVtx != iv) continue;
1181  if (std::abs(tcl[icl].EndAng - thclus) < fKinkAngCut[pass]) return true;
1182  }
1183  }
1184 
1185  return false;
1186 
1187  } // CrawlVtxChk2()
float fScaleF
scale factor from Tick/Wire to dx/du
std::vector< ClusterStore > tcl
the clusters we are creating
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
unsigned int cluster::ClusterCrawlerAlg::DeadWireCount ( )
private

Definition at line 6073 of file ClusterCrawlerAlg.cxx.

6074  {
6075  // Counts the number of dead wires in the range spanned by fcl2hits
6076  if (fcl2hits.size() < 2) return 0;
6077  unsigned int wire, ndead = 0;
6078  unsigned int iht = fcl2hits[fcl2hits.size() - 1];
6079  unsigned int eWire = fHits[iht].WireID().Wire;
6080  iht = fcl2hits[0];
6081  unsigned int bWire = fHits[iht].WireID().Wire + 1;
6082  for (wire = eWire; wire < bWire; ++wire)
6083  if (WireHitRange[wire].first == -1) ++ndead;
6084  return ndead;
6085  } // DeadWireCount
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
unsigned int cluster::ClusterCrawlerAlg::DeadWireCount ( unsigned int  inWire1,
unsigned int  inWire2 
)
private

Definition at line 6057 of file ClusterCrawlerAlg.cxx.

References tmp.

6058  {
6059  if (inWire1 > inWire2) {
6060  // put in increasing order
6061  unsigned int tmp = inWire1;
6062  inWire1 = inWire2;
6063  inWire2 = tmp;
6064  } // inWire1 > inWire2
6065  ++inWire2;
6066  unsigned int wire, ndead = 0;
6067  for (wire = inWire1; wire < inWire2; ++wire)
6068  if (WireHitRange[wire].first == -1) ++ndead;
6069  return ndead;
6070  } // DeadWireCount
std::vector< std::pair< int, int > > WireHitRange
Float_t tmp
Definition: plot.C:35
static geo::PlaneID cluster::ClusterCrawlerAlg::DecodeCTP ( CTP_t  CTP)
inlinestatic

Definition at line 47 of file ClusterCrawlerAlg.h.

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

48  {
49  return {CTP / (CTPpad * CTPpad), CTP / CTPpad % CTPpad, CTP % CTPpad};
50  }
static constexpr unsigned int CTPpad
float cluster::ClusterCrawlerAlg::DoCA ( short  icl,
unsigned short  end,
float  vwire,
float  vtick 
)
private

Definition at line 6128 of file ClusterCrawlerAlg.cxx.

6129  {
6130  // Find the Distance of Closest Approach betweeen a cluster and a point (vwire, vtick). The
6131  // DoCA is returned in Tick units.
6132 
6133  if (icl > (short)tcl.size()) return 9999;
6134 
6135  float cwire, cslp, ctick;
6136  // figure out which cluster to use
6137  if (icl < 0) {
6138  if (fcl2hits.size() == 0) return 9999;
6139  // cluster under construction
6140  if (end == 0) {
6141  cwire = clBeginWir;
6142  cslp = clBeginSlp;
6143  ctick = clBeginTim;
6144  }
6145  else {
6146  cwire = clpar[2];
6147  cslp = clpar[1];
6148  ctick = clpar[0];
6149  } // end
6150  }
6151  else {
6152  // tcl cluster
6153  if (end == 0) {
6154  cwire = tcl[icl].BeginWir;
6155  cslp = tcl[icl].BeginSlp;
6156  ctick = tcl[icl].BeginTim;
6157  }
6158  else {
6159  cwire = tcl[icl].EndWir;
6160  cslp = tcl[icl].EndSlp;
6161  ctick = tcl[icl].EndTim;
6162  } // end
6163  }
6164 
6165  // Closest approach wire
6166  float docaW = (vwire + cslp * (vtick - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6167  float dW = docaW - vwire;
6168  float dT = ctick + (vwire - cwire) * cslp - vtick;
6169  return sqrt(dW * dW + dT * dT);
6170 
6171  } // DoCA
std::vector< ClusterStore > tcl
the clusters we are creating
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
float clBeginSlp
begin slope (= DS end = high wire number)
unsigned int clBeginWir
begin wire
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::DoMerge ( unsigned short  it1,
unsigned short  it2,
short  ProcCode 
)
private

Definition at line 3129 of file ClusterCrawlerAlg.cxx.

References cluster::ClusterCrawlerAlg::ClusterStore::BeginAng, cluster::ClusterCrawlerAlg::ClusterStore::BeginChg, cluster::ClusterCrawlerAlg::ClusterStore::BeginChgNear, cluster::ClusterCrawlerAlg::ClusterStore::BeginSlp, cluster::ClusterCrawlerAlg::ClusterStore::BeginSlpErr, cluster::ClusterCrawlerAlg::ClusterStore::BeginTim, cluster::ClusterCrawlerAlg::ClusterStore::BeginVtx, cluster::ClusterCrawlerAlg::ClusterStore::BeginWir, cluster::ClusterCrawlerAlg::ClusterStore::CTP, cluster::ClusterCrawlerAlg::ClusterStore::EndAng, cluster::ClusterCrawlerAlg::ClusterStore::EndChg, cluster::ClusterCrawlerAlg::ClusterStore::EndChgNear, cluster::ClusterCrawlerAlg::ClusterStore::EndSlp, cluster::ClusterCrawlerAlg::ClusterStore::EndSlpErr, cluster::ClusterCrawlerAlg::ClusterStore::EndTim, cluster::ClusterCrawlerAlg::ClusterStore::EndVtx, cluster::ClusterCrawlerAlg::ClusterStore::EndWir, cluster::ClusterCrawlerAlg::ClusterStore::ID, cluster::ClusterCrawlerAlg::ClusterStore::StopCode, and cluster::ClusterCrawlerAlg::ClusterStore::tclhits.

3130  {
3131  // Merge clusters.
3132 
3133  ClusterStore& cl1 = tcl[it1];
3134  ClusterStore& cl2 = tcl[it2];
3135 
3136  if (cl1.tclhits.size() < 3) return;
3137  if (cl2.tclhits.size() < 3) return;
3138 
3139  unsigned int lowire, hiwire, whsize, ii, iht, indx;
3140  // do a fit across the boundary between cl1 and cl2 to
3141  // ensure that they truly should be merged
3142  unsigned int fithit;
3143  // Find the low and high wire for both clusters.
3144  // Assume that cluster 1 is DS
3145  bool cl1DS = true;
3146  hiwire = cl1.BeginWir;
3147  fithit = cl1.tclhits[cl1.tclhits.size() - 2];
3148  if (cl2.BeginWir > hiwire) {
3149  hiwire = cl2.BeginWir;
3150  fithit = cl2.tclhits[cl2.tclhits.size() - 2];
3151  cl1DS = false;
3152  }
3153  lowire = cl1.EndWir;
3154  if (cl2.EndWir < lowire) lowire = cl2.EndWir;
3155 
3156  // make a vector of wire hits
3157  whsize = hiwire + 2 - lowire;
3158  std::vector<int> wirehit(whsize, -1);
3159  // put in the hit IDs for cluster 2
3160  for (ii = 0; ii < cl2.tclhits.size(); ++ii) {
3161  iht = cl2.tclhits[ii];
3162  indx = fHits[iht].WireID().Wire - lowire;
3163  wirehit[indx] = iht;
3164  } // iht
3165  // now cluster 1
3166  for (ii = 0; ii < cl1.tclhits.size(); ++ii) {
3167  iht = cl1.tclhits[ii];
3168  indx = fHits[iht].WireID().Wire - lowire;
3169  wirehit[indx] = iht;
3170  } // iht
3171  // make the new cluster
3172  fcl2hits.clear();
3173  for (std::vector<int>::reverse_iterator rit = wirehit.rbegin(); rit != wirehit.rend(); ++rit) {
3174  if (*rit < 0) continue;
3175  fcl2hits.push_back(*rit);
3176  } // rit
3177 
3178  // fit the 6 hits that are near the merging point
3179  short nhitfit = 6;
3180  FitClusterMid(fcl2hits, fithit, nhitfit);
3181  if (clChisq > 5) return;
3182 
3183  // mark cl1 and cl2 obsolete
3184  MakeClusterObsolete(it1);
3185  MakeClusterObsolete(it2);
3186 
3187  short endVtx = 0;
3188  short begVtx = 0;
3189  short del1Vtx = -99;
3190  short del2Vtx = -99;
3191  if (cl1DS) {
3192  // use cluster 1 Begin info
3193  clBeginSlp = cl1.BeginSlp;
3194  clBeginSlpErr = cl1.BeginSlpErr;
3195  clBeginAng = cl1.BeginAng;
3196  clBeginWir = cl1.BeginWir;
3197  clBeginTim = cl1.BeginTim;
3198  clBeginChg = cl1.BeginChg;
3199  clBeginChgNear = cl1.BeginChgNear;
3200  begVtx = cl1.BeginVtx;
3201  del1Vtx = cl1.EndVtx;
3202  // and cluster 2 End info
3203  clEndSlp = cl2.EndSlp;
3204  clEndSlpErr = cl2.EndSlpErr;
3205  clEndAng = cl2.EndAng;
3206  clEndWir = cl2.EndWir;
3207  clEndTim = cl2.EndTim;
3208  clEndChg = cl2.EndChg;
3209  clEndChgNear = cl2.EndChgNear;
3210  endVtx = cl2.EndVtx;
3211  del2Vtx = cl2.BeginVtx;
3212  clStopCode = cl2.StopCode;
3213  }
3214  else {
3215  // use cluster 2 Begin info
3216  clBeginSlp = cl2.BeginSlp;
3217  clBeginSlpErr = cl2.BeginSlpErr;
3218  clBeginAng = cl2.BeginAng;
3219  clBeginWir = cl2.BeginWir;
3220  clBeginTim = cl2.BeginTim;
3221  clBeginChg = cl2.BeginChg;
3222  clBeginChgNear = cl2.BeginChgNear;
3223  begVtx = cl2.BeginVtx;
3224  del2Vtx = cl2.EndVtx;
3225  // and cluster 1 End info
3226  clEndSlp = cl1.EndSlp;
3227  clEndSlpErr = cl1.EndSlpErr;
3228  clEndWir = cl1.EndWir;
3229  clEndTim = cl1.EndTim;
3230  clEndChg = cl1.EndChg;
3231  clEndChgNear = cl1.EndChgNear;
3232  endVtx = cl1.EndVtx;
3233  del1Vtx = cl1.BeginVtx;
3234  clStopCode = cl1.StopCode;
3235  }
3236 
3237  // append it to the tcl vector
3238  clCTP = cl1.CTP;
3239  if (!TmpStore()) return;
3240  unsigned short itnew = tcl.size() - 1;
3241  if (prt)
3242  mf::LogVerbatim("CC") << "DoMerge " << cl1.ID << " " << cl2.ID << " -> " << tcl[itnew].ID;
3243  // stuff the processor code with the current pass
3244  tcl[itnew].ProcCode = inProcCode + pass;
3245  // transfer the vertex info
3246  // delete a vertex between these two?
3247  if (del1Vtx >= 0 && del1Vtx == del2Vtx) vtx[del1Vtx].NClusters = 0;
3248  // preserve the vertex assignments
3249  tcl[itnew].BeginVtx = begVtx;
3250  tcl[itnew].EndVtx = endVtx;
3251  } // DoMerge
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
CTP_t clCTP
Cryostat/TPC/Plane code.
unsigned int clEndWir
begin wire
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
float clBeginSlp
begin slope (= DS end = high wire number)
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
float clEndChg
end average charge
unsigned int clBeginWir
begin wire
float clBeginChgNear
nearby charge
std::vector< VtxStore > vtx
the endpoints we are reconstructing
float clEndChgNear
nearby charge
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
static CTP_t cluster::ClusterCrawlerAlg::EncodeCTP ( unsigned int  cryo,
unsigned int  tpc,
unsigned int  plane 
)
inlinestatic

Definition at line 39 of file ClusterCrawlerAlg.h.

40  {
41  return cryo * CTPpad * CTPpad + tpc * CTPpad + plane;
42  }
static constexpr unsigned int CTPpad
static CTP_t cluster::ClusterCrawlerAlg::EncodeCTP ( const geo::PlaneID planeID)
inlinestatic

Definition at line 43 of file ClusterCrawlerAlg.h.

References geo::CryostatID::Cryostat, tca::EncodeCTP(), geo::PlaneID::Plane, and geo::TPCID::TPC.

44  {
45  return EncodeCTP(planeID.Cryostat, planeID.TPC, planeID.Plane);
46  }
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:195
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:373
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:315
float cluster::ClusterCrawlerAlg::EndKinkAngle ( )
private

Definition at line 3988 of file ClusterCrawlerAlg.cxx.

References util::abs().

3989  {
3990  // find the kink angle (crudely) from the 0th and 2nd hit on the cluster under construction
3991 
3992  unsigned int ih0 = fcl2hits.size() - 1;
3993  unsigned int hit0 = fcl2hits[ih0];
3994  unsigned int ih2 = ih0 - 2;
3995  unsigned int hit2 = fcl2hits[ih2];
3996  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3997  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3998  float th02 = std::atan(fScaleF * dt02 / dw02);
3999  // and the 3rd and 5th hit
4000  unsigned int ih3 = ih2 - 1;
4001  unsigned int hit3 = fcl2hits[ih3];
4002  unsigned int ih5 = ih3 - 2;
4003  unsigned int hit5 = fcl2hits[ih5];
4004  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
4005  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
4006  float th35 = std::atan(fScaleF * dt35 / dw35);
4007  return std::abs(th02 - th35);
4008  }
float fScaleF
scale factor from Tick/Wire to dx/du
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::FclTrimUS ( unsigned short  nTrim)
private

Definition at line 856 of file ClusterCrawlerAlg.cxx.

857  {
858 
859  // Trims nTrim hits off the UpStream end of the fcl2hits, etc vectors.
860  if (nTrim == 0) return;
861 
862  if (nTrim >= fcl2hits.size()) nTrim = fcl2hits.size();
863 
864  // RestoreUnMergedClusterHits((short)nTrim);
865  for (unsigned short ii = 0; ii < nTrim; ++ii) {
866  fcl2hits.pop_back();
867  chifits.pop_back();
868  hitNear.pop_back();
869  chgNear.pop_back();
870  } // ii
871 
872  } // FclTrim
std::vector< short > hitNear
std::vector< float > chifits
fit chisq for monitoring kinks, etc
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::FindHammerClusters ( detinfo::DetectorPropertiesData const &  det_prop)
private

Definition at line 5488 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorPropertiesData::ConvertTicksToX(), cluster::ClusterCrawlerAlg::Vtx3Store::CStat, cluster::ClusterCrawlerAlg::VtxStore::CTP, e, tca::EncodeCTP(), cluster::ClusterCrawlerAlg::VtxStore::Fixed, geo::TPCGeo::GetCenter(), geo::TPCGeo::HalfHeight(), geo::TPCGeo::Length(), cluster::ClusterCrawlerAlg::Vtx3Store::ProcCode, cluster::ClusterCrawlerAlg::Vtx3Store::Ptr2D, util::size(), geo::InvalidWireError::suggestedWireID(), cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::TimeErr, cluster::ClusterCrawlerAlg::VtxStore::Topo, cluster::ClusterCrawlerAlg::Vtx3Store::TPC, cluster::ClusterCrawlerAlg::VtxStore::Wire, cluster::ClusterCrawlerAlg::Vtx3Store::Wire, geo::WireID::Wire, cluster::ClusterCrawlerAlg::VtxStore::WireErr, X, cluster::ClusterCrawlerAlg::Vtx3Store::X, cluster::ClusterCrawlerAlg::Vtx3Store::XErr, y, cluster::ClusterCrawlerAlg::Vtx3Store::Y, cluster::ClusterCrawlerAlg::Vtx3Store::YErr, cluster::ClusterCrawlerAlg::Vtx3Store::Z, z, and cluster::ClusterCrawlerAlg::Vtx3Store::ZErr.

5489  {
5490  // look for a long cluster that stops at a short cluster in two views. This can occur in a CCmu
5491  // interaction where two protons are emitted back-to-back and are therefore reconstructed as one cluster
5492  // This routine looks for this signature, and if found, splits the short clusters and creates a new 3D vertex.
5493  // This routine only considers the case where the long cluster intersects the short cluster at the US (End) end.
5494 
5495  unsigned int nPln = wireReadoutGeom->Nplanes(geo::TPCID(cstat, tpc));
5496  if (nPln != 3) return;
5497 
5498  float ew1, ew2, bw2, fvw;
5499 
5500  struct Hammer {
5501  bool Used;
5502  unsigned int Wire; // intersection point of the long cluster and the short cluster
5503  float Tick; // intersection point of the long cluster and the short cluster
5504  float X;
5505  unsigned short longClIndex;
5506  unsigned short shortClIndex;
5507  unsigned short splitPos;
5508  };
5509  std::array<std::vector<Hammer>, 3> hamrVec;
5510 
5511  unsigned int ipl;
5512  bool useit = false;
5513  for (ipl = 0; ipl < 3; ++ipl) {
5514  clCTP = EncodeCTP(cstat, tpc, ipl);
5515  for (unsigned short ic1 = 0; ic1 < tcl.size(); ++ic1) {
5516  if (tcl[ic1].ID < 0) continue;
5517  // require a long cluster
5518  if (tcl[ic1].tclhits.size() < 20) continue;
5519  if (tcl[ic1].CTP != clCTP) continue;
5520  // ignore long clusters with an End vertex assignment
5521  if (tcl[ic1].EndVtx >= 0) continue;
5522  ew1 = tcl[ic1].EndWir;
5523  for (unsigned short ic2 = 0; ic2 < tcl.size(); ++ic2) {
5524  if (tcl[ic2].ID < 0) continue;
5525  // require a short cluster
5526  if (tcl[ic2].tclhits.size() > 20) continue;
5527  // but not too short cluster
5528  if (tcl[ic2].tclhits.size() < 6) continue;
5529  if (tcl[ic2].CTP != clCTP) continue;
5530  ew2 = tcl[ic2].EndWir;
5531  bw2 = tcl[ic2].BeginWir;
5532  // check the US end. The End of the long cluster must lie between the Begin and End wire of the
5533  // short cluster
5534  if (ew1 < ew2 || ew1 > bw2) continue;
5535  // look for intersection of the two clusters
5536  float best = 10;
5537  short ibst = -1;
5538  unsigned short spos = 0;
5539  for (unsigned short ii = 0; ii < tcl[ic2].tclhits.size(); ++ii) {
5540  unsigned int iht = tcl[ic2].tclhits[ii];
5541  float dw = fHits[iht].WireID().Wire - tcl[ic1].EndWir;
5542  float dt = fabs(fHits[iht].PeakTime() - tcl[ic1].EndTim - tcl[ic1].EndSlp * dw);
5543  if (dt < best) {
5544  best = dt;
5545  ibst = iht;
5546  spos = ii;
5547  }
5548  } // ii
5549  if (ibst < 0) continue;
5550  fvw = 0.5 + fHits[ibst].WireID().Wire;
5551  Hammer aHam;
5552  aHam.Used = false;
5553  aHam.Wire = (0.5 + fvw);
5554  aHam.Tick = fHits[ibst].PeakTime();
5555  aHam.X = det_prop.ConvertTicksToX((double)aHam.Tick, (int)ipl, (int)tpc, (int)cstat);
5556  aHam.longClIndex = ic1;
5557  aHam.shortClIndex = ic2;
5558  aHam.splitPos = spos;
5559  unsigned short indx = hamrVec[ipl].size();
5560  hamrVec[ipl].resize(indx + 1);
5561  hamrVec[ipl][indx] = aHam;
5562  useit = true;
5563  } // ic2
5564  if (useit) break;
5565  } // ic1
5566  } // ipl
5567 
5568  unsigned short noham = 0;
5569  for (ipl = 0; ipl < 3; ++ipl)
5570  if (hamrVec[ipl].size() == 0) ++noham;
5571  if (noham > 1) return;
5572 
5573  // Y,Z limits of the detector
5574 
5575  geo::TPCID const tpcid(cstat, tpc);
5576  const geo::TPCGeo& thetpc = geom->TPC(tpcid);
5577  auto const world = thetpc.GetCenter();
5578  float YLo = world.Y() - thetpc.HalfHeight() + 1;
5579  float YHi = world.Y() + thetpc.HalfHeight() - 1;
5580  float ZLo = world.Z() - thetpc.Length() / 2 + 1;
5581  float ZHi = world.Z() + thetpc.Length() / 2 - 1;
5582 
5583  // Match in 3D
5584  float dX;
5585  unsigned short icl, jpl, jcl, kpl, splitPos;
5586  for (ipl = 0; ipl < 3; ++ipl) {
5587  if (hamrVec[ipl].size() == 0) continue;
5588  jpl = (ipl + 1) % nPln;
5589  kpl = (jpl + 1) % nPln;
5590  for (unsigned short ii = 0; ii < hamrVec[ipl].size(); ++ii) {
5591  if (hamrVec[ipl][ii].Used) continue;
5592  for (unsigned short jj = 0; jj < hamrVec[jpl].size(); ++jj) {
5593  if (hamrVec[jpl][jj].Used) continue;
5594  dX = hamrVec[ipl][ii].X - hamrVec[jpl][jj].X;
5595  if (fabs(dX) > fVertex3DCut) continue;
5596  geo::PlaneID const plane_i{tpcid, ipl};
5597  geo::PlaneID const plane_j{tpcid, jpl};
5598  auto const intersection =
5599  wireReadoutGeom->WireIDsIntersect(geo::WireID{plane_i, hamrVec[ipl][ii].Wire},
5600  geo::WireID{plane_j, hamrVec[jpl][jj].Wire});
5601  if (!intersection) continue;
5602 
5603  auto const [y, z] = std::make_pair(intersection->y, intersection->z);
5604  if (y < YLo || y > YHi || z < ZLo || z > ZHi) continue;
5605  // mark them used
5606  hamrVec[ipl][ii].Used = true;
5607  hamrVec[jpl][jj].Used = true;
5608  // make a new 3D vertex
5609  Vtx3Store newVtx3;
5610  newVtx3.ProcCode = 7;
5611  newVtx3.X = 0.5 * (hamrVec[ipl][ii].X + hamrVec[jpl][jj].X);
5612  // TODO: do this correctly;
5613  newVtx3.XErr = fabs(hamrVec[ipl][ii].X - hamrVec[jpl][jj].X);
5614  newVtx3.Y = y;
5615  newVtx3.YErr = 1; // TODO
5616  newVtx3.Z = z;
5617  newVtx3.ZErr = 1; // TODO
5618  newVtx3.CStat = cstat;
5619  newVtx3.TPC = tpc;
5620 
5621  // make 2D vertex in ipl
5622  VtxStore newVtx2;
5623  newVtx2.Wire = hamrVec[ipl][ii].Wire;
5624  newVtx2.WireErr = 2;
5625  newVtx2.Time = hamrVec[ipl][ii].Tick;
5626  newVtx2.TimeErr = 5;
5627  newVtx2.Topo = 6;
5628  newVtx2.Fixed = false;
5629  icl = hamrVec[ipl][ii].longClIndex;
5630  newVtx2.CTP = tcl[icl].CTP;
5631  vtx.push_back(newVtx2);
5632  unsigned short ivnew = vtx.size() - 1;
5633  // associate the new vertex with the long cluster
5634  tcl[icl].EndVtx = ivnew;
5635  FitVtx(ivnew);
5636  // stash the index in newVtx3
5637  newVtx3.Ptr2D[ipl] = (short)ivnew;
5638  // split the short cluster and associate the new clusters with the new vtx
5639  icl = hamrVec[ipl][ii].shortClIndex;
5640  splitPos = hamrVec[ipl][ii].splitPos;
5641  if (!SplitCluster(icl, splitPos, ivnew)) return;
5642 
5643  // make 2D vertex in jpl
5644  newVtx2.Wire = hamrVec[jpl][jj].Wire;
5645  newVtx2.Time = hamrVec[jpl][jj].Tick;
5646  newVtx2.Topo = 6;
5647  jcl = hamrVec[jpl][jj].longClIndex;
5648  newVtx2.CTP = tcl[jcl].CTP;
5649  vtx.push_back(newVtx2);
5650  ivnew = vtx.size() - 1;
5651  // associate the new vertex with the long cluster
5652  tcl[jcl].EndVtx = ivnew;
5653  // stash the index in newVtx3
5654  newVtx3.Ptr2D[jpl] = (short)(vtx.size() - 1);
5655  // split the short cluster and associate the new clusters with the new
5656  // vtx
5657  jcl = hamrVec[jpl][jj].shortClIndex;
5658  splitPos = hamrVec[jpl][jj].splitPos;
5659  if (!SplitCluster(jcl, splitPos, vtx.size() - 1)) return;
5660  FitVtx(ivnew);
5661  // set the kpl 2D vertex index < 0. Let follow-on code find the 3rd
5662  // plane vertex
5663  newVtx3.Ptr2D[kpl] = -1;
5664  geo::Point_t const WPos{0, y, z};
5665  try {
5666  newVtx3.Wire = wireReadoutGeom->Plane({cstat, tpc, kpl}).NearestWireID(WPos).Wire;
5667  }
5668  catch (geo::InvalidWireError const& e) {
5669  newVtx3.Wire = e.suggestedWireID().Wire; // pick the closest valid wire
5670  }
5671  vtx3.push_back(newVtx3);
5672  } // jj
5673  } // ii
5674  }
5675 
5676  } // FindHammerClusters
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:85
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:276
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
Geometry information for a single TPC.
Definition: TPCGeo.h:33
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:403
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
CTP_t clCTP
Cryostat/TPC/Plane code.
art::ServiceHandle< geo::Geometry const > geom
double Length() const
Length is associated with z coordinate [cm].
Definition: TPCGeo.h:110
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
Point_t GetCenter() const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.h:132
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
geo::WireReadoutGeom const * wireReadoutGeom
The data type to uniquely identify a TPC.
Definition: geo_types.h:306
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, Point_t &intersection) const
Computes the intersection between two wires.
unsigned int Nplanes(TPCID const &tpcid=details::tpc_zero) const
Returns the total number of planes in the specified TPC.
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
double HalfHeight() const
Height is associated with y coordinate [cm].
Definition: TPCGeo.h:106
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
Exception thrown on invalid wire number.
Definition: Exceptions.h:37
std::vector< VtxStore > vtx
the endpoints we are reconstructing
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:448
Float_t e
Definition: plot.C:35
Float_t X
Definition: plot.C:37
std::pair< size_t, size_t > cluster::ClusterCrawlerAlg::FindHitMultiplet ( size_t  iHit) const
private

Returns a pair of first and past-the-last index of all the contiguous hits belonging to the same multiplet

Definition at line 6096 of file ClusterCrawlerAlg.cxx.

6097  {
6098  std::pair<size_t, size_t> range{iHit, iHit};
6099 
6100  range.first = iHit - fHits[iHit].LocalIndex();
6101  range.second = range.first + fHits[iHit].Multiplicity();
6102 
6103  return range;
6104  } // ClusterCrawlerAlg::FindHitMultiplet()
std::vector< recob::Hit > fHits
our version of the hits
void cluster::ClusterCrawlerAlg::FindStarVertices ( )
private

Definition at line 1762 of file ClusterCrawlerAlg.cxx.

References util::abs(), cluster::ClusterCrawlerAlg::VtxStore::CTP, cluster::ClusterCrawlerAlg::VtxStore::Fixed, tca::PrintClusters(), cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::TimeErr, cluster::ClusterCrawlerAlg::VtxStore::Topo, cluster::ClusterCrawlerAlg::VtxStore::Wire, and cluster::ClusterCrawlerAlg::VtxStore::WireErr.

1763  {
1764  // Make 2D vertices with a star topology with short back-to-back
1765  // clusters. Vertices must reside on the US end of the longest
1766  // cluster, so vertex finding uses the End information only.
1767  // This routine is called after all passes are completed
1768  // in the current CTP
1769  if (tcl.size() < 2) return;
1770 
1771  // This code has some issues...
1772  return;
1773 
1774  vtxprt = (fDebugPlane == (int)plane && fDebugHit < 0);
1775  if (vtxprt) {
1776  mf::LogVerbatim("CC") << "FindStarVertices";
1777  PrintClusters();
1778  }
1779 
1780  unsigned short vtxSizeIn = vtx.size();
1781 
1782  float fvw = 0.;
1783  float fvt = 0.;
1784  float dsl = 0, dth = 0;
1785  float es1 = 0, es2 = 0;
1786  float eth1 = 0, eth2 = 0;
1787  float bt1 = 0, bt2 = 0;
1788  float et1 = 0, et2 = 0;
1789  float bw1 = 0, bw2 = 0;
1790  float ew1 = 0, ew2 = 0;
1791  float lotime = 0, hitime = 0, nwirecut = 0;
1792  unsigned short tclsize = tcl.size();
1793  for (unsigned short it1 = 0; it1 < tclsize - 1; ++it1) {
1794  // ignore obsolete clusters
1795  if (tcl[it1].ID < 0) continue;
1796  if (tcl[it1].CTP != clCTP) continue;
1797  // long dead-straight cluster?
1798  if (tcl[it1].tclhits.size() > 100) {
1799  dth = tcl[it1].BeginAng - tcl[it1].EndAng;
1800  if (std::abs(dth) < 0.1) continue;
1801  }
1802  es1 = tcl[it1].EndSlp;
1803  eth1 = tcl[it1].EndAng;
1804  ew1 = tcl[it1].EndWir;
1805  et1 = tcl[it1].EndTim;
1806  bw1 = tcl[it1].BeginWir;
1807  bt1 = tcl[it1].BeginTim;
1808  for (unsigned short it2 = it1 + 1; it2 < tclsize; ++it2) {
1809  if (tcl[it2].ID < 0) continue;
1810  if (tcl[it2].CTP != clCTP) continue;
1811  // long dead-straight cluster?
1812  if (tcl[it2].tclhits.size() > 100) {
1813  dth = tcl[it2].BeginAng - tcl[it2].EndAng;
1814  if (std::abs(dth) < 0.05) continue;
1815  }
1816  es2 = tcl[it2].EndSlp;
1817  eth2 = tcl[it2].EndAng;
1818  ew2 = tcl[it2].EndWir;
1819  et2 = tcl[it2].EndTim;
1820  bw2 = tcl[it2].BeginWir;
1821  bt2 = tcl[it2].BeginTim;
1822  // require angle difference
1823  dth = std::abs(eth1 - eth2);
1824  if (dth < 0.3) continue;
1825  dsl = es2 - es1;
1826  fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
1827  // intersection within the wire boundaries
1828  if (fvw < ew1 || fvw > bw1) continue;
1829  if (fvw < ew2 || fvw > bw2) continue;
1830  if (vtxprt)
1831  mf::LogVerbatim("CC") << "Chk clusters " << tcl[it1].ID << " " << tcl[it2].ID
1832  << " topo5 vtx wire " << fvw;
1833  // ensure that the intersection is close to the US end of the longer
1834  // cluster if it is more than 20 hits long
1835  if (tcl[it1].tclhits.size() > tcl[it2].tclhits.size()) {
1836  if (tcl[it1].tclhits.size() > 20) {
1837  nwirecut = 0.5 * tcl[it1].tclhits.size();
1838  if ((fvw - ew1) > nwirecut) continue;
1839  }
1840  }
1841  else {
1842  if (tcl[it2].tclhits.size() > 20) {
1843  nwirecut = 0.5 * tcl[it2].tclhits.size();
1844  if ((fvw - ew2) > nwirecut) continue;
1845  }
1846  }
1847  fvt = et1 + (fvw - ew1) * es1;
1848  // and time boundaries
1849  lotime = 9999;
1850  if (et1 < lotime) lotime = et1;
1851  if (bt1 < lotime) lotime = bt1;
1852  if (et2 < lotime) lotime = et2;
1853  if (bt2 < lotime) lotime = bt2;
1854  hitime = 0;
1855  if (et1 > hitime) hitime = et1;
1856  if (bt1 > hitime) hitime = bt1;
1857  if (et2 > hitime) hitime = et2;
1858  if (bt2 > hitime) hitime = bt2;
1859  if (fvt < lotime || fvt > hitime) continue;
1860  if (vtxprt)
1861  mf::LogVerbatim("CC") << " vertex time " << fvt << " lotime " << lotime << " hitime "
1862  << hitime;
1863  unsigned int vw = (0.5 + fvw);
1864  // ensure that the vertex is near a hit on both clusters
1865  unsigned int pos1 = 0;
1866  for (unsigned short ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
1867  if (fHits[tcl[it1].tclhits[ii]].WireID().Wire <= vw) {
1868  if (std::abs(int(fHits[tcl[it1].tclhits[ii]].PeakTime() - fvt)) < 10) pos1 = ii;
1869  break;
1870  }
1871  } // ii
1872  // vertex is not near a hit on cluster 1
1873  if (pos1 == 0) continue;
1874  unsigned short pos2 = 0;
1875  for (unsigned short ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
1876  if (fHits[tcl[it2].tclhits[ii]].WireID().Wire <= vw) {
1877  if (std::abs(int(fHits[tcl[it2].tclhits[ii]].PeakTime() - fvt)) < 10) pos2 = ii;
1878  break;
1879  }
1880  } // ii
1881  // vertex is not near a hit on cluster 2
1882  if (pos2 == 0) continue;
1883  // ensure we aren't near an existing vertex
1884  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1885  if (std::abs(fvw - vtx[iv].Wire) < 2 && std::abs(fvt - vtx[iv].Time) < 10) continue;
1886  }
1887  // make a new vertex
1888  VtxStore newvx;
1889  newvx.Wire = fvw;
1890  newvx.WireErr = 1;
1891  newvx.Time = fvt;
1892  newvx.TimeErr = 1;
1893  newvx.Topo = 5;
1894  newvx.CTP = clCTP;
1895  newvx.Fixed = false;
1896  vtx.push_back(newvx);
1897  unsigned short ivx = vtx.size() - 1;
1898  if (vtxprt)
1899  mf::LogVerbatim("CC") << " new vertex " << ivx << " cluster " << tcl[it1].ID
1900  << " split pos " << pos1;
1901  if (!SplitCluster(it1, pos1, ivx)) continue;
1902  tcl[tcl.size() - 1].ProcCode += 1000;
1903  tcl[tcl.size() - 2].ProcCode += 1000;
1904  if (vtxprt)
1905  mf::LogVerbatim("CC") << " new vertex " << ivx << " cluster " << tcl[it2].ID
1906  << " split pos " << pos2;
1907  if (!SplitCluster(it2, pos2, ivx)) continue;
1908  tcl[tcl.size() - 1].ProcCode += 1000;
1909  tcl[tcl.size() - 2].ProcCode += 1000;
1910  FitVtx(ivx);
1911  break;
1912  } // it2
1913  } // it1
1914 
1915  if (vtx.size() > vtxSizeIn) {
1916  // try to split other clusters
1917  VtxClusterSplit();
1918  // try to attach other clusters to it
1919  VertexCluster(vtx.size() - 1);
1920  FitAllVtx(clCTP);
1921  } // new vertex
1922 
1923  if (vtxprt) {
1924  mf::LogVerbatim("CC") << "Vertices " << vtx.size();
1925  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1926  if (vtx[iv].CTP != clCTP) continue;
1927  mf::LogVerbatim("CC") << "vtx " << iv << " wire " << vtx[iv].Wire << " time "
1928  << (int)vtx[iv].Time << " NClusters " << vtx[iv].NClusters << " topo "
1929  << vtx[iv].Topo;
1930  }
1931  PrintClusters();
1932  }
1933 
1934  } // FindStarVertices()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
int fDebugHit
out detailed information while crawling
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void VertexCluster(unsigned short ivx)
void cluster::ClusterCrawlerAlg::FindVertices ( )
private

Definition at line 2024 of file ClusterCrawlerAlg.cxx.

References util::abs(), util::empty(), greaterThan(), and tca::PrintClusters().

2025  {
2026  // try to make 2D vertices
2027 
2028  if (tcl.size() < 2) return;
2029 
2030  // sort clusters starting with the longest
2031  std::vector<CluLen> clulens;
2032  CluLen clulen;
2033  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
2034  if (tcl[icl].ID < 0) continue;
2035  if (tcl[icl].CTP != clCTP) continue;
2036  if (tcl[icl].BeginVtx >= 0 && tcl[icl].EndVtx >= 0) continue;
2037  clulen.index = icl;
2038  clulen.length = tcl[icl].tclhits.size();
2039  clulens.push_back(clulen);
2040  }
2041  if (empty(clulens)) return;
2042  std::sort(clulens.begin(), clulens.end(), greaterThan);
2043 
2044  float nwires = fNumWires;
2045  float maxtime = fMaxTime;
2046 
2047  unsigned short vtxSizeIn = vtx.size();
2048 
2049  vtxprt = (fDebugPlane == (short)plane && fDebugHit < 0);
2050  if (vtxprt) {
2051  mf::LogVerbatim("CC") << "FindVertices plane " << plane << " pass " << pass;
2052  PrintClusters();
2053  }
2054 
2055  float es1 = 0, eth1 = 0, ew1 = 0, et1 = 0;
2056  float bs1 = 0, bth1 = 0, bw1 = 0, bt1 = 0;
2057  float es2 = 0, eth2 = 0, ew2 = 0, et2 = 0;
2058  float bs2 = 0, bth2 = 0, bw2 = 0, bt2 = 0;
2059  float dth = 0, dsl = 0, fvw = 0, fvt = 0;
2060  float angcut = 0;
2061  unsigned int vw = 0, pass1, pass2, ii1, it1, ii2, it2;
2062  bool SigOK = false;
2063  for (ii1 = 0; ii1 < clulens.size() - 1; ++ii1) {
2064  it1 = clulens[ii1].index;
2065  es1 = tcl[it1].EndSlp;
2066  eth1 = tcl[it1].EndAng;
2067  ew1 = tcl[it1].EndWir;
2068  et1 = tcl[it1].EndTim;
2069  bs1 = tcl[it1].BeginSlp;
2070  bth1 = tcl[it1].BeginAng;
2071  bw1 = tcl[it1].BeginWir;
2072  bt1 = tcl[it1].BeginTim;
2073  pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2074  for (ii2 = ii1 + 1; ii2 < clulens.size(); ++ii2) {
2075  it2 = clulens[ii2].index;
2076  // try to attach cluster to existing vertices at either end
2077  ClusterVertex(it2);
2078  // ignore if both clusters are short
2079  if (tcl[it1].tclhits.size() < 5 && tcl[it2].tclhits.size() < 5) continue;
2080  es2 = tcl[it2].EndSlp;
2081  eth2 = tcl[it2].EndAng;
2082  ew2 = tcl[it2].EndWir;
2083  et2 = tcl[it2].EndTim;
2084  bs2 = tcl[it2].BeginSlp;
2085  bth2 = tcl[it2].BeginAng;
2086  bw2 = tcl[it2].BeginWir;
2087  bt2 = tcl[it2].BeginTim;
2088  pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2089  if (pass1 < pass2) { angcut = fKinkAngCut[pass2]; }
2090  else {
2091  angcut = fKinkAngCut[pass1];
2092  }
2093  // topo 1: check for vtx US of the ends of both clusters
2094  dth = fabs(eth1 - eth2);
2095  if (tcl[it1].EndVtx < 0 && tcl[it2].EndVtx < 0 && dth > 0.1) {
2096  dsl = es2 - es1;
2097  // find vertex wire and vertex time in float precision (fvw, fvt)
2098  fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
2099  // vertex wire in the detector?
2100  if (fvw > 0. && fvw < nwires) {
2101  // require vtx in the range of wires with hits AND
2102  vw = (0.5 + fvw);
2103  // vtx US of both clusters AND
2104  // vtx not too far US of both clusters
2105  if (vw >= fFirstWire - 1 && fvw <= ew1 + 3 && fvw <= ew2 + 3 && fvw > (ew1 - 10) &&
2106  fvw > (ew2 - 10)) {
2107  fvt = et1 + (fvw - ew1) * es1;
2108  if (vtxprt)
2109  mf::LogVerbatim("CC")
2110  << "Chk clusters topo1 " << tcl[it1].ID << " " << tcl[it2].ID << " vtx wire "
2111  << vw << " time " << (int)fvt << " dth " << dth;
2112  if (fvt > 0 && fvt < maxtime) {
2113  // Vertex wire US of cluster ends and time in the detector.
2114  // Check for signal at the vertex position and adjust the vertex by 1 wire
2115  // if necessary
2116  SigOK = ChkSignal(vw, fvt, vw, fvt);
2117  if (!SigOK) {
2118  fvw += 1.;
2119  vw = (0.5 + fvw);
2120  SigOK = ChkSignal(vw, fvt, vw, fvt);
2121  }
2122  // Check this against existing vertices and update
2123  if (SigOK) ChkVertex(fvw, fvt, it1, it2, 1);
2124  } // fvt in detector
2125  } // vw topo 1 check
2126  } // fvw in detector
2127  } // topo 1
2128  // topo 2: check for vtx US of it1 and DS of it2
2129  dth = std::abs(eth1 - bth2);
2130  if (tcl[it1].EndVtx < 0 && tcl[it2].BeginVtx < 0 && dth > angcut) {
2131  dsl = bs2 - es1;
2132  if (fabs(ew1 - bw2) < 3 && fabs(et1 - bt2) < 500) { fvw = 0.5 * (ew1 + bw2); }
2133  else {
2134  fvw = (et1 - ew1 * es1 - bt2 + bw2 * bs2) / dsl;
2135  }
2136  if (fvw > 0 && fvw < nwires) {
2137  // vertex wire in the detector
2138  vw = (0.5 + fvw);
2139  // require vtx US of cluster 1 End AND
2140  // vtx DS of cluster 2 Begin
2141  if (fvw <= ew1 + 2 && fvw >= bw2 - 2) {
2142  fvt = et1 + (vw - ew1) * es1;
2143  fvt += bt2 + (vw - bw2) * bs2;
2144  fvt /= 2;
2145  if (vtxprt)
2146  mf::LogVerbatim("CC")
2147  << "Chk clusters topo2 " << tcl[it1].ID << " " << tcl[it2].ID << " vtx wire "
2148  << vw << " time " << (int)fvt << " dth " << dth;
2149  if (fvt > 0. && fvt < maxtime) {
2150  ChkVertex(fvw, fvt, it1, it2, 2);
2151  } // fvt in detector
2152  } // vw topo 2 check
2153  } // fvw in detector
2154  } // topo 2
2155  // topo 3: check for vtx DS of it1 and US of it2
2156  dth = std::abs(bth1 - eth2);
2157  if (tcl[it1].BeginVtx < 0 && tcl[it2].EndVtx < 0 && dth > angcut) {
2158  dsl = bs1 - es2;
2159  if (fabs(bw1 - ew2) < 3 && fabs(bt1 - et2) < 500) { fvw = 0.5 * (bw1 + ew2); }
2160  else {
2161  fvw = (et2 - ew2 * es2 - bt1 + bw1 * bs1) / dsl;
2162  }
2163  if (fvw > 0 && fvw < nwires) {
2164  vw = (0.5 + fvw);
2165  // require vtx US of cluster 2 Begin AND
2166  // vtx DS of cluster 1 End
2167  if (fvw <= ew2 + 2 && fvw >= bw1 - 2) {
2168  fvt = et2 + (fvw - ew2) * es2;
2169  fvt += bt1 + (fvw - bw1) * es1;
2170  fvt /= 2;
2171  if (vtxprt)
2172  mf::LogVerbatim("CC")
2173  << "Chk clusters topo3 " << tcl[it1].ID << " " << tcl[it2].ID << " vtx wire "
2174  << vw << " time " << (int)fvt << " dth " << dth;
2175  if (fvt > 0. && fvt < maxtime) {
2176  ChkVertex(fvw, fvt, it1, it2, 3);
2177  } // fvt in detector
2178  } // vw topo 3 check
2179  } // fvw in detector
2180  } // topo 3
2181  // topo 4: check for vtx DS of it1 and DS of it2
2182  dth = std::abs(bth1 - bth2);
2183  if (tcl[it1].BeginVtx < 0 && tcl[it2].BeginVtx < 0 && dth > 0.1) {
2184  dsl = bs2 - bs1;
2185  // find vertex wire and vertex time in float precision (fvw, fvt)
2186  // convert to integer if within the detector (vw, vt)
2187  fvw = (bt1 - bw1 * bs1 - bt2 + bw2 * bs2) / dsl;
2188  if (vtxprt)
2189  mf::LogVerbatim("CC") << "Chk clusters topo4 " << bw1 << ":" << (int)bt1 << " " << bw2
2190  << ":" << (int)bt2 << " fvw " << fvw << " nwires " << nwires;
2191  if (fvw > 0 && fvw < nwires) {
2192  // vertex wire in the detector
2193  vw = (0.5 + fvw);
2194  // require vtx in the range of wires with hits AND vtx DS of both clusters AND
2195  // vtx not too far DS of both clusters
2196  float dwcut = 10;
2197  if (tcl[it1].tclhits.size() < 2 * dwcut) dwcut = tcl[it1].tclhits.size() / 2;
2198  if (tcl[it2].tclhits.size() < 2 * dwcut) dwcut = tcl[it2].tclhits.size() / 2;
2199  if (fvw <= fLastWire + 1 && fvw >= bw1 - dwcut && fvw <= bw1 + dwcut &&
2200  fvw >= bw2 - dwcut && fvw <= bw1 + dwcut) {
2201  fvt = bt1 + (fvw - bw1) * bs1;
2202  if (vtxprt)
2203  mf::LogVerbatim("CC")
2204  << " vtx wire " << vw << " time " << fvt << " dth " << dth << " dwcut " << dwcut;
2205  if (fvt > 0. && fvt < maxtime) {
2206  // vertex wire US of cluster ends and time in the detector
2207  // Check for signal at the vertex position and adjust the vertex by 1 wire
2208  // if necessary
2209  SigOK = ChkSignal(vw, fvt, vw, fvt);
2210  if (!SigOK) {
2211  fvw -= 1.;
2212  vw = (0.5 + fvw);
2213  SigOK = ChkSignal(vw, fvt, vw, fvt);
2214  }
2215  // Check this against existing vertices and update
2216  if (SigOK) ChkVertex(fvw, fvt, it1, it2, 4);
2217  } // fvt in detector
2218  } // vw topo 4 check
2219  } // fvw in detector
2220  } // topo4
2221  } // it2
2222  } // it1
2223 
2224  // Fix vertices where both ends of a cluster are assigned to the
2225  // same vertex. This can happen with short clusters
2226  for (unsigned short it = 0; it < tcl.size(); ++it) {
2227  if (tcl[it].ID < 0) continue;
2228  if (tcl[it].CTP != clCTP) continue;
2229  if (tcl[it].BeginVtx > -1 && tcl[it].BeginVtx == tcl[it].EndVtx) {
2230  unsigned short iv = tcl[it].BeginVtx;
2231  float dwir = tcl[it].BeginWir - vtx[iv].Wire;
2232  float dtim = tcl[it].BeginTim - vtx[iv].Time;
2233  float rbeg = dwir * dwir + dtim * dtim;
2234  dwir = tcl[it].EndWir - vtx[iv].Wire;
2235  dtim = tcl[it].EndTim - vtx[iv].Time;
2236  float rend = dwir * dwir + dtim * dtim;
2237  if (rend < rbeg) { tcl[it].EndVtx = -99; }
2238  else {
2239  tcl[it].BeginVtx = -99;
2240  }
2241  } // tcl[it].BeginVtx == tcl[it].EndVtx
2242  } // it
2243 
2244  if (vtx.size() > vtxSizeIn) FitAllVtx(clCTP);
2245 
2246  // "delete" any vertices that have only one cluster
2247  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
2248  if (vtx[ivx].CTP != clCTP) continue;
2249  if (vtx[ivx].NClusters == 1) {
2250  vtx[ivx].NClusters = 0;
2251  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
2252  if (tcl[icl].CTP != clCTP) continue;
2253  if (tcl[icl].BeginVtx == ivx) {
2254  tcl[icl].BeginVtx = -99;
2255  break;
2256  }
2257  if (tcl[icl].EndVtx == ivx) {
2258  tcl[icl].EndVtx = -99;
2259  break;
2260  }
2261  } // icl
2262  } // vtx[ivx].NClusters == 1
2263  } // ivx
2264 
2265  } // FindVertices()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
bool ChkSignal(unsigned int iht, unsigned int jht)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
int fDebugHit
out detailed information while crawling
if(nlines<=0)
unsigned int fFirstWire
the first wire with a hit
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
bool greaterThan(CluLen c1, CluLen c2)
void ClusterVertex(unsigned short it2)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void ChkVertex(float fvw, float fvt, unsigned short it1, unsigned short it2, short topo)
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
void cluster::ClusterCrawlerAlg::FitAllVtx ( CTP_t  inCTP)
private

Definition at line 2013 of file ClusterCrawlerAlg.cxx.

2014  {
2015 
2016  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
2017  if (vtx[iv].CTP != inCTP) continue;
2018  FitVtx(iv);
2019  }
2020 
2021  } // FitAllVtx
void FitVtx(unsigned short iv)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::FitCluster ( )
private

Definition at line 4234 of file ClusterCrawlerAlg.cxx.

4235  {
4236  // Fits the hits on the US end of a cluster. This routine assumes that
4237  // wires are numbered from lower (upstream) to higher (downstream) and
4238  // that the hits in the fclhits vector are sorted so that upstream hits
4239  // are at the end of the vector
4240 
4241  clChisq = 999.;
4242 
4243  if (pass > fNumPass - 1) {
4244  mf::LogError("CC") << "FitCluster called on invalid pass " << pass;
4245  return;
4246  }
4247 
4248  unsigned short ii, nht = 0;
4249  // fit all hits or truncate?
4250  nht = fcl2hits.size();
4251  if (clLA) {
4252  // Fit large angle cluster
4253  if (nht > fLAClusMaxHitsFit) nht = fLAClusMaxHitsFit;
4254  }
4255  else {
4256  if (nht > fMaxHitsFit[pass]) nht = fMaxHitsFit[pass];
4257  }
4258  if (nht < 2) return;
4259 
4260  std::vector<float> xwir;
4261  std::vector<float> ytim;
4262  std::vector<float> ytimerr2;
4263  // apply an angle dependent scale factor.
4264  float angfactor = AngleFactor(clpar[1]);
4265 
4266  unsigned int wire;
4267  unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4268  unsigned int ihit;
4269  float terr, qave = 0, qwt;
4270  for (ii = 0; ii < nht; ++ii) {
4271  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4272  qave += fHits[ihit].Integral();
4273  } // ii
4274  qave /= (float)nht;
4275  for (ii = 0; ii < nht; ++ii) {
4276  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4277  wire = fHits[ihit].WireID().Wire;
4278  xwir.push_back(wire - wire0);
4279  ytim.push_back(fHits[ihit].PeakTime());
4280  // Scale error by hit multiplicity to account for bias in hit
4281  // multiplet fitting
4282  terr = fHitErrFac * fHits[ihit].RMS() * fHits[ihit].Multiplicity();
4283  if (fAveChg > 0) {
4284  // increase the error for large charge hits
4285  qwt = (fHits[ihit].Integral() / qave) - 1;
4286  if (qwt < 1) qwt = 1;
4287  terr *= qwt;
4288  }
4289  if (terr < 0.01) terr = 0.01;
4290  ytimerr2.push_back(angfactor * terr * terr);
4291  }
4293  if (prt) {
4294  mf::LogVerbatim myprt("CC");
4295  myprt << "FitCluster W:T ";
4296  unsigned short cnt = 0;
4297  for (std::vector<unsigned int>::reverse_iterator it = fcl2hits.rbegin();
4298  it != fcl2hits.rend();
4299  ++it) {
4300  unsigned int ihit = *it;
4301  unsigned short wire = fHits[ihit].WireID().Wire;
4302  myprt << wire << ":" << (short)fHits[ihit].PeakTime() << " ";
4303  ++cnt;
4304  if (cnt == 8) {
4305  myprt << " .... ";
4306  break;
4307  }
4308  }
4309  } // prt
4310 
4311  if (xwir.size() < 2) return;
4312 
4313  float intcpt = 0.;
4314  float slope = 0.;
4315  float intcpterr = 0.;
4316  float slopeerr = 0.;
4317  float chidof = 0.;
4318  fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4319  clChisq = chidof;
4320  if (chidof > fChiCut[0]) return;
4321  clpar[0] = intcpt;
4322  clpar[1] = slope;
4323  clpar[2] = wire0;
4324  clparerr[0] = intcpterr;
4325  clparerr[1] = slopeerr;
4326 
4327  if (prt)
4328  mf::LogVerbatim("CC") << "nht " << nht << " fitpar " << (int)clpar[0] << "+/-"
4329  << (int)intcpterr << " " << clpar[1] << "+/-" << slopeerr << " clChisq "
4330  << clChisq;
4331  }
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
float clparerr[2]
cluster parameter errors
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF) const
Definition: LinFitAlg.cxx:16
unsigned short fNumPass
number of passes over the hit collection
unsigned short fLAClusMaxHitsFit
max hits fitted on a Large Angle cluster
std::vector< unsigned short > fMaxHitsFit
Max number of hits fitted.
float clChisq
chisq of the current fit
bool clLA
using Large Angle crawling code
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::FitClusterChg ( )
private

Definition at line 4355 of file ClusterCrawlerAlg.cxx.

4356  {
4357  // Fits the charge of hits on the fcl2hits vector to a line, or simply
4358  // uses the average of 1 or 2 hits as determined by NHitsAve
4359 
4360  if (fcl2hits.size() == 0) return;
4361  unsigned int ih0 = fcl2hits.size() - 1;
4362 
4363  if (pass >= fNumPass) {
4364  mf::LogError("CC") << "FitClusterChg bad pass " << pass;
4365  return;
4366  }
4367 
4368  // Handle Large Angle clusters
4369  if (clLA) {
4370  // simple average of the charge (and the hit width
4371  // while we are here)
4372  unsigned short nhave = fLAClusMaxHitsFit;
4373  if (nhave > fcl2hits.size()) nhave = fcl2hits.size();
4374  fAveChg = 0;
4375  fChgSlp = 0;
4376  fAveHitWidth = 0;
4377  unsigned int iht;
4378  for (unsigned short ii = 0; ii < nhave; ++ii) {
4379  iht = fcl2hits[fcl2hits.size() - 1 - ii];
4380  fAveChg += fHits[iht].Integral();
4381  fAveHitWidth += (fHits[iht].EndTick() - fHits[iht].StartTick());
4382  } // ii
4383  fAveChg /= (float)fcl2hits.size();
4384  fAveHitWidth /= (float)fcl2hits.size();
4385  return;
4386  } // clLA
4387 
4388  // number of hits at the leading edge that we will fit
4389  unsigned short fitLen = fNHitsAve[pass];
4390  // start fitting charge when there are at least 6 hits if we are tracking
4391  // long clusters
4392  if (fitLen > 5 && // Fit 6 hits when tracking long clusters AND
4393  fcl2hits.size() > 5 && // there are at least 6 hits AND
4394  fcl2hits.size() < fitLen) // there are less than fNHitsAve[pass]
4395  fitLen = 5;
4396 
4397  // don't find the average charge --> no charge cut is made
4398  if (fNHitsAve[pass] < 1) return;
4399 
4400  if (fNHitsAve[pass] == 1) {
4401  // simply use the charge and width the last hit
4402  fAveChg = fHits[fcl2hits[ih0]].Integral();
4403  fChgSlp = 0.;
4404  }
4405  else if (fNHitsAve[pass] == 2) {
4406  // average the last two points if requested
4407  fAveChg = (fHits[fcl2hits[ih0]].Integral() + fHits[fcl2hits[ih0 - 1]].Integral()) / 2.;
4408  fChgSlp = 0.;
4409  }
4410  else if ((unsigned short)fcl2hits.size() > fitLen) {
4411  // do a real fit
4412  std::vector<float> xwir;
4413  std::vector<float> ychg;
4414  std::vector<float> ychgerr2;
4415  // origin of the fit
4416  unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4417  // find the mean and rms of the charge
4418  unsigned short npt = 0;
4419  unsigned short imlast = 0;
4420  float ave = 0.;
4421  float rms = 0.;
4422  // this loop intentionally ignores the Begin hit
4423  for (unsigned int ii = fcl2hits.size() - 1; ii > 0; --ii) {
4424  ++npt;
4425  float chg = fHits[fcl2hits[ii]].Integral();
4426  ave += chg;
4427  rms += chg * chg;
4428  if (npt == fitLen) {
4429  imlast = ii;
4430  break;
4431  }
4432  }
4433  float fnpt = npt;
4434  ave /= fnpt;
4435  rms = std::sqrt((rms - fnpt * ave * ave) / (fnpt - 1));
4436  float chgcut = ave + rms;
4437  float chg;
4438  unsigned int wire;
4439  for (unsigned short ii = fcl2hits.size() - 1; ii > imlast; --ii) {
4440  wire = fHits[fcl2hits[ii]].WireID().Wire;
4441  chg = fHits[fcl2hits[ii]].Integral();
4442  if (chg > chgcut) continue;
4443  xwir.push_back((float)(wire - wire0));
4444  ychg.push_back(chg);
4445  ychgerr2.push_back(chg);
4446  }
4447  if (ychg.size() < 3) return;
4448  float intcpt;
4449  float slope;
4450  float intcpterr;
4451  float slopeerr;
4452  float chidof;
4453  fLinFitAlg.LinFit(xwir, ychg, ychgerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4454  if (prt)
4455  mf::LogVerbatim("CC") << "FitClusterChg wire " << wire0 << " chidof " << (int)chidof
4456  << " npt " << xwir.size() << " charge = " << (int)intcpt
4457  << " slope = " << (int)slope << " first ave " << (int)ave << " rms "
4458  << (int)rms;
4459  if (chidof > 100.) return;
4460  // fit must have gone wrong if the fStepCrawlChgRatCut average is greater than
4461  // the average using all points
4462  if (intcpt > ave) return;
4463  // ensure that change does not exceed 30%
4464  if (fAveChg > 0) {
4465  ave = intcpt / fAveChg;
4466  if (ave > 1.3) return;
4467  if (ave < 0.77) return;
4468  }
4469  fAveChg = intcpt;
4470  fChgSlp = slope;
4471  }
4472  } // fitchg
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fAveHitWidth
average width (EndTick - StartTick) of hits
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF) const
Definition: LinFitAlg.cxx:16
unsigned short fNumPass
number of passes over the hit collection
if(nlines<=0)
unsigned short fLAClusMaxHitsFit
max hits fitted on a Large Angle cluster
bool clLA
using Large Angle crawling code
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
float fChgSlp
slope of the charge vs wire
std::vector< unsigned short > fNHitsAve
void cluster::ClusterCrawlerAlg::FitClusterMid ( unsigned short  it1,
unsigned int  iht,
short  nhit 
)
private

Definition at line 4126 of file ClusterCrawlerAlg.cxx.

4127  {
4128  FitClusterMid(tcl[it1].tclhits, ihtin, nhit);
4129  } // FitClusterMid
std::vector< ClusterStore > tcl
the clusters we are creating
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
void cluster::ClusterCrawlerAlg::FitClusterMid ( std::vector< unsigned int > &  hitVec,
unsigned int  iht,
short  nhit 
)
private

Definition at line 4132 of file ClusterCrawlerAlg.cxx.

4135  {
4136  // Fits hits on temp cluster it1 to a line starting at hit ihtin and including
4137  // nhit hits incrementing towards the hit vector End when nhit > 0 and
4138  // decrementing towards the hit vector Begin when nhit < 0.
4139  // The fit params are stashed in the clpar and clparerr arrays.
4140  // fAveChg is re-calculated as well.
4141 
4142  // set chisq bad in case something doesn't work out
4143  clChisq = 99.;
4144 
4145  if (hitVec.size() < 3) return;
4146 
4147  std::vector<float> xwir;
4148  std::vector<float> ytim;
4149  std::vector<float> ytimerr2;
4150 
4151  unsigned short ii, hitcnt = 0, nht = 0, usnhit;
4152  float wire0 = 0;
4153  unsigned int iht;
4154  bool UseEm = false;
4155  fAveChg = 0.;
4156  fChgSlp = 0.;
4157 
4158  if (nhit > 0) {
4159  usnhit = nhit;
4160  // find the first desired hit and move towards the End
4161  for (ii = 0; ii < hitVec.size(); ++ii) {
4162  iht = hitVec[ii];
4163  if (iht > fHits.size() - 1) {
4164  mf::LogError("CC") << "FitClusterMid bad iht " << iht;
4165  return;
4166  }
4167  // look for the desired first hit. Use this as the origin wire
4168  if (iht == ihtin) {
4169  UseEm = true;
4170  wire0 = fHits[iht].WireID().Wire;
4171  }
4172  // use hits after finding the first desired hit
4173  if (UseEm) {
4174  xwir.push_back((float)fHits[iht].WireID().Wire - wire0);
4175  ytim.push_back(fHits[iht].PeakTime());
4176  // pass the error^2 to the fitter
4177  float terr = fHitErrFac * fHits[iht].RMS();
4178  ytimerr2.push_back(terr * terr);
4179  fAveChg += fHits[iht].Integral();
4180  ++hitcnt;
4181  if (hitcnt == usnhit) break;
4182  }
4183  }
4184  nht = hitcnt;
4185  }
4186  else {
4187  usnhit = -nhit;
4188  // find the first desired hit and move towards the Begin
4189  for (auto ii = hitVec.crbegin(); ii != hitVec.crend(); ++ii) {
4190  iht = *ii;
4191  if (iht > fHits.size() - 1) {
4192  mf::LogVerbatim("CC") << "FitClusterMid bad iht " << iht;
4193  return;
4194  }
4195  // look for the desired first hit. Use this as the origin wire
4196  if (iht == ihtin) {
4197  UseEm = true;
4198  wire0 = fHits[iht].WireID().Wire;
4199  }
4200  // use hits after finding the first desired hit
4201  if (UseEm) {
4202  xwir.push_back((float)fHits[iht].WireID().Wire - wire0);
4203  ytim.push_back(fHits[iht].PeakTime());
4204  float terr = fHitErrFac * fHits[iht].RMS();
4205  ytimerr2.push_back(terr * terr);
4206  fAveChg += fHits[iht].Integral();
4207  ++hitcnt;
4208  if (hitcnt == usnhit) break;
4209  }
4210  }
4211  nht = hitcnt;
4212  }
4213 
4214  if (nht < 2) return;
4215  fAveChg = fAveChg / (float)nht;
4216  fChgSlp = 0.;
4217 
4218  float intcpt = 0.;
4219  float slope = 0.;
4220  float intcpterr = 0.;
4221  float slopeerr = 0.;
4222  float chidof = 0.;
4223  fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4224  clChisq = chidof;
4225  if (clChisq > fChiCut[0]) return;
4226  clpar[0] = intcpt;
4227  clpar[1] = slope;
4228  clpar[2] = wire0;
4229  clparerr[0] = intcpterr;
4230  clparerr[1] = slopeerr;
4231  }
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
float clparerr[2]
cluster parameter errors
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
std::vector< float > fChiCut
stop adding hits to clusters if chisq too high
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF) const
Definition: LinFitAlg.cxx:16
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
float fChgSlp
slope of the charge vs wire
void cluster::ClusterCrawlerAlg::FitVtx ( unsigned short  iv)
private

Definition at line 5052 of file ClusterCrawlerAlg.cxx.

References tca::DecodeCTP(), x, and y.

5053  {
5054  std::vector<float> x;
5055  std::vector<float> y;
5056  std::vector<float> ey2;
5057  float arg;
5058 
5059  // don't fit fixed vertices
5060  if (vtx[iv].Fixed) return;
5061 
5062  // Set this large in case something bad happens
5063  vtx[iv].ChiDOF = 99;
5064 
5065  // make a list of clusters
5066  unsigned short icl;
5067  std::vector<unsigned short> vcl;
5068  for (icl = 0; icl < tcl.size(); ++icl) {
5069  if (tcl[icl].ID < 0) continue;
5070  if (tcl[icl].CTP != vtx[iv].CTP) continue;
5071  if (tcl[icl].EndVtx == iv) vcl.push_back(icl);
5072  if (tcl[icl].BeginVtx == iv) vcl.push_back(icl);
5073  }
5074 
5075  vtx[iv].NClusters = vcl.size();
5076 
5077  if (vcl.size() == 0) return;
5078 
5079  // don't let the time error be less than the expected
5080  // time error of hits on a cluster. This is crude by
5081  // probably good enough
5082  icl = vcl[0];
5083  unsigned short indx = tcl[icl].tclhits.size() - 1;
5084  unsigned int hit = tcl[icl].tclhits[indx];
5085  float minTimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5086 
5087  if (vcl.size() == 1) {
5088  icl = vcl[0];
5089  // Put the vertex at the appropriate end of the cluster
5090  if (tcl[icl].EndVtx == iv) {
5091  vtx[iv].Wire = tcl[icl].EndWir;
5092  vtx[iv].WireErr = 1;
5093  vtx[iv].Time = tcl[icl].EndTim;
5094  // set the vertex time error to the hit error used for fitting
5095  indx = tcl[icl].tclhits.size() - 1;
5096  hit = tcl[icl].tclhits[indx];
5097  vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5098  vtx[iv].ChiDOF = 0;
5099  }
5100  if (tcl[icl].BeginVtx == iv) {
5101  vtx[iv].Wire = tcl[icl].BeginWir;
5102  vtx[iv].WireErr = 1;
5103  vtx[iv].Time = tcl[icl].BeginTim;
5104  // set the vertex time error to the hit error used for fitting
5105  hit = tcl[icl].tclhits[0];
5106  vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5107  vtx[iv].ChiDOF = 0;
5108  }
5109  return;
5110  } // size 1
5111 
5112  std::vector<double> slps;
5113  std::vector<double> slperrs;
5114  for (unsigned short ii = 0; ii < vcl.size(); ++ii) {
5115  icl = vcl[ii];
5116  if (tcl[icl].EndVtx == iv) {
5117  x.push_back(tcl[icl].EndSlp);
5118  slps.push_back(tcl[icl].EndSlp);
5119  slperrs.push_back(tcl[icl].EndSlpErr);
5120  arg = tcl[icl].EndSlp * tcl[icl].EndWir - tcl[icl].EndTim;
5121  y.push_back(arg);
5122  if (tcl[icl].EndSlpErr > 0.) { arg = tcl[icl].EndSlpErr * tcl[icl].EndWir; }
5123  else {
5124  arg = .1 * tcl[icl].EndWir;
5125  }
5126  ey2.push_back(arg * arg);
5127  }
5128  else if (tcl[icl].BeginVtx == iv) {
5129  x.push_back(tcl[icl].BeginSlp);
5130  slps.push_back(tcl[icl].BeginSlp);
5131  slperrs.push_back(tcl[icl].BeginSlpErr);
5132  arg = tcl[icl].BeginSlp * tcl[icl].BeginWir - tcl[icl].BeginTim;
5133  y.push_back(arg);
5134  if (tcl[icl].BeginSlpErr > 0.) { arg = tcl[icl].BeginSlpErr * tcl[icl].BeginWir; }
5135  else {
5136  arg = .1 * tcl[icl].BeginWir;
5137  }
5138  ey2.push_back(arg * arg);
5139  }
5140  } // ii
5141  if (x.size() < 2) return;
5142 
5143  // calculate error
5144  double sumerr = 0, cnt = 0;
5145  for (unsigned short ii = 0; ii < slps.size() - 1; ++ii) {
5146  for (unsigned short jj = ii + 1; jj < slps.size(); ++jj) {
5147  arg = std::min(slperrs[ii], slperrs[jj]);
5148  arg /= (slps[ii] - slps[jj]);
5149  sumerr += arg * arg;
5150  ++cnt;
5151  } // jj
5152  } // ii
5153  sumerr /= cnt;
5154 
5155  float vTime = 0.;
5156  float vTimeErr = 0.;
5157  float vWire = 0.;
5158  float vWireErr = 0.;
5159  float chiDOF;
5160  fLinFitAlg.LinFit(x, y, ey2, vTime, vWire, vTimeErr, vWireErr, chiDOF);
5161  if (chiDOF > 900) return;
5162  vTime = -vTime;
5163  // a crazy time from the fit?
5164  if (vTime < 0 || vTime > fMaxTime) return;
5165  // a crazy wire from the fit?
5166  geo::PlaneID iplID = DecodeCTP(vtx[iv].CTP);
5167  if (vWire < 0 || vWire > wireReadoutGeom->Nwires(iplID)) return;
5168  vtx[iv].ChiDOF = chiDOF;
5169  vtx[iv].Wire = vWire;
5170  vtx[iv].Time = vTime;
5171  vtx[iv].WireErr = vWire * sqrt(sumerr);
5172  vtx[iv].TimeErr = vTime * fabs(sumerr);
5173  // set minimum wire error
5174  if (vtx[iv].WireErr < 1) vtx[iv].WireErr = 2;
5175  // set minimum time error
5176  if (vtx[iv].TimeErr < minTimeErr) vtx[iv].TimeErr = minTimeErr;
5177 
5178  } // FitVtx
Float_t x
Definition: compare.C:6
std::vector< ClusterStore > tcl
the clusters we are creating
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
Float_t y
Definition: compare.C:6
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
static geo::PlaneID DecodeCTP(CTP_t CTP)
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF) const
Definition: LinFitAlg.cxx:16
geo::WireReadoutGeom const * wireReadoutGeom
Detector simulation of raw signals on wires.
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::FixMultipletLocalIndices ( size_t  begin,
size_t  end,
short int  multiplicity = -1 
)
private

Resets the local index and multiplicity of all the hits in [begin;end[.

Definition at line 1706 of file ClusterCrawlerAlg.cxx.

References recob::Hit::Channel(), recob::Hit::DegreesOfFreedom(), util::end(), recob::Hit::EndTick(), recob::Hit::GoodnessOfFit(), recob::Hit::HitSummedADC(), recob::Hit::Integral(), recob::Hit::PeakAmplitude(), recob::Hit::PeakTime(), recob::Hit::RMS(), recob::Hit::ROISummedADC(), recob::Hit::SigmaIntegral(), recob::Hit::SigmaPeakAmplitude(), recob::Hit::SigmaPeakTime(), recob::Hit::SignalType(), recob::Hit::StartTick(), recob::Hit::View(), and recob::Hit::WireID().

1709  {
1710  //
1711  // Resets multiplicity and local index of the hits in the range.
1712  // All hits are assumed to be in the same multiplet.
1713  // All hits that are not obsolete are given a multiplicity equal to the
1714  // number of non-obsolete hits in the multiplet, and the local index is
1715  // assigned as an increasing number starting from 0 with the first
1716  // non-obsolete hit on.
1717  //
1718 
1719  // first pass: determine the actual number of hits in the multiplet
1720  if (multiplicity < 0) {
1721  multiplicity = 0;
1722  for (size_t iHit = begin; iHit < end; ++iHit) {
1723  if (inClus[iHit] < 0) continue;
1724  ++multiplicity;
1725  } // for
1726  } // if no valid multiplicity is given
1727 
1728  // second pass: assign the correct multiplicity
1729  short int local_index = 0;
1730  for (size_t iHit = begin; iHit < end; ++iHit) {
1731  if (inClus[iHit] < 0) continue;
1732 
1733  // copy everything but overwrite the local index and multiplicity
1734  // TODO use a write wrapper!
1735  recob::Hit const& hit = fHits[iHit];
1736  fHits[iHit] = recob::Hit(hit.Channel(),
1737  hit.StartTick(),
1738  hit.EndTick(),
1739  hit.PeakTime(),
1740  hit.SigmaPeakTime(),
1741  hit.RMS(),
1742  hit.PeakAmplitude(),
1743  hit.SigmaPeakAmplitude(),
1744  hit.ROISummedADC(),
1745  hit.HitSummedADC(),
1746  hit.Integral(),
1747  hit.SigmaIntegral(),
1748  multiplicity, // multiplicity
1749  local_index, // local index
1750  hit.GoodnessOfFit(),
1751  hit.DegreesOfFreedom(),
1752  hit.View(),
1753  hit.SignalType(),
1754  hit.WireID());
1755 
1756  ++local_index;
1757  } // for
1758 
1759  } // FixMultipletLocalIndices()
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:282
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:234
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:242
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:258
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:274
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:254
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:286
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:290
float GoodnessOfFit() const
Degrees of freedom in the determination of the hit signal shape (-1 by default)
Definition: Hit.h:270
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:238
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:218
float HitSummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:250
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:222
float ROISummedADC() const
The sum of calibrated ADC counts of the ROI (0. by default)
Definition: Hit.h:246
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:230
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:278
std::vector<ClusterStore> const& cluster::ClusterCrawlerAlg::GetClusters ( ) const
inline

Returns a constant reference to the clusters found.

Definition at line 127 of file ClusterCrawlerAlg.h.

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

127 { return tcl; }
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector<VtxStore> const& cluster::ClusterCrawlerAlg::GetEndPoints ( ) const
inline

Returns a constant reference to the 2D end points found.

Definition at line 130 of file ClusterCrawlerAlg.h.

Referenced by cluster::LineCluster::produce().

130 { return vtx; }
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::GetHitRange ( CTP_t  CTP)
private

Definition at line 5940 of file ClusterCrawlerAlg.cxx.

References util::abs(), tca::DecodeCTP(), and art::errors::LogicError.

5941  {
5942  // fills the WireHitRange vector for the supplied Cryostat/TPC/Plane code
5943  // Hits must have been sorted by increasing wire number
5944  fFirstHit = 0;
5945  geo::PlaneID planeID = DecodeCTP(CTP);
5946  unsigned int nwires = wireReadoutGeom->Nwires(planeID);
5947  WireHitRange.resize(nwires + 1);
5948 
5949  // These will be re-defined later
5950  fFirstWire = 0;
5951  fLastWire = 0;
5952 
5953  unsigned int wire, iht;
5954  unsigned int nHitInPlane;
5955  std::pair<int, int> flag;
5956 
5957  // Define the "no hits on wire" condition
5958  flag.first = -2;
5959  flag.second = -2;
5960  for (auto& apair : WireHitRange)
5961  apair = flag;
5962 
5963  nHitInPlane = 0;
5964 
5965  std::vector<bool> firsthit;
5966  firsthit.resize(nwires + 1, true);
5967  bool firstwire = true;
5968  for (iht = 0; iht < fHits.size(); ++iht) {
5969  if (fHits[iht].WireID().asPlaneID() != planeID) continue;
5970  wire = fHits[iht].WireID().Wire;
5971  // define the first hit start index in this TPC, Plane
5972  if (firsthit[wire]) {
5973  WireHitRange[wire].first = iht;
5974  firsthit[wire] = false;
5975  }
5976  if (firstwire) {
5977  fFirstWire = wire;
5978  firstwire = false;
5979  }
5980  WireHitRange[wire].second = iht + 1;
5981  fLastWire = wire + 1;
5982  ++nHitInPlane;
5983  }
5984  // overwrite with the "dead wires" condition
5985  lariov::ChannelStatusProvider const& channelStatus =
5987 
5988  flag.first = -1;
5989  flag.second = -1;
5990  unsigned int nbad = 0;
5991  for (wire = 0; wire < nwires; ++wire) {
5993  if (!channelStatus.IsGood(chan)) {
5994  WireHitRange[wire] = flag;
5995  ++nbad;
5996  }
5997  } // wire
5998  // define the MergeAvailable vector and check for errors
5999  if (mergeAvailable.size() < fHits.size())
6001  << "GetHitRange: Invalid mergeAvailable vector size " << mergeAvailable.size()
6002  << fHits.size();
6003  unsigned int firstHit, lastHit;
6004  unsigned int cnt;
6005  cnt = 0;
6006  float maxRMS, chiSep, peakCut;
6007  for (wire = 0; wire < nwires; ++wire) {
6008  // ignore dead wires and wires with no hits
6009  if (WireHitRange[wire].first < 0) continue;
6010  firstHit = WireHitRange[wire].first;
6011  lastHit = WireHitRange[wire].second;
6012  for (iht = firstHit; iht < lastHit; ++iht) {
6013  if (fHits[iht].WireID().Wire != wire)
6015  << "Bad WireHitRange on wire " << wire << "\n";
6016  ++cnt;
6017  if (fHits[iht].Multiplicity() > 1) {
6018  peakCut = 0.6 * fHits[iht].PeakAmplitude();
6019  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(iht);
6020  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
6021  if (jht == iht) continue;
6022  // require that the j hit be similar in magnitude to the i hit
6023  if (fHits[jht].PeakAmplitude() < peakCut) continue;
6024  maxRMS = std::max(fHits[iht].RMS(), fHits[jht].RMS());
6025  chiSep = std::abs(fHits[iht].PeakTime() - fHits[jht].PeakTime()) / maxRMS;
6026  if (chiSep < fHitMergeChiCut) {
6027  mergeAvailable[iht] = true;
6028  break;
6029  }
6030  } // jht
6031  } // fHits[iht].Multiplicity() > 1
6032  } // iht
6033  } // wire
6034  if (cnt != nHitInPlane)
6035  mf::LogWarning("CC") << "Bad WireHitRange count " << cnt << " " << nHitInPlane << "\n";
6036 
6037  if (!fMergeAllHits) return;
6038 
6039  // Merge all of the hits
6040  bool didMerge;
6041  for (wire = 0; wire < nwires; ++wire) {
6042  if (WireHitRange[wire].first < 0) continue;
6043  firstHit = WireHitRange[wire].first;
6044  lastHit = WireHitRange[wire].second;
6045  for (iht = firstHit; iht < lastHit; ++iht) {
6046  if (!mergeAvailable[iht]) continue;
6047  // already merged?
6048  if (fHits[iht].GoodnessOfFit() == 6666) continue;
6049  MergeHits(iht, didMerge);
6050  mergeAvailable[iht] = false;
6051  } // iht
6052  } // wire
6053 
6054  } // GetHitRange()
std::vector< std::pair< int, int > > WireHitRange
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
constexpr auto abs(T v)
Returns the absolute value of the argument.
void MergeHits(const unsigned int theHit, bool &didMerge)
static geo::PlaneID DecodeCTP(CTP_t CTP)
unsigned int fLastWire
the last wire with a hit
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
unsigned int fFirstWire
the first wire with a hit
virtual raw::ChannelID_t PlaneWireToChannel(WireID const &wireID) const =0
Returns the channel ID a wire is connected to.
geo::WireReadoutGeom const * wireReadoutGeom
std::pair< size_t, size_t > FindHitMultiplet(size_t iHit) const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< recob::Hit > fHits
our version of the hits
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
unsigned int fFirstHit
first hit used
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
std::vector<recob::Hit> cluster::ClusterCrawlerAlg::GetHits ( )
inline

Returns the collection of reconstructed hits.

Definition at line 124 of file ClusterCrawlerAlg.h.

124 { return fHits; }
std::vector< recob::Hit > fHits
our version of the hits
std::vector<short> const& cluster::ClusterCrawlerAlg::GetinClus ( ) const
inline

Returns (and loses) the collection of reconstructed hits.

Definition at line 118 of file ClusterCrawlerAlg.h.

Referenced by cluster::ClusterCrawler::produce().

118 { return inClus; }
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector<Vtx3Store> const& cluster::ClusterCrawlerAlg::GetVertices ( ) const
inline

Returns a constant reference to the 3D vertices found.

Definition at line 133 of file ClusterCrawlerAlg.h.

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

133 { return vtx3; }
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
void cluster::ClusterCrawlerAlg::KillGarbageClusters ( )
private

Definition at line 497 of file ClusterCrawlerAlg.cxx.

References util::abs().

498  {
499  // Ghost Clusters:
500 
501  if (tcl.size() < 2) return;
502 
503  unsigned short icl, jcl;
504  // This code preferentially selects icl clusters that were
505  // reconstructed on an early pass (unless they were split)
506  std::vector<float> iHits, jHits;
507  unsigned int indx;
508  // find the average hit width on the first pass and construct
509  // a hit separation cut
510  float sepcut = 0, iFrac, jFrac;
511  bool first = true;
512  unsigned short iLoIndx, jLoIndx, olapSize, iop, ii, jj;
513  unsigned short nclose;
514  float iChg, jChg;
515  // vecrtor of clusters that will be killed after all is done
516  std::vector<unsigned short> killMe;
517  bool doKill;
518  for (icl = 0; icl < tcl.size() - 1; ++icl) {
519  if (tcl[icl].ID < 0) continue;
520  if (tcl[icl].CTP != clCTP) continue;
521  // put the hits into a wire ordered vector
522  iHits.clear();
523  // initialize to a large positive value
524  iHits.resize(tcl[icl].BeginWir - tcl[icl].EndWir + 1, 1000);
525  iChg = 0;
526  for (auto iht : tcl[icl].tclhits) {
527  indx = fHits[iht].WireID().Wire - tcl[icl].EndWir;
528  if (indx > iHits.size() - 1) {
529  mf::LogWarning("CC") << "KillGarbageClusters: icl ID " << tcl[icl].ID << " Bad indx "
530  << indx << " " << iHits.size() << "\n";
531  continue;
532  }
533  iHits[indx] = fHits[iht].PeakTime();
534  iChg += fHits[iht].Integral();
535  if (first) sepcut += fHits[iht].RMS();
536  } // iht
537  if (first) {
538  sepcut /= (float)tcl[icl].tclhits.size();
539  // clusters are consider ghost candidates if many hits
540  // are within sepcut of each other on the same wire
541  sepcut *= 10;
542  first = false;
543  } // first
544  for (jcl = icl + 1; jcl < tcl.size(); ++jcl) {
545  if (tcl[jcl].ID < 0) continue;
546  if (tcl[jcl].CTP != clCTP) continue;
547  // ignore if there is no overlap
548  if (tcl[icl].BeginWir < tcl[jcl].EndWir) continue;
549  if (tcl[icl].EndWir > tcl[jcl].BeginWir) continue;
550  // require similar angle
551  if (std::abs(tcl[icl].BeginAng - tcl[jcl].BeginAng) > fKillGarbageClusters) continue;
552  // find the overlap region
553  if (tcl[icl].EndWir < tcl[jcl].EndWir) {
554  // icl E-----------....
555  // jcl E----------....
556  // olap xxxxxxxxxx...
557  iLoIndx = tcl[jcl].EndWir - tcl[icl].EndWir;
558  jLoIndx = 0;
559  if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
560  // icl E-----------B
561  // jcl E------------B
562  // olap xxxxxxxxxx
563  olapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
564  }
565  else {
566  // icl E-----------B
567  // jcl E-----B
568  // olap xxxxxxx
569  olapSize = tcl[jcl].BeginWir - tcl[jcl].EndWir + 1;
570  } // iBegin
571  } // iEnd < jEnd
572  else {
573  // icl E-----------....
574  // jcl E----------....
575  // olap xxxxxxxxxx...
576  iLoIndx = 0;
577  jLoIndx = tcl[icl].EndWir - tcl[icl].EndWir;
578  if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
579  // icl E-----B
580  // jcl E-----------B
581  // olap xxxxxxx
582  olapSize = tcl[icl].BeginWir - tcl[icl].EndWir + 1;
583  }
584  else {
585  // icl E-----------B
586  // jcl E----------B
587  // olap xxxxxxxxx
588  olapSize = tcl[jcl].BeginWir - tcl[icl].EndWir + 1;
589  }
590  } // iEnd > jEnd
591  jHits.clear();
592  // initialize to a large negative value
593  jHits.resize(tcl[jcl].BeginWir - tcl[jcl].EndWir + 1, -1000);
594  jChg = 0;
595  for (auto jht : tcl[jcl].tclhits) {
596  indx = fHits[jht].WireID().Wire - tcl[jcl].EndWir;
597  if (indx > jHits.size() - 1) {
598  mf::LogWarning("CC") << "KillGarbageClusters: jcl ID " << tcl[jcl].ID << " Bad indx "
599  << indx << " " << jHits.size() << "\n";
600  continue;
601  }
602  jHits[indx] = fHits[jht].PeakTime();
603  jChg += fHits[jht].Integral();
604  } // jht
605  // count the number of close hits
606  nclose = 0;
607  for (iop = 0; iop < olapSize; ++iop) {
608  ii = iLoIndx + iop;
609  if (ii > iHits.size() - 1) continue;
610  jj = jLoIndx + iop;
611  if (jj > jHits.size() - 1) continue;
612  if (std::abs(iHits[ii] - jHits[jj]) < sepcut) ++nclose;
613  } // iop
614  iFrac = (float)nclose / (float)iHits.size();
615  jFrac = (float)nclose / (float)jHits.size();
616  if (iFrac < 0.5 && jFrac < 0.5) continue;
617  doKill = (iFrac < jFrac && iChg > jChg);
618  if (doKill) killMe.push_back(jcl);
619  } // jcl
620  } // icl
621 
622  if (killMe.size() == 0) return;
623  for (auto icl : killMe) {
624  // killing time
625  if (tcl[icl].ID < 0) continue;
626  tcl[icl].ProcCode = 666;
627  MakeClusterObsolete(icl);
628  } // icl
629 
630  } // KillGarbageClusters
std::vector< ClusterStore > tcl
the clusters we are creating
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
std::vector< recob::Hit > fHits
our version of the hits
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
void cluster::ClusterCrawlerAlg::LACrawlUS ( )
private

Definition at line 3539 of file ClusterCrawlerAlg.cxx.

References util::abs().

3540  {
3541  // Crawl a large angle cluster upstream. Similar to CrawlUS but require
3542  // that a hit be added on each wire
3543 
3544  unsigned int dhit = fcl2hits[0];
3545  short dwir = fHits[dhit].WireID().Wire;
3546  clLA = true;
3547  prt = false;
3548  if (fDebugPlane == (short)plane && dwir == fDebugWire && fDebugHit > 0)
3549  prt = std::abs(fHits[dhit].PeakTime() - fDebugHit) < 40;
3550 
3551  if (prt) {
3552  mf::LogVerbatim myprt("CC");
3553  myprt << "******************* LACrawlUS PASS " << pass << " Hits ";
3554  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3555  unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3556  myprt << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime() << " ";
3557  }
3558  }
3559 
3560  bool SigOK = true;
3561  bool HitOK = true;
3562  short nmissed = 0;
3563  // count the number of kinks encountered. Hits US of the kink are removed
3564  // and crawling continues unless another kink is encountered
3565  unsigned short kinkOnWire = 0;
3566  unsigned int it = fcl2hits.size() - 1;
3567  unsigned int lasthit = fcl2hits[it];
3568  unsigned int lastwire = fHits[lasthit].WireID().Wire;
3569  unsigned int prevHit, prevWire;
3570  bool ChkCharge = false;
3571  for (unsigned int nextwire = lastwire - 1; nextwire >= fFirstWire; --nextwire) {
3572  if (prt)
3573  mf::LogVerbatim("CC") << "LACrawlUS: next wire " << nextwire << " HitRange "
3574  << WireHitRange[nextwire].first;
3575  // stop crawling if there is a nearby vertex
3576  if (CrawlVtxChk(nextwire)) {
3577  if (prt) mf::LogVerbatim("CC") << "LACrawlUS: stop at vertex";
3578  clStopCode = 6;
3579  break;
3580  }
3581  // AddLAHit will merge the hit on nextwire if necessary
3582  AddLAHit(nextwire, ChkCharge, HitOK, SigOK);
3583  if (prt)
3584  mf::LogVerbatim("CC") << "LACrawlUS: HitOK " << HitOK << " SigOK " << SigOK
3585  << " nmissed SigOK " << nmissed << " cut " << fAllowNoHitWire;
3586  if (SigOK) nmissed = 0;
3587  if (!SigOK) {
3588  ++nmissed;
3589  if (nmissed > fAllowNoHitWire) {
3590  clStopCode = 1;
3591  break;
3592  }
3593  continue;
3594  }
3595  // If a hit was added after a gap, check to see if there is indeed
3596  // a wire signal in the gap
3597  if (HitOK) {
3598  prevHit = fcl2hits[fcl2hits.size() - 2];
3599  prevWire = fHits[prevHit].WireID().Wire;
3600  if (prevWire > nextwire + 2) {
3601  if (!ChkSignal(fcl2hits[fcl2hits.size() - 1], fcl2hits[fcl2hits.size() - 2])) {
3602  // no hit so trim the last hit and quit
3603  FclTrimUS(1);
3604  break;
3605  } // no signal
3606  } // prevWire > nextwire + 2
3607  } // HitOK
3608  // Merge all of the hit multiplets in the fcl2hits array into single
3609  // hits when enough hits have been found to call this a credible large
3610  // angle cluster. The last hit was already merged in AddHit
3611  if (fcl2hits.size() == 4) {
3612  bool didMerge;
3613  for (unsigned short kk = 0; kk < fcl2hits.size() - 1; ++kk) {
3614  unsigned int hit = fcl2hits[kk];
3615  if (mergeAvailable[hit]) MergeHits(hit, didMerge);
3616  }
3617  // update the fit
3618  FitCluster();
3619  clBeginSlp = clpar[1];
3620  // start checking the charge ratio when adding new hits
3621  ChkCharge = true;
3622  continue;
3623  } // fcl2hits.size() == 4
3624  unsigned short chsiz = chifits.size() - 1;
3625  // chsiz is fcl2hits.size() - 1...
3626  if (chsiz < 6) continue;
3627  if (fKinkChiRat[pass] <= 0) continue;
3628  if (chifits.size() != fcl2hits.size()) {
3629  mf::LogError("CC") << "LACrawlUS: chifits size error " << chifits.size() << " "
3630  << fcl2hits.size();
3631  return;
3632  }
3633  if (prt)
3634  mf::LogVerbatim("CC") << "Kink chk " << chifits[chsiz] << " " << chifits[chsiz - 1] << " "
3635  << chifits[chsiz - 2] << " " << chifits[chsiz - 3];
3636  if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3637  chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3638  // find the kink angle (crudely) from the 0th and 2nd hit
3639  unsigned int ih0 = fcl2hits.size() - 1;
3640  unsigned int hit0 = fcl2hits[ih0];
3641  unsigned int ih2 = ih0 - 2;
3642  unsigned int hit2 = fcl2hits[ih2];
3643  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3644  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3645  float th02 = std::atan(fScaleF * dt02 / dw02);
3646  // and the 3rd and 5th hit
3647  unsigned int ih3 = ih2 - 1;
3648  unsigned int hit3 = fcl2hits[ih3];
3649  unsigned int ih5 = ih3 - 2;
3650  unsigned int hit5 = fcl2hits[ih5];
3651  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
3652  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
3653  float th35 = std::atan(fScaleF * dt35 / dw35);
3654  float dth = std::abs(th02 - th35);
3655  if (prt)
3656  mf::LogVerbatim("CC") << " Kink angle " << std::setprecision(3) << dth << " cut "
3657  << fKinkAngCut[pass];
3658  if (dth > fKinkAngCut[pass]) {
3659  // hit a kink. Lop of the first 3 hits, refit and keep crawling?
3660  FclTrimUS(3);
3661  FitCluster();
3662  // See if this is a second kink and it is close to the first
3663  // kink (which had hits removed).
3664  if (kinkOnWire > 0) {
3665  if (kinkOnWire - nextwire < 4) {
3666  if (prt)
3667  mf::LogVerbatim("CC")
3668  << "Hit a second kink. kinkOnWire = " << kinkOnWire << " Stopping";
3669  // set the kink stop code
3670  clStopCode = 3;
3671  break;
3672  }
3673  }
3674  kinkOnWire = nextwire;
3675  if (prt) mf::LogVerbatim("CC") << "Removed kink hits";
3676  } // kinkang check
3677  } // chifits test
3678  } // nextwire
3679 
3681 
3682  clProcCode += 300;
3683  if (prt) mf::LogVerbatim("CC") << "LACrawlUS done. Nhits = " << fcl2hits.size();
3684  prt = false;
3685  } // LACrawlUS
float fScaleF
scale factor from Tick/Wire to dx/du
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< std::pair< int, int > > WireHitRange
bool ChkSignal(unsigned int iht, unsigned int jht)
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
constexpr auto abs(T v)
Returns the absolute value of the argument.
void MergeHits(const unsigned int theHit, bool &didMerge)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
void AddLAHit(unsigned int kwire, bool &ChkCharge, bool &HitOK, bool &SigOK)
void FclTrimUS(unsigned short nTrim)
bool CrawlVtxChk(unsigned int kwire)
int fDebugHit
out detailed information while crawling
unsigned int fFirstWire
the first wire with a hit
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
std::vector< float > fKinkChiRat
float clBeginSlp
begin slope (= DS end = high wire number)
Detector simulation of raw signals on wires.
bool clLA
using Large Angle crawling code
std::vector< recob::Hit > fHits
our version of the hits
std::vector< float > chifits
fit chisq for monitoring kinks, etc
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::MakeClusterObsolete ( unsigned short  icl)
private

Marks the cluster as obsolete and frees hits still associated with it.

Definition at line 825 of file ClusterCrawlerAlg.cxx.

826  {
827  short& ID = tcl[icl].ID;
828  if (ID <= 0) {
829  mf::LogError("CC") << "Trying to make already-obsolete cluster obsolete ID = " << ID;
830  return; // already obsolete
831  }
832  ID = -ID; // mark the cluster as obsolete
833 
834  // release the hits
835  for (unsigned int iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
836  inClus[tcl[icl].tclhits[iht]] = 0;
837 
838  } // ClusterCrawlerAlg::MakeClusterObsolete()
std::vector< ClusterStore > tcl
the clusters we are creating
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
void cluster::ClusterCrawlerAlg::MergeHits ( const unsigned int  theHit,
bool &  didMerge 
)
private

Definition at line 1546 of file ClusterCrawlerAlg.cxx.

References util::abs(), recob::Hit::Channel(), recob::Hit::DegreesOfFreedom(), recob::Hit::EndTick(), recob::Hit::HitSummedADC(), recob::Hit::Integral(), recob::Hit::Multiplicity(), recob::Hit::PeakAmplitude(), recob::Hit::PeakTime(), recob::Hit::PeakTimeMinusRMS(), recob::Hit::PeakTimePlusRMS(), geo::PlaneID::Plane, recob::Hit::RMS(), recob::Hit::ROISummedADC(), recob::Hit::SigmaIntegral(), recob::Hit::SigmaPeakAmplitude(), recob::Hit::SigmaPeakTime(), recob::Hit::SignalType(), recob::Hit::StartTick(), recob::Hit::View(), geo::WireID::Wire, and recob::Hit::WireID().

1547  {
1548  // Merge all unused separate hits in the multiplet of which
1549  // theHit is a member into one hit (= theHit).
1550  // Mark the merged hits other than theHit obsolete.
1551  // Hits in the multiplet that are associated with an existing cluster are
1552  // not affected.
1553  // Hit multiplicity is reworked (including all the hits in the multiplet).
1554  // Used hits have the multiplicity and index corrected too; the local
1555  // index reflects the peak time.
1556  // Note that theHit may or may not be marked free (usually, it is not)
1557 
1558  didMerge = false;
1559 
1560  if (theHit > fHits.size() - 1) { return; }
1561 
1562  recob::Hit const& hit = fHits[theHit];
1563 
1564  // don't bother trying to merge an already merged hit
1565  if (fHits[theHit].GoodnessOfFit() == 6666) {
1566  if (prt)
1567  mf::LogVerbatim("CC") << "MergeHits Trying to merge already merged hit "
1568  << hit.WireID().Plane << ":" << hit.WireID().Wire << ":"
1569  << (int)hit.PeakTime() << " Multiplicity " << hit.Multiplicity()
1570  << " theHit " << theHit;
1571  return;
1572  }
1573 
1574  // don't merge if it isn't available
1575  if (!mergeAvailable[theHit]) { return; }
1576 
1577  if (hit.Multiplicity() < 2) return;
1578 
1579  // number of hits in this hit multiplet
1580  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(theHit);
1581 
1582  // ensure that this is a high multiplicity hit:
1583  if (MultipletRange.second <= MultipletRange.first) return;
1584 
1585  // do a quick check to see how many hits are available to be merged
1586  unsigned short nAvailable = 0;
1587  unsigned short nInClus = 0;
1588  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1589  if (jht == theHit) continue;
1590  if (fHits[jht].GoodnessOfFit() == 6666) continue;
1591  if (inClus[jht] != 0) {
1592  ++nInClus;
1593  continue;
1594  }
1595  ++nAvailable;
1596  } // jht
1597  if (nAvailable == 0) return;
1598  // don't merge if any hit is used
1599  if (nInClus > 0) return;
1600 
1601  // calculate the Charge normalization factor using the hit information
1602  // instead of passing CCHitFinder ChgNorms all the way down here
1603  float chgNorm = 2.507 * hit.PeakAmplitude() * hit.RMS() / hit.Integral();
1604 
1605  short loTime = 9999;
1606  short hiTime = 0;
1607  unsigned short nGaus = 1;
1608  float hitSep;
1609  // number of hits that are close to theHit
1610  unsigned short nclose = 0;
1611  // find the time range for the hit multiplet
1612  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1613  if (inClus[jht] < 0) continue;
1614  recob::Hit const& other_hit = fHits[jht];
1615  // error checking
1616  if ((other_hit.StartTick() != hit.StartTick()) || (other_hit.WireID() != hit.WireID())) {
1617  return;
1618  }
1619  if (other_hit.Multiplicity() != hit.Multiplicity()) { return; }
1620  // hit is not used by another cluster
1621  if (inClus[jht] != 0) continue;
1622  short arg = (short)(other_hit.PeakTimeMinusRMS(3));
1623  if (arg < loTime) loTime = arg;
1624  arg = (short)(other_hit.PeakTimePlusRMS(3));
1625  if (arg > hiTime) hiTime = arg;
1626  if (jht != theHit) ++nGaus;
1627  hitSep = std::abs(other_hit.PeakTime() - hit.PeakTime()) / other_hit.RMS();
1628  if (jht != theHit && hitSep < 3) ++nclose;
1629  } // jht
1630  // all hits in the multiplet other than this one used?
1631  if (nGaus < 2) return;
1632 
1633  // the hits in this multiplet will have this multiplicity from now on
1634  const short int NewMultiplicity = hit.Multiplicity() + 1 - nGaus;
1635 
1636  if (loTime < 0) loTime = 0;
1637  ++hiTime;
1638  // define a signal shape, fill it with zeros
1639  std::vector<double> signal(hiTime - loTime, 0.);
1640  // now add the Gaussians for each hit
1641  double chgsum = 0.;
1642  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1643  recob::Hit const& other_hit = fHits[jht];
1644  if (jht != theHit) {
1645  // hit used in another cluster
1646  if (inClus[jht] != 0) continue;
1647  // declare this hit obsolete
1648  inClus[jht] = -1;
1649  } // jht != theHit
1650  // add up the charge
1651  chgsum += other_hit.Integral();
1652  for (unsigned short time = loTime; time < hiTime; ++time) {
1653  unsigned short indx = time - loTime;
1654  double arg = (other_hit.PeakTime() - (double)time) / other_hit.RMS();
1655  signal[indx] += other_hit.PeakAmplitude() * exp(-0.5 * arg * arg);
1656  } // time
1657  } // jj
1658  // find the average weighted time
1659  double sigsum = 0.;
1660  double sigsumt = 0.;
1661  for (unsigned short time = loTime; time < hiTime; ++time) {
1662  sigsum += signal[time - loTime];
1663  sigsumt += signal[time - loTime] * time;
1664  }
1665  if (sigsum == 0.) {
1666  // mf::LogError("CC")<<"MergeHits: bad sum";
1667  return;
1668  }
1669  double aveTime = sigsumt / sigsum;
1670  // find the RMS
1671  sigsumt = 0.;
1672  for (unsigned short time = loTime; time < hiTime; ++time) {
1673  double dtime = time - aveTime;
1674  sigsumt += signal[time - loTime] * dtime * dtime;
1675  }
1676  const float RMS = std::sqrt(sigsumt / sigsum);
1677  // find the amplitude from the integrated charge and the RMS
1678  const float amplitude = chgsum * chgNorm / (2.507 * RMS);
1679  // modify the hit "in place" (actually completely overwrite it...)
1680  // TODO a lot of these quantities need revamp!!
1681  fHits[theHit] = recob::Hit(hit.Channel(),
1682  hit.StartTick(),
1683  hit.EndTick(),
1684  aveTime, // peak_time
1685  hit.SigmaPeakTime(),
1686  RMS, // rms
1687  amplitude, // peak_amplitude
1688  hit.SigmaPeakAmplitude(),
1689  hit.ROISummedADC(),
1690  hit.HitSummedADC(),
1691  chgsum, // hit_integral
1692  hit.SigmaIntegral(),
1693  NewMultiplicity, // multiplicity
1694  0, // local index
1695  6666, // GoodnessOfFit (flag for merged hit)
1696  hit.DegreesOfFreedom(),
1697  hit.View(),
1698  hit.SignalType(),
1699  hit.WireID());
1700  FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1701  didMerge = true;
1702 
1703  } // MergeHits()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:282
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:234
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:242
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:258
constexpr auto abs(T v)
Returns the absolute value of the argument.
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:274
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:254
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:286
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
void FixMultipletLocalIndices(size_t begin, size_t end, short int multiplicity=-1)
Resets the local index and multiplicity of all the hits in [begin;end[.
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:290
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:262
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:238
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:373
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:218
std::pair< size_t, size_t > FindHitMultiplet(size_t iHit) const
float PeakTimeMinusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:300
float HitSummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:250
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:222
float ROISummedADC() const
The sum of calibrated ADC counts of the ROI (0. by default)
Definition: Hit.h:246
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:230
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:295
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:278
void cluster::ClusterCrawlerAlg::MergeOverlap ( )
private

Definition at line 633 of file ClusterCrawlerAlg.cxx.

References util::abs(), tca::PrintHit(), and cluster::SortByLowHit().

634  {
635  // Tries to merge overlapping clusters schematically shown below. The minimal condition is that both
636  // clusters have a length of at least minLen wires with minOvrLap of the minLen wires in the overlap region
637  // End Begin
638  // icl ------
639  // jcl ------
640  // End Begin
641  // This can occur when tracking cosmic rays through delta ray showers.
642  // If successfull the hits in clusters icl and jcl are merged into one long cluster
643  // and a short cluster if there are sufficient remaining hits.
644  // This routine changes the "pass" variable to define cuts and should NOT be used inside any pass loops
645 
646  unsigned short icl, jcl;
647 
648  bool chkprt = (fDebugWire == 666);
649  if (chkprt) mf::LogVerbatim("CC") << "Inside MergeOverlap using clCTP " << clCTP;
650 
651  unsigned short minLen = 6;
652  unsigned short minOvrLap = 2;
653 
654  // use the loosest dTick cut which is probably the last one
655  float maxDTick = fTimeDelta[fTimeDelta.size() - 1];
656 
657  unsigned int overlapSize, ii, indx, bWire, eWire;
658  unsigned int iht, jht;
659  float dang, prtime, dTick;
660  for (icl = 0; icl < tcl.size(); ++icl) {
661  if (tcl[icl].ID < 0) continue;
662  if (tcl[icl].CTP != clCTP) continue;
663  prt = chkprt && fDebugPlane == (int)clCTP;
664  if (tcl[icl].BeginVtx >= 0) continue;
665  if (tcl[icl].tclhits.size() < minLen) continue;
666  for (jcl = 0; jcl < tcl.size(); ++jcl) {
667  if (icl == jcl) continue;
668  if (tcl[jcl].ID < 0) continue;
669  if (tcl[jcl].CTP != clCTP) continue;
670  if (tcl[jcl].EndVtx >= 0) continue;
671  if (tcl[jcl].tclhits.size() < minLen) continue;
672  // icl Begin is not far enough DS from the end of jcl
673  if (tcl[icl].BeginWir < tcl[jcl].EndWir + minOvrLap) continue;
674  // and it doesn't end within the wire boundaries of jcl
675  if (tcl[icl].BeginWir > tcl[jcl].BeginWir - minOvrLap) continue;
676  // jcl End isn't far enough US from the end of icl
677  if (tcl[jcl].EndWir < tcl[icl].EndWir + minOvrLap) continue;
678  dang = std::abs(tcl[icl].BeginAng - tcl[jcl].EndAng);
679  if (prt)
680  mf::LogVerbatim("CC") << "MergeOverlap icl ID " << tcl[icl].ID << " jcl ID "
681  << tcl[jcl].ID << " dang " << dang;
682  if (dang > 0.5) continue;
683  overlapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
684  eWire = tcl[jcl].EndWir;
685  bWire = tcl[icl].BeginWir;
686  if (prt)
687  mf::LogVerbatim("CC") << " Candidate icl ID " << tcl[icl].ID << " " << tcl[icl].EndWir
688  << "-" << tcl[icl].BeginWir << " jcl ID " << tcl[jcl].ID << " "
689  << tcl[jcl].EndWir << "-" << tcl[jcl].BeginWir << " overlapSize "
690  << overlapSize << " bWire " << bWire << " eWire " << eWire;
691  iht = 0;
692  jht = 0;
693  for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
694  iht = tcl[icl].tclhits[ii];
695  if (fHits[iht].WireID().Wire < eWire) break;
696  } // ii
697  // require that the ends be similar in time
698  dTick = std::abs(fHits[iht].PeakTime() - tcl[jcl].EndTim);
699  if (dTick > maxDTick) continue;
700  if (prt)
701  mf::LogVerbatim("CC") << " dTick icl iht time " << PrintHit(iht) << " jcl EndTim "
702  << tcl[jcl].EndTim << " dTick " << dTick;
703  for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
704  jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
705  if (fHits[jht].WireID().Wire > bWire) break;
706  } // ii
707  dTick = std::abs(fHits[jht].PeakTime() - tcl[icl].BeginTim);
708  if (dTick > maxDTick) continue;
709  if (prt)
710  mf::LogVerbatim("CC") << " dTick jcl jht time " << PrintHit(jht) << " icl BeginTim "
711  << tcl[icl].BeginTim << " dTick " << dTick;
712  // Calculate the line between iht and jht
713  clpar[0] = fHits[iht].PeakTime();
714  clpar[2] = fHits[iht].WireID().Wire;
715  clpar[1] = (fHits[jht].PeakTime() - fHits[iht].PeakTime()) /
716  ((float)fHits[jht].WireID().Wire - clpar[2]);
717  // put the hits in the overlap region into a vector if they are close to the line
718  std::vector<unsigned int> oWireHits(overlapSize, INT_MAX);
719  std::vector<float> delta(overlapSize, maxDTick);
720  for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
721  iht = tcl[icl].tclhits[ii];
722  if (fHits[iht].WireID().Wire < eWire) break;
723  prtime = clpar[0] + clpar[1] * ((float)fHits[iht].WireID().Wire - clpar[2]);
724  dTick = std::abs(fHits[iht].PeakTime() - prtime);
725  indx = fHits[iht].WireID().Wire - eWire;
726  if (dTick > delta[indx]) continue;
727  delta[indx] = dTick;
728  oWireHits[indx] = iht;
729  } // ii
730  // enter the second set of hits
731  for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
732  jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
733  if (fHits[jht].WireID().Wire > bWire) break;
734  prtime = clpar[0] + clpar[1] * ((float)fHits[jht].WireID().Wire - clpar[2]);
735  dTick = std::abs(fHits[jht].PeakTime() - prtime);
736  indx = fHits[jht].WireID().Wire - eWire;
737  if (dTick > delta[indx]) continue;
738  delta[indx] = dTick;
739  oWireHits[indx] = jht;
740  } // ii
741  // stuff them into fcl2hits
742  fcl2hits.clear();
743  for (ii = 0; ii < oWireHits.size(); ++ii) {
744  if (oWireHits[ii] == INT_MAX) continue;
745  iht = oWireHits[ii];
746  fcl2hits.push_back(iht);
747  if (prt) mf::LogVerbatim("CC") << "hit " << PrintHit(iht);
748  } // ii
749  if (fcl2hits.size() < 0.5 * overlapSize) continue;
750  if (fcl2hits.size() < 3) continue;
751  std::sort(fcl2hits.begin(), fcl2hits.end(), SortByLowHit);
752  FitCluster();
753  if (prt)
754  mf::LogVerbatim("CC") << " Overlap size " << overlapSize << " fit chisq " << clChisq
755  << " nhits " << fcl2hits.size();
756  if (clChisq > 20) continue;
757  // save these hits so we can paste them back on fcl2hits when merging
758  std::vector<unsigned int> oHits = fcl2hits;
759  // prepare to make a new cluster
760  TmpGet(jcl);
761  // resize it
762  unsigned short jclNewSize;
763  for (jclNewSize = 0; jclNewSize < fcl2hits.size(); ++jclNewSize) {
764  iht = fcl2hits[jclNewSize];
765  if (fHits[iht].WireID().Wire <= bWire) break;
766  } // jclNewSize
767  if (prt) {
768  mf::LogVerbatim("CC") << "jcl old size " << fcl2hits.size() << " newSize " << jclNewSize;
769  iht = fcl2hits[fcl2hits.size() - 1];
770  unsigned int iiht = fcl2hits[jclNewSize - 1];
771  mf::LogVerbatim("CC") << "jcl old last wire " << fHits[iht].WireID().Wire
772  << " After resize last wire " << fHits[iiht].WireID().Wire;
773  }
774  fcl2hits.resize(jclNewSize);
775  // append the hits in the overlap region
776  fcl2hits.insert(fcl2hits.end(), oHits.begin(), oHits.end());
777  // now paste in the icl hits that are US of the overlap region
778  for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
779  iht = tcl[icl].tclhits[ii];
780  if ((unsigned int)fHits[iht].WireID().Wire >= eWire) continue;
781  fcl2hits.insert(fcl2hits.end(), tcl[icl].tclhits.begin() + ii, tcl[icl].tclhits.end());
782  break;
783  }
784  clBeginSlp = tcl[jcl].BeginSlp;
785  clBeginSlpErr = tcl[jcl].BeginSlpErr;
786  clBeginAng = tcl[jcl].BeginAng;
787  clBeginWir = tcl[jcl].BeginWir;
788  clBeginTim = tcl[jcl].BeginTim;
789  clBeginChg = tcl[jcl].BeginChg;
790  clBeginChgNear = tcl[jcl].BeginChgNear;
791  // End info from icl
792  clEndSlp = tcl[icl].EndSlp;
793  clEndSlpErr = tcl[icl].EndSlpErr;
794  clEndAng = tcl[icl].EndAng;
795  clEndWir = tcl[icl].EndWir;
796  clEndTim = tcl[icl].EndTim;
797  clEndChg = tcl[icl].EndChg;
798  clEndChgNear = tcl[icl].EndChgNear;
799  clStopCode = tcl[icl].StopCode;
800  clProcCode = tcl[icl].ProcCode + 500;
801  MakeClusterObsolete(icl);
802  MakeClusterObsolete(jcl);
803  if (!TmpStore()) {
804  // Merged cluster is fubar. Try to recover
808  continue;
809  }
811  tcl[tcl.size() - 1].BeginVtx = tcl[jcl].BeginVtx;
812  tcl[tcl.size() - 1].EndVtx = tcl[icl].BeginVtx;
813  // after this point any failure should result in a jcl loop break
814  if (prt)
815  mf::LogVerbatim("CC") << "MergeOverlap new long cluster ID " << tcl[tcl.size() - 1].ID
816  << " in clCTP " << clCTP;
817  // icl cluster made obsolete so we must have done something
818  if (tcl[icl].ID < 0) break;
819  } // jcl
820  } // icl
821 
822  } // MergeOverlap()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< float > fTimeDelta
max time difference for matching
float clBeginChg
begin average charge
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
float clEndSlp
slope at the end (= US end = low wire number)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CTP_t clCTP
Cryostat/TPC/Plane code.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
unsigned int clEndWir
begin wire
bool SortByLowHit(unsigned int i, unsigned int j)
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
void RestoreObsoleteCluster(unsigned short icl)
Restores an obsolete cluster.
void TmpGet(unsigned short it1)
float clBeginSlp
begin slope (= DS end = high wire number)
std::string PrintHit(unsigned int iht)
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the hits
float clEndChg
end average charge
unsigned int clBeginWir
begin wire
float clBeginChgNear
nearby charge
float clEndChgNear
nearby charge
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
float cluster::ClusterCrawlerAlg::PointVertexChi ( float  wire,
float  tick,
unsigned short  ivx 
)
private

Definition at line 6241 of file ClusterCrawlerAlg.cxx.

6242  {
6243  // Returns the Chisq/DOF between a (Wire, Tick) point and a vertex
6244 
6245  if (ivx > vtx.size()) return 9999;
6246 
6247  float dW = wire - vtx[ivx].Wire;
6248  float chi = dW / vtx[ivx].WireErr;
6249  float totChi = chi * chi;
6250  float dT = tick - vtx[ivx].Time;
6251  chi = dT / vtx[ivx].TimeErr;
6252  totChi += chi * chi;
6253 
6254  return totChi;
6255 
6256  } // PointVertexChi
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:73
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::PrintClusters ( )
private

Definition at line 3318 of file ClusterCrawlerAlg.cxx.

References util::abs(), and art::right().

3319  {
3320 
3321  // prints clusters to the screen for code development
3322  mf::LogVerbatim myprt("CC");
3323 
3324  PrintVertices();
3325 
3326  float aveRMS, aveRes;
3327  myprt << "*************************************** Clusters "
3328  "*********************************************************************\n";
3329  myprt << " ID CTP nht Stop Proc beg_W:T bAng bSlp Err bChg end_W:T eAng eSlp "
3330  "Err eChg bVx eVx aveRMS Qual cnt\n";
3331  for (unsigned short ii = 0; ii < tcl.size(); ++ii) {
3332  // print clusters in all planes (fDebugPlane = 3) or in a selected plane
3333  if (fDebugPlane < 3 && fDebugPlane != (int)tcl[ii].CTP) continue;
3334  myprt << std::right << std::setw(4) << tcl[ii].ID;
3335  myprt << std::right << std::setw(3) << tcl[ii].CTP;
3336  myprt << std::right << std::setw(5) << tcl[ii].tclhits.size();
3337  myprt << std::right << std::setw(4) << tcl[ii].StopCode;
3338  myprt << std::right << std::setw(6) << tcl[ii].ProcCode;
3339  unsigned int iTime = tcl[ii].BeginTim;
3340  myprt << std::right << std::setw(6) << tcl[ii].BeginWir << ":" << iTime;
3341  if (iTime < 10) { myprt << " "; }
3342  else if (iTime < 100) {
3343  myprt << " ";
3344  }
3345  else if (iTime < 1000)
3346  myprt << " ";
3347  myprt << std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].BeginAng;
3348  if (std::abs(tcl[ii].BeginSlp) < 100) {
3349  myprt << std::right << std::setw(6) << std::fixed << std::setprecision(2)
3350  << tcl[ii].BeginSlp;
3351  }
3352  else {
3353  myprt << std::right << std::setw(6) << (int)tcl[ii].BeginSlp;
3354  }
3355  myprt << std::right << std::setw(6) << std::fixed << std::setprecision(2)
3356  << tcl[ii].BeginSlpErr;
3357  myprt << std::right << std::setw(5) << (int)tcl[ii].BeginChg;
3358  iTime = tcl[ii].EndTim;
3359  myprt << std::right << std::setw(6) << tcl[ii].EndWir << ":" << iTime;
3360  if (iTime < 10) { myprt << " "; }
3361  else if (iTime < 100) {
3362  myprt << " ";
3363  }
3364  else if (iTime < 1000)
3365  myprt << " ";
3366  myprt << std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].EndAng;
3367  if (std::abs(tcl[ii].EndSlp) < 100) {
3368  myprt << std::right << std::setw(6) << std::fixed << std::setprecision(2) << tcl[ii].EndSlp;
3369  }
3370  else {
3371  myprt << std::right << std::setw(6) << (int)tcl[ii].EndSlp;
3372  }
3373  myprt << std::right << std::setw(6) << std::fixed << std::setprecision(2)
3374  << tcl[ii].EndSlpErr;
3375  myprt << std::right << std::setw(5) << (int)tcl[ii].EndChg;
3376  myprt << std::right << std::setw(5) << tcl[ii].BeginVtx;
3377  myprt << std::right << std::setw(5) << tcl[ii].EndVtx;
3378  aveRMS = 0;
3379  unsigned int iht = 0;
3380  for (unsigned short jj = 0; jj < tcl[ii].tclhits.size(); ++jj) {
3381  iht = tcl[ii].tclhits[jj];
3382  aveRMS += fHits[iht].RMS();
3383  }
3384  aveRMS /= (float)tcl[ii].tclhits.size();
3385  myprt << std::right << std::setw(5) << std::fixed << std::setprecision(1) << aveRMS;
3386  aveRes = 0;
3387  // find cluster tracking resolution
3388  unsigned int hit0, hit1, hit2, cnt = 0;
3389  float arg;
3390  for (unsigned short iht = 1; iht < tcl[ii].tclhits.size() - 1; ++iht) {
3391  hit1 = tcl[ii].tclhits[iht];
3392  hit0 = tcl[ii].tclhits[iht - 1];
3393  hit2 = tcl[ii].tclhits[iht + 1];
3394  // require hits on adjacent wires
3395  if (fHits[hit1].WireID().Wire + 1 != fHits[hit0].WireID().Wire) continue;
3396  if (fHits[hit2].WireID().Wire + 1 != fHits[hit1].WireID().Wire) continue;
3397  arg = (fHits[hit0].PeakTime() + fHits[hit2].PeakTime()) / 2 - fHits[hit1].PeakTime();
3398  aveRes += arg * arg;
3399  ++cnt;
3400  }
3401  if (cnt > 1) {
3402  aveRes /= (float)cnt;
3403  aveRes = sqrt(aveRes);
3404  // convert to a quality factor
3405  aveRes /= (aveRMS * fHitErrFac);
3406  myprt << std::right << std::setw(6) << std::fixed << std::setprecision(1) << aveRes;
3407  myprt << std::right << std::setw(5) << std::fixed << cnt;
3408  }
3409  else {
3410  myprt << " NA";
3411  myprt << std::right << std::setw(5) << std::fixed << cnt;
3412  }
3413  myprt << "\n";
3414  } // ii
3415 
3416  } // PrintClusters()
std::vector< ClusterStore > tcl
the clusters we are creating
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
constexpr auto abs(T v)
Returns the absolute value of the argument.
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::vector< recob::Hit > fHits
our version of the hits
std::string cluster::ClusterCrawlerAlg::PrintHit ( unsigned int  iht)
private

Definition at line 6259 of file ClusterCrawlerAlg.cxx.

References util::to_string().

6260  {
6261 
6262  if (iht > fHits.size() - 1) return "Bad Hit";
6263  return std::to_string(fHits[iht].WireID().Plane) + ":" +
6264  std::to_string(fHits[iht].WireID().Wire) + ":" +
6265  std::to_string((int)fHits[iht].PeakTime());
6266 
6267  } // PrintHit
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
std::vector< recob::Hit > fHits
our version of the hits
recob::tracking::Plane Plane
Definition: TrackState.h:17
void cluster::ClusterCrawlerAlg::PrintVertices ( )
private

Definition at line 3254 of file ClusterCrawlerAlg.cxx.

References art::right().

3255  {
3256 
3257  mf::LogVerbatim myprt("CC");
3258 
3259  if (vtx3.size() > 0) {
3260  // print out 3D vertices
3261  myprt
3262  << "****** 3D vertices ******************************************__2DVtx_Indx__*******\n";
3263  myprt
3264  << "Vtx Cstat TPC Proc X Y Z XEr YEr ZEr pln0 pln1 pln2 Wire\n";
3265  for (unsigned short iv = 0; iv < vtx3.size(); ++iv) {
3266  myprt << std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3267  myprt << std::right << std::setw(7) << vtx3[iv].CStat;
3268  myprt << std::right << std::setw(5) << vtx3[iv].TPC;
3269  myprt << std::right << std::setw(5) << vtx3[iv].ProcCode;
3270  myprt << std::right << std::setw(8) << vtx3[iv].X;
3271  myprt << std::right << std::setw(8) << vtx3[iv].Y;
3272  myprt << std::right << std::setw(8) << vtx3[iv].Z;
3273  myprt << std::right << std::setw(5) << vtx3[iv].XErr;
3274  myprt << std::right << std::setw(5) << vtx3[iv].YErr;
3275  myprt << std::right << std::setw(5) << vtx3[iv].ZErr;
3276  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[0];
3277  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[1];
3278  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[2];
3279  myprt << std::right << std::setw(5) << vtx3[iv].Wire;
3280  if (vtx3[iv].Wire < 0) { myprt << " Matched in all planes"; }
3281  else {
3282  myprt << " Incomplete";
3283  }
3284  myprt << "\n";
3285  }
3286  } // vtx3.size
3287 
3288  if (vtx.size() > 0) {
3289  // print out 2D vertices
3290  myprt << "************ 2D vertices ************\n";
3291  myprt << "Vtx CTP wire error tick error ChiDOF NCl topo cluster IDs\n";
3292  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
3293  if (fDebugPlane < 3 && fDebugPlane != (int)vtx[iv].CTP) continue;
3294  myprt << std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3295  myprt << std::right << std::setw(6) << vtx[iv].CTP;
3296  myprt << std::right << std::setw(8) << vtx[iv].Wire << " +/- ";
3297  myprt << std::right << std::setw(4) << vtx[iv].WireErr;
3298  myprt << std::right << std::setw(8) << vtx[iv].Time << " +/- ";
3299  myprt << std::right << std::setw(4) << vtx[iv].TimeErr;
3300  myprt << std::right << std::setw(8) << vtx[iv].ChiDOF;
3301  myprt << std::right << std::setw(5) << vtx[iv].NClusters;
3302  myprt << std::right << std::setw(6) << vtx[iv].Topo;
3303  myprt << " ";
3304  // display the cluster IDs
3305  for (unsigned short ii = 0; ii < tcl.size(); ++ii) {
3306  if (fDebugPlane < 3 && fDebugPlane != (int)tcl[ii].CTP) continue;
3307  if (tcl[ii].ID < 0) continue;
3308  if (tcl[ii].BeginVtx == (short)iv) myprt << std::right << std::setw(4) << tcl[ii].ID;
3309  if (tcl[ii].EndVtx == (short)iv) myprt << std::right << std::setw(4) << tcl[ii].ID;
3310  }
3311  myprt << "\n";
3312  } // iv
3313  } // vtx.size
3314 
3315  } // PrintVertices
std::vector< ClusterStore > tcl
the clusters we are creating
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::RefineVertexClusters ( unsigned short  ivx)
private

Definition at line 1256 of file ClusterCrawlerAlg.cxx.

References util::abs().

1257  {
1258 
1259  // Try to attach or remove hits on the ends of vertex clusters
1260 
1261  std::vector<unsigned short> begClusters;
1262  std::vector<short> begdW;
1263  std::vector<unsigned short> endClusters;
1264  std::vector<short> enddW;
1265 
1266  unsigned int vWire = (unsigned int)(vtx[iv].Wire + 0.5);
1267  unsigned int vWireErr = (unsigned int)(2 * vtx[iv].WireErr);
1268  unsigned int vWireLo = vWire - vWireErr;
1269  unsigned int vWireHi = vWire + vWireErr;
1270 
1271  unsigned short icl, ii;
1272  short dW;
1273  bool needsWork = false;
1274  short maxdW = -100;
1275  short mindW = 100;
1276  for (icl = 0; icl < tcl.size(); ++icl) {
1277  if (tcl[icl].ID < 0) continue;
1278  if (tcl[icl].CTP != vtx[iv].CTP) continue;
1279  if (tcl[icl].BeginVtx == iv) {
1280  dW = vWire - tcl[icl].BeginWir;
1281  if (dW > maxdW) maxdW = dW;
1282  if (dW < mindW) mindW = dW;
1283  if (std::abs(dW) > 1) needsWork = true;
1284  // TODO: Check dTime also?
1285  begClusters.push_back(icl);
1286  begdW.push_back(dW);
1287  }
1288  if (tcl[icl].EndVtx == iv) {
1289  dW = vWire - tcl[icl].EndWir;
1290  if (dW > maxdW) maxdW = dW;
1291  if (dW < mindW) mindW = dW;
1292  if (std::abs(dW) > 1) needsWork = true;
1293  endClusters.push_back(icl);
1294  enddW.push_back(dW);
1295  }
1296  } // icl
1297 
1298  if (vtxprt)
1299  mf::LogVerbatim("CC") << "RefineVertexClusters: vertex " << iv << " needsWork " << needsWork
1300  << " mindW " << mindW << " maxdW " << maxdW << " vWireErr " << vWireErr;
1301 
1302  if (!needsWork) return;
1303 
1304  // See if we can move the vertex within errors to reconcile the differences
1305  // without altering the clusters
1306  if (((unsigned int)std::abs(mindW) < vWireErr) && ((unsigned int)std::abs(maxdW) < vWireErr) &&
1307  std::abs(maxdW - mindW) < 2) {
1308  if (vtxprt) mf::LogVerbatim("CC") << " Move vtx wire " << vtx[iv].Wire;
1309  vtx[iv].Wire -= (float)(maxdW + mindW) / 2;
1310  if (vtxprt) mf::LogVerbatim("CC") << " to " << vtx[iv].Wire;
1311  // TODO: Fix the vertex time here if necessary
1312  vtx[iv].Fixed = true;
1313  // try to attach other clusters
1314  VertexCluster(iv);
1315  return;
1316  }
1317 
1318  // Check the vertex End clusters
1319  unsigned short newSize;
1320  for (ii = 0; ii < endClusters.size(); ++ii) {
1321  icl = endClusters[ii];
1322  if (vtxprt)
1323  mf::LogVerbatim("CC") << " endCluster " << tcl[icl].ID << " dW " << enddW[ii] << " vWire "
1324  << vWire;
1325  if (tcl[icl].EndWir < vWire) {
1326  // vertex is DS of the cluster end -> remove hits
1327  TmpGet(icl);
1328  newSize = fcl2hits.size();
1329  for (auto hiter = fcl2hits.rbegin(); hiter < fcl2hits.rend(); ++hiter) {
1330  if (fHits[*hiter].WireID().Wire > vWire) break;
1331  --newSize;
1332  }
1333  // release the hits
1334  for (auto hiter = fcl2hits.begin(); hiter < fcl2hits.end(); ++hiter)
1335  inClus[*hiter] = 0;
1336  // shorten the cluster
1337  fcl2hits.resize(newSize);
1338  MakeClusterObsolete(icl);
1339  // fit
1340  FitCluster();
1341  clProcCode += 700;
1342  // store it
1343  TmpStore();
1344  tcl[tcl.size() - 1].EndVtx = iv;
1345  // update the vertex association
1346  if (vtxprt)
1347  mf::LogVerbatim("CC") << " modified cluster " << tcl[icl].ID << " -> "
1348  << tcl[tcl.size() - 1].ID;
1349  } // tcl[icl].EndWir < vWire
1350  else if (tcl[icl].EndWir > vWire) {
1351  mf::LogVerbatim("CC") << "RefineVertexClusters: Write some EndVtx code";
1352  } //
1353  } // ii endClusters
1354 
1355  if (begClusters.size() > 0)
1356  mf::LogVerbatim("CC") << "RefineVertexClusters: Write some BeginVtx code";
1357 
1358  if (mindW < 0 && maxdW > 0) {
1359  // vertex wire is in between the ends of the clusters
1360  // inspect the hits on both clusters near the vertex. The vertex should probably be on the hit
1361  // with the highest charge
1362  int vtxHit = -1;
1363  unsigned short clsBigChg = 0;
1364  float bigChg = 0;
1365  unsigned int iht;
1366  unsigned int ihit;
1367  // check the begClusters
1368  for (ii = 0; ii < begClusters.size(); ++ii) {
1369  icl = begClusters[ii];
1370  for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1371  ihit = tcl[icl].tclhits[iht];
1372  if (fHits[ihit].Integral() > bigChg) {
1373  bigChg = fHits[ihit].Integral();
1374  vtxHit = ihit;
1375  clsBigChg = icl;
1376  }
1377  if (fHits[ihit].WireID().Wire < vWireLo) break;
1378  } // iht
1379  } // ii
1380  // now check the endClusters
1381  for (ii = 0; ii < endClusters.size(); ++ii) {
1382  icl = endClusters[ii];
1383  for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1384  ihit = tcl[icl].tclhits[tcl[icl].tclhits.size() - 1 - iht];
1385  if (fHits[ihit].Integral() > bigChg) {
1386  bigChg = fHits[ihit].Integral();
1387  vtxHit = ihit;
1388  clsBigChg = icl;
1389  }
1390  if (fHits[ihit].WireID().Wire > vWireHi) break;
1391  } // iht
1392  } // ii
1393  if (vtxHit > 0) {
1394  if (vtxprt)
1395  mf::LogVerbatim("CC") << " moving vertex location to hit " << fHits[vtxHit].WireID().Wire
1396  << ":" << (int)fHits[vtxHit].PeakTime() << " on cluster "
1397  << tcl[clsBigChg].ID;
1398  vtx[iv].Wire = fHits[vtxHit].WireID().Wire;
1399  vtx[iv].Time = fHits[vtxHit].PeakTime();
1400  vtx[iv].Fixed = true;
1401  } // vtxHit > 0
1402  } // mindW < 0 && maxdW > 0
1403 
1404  FitVtx(iv);
1405 
1406  } // RefineVertexClusters
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
void TmpGet(unsigned short it1)
std::vector< recob::Hit > fHits
our version of the hits
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void VertexCluster(unsigned short ivx)
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::RemoveObsoleteHits ( )
private

Removes obsolete hits from hits, updating the indices.

Definition at line 933 of file ClusterCrawlerAlg.cxx.

References hits().

934  {
935 
936  unsigned int destHit = 0;
937 
938  if (fHits.size() != inClus.size()) {
939  mf::LogError("CC") << "RemoveObsoleteHits size mis-match " << fHits.size() << " "
940  << inClus.size();
941  return;
942  }
943 
944  unsigned short icl;
945  for (unsigned int srcHit = 0; srcHit < fHits.size(); ++srcHit) {
946  if (inClus[srcHit] < 0) continue;
947  if (srcHit != destHit) {
948  fHits[destHit] = std::move(fHits[srcHit]);
949  inClus[destHit] = inClus[srcHit];
950  if (inClus[destHit] > 0) {
951  // hit is in a cluster. Find it and change the index
952  icl = inClus[destHit] - 1;
953  auto& hits = tcl[icl].tclhits;
954  auto iHitIndex = std::find(hits.begin(), hits.end(), srcHit);
955  if (iHitIndex == hits.end()) {
956  mf::LogError("CC") << "RemoveObsoleteHits: Hit #" << srcHit
957  << " not found in cluster ID " << inClus[destHit];
958  }
959  else {
960  *iHitIndex = destHit; // update the index
961  }
962  } // inClus[destHit] > 0
963  }
964  ++destHit;
965  } // srcHit
966 
967  fHits.resize(destHit);
968  inClus.resize(destHit);
969 
970  } // RemoveObsoleteHits()
std::vector< ClusterStore > tcl
the clusters we are creating
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
void hits()
Definition: readHits.C:15
std::vector< recob::Hit > fHits
our version of the hits
void cluster::ClusterCrawlerAlg::RestoreObsoleteCluster ( unsigned short  icl)
private

Restores an obsolete cluster.

Definition at line 841 of file ClusterCrawlerAlg.cxx.

842  {
843  short& ID = tcl[icl].ID;
844  if (ID > 0) {
845  mf::LogError("CC") << "Trying to restore non-obsolete cluster ID = " << ID;
846  return;
847  }
848  ID = -ID;
849 
850  for (unsigned short iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
851  inClus[tcl[icl].tclhits[iht]] = ID;
852 
853  } // RestoreObsoleteCluster()
std::vector< ClusterStore > tcl
the clusters we are creating
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
void cluster::ClusterCrawlerAlg::RunCrawler ( detinfo::DetectorClocksData const &  clock_data,
detinfo::DetectorPropertiesData const &  det_prop,
std::vector< recob::Hit > const &  srchits 
)

Definition at line 198 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorPropertiesData::DriftVelocity(), detinfo::DetectorPropertiesData::Efield(), tca::EncodeCTP(), detinfo::DetectorPropertiesData::NumberTimeSamples(), tca::PrintClusters(), detinfo::sampling_rate(), and detinfo::DetectorPropertiesData::Temperature().

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

201  {
202  // Run the ClusterCrawler algorithm - creating seed clusters and crawling upstream.
203 
204  CrawlInit();
205 
206  fHits = srchits; // plain copy of the sources; it's the base of our hit result
207 
208  if (fHits.size() < 3) return;
209  if (fHits.size() > UINT_MAX) {
210  mf::LogWarning("CC") << "Too many hits for ClusterCrawler " << fHits.size();
211  return;
212  }
213 
214  // don't do anything...
215  if (fNumPass == 0) return;
216 
217  // sort it as needed;
218  // that is, sorted by wire ID number,
219  // then by start of the region of interest in time, then by the multiplet
220  std::sort(fHits.begin(), fHits.end(), &SortByMultiplet);
221 
222  inClus.resize(fHits.size());
223  mergeAvailable.resize(fHits.size());
224  for (unsigned int iht = 0; iht < inClus.size(); ++iht) {
225  inClus[iht] = 0;
226  mergeAvailable[iht] = false;
227  }
228 
229  // FIXME (KJK): The 'cstat', 'tpc', and 'plane' class variables should be removed.
230  for (geo::TPCID const& tpcid : geom->Iterate<geo::TPCID>()) {
231  cstat = tpcid.Cryostat;
232  tpc = tpcid.TPC;
233  for (geo::PlaneID const& planeid : wireReadoutGeom->Iterate<geo::PlaneID>(tpcid)) {
234  plane = planeid.Plane;
235  WireHitRange.clear();
236  // define a code to ensure clusters are compared within the same plane
237  clCTP = EncodeCTP(tpcid.Cryostat, tpcid.TPC, planeid.Plane);
238  cstat = tpcid.Cryostat;
239  tpc = tpcid.TPC;
240  // fill the WireHitRange vector with first/last hit on each wire
241  // dead wires and wires with no hits are flagged < 0
243 
244  // sanity check
245  if (WireHitRange.empty() || (fFirstWire == fLastWire)) continue;
246  raw::ChannelID_t channel = fHits[fFirstHit].Channel();
247  // get the scale factor to convert dTick/dWire to dX/dU. This is used
248  // to make the kink and merging cuts
249  float wirePitch = wireReadoutGeom->Plane(tpcid, wireReadoutGeom->View(channel)).WirePitch();
250  float tickToDist = det_prop.DriftVelocity(det_prop.Efield(), det_prop.Temperature());
251  tickToDist *= 1.e-3 * sampling_rate(clock_data); // 1e-3 is conversion of 1/us to 1/ns
252  fScaleF = tickToDist / wirePitch;
253  // convert Large Angle Cluster crawling cut to a slope cut
254  if (fLAClusAngleCut > 0)
255  fLAClusSlopeCut = std::tan(3.142 * fLAClusAngleCut / 180.) / fScaleF;
256  fMaxTime = det_prop.NumberTimeSamples();
257  fNumWires = wireReadoutGeom->Nwires(planeid);
258  // look for clusters
259  if (fNumPass > 0) ClusterLoop();
260  } // plane
261  if (fVertex3DCut > 0) {
262  // Match vertices in 3 planes
263  VtxMatch(det_prop, tpcid);
264  Vtx3ClusterMatch(det_prop, tpcid);
266  // split clusters using 3D vertices
267  Vtx3ClusterSplit(det_prop, tpcid);
268  }
269  if (fDebugPlane >= 0) {
270  mf::LogVerbatim("CC") << "Clustering done in TPC ";
271  PrintClusters();
272  }
273  } // for all tpcs
274 
275  // clean up
276  WireHitRange.clear();
277  fcl2hits.clear();
278  chifits.clear();
279  hitNear.clear();
280  chgNear.clear();
281 
282  // remove the hits that have become obsolete
284 
285  } // RunCrawler
float fScaleF
scale factor from Tick/Wire to dx/du
std::vector< short > hitNear
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< std::pair< int, int > > WireHitRange
void RemoveObsoleteHits()
Removes obsolete hits from hits, updating the indices.
unsigned int Nwires(PlaneID const &planeid) const
Returns the total number of wires in the specified plane.
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
static bool SortByMultiplet(recob::Hit const &a, recob::Hit const &b)
Comparison for sorting hits by wire and hit multiplet.
CTP_t clCTP
Cryostat/TPC/Plane code.
art::ServiceHandle< geo::Geometry const > geom
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
unsigned short fNumPass
number of passes over the hit collection
unsigned int fFirstWire
the first wire with a hit
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
geo::WireReadoutGeom const * wireReadoutGeom
void VtxMatch(detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
The data type to uniquely identify a TPC.
Definition: geo_types.h:306
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::vector< recob::Hit > fHits
our version of the hits
void Vtx3ClusterSplit(detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
std::vector< float > chifits
fit chisq for monitoring kinks, etc
View_t View(raw::ChannelID_t const channel) const
Returns the view (wire orientation) on the specified TPC channel.
float fLAClusAngleCut
call Large Angle Clustering code if > 0
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
range_type< T > Iterate() const
Definition: Iterable.h:121
unsigned int fFirstHit
first hit used
void Vtx3ClusterMatch(detinfo::DetectorPropertiesData const &det_prop, geo::TPCID const &tpcid)
std::vector< float > chgNear
charge near a cluster on each wire
bool fFindHammerClusters
look for hammer type clusters
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
void FindHammerClusters(detinfo::DetectorPropertiesData const &det_prop)
bool cluster::ClusterCrawlerAlg::SortByMultiplet ( recob::Hit const &  a,
recob::Hit const &  b 
)
static

Comparison for sorting hits by wire and hit multiplet.

Definition at line 134 of file ClusterCrawlerAlg.cxx.

References recob::Hit::LocalIndex(), recob::Hit::StartTick(), and recob::Hit::WireID().

135  {
136  auto const a_tup = std::make_tuple(a.WireID(), a.StartTick(), a.LocalIndex());
137  auto const b_tup = std::make_tuple(b.WireID(), b.StartTick(), b.LocalIndex());
138  return a_tup < b_tup;
139  }
bool cluster::ClusterCrawlerAlg::SplitCluster ( unsigned short  icl,
unsigned short  pos,
unsigned short  ivx 
)
private

Definition at line 2669 of file ClusterCrawlerAlg.cxx.

2670  {
2671  // split cluster icl into two clusters
2672 
2673  if (tcl[icl].ID < 0) return false;
2674 
2675  // declare icl obsolete
2676  MakeClusterObsolete(icl);
2677 
2678  unsigned short ii, iclnew;
2679  unsigned int iht;
2680 
2681  if (pos > 2) {
2682  // Have enough hits to make a cluster at the Begin end
2683  // Create the first cluster (DS) using the Begin info
2684  clBeginSlp = tcl[icl].BeginSlp;
2685  clBeginSlpErr = tcl[icl].BeginSlpErr;
2686  clBeginAng = tcl[icl].BeginAng;
2687  clBeginWir = tcl[icl].BeginWir;
2688  clBeginTim = tcl[icl].BeginTim;
2689  clBeginChg = tcl[icl].BeginChg;
2690  clStopCode = 5;
2691  clProcCode = tcl[icl].ProcCode;
2692  fcl2hits.clear();
2693  chifits.clear();
2694  hitNear.clear();
2695  chgNear.clear();
2696  for (ii = 0; ii < pos; ++ii) {
2697  iht = tcl[icl].tclhits[ii];
2698  fcl2hits.push_back(iht);
2699  }
2700  // determine the pass in which this cluster was created
2701  pass = tcl[icl].ProcCode - 10 * (tcl[icl].ProcCode / 10);
2702  if (pass > fNumPass - 1) pass = fNumPass - 1;
2703  // fit the end hits
2704  FitCluster();
2705  clEndSlp = clpar[1];
2706  clEndSlpErr = clparerr[1];
2707  clEndAng = std::atan(fScaleF * clEndSlp);
2708  // find the charge at the end
2709  FitClusterChg();
2710  clEndChg = fAveChg;
2711  if (!TmpStore()) {
2713  return false;
2714  }
2715  // associate the End with the supplied vertex
2716  iclnew = tcl.size() - 1;
2717  tcl[iclnew].EndVtx = ivx;
2718  tcl[iclnew].BeginVtx = tcl[icl].BeginVtx;
2719  if (vtxprt)
2720  mf::LogVerbatim("CC") << "SplitCluster made cluster " << iclnew << " attached to Begin vtx "
2721  << ivx;
2722  } // pos > 2
2723 
2724  if (pos < tcl[icl].tclhits.size() - 3) {
2725  // have enough hits to make a cluster at the End
2726  // now create the second cluster (US)
2727  clEndSlp = tcl[icl].EndSlp;
2728  clEndSlpErr = tcl[icl].EndSlpErr;
2729  clEndAng = std::atan(fScaleF * clEndSlp);
2730  clEndWir = tcl[icl].EndWir;
2731  clEndTim = tcl[icl].EndTim;
2732  clEndChg = tcl[icl].EndChg;
2733  clStopCode = 5;
2734  clProcCode = tcl[icl].ProcCode;
2735  fcl2hits.clear();
2736  chifits.clear();
2737  hitNear.clear();
2738  chgNear.clear();
2739  bool didFit = false;
2740  for (ii = pos; ii < tcl[icl].tclhits.size(); ++ii) {
2741  iht = tcl[icl].tclhits[ii];
2742  if (inClus[iht] != 0) {
2744  return false;
2745  }
2746  fcl2hits.push_back(iht);
2747  // define the Begin parameters
2748  if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
2749  FitCluster();
2750  clBeginSlp = clpar[1];
2751  clBeginAng = std::atan(fScaleF * clBeginSlp);
2752  clBeginSlpErr = clparerr[1];
2753  didFit = true;
2754  }
2755  if ((unsigned short)fcl2hits.size() == fNHitsAve[pass] + 1) {
2756  FitClusterChg();
2757  clBeginChg = fAveChg;
2758  didFit = true;
2759  }
2760  } // ii
2761  // do a fit using all hits if one wasn't done
2762  if (!didFit) {
2763  FitCluster();
2764  FitClusterChg();
2765  clBeginChg = fAveChg;
2766  }
2767  if (!TmpStore()) {
2768  // clobber the previously stored cluster
2769  MakeClusterObsolete(tcl.size() - 1);
2771  return false;
2772  }
2773  // associate the End with the supplied vertex
2774  iclnew = tcl.size() - 1;
2775  tcl[iclnew].BeginVtx = ivx;
2776  tcl[iclnew].EndVtx = tcl[icl].EndVtx;
2777  if (vtxprt)
2778  mf::LogVerbatim("CC") << "SplitCluster made cluster " << iclnew << " attached to End vtx "
2779  << ivx;
2780  }
2781 
2782  return true;
2783  } // SplitCluster()
float fScaleF
scale factor from Tick/Wire to dx/du
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned short fNumPass
number of passes over the hit collection
unsigned int clEndWir
begin wire
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
void RestoreObsoleteCluster(unsigned short icl)
Restores an obsolete cluster.
float clBeginSlp
begin slope (= DS end = high wire number)
std::vector< unsigned short > fMaxHitsFit
Max number of hits fitted.
std::vector< unsigned short > fMinHits
Min number of hits to make a cluster.
float clEndChg
end average charge
std::vector< float > chifits
fit chisq for monitoring kinks, etc
unsigned int clBeginWir
begin wire
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
std::vector< unsigned short > fNHitsAve
void cluster::ClusterCrawlerAlg::TmpGet ( unsigned short  it1)
private

Definition at line 3419 of file ClusterCrawlerAlg.cxx.

3420  {
3421  // copies temp cluster it1 into the fcl2hits vector, etc. This is
3422  // effectively the inverse of cl2TmpStore
3423 
3424  if (it1 > tcl.size()) return;
3425 
3426  clBeginSlp = tcl[it1].BeginSlp;
3427  clBeginSlpErr = tcl[it1].BeginSlpErr;
3428  clBeginAng = tcl[it1].BeginAng;
3429  clBeginWir = tcl[it1].BeginWir;
3430  clBeginTim = tcl[it1].BeginTim;
3431  clBeginChg = tcl[it1].BeginChg;
3432  clBeginChgNear = tcl[it1].BeginChgNear;
3433  clEndSlp = tcl[it1].EndSlp;
3434  clEndSlpErr = tcl[it1].EndSlpErr;
3435  clEndAng = tcl[it1].EndAng;
3436  clEndWir = tcl[it1].EndWir;
3437  clEndTim = tcl[it1].EndTim;
3438  clEndChg = tcl[it1].EndChg;
3439  clEndChgNear = tcl[it1].EndChgNear;
3440  clStopCode = tcl[it1].StopCode;
3441  clProcCode = tcl[it1].ProcCode;
3442  clCTP = tcl[it1].CTP;
3443  fcl2hits = tcl[it1].tclhits;
3444  }
std::vector< ClusterStore > tcl
the clusters we are creating
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
CTP_t clCTP
Cryostat/TPC/Plane code.
unsigned int clEndWir
begin wire
float clBeginSlp
begin slope (= DS end = high wire number)
float clEndChg
end average charge
unsigned int clBeginWir
begin wire
float clBeginChgNear
nearby charge
float clEndChgNear
nearby charge
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
bool cluster::ClusterCrawlerAlg::TmpStore ( )
private

Definition at line 3447 of file ClusterCrawlerAlg.cxx.

References cluster::ClusterCrawlerAlg::ClusterStore::BeginAng, cluster::ClusterCrawlerAlg::ClusterStore::BeginChg, cluster::ClusterCrawlerAlg::ClusterStore::BeginChgNear, cluster::ClusterCrawlerAlg::ClusterStore::BeginSlp, cluster::ClusterCrawlerAlg::ClusterStore::BeginSlpErr, cluster::ClusterCrawlerAlg::ClusterStore::BeginTim, cluster::ClusterCrawlerAlg::ClusterStore::BeginVtx, cluster::ClusterCrawlerAlg::ClusterStore::BeginWir, cluster::ClusterCrawlerAlg::ClusterStore::CTP, tca::EncodeCTP(), cluster::ClusterCrawlerAlg::ClusterStore::EndAng, cluster::ClusterCrawlerAlg::ClusterStore::EndChg, cluster::ClusterCrawlerAlg::ClusterStore::EndChgNear, cluster::ClusterCrawlerAlg::ClusterStore::EndSlp, cluster::ClusterCrawlerAlg::ClusterStore::EndSlpErr, cluster::ClusterCrawlerAlg::ClusterStore::EndTim, cluster::ClusterCrawlerAlg::ClusterStore::EndVtx, cluster::ClusterCrawlerAlg::ClusterStore::EndWir, cluster::ClusterCrawlerAlg::ClusterStore::ID, cluster::ClusterCrawlerAlg::ClusterStore::ProcCode, cluster::ClusterCrawlerAlg::ClusterStore::StopCode, and cluster::ClusterCrawlerAlg::ClusterStore::tclhits.

3448  {
3449 
3450  if (fcl2hits.size() < 2) return false;
3451  if (fcl2hits.size() > fHits.size()) return false;
3452 
3453  if (NClusters == SHRT_MAX) return false;
3454 
3455  ++NClusters;
3456 
3457  unsigned int hit0 = fcl2hits[0];
3458  unsigned int hit;
3459  unsigned int tCST = fHits[hit0].WireID().Cryostat;
3460  unsigned int tTPC = fHits[hit0].WireID().TPC;
3461  unsigned int tPlane = fHits[hit0].WireID().Plane;
3462  unsigned int lastWire = 0;
3463 
3464  for (unsigned short it = 0; it < fcl2hits.size(); ++it) {
3465  hit = fcl2hits[it];
3466  if (inClus[hit] != 0) {
3467  --NClusters;
3468  return false;
3469  }
3470  // check for WireID() consistency
3471  if (fHits[hit].WireID().Cryostat != tCST || fHits[hit].WireID().TPC != tTPC ||
3472  fHits[hit].WireID().Plane != tPlane) {
3473  --NClusters;
3474  return false;
3475  }
3476  // check for decreasing wire number
3477  if (clProcCode < 900 && it > 0 && fHits[hit].WireID().Wire >= lastWire) {
3478  --NClusters;
3479  return false;
3480  }
3481  lastWire = fHits[hit].WireID().Wire;
3482  inClus[hit] = NClusters;
3483  }
3484 
3485  // ensure that the cluster begin/end info is correct
3486 
3487  // define the begin/end charge if it wasn't done already
3488  if (clEndChg <= 0) {
3489  // use the next to the last two hits. The End hit may have low charge
3490  unsigned int ih0 = fcl2hits.size() - 2;
3491  hit = fcl2hits[ih0];
3492  clEndChg = fHits[hit].Integral();
3493  hit = fcl2hits[ih0 - 1];
3494  clEndChg += fHits[hit].Integral();
3495  clEndChg = clEndChg / 2.;
3496  }
3497  if (clBeginChg <= 0) {
3498  // use the 2nd and third hit. The Begin hit may have low charge
3499  hit = fcl2hits[1];
3500  clBeginChg = fHits[hit].Integral();
3501  hit = fcl2hits[2];
3502  clBeginChg += fHits[hit].Integral();
3503  clBeginChg = clBeginChg / 2.;
3504  }
3505 
3506  hit0 = fcl2hits[0];
3507  hit = fcl2hits[fcl2hits.size() - 1];
3508 
3509  // store the cluster in the temporary ClusterStore struct
3510  ClusterStore clstr;
3511 
3512  clstr.ID = NClusters;
3513  clstr.BeginSlp = clBeginSlp;
3514  clstr.BeginSlpErr = clBeginSlpErr;
3515  clstr.BeginAng = std::atan(fScaleF * clBeginSlp);
3516  clstr.BeginWir = fHits[hit0].WireID().Wire;
3517  clstr.BeginTim = fHits[hit0].PeakTime();
3518  clstr.BeginChg = clBeginChg;
3519  clstr.BeginChgNear = clBeginChgNear;
3520  clstr.EndSlp = clEndSlp;
3521  clstr.EndSlpErr = clEndSlpErr;
3522  clstr.EndAng = std::atan(fScaleF * clEndSlp);
3523  clstr.EndWir = fHits[hit].WireID().Wire;
3524  clstr.EndTim = fHits[hit].PeakTime();
3525  clstr.EndChg = clEndChg;
3526  clstr.EndChgNear = clEndChgNear;
3527  clstr.StopCode = clStopCode;
3528  clstr.ProcCode = clProcCode;
3529  clstr.BeginVtx = -99;
3530  clstr.EndVtx = -99;
3531  clstr.CTP = EncodeCTP(tCST, tTPC, tPlane);
3532  clstr.tclhits = fcl2hits;
3533  tcl.push_back(clstr);
3534 
3535  return true;
3536  } // TmpStore()
float fScaleF
scale factor from Tick/Wire to dx/du
std::vector< ClusterStore > tcl
the clusters we are creating
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
float clBeginSlp
begin slope (= DS end = high wire number)
Detector simulation of raw signals on wires.
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::vector< recob::Hit > fHits
our version of the hits
float clEndChg
end average charge
float clBeginChgNear
nearby charge
float clEndChgNear
nearby charge
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::VertexCluster ( unsigned short  ivx)
private

Definition at line 1937 of file ClusterCrawlerAlg.cxx.

1938  {
1939  // try to attach clusters to the specified vertex
1940  if (vtx[iv].NClusters == 0) return;
1941 
1942  short dwb, dwe, dtb, dte;
1943  bool sigOK;
1944 
1945  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
1946  if (tcl[icl].ID < 0) continue;
1947  if (tcl[icl].CTP != vtx[iv].CTP) continue;
1948 
1949  dwb = vtx[iv].Wire - tcl[icl].BeginWir;
1950  dtb = vtx[iv].Time - tcl[icl].BeginTim;
1951  dwe = vtx[iv].Wire - tcl[icl].EndWir;
1952  dte = vtx[iv].Time - tcl[icl].EndTim;
1953 
1954  float drb = dwb * dwb + dtb * dtb;
1955  float dre = dwe * dwe + dte * dte;
1956 
1957  bool bCloser = (drb < dre);
1958 
1959  // ignore clusters in showers
1960  if (bCloser) {
1961  if (tcl[icl].BeginChgNear > fChgNearCut) continue;
1962  }
1963  else {
1964  if (tcl[icl].EndChgNear > fChgNearCut) continue;
1965  }
1966 
1967  if (vtxprt)
1968  mf::LogVerbatim("CC") << "VertexCluster: Try icl ID " << tcl[icl].ID << " w vtx " << iv
1969  << " dwb " << dwb << " dwe " << dwe << " drb " << drb << " dre "
1970  << dre << " Begin closer? " << bCloser;
1971 
1972  if (tcl[icl].BeginVtx < 0 && bCloser && dwb > -3 && dwb < 3 && tcl[icl].EndVtx != iv) {
1973  sigOK = ChkSignal(tcl[icl].BeginWir, tcl[icl].BeginTim, vtx[iv].Wire, vtx[iv].Time);
1974  if (vtxprt)
1975  mf::LogVerbatim("CC") << " Attach cluster Begin to vtx? " << iv << " sigOK " << sigOK;
1976  if (sigOK) {
1977  if (vtxprt)
1978  mf::LogVerbatim("CC") << " check ClusterVertexChi " << ClusterVertexChi(icl, 0, iv);
1979  if (ClusterVertexChi(icl, 0, iv) < fVertex2DCut) {
1980  // do a fit and check the vertex error
1981  tcl[icl].BeginVtx = iv;
1982  FitVtx(iv);
1983  if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
1984  tcl[icl].BeginVtx = -99;
1985  FitVtx(iv);
1986  }
1987  } // good DoCA
1988  } // sigOK
1989  } // check BEGIN
1990 
1991  if (tcl[icl].EndVtx < 0 && !bCloser && dwe > -3 && dwe < 3 && tcl[icl].BeginVtx != iv) {
1992  sigOK = ChkSignal(tcl[icl].EndWir, tcl[icl].EndTim, vtx[iv].Wire, vtx[iv].Time);
1993  if (vtxprt)
1994  mf::LogVerbatim("CC") << " Attach cluster End to vtx? " << iv << " sigOK " << sigOK;
1995  if (sigOK) {
1996  if (vtxprt)
1997  mf::LogVerbatim("CC") << " check ClusterVertexChi " << ClusterVertexChi(icl, 1, iv);
1998  if (ClusterVertexChi(icl, 1, iv) < 3) {
1999  // do a fit and check the vertex error
2000  tcl[icl].EndVtx = iv;
2001  FitVtx(iv);
2002  if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2003  tcl[icl].EndVtx = -99;
2004  FitVtx(iv);
2005  }
2006  } // good DoCA
2007  } // sigOK
2008  } // check END
2009  } // icl
2010  } // VertexCluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
float fVertex2DCut
2D vtx -> cluster matching cut (chisq/dof)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::Vtx3ClusterMatch ( detinfo::DetectorPropertiesData const &  det_prop,
geo::TPCID const &  tpcid 
)
private

Definition at line 5181 of file ClusterCrawlerAlg.cxx.

References lar::util::absDiff(), detinfo::DetectorPropertiesData::ConvertXToTicks(), geo::CryostatID::Cryostat, cluster::ClusterCrawlerAlg::VtxStore::CTP, util::empty(), tca::EncodeCTP(), cluster::ClusterCrawlerAlg::VtxStore::Fixed, cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::Topo, geo::TPCID::TPC, cluster::ClusterCrawlerAlg::VtxStore::Wire, and X.

5183  {
5184  // Look for clusters that end/begin near the expected wire/time
5185  // for incomplete 3D vertices
5186  if (empty(vtx3)) return;
5187 
5188  const unsigned int cstat = tpcid.Cryostat;
5189  const unsigned int tpc = tpcid.TPC;
5190 
5191  unsigned int thePlane, theWire;
5192  float theTime;
5193  int dwb, dwe;
5194 
5195  for (unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5196  // A complete 3D vertex with matching 2D vertices in all planes?
5197  if (vtx3[ivx].Wire < 0) continue;
5198  if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc) continue;
5199  // Find the plane that is missing a 2D vertex
5200  thePlane = 3;
5201  theWire = vtx3[ivx].Wire;
5202  for (plane = 0; plane < 3; ++plane) {
5203  if (vtx3[ivx].Ptr2D[plane] >= 0) continue;
5204  thePlane = plane;
5205  break;
5206  } // plane
5207  if (thePlane > 2) continue;
5208  theTime = det_prop.ConvertXToTicks(vtx3[ivx].X, thePlane, tpc, cstat);
5209  clCTP = EncodeCTP(cstat, tpc, thePlane);
5210  // Create a new 2D vertex and see how many clusters we can attach to it
5211  VtxStore vnew;
5212  vnew.Wire = theWire;
5213  vnew.Time = theTime;
5214  vnew.CTP = clCTP;
5215  vnew.Topo = 7;
5216  vnew.Fixed = false;
5217  vtx.push_back(vnew);
5218  unsigned short ivnew = vtx.size() - 1;
5219  std::vector<short> vclIndex;
5220  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
5221  if (tcl[icl].ID < 0) continue;
5222  if (tcl[icl].CTP != clCTP) continue;
5223  dwb = lar::util::absDiff(theWire, tcl[icl].BeginWir);
5224  dwe = lar::util::absDiff(theWire, tcl[icl].EndWir);
5225  // rough cut to start
5226  if (dwb > 10 && dwe > 10) continue;
5227  if (dwb < dwe && dwb < 10 && tcl[icl].BeginVtx < 0) {
5228  // cluster begin is closer
5229  if (theWire < tcl[icl].BeginWir + 5) continue;
5230  if (ClusterVertexChi(icl, 0, ivnew) > fVertex3DCut) continue;
5231  tcl[icl].BeginVtx = ivnew;
5232  vclIndex.push_back(icl);
5233  }
5234  else if (dwe < 10 && tcl[icl].EndVtx < 0) {
5235  // cluster end is closer
5236  if (theWire > tcl[icl].EndWir - 5) continue;
5237  if (ClusterVertexChi(icl, 1, ivnew) > fVertex3DCut) continue;
5238  tcl[icl].EndVtx = ivnew;
5239  vclIndex.push_back(icl);
5240  } // dwb/dwe check
5241  } // icl
5242  bool goodVtx = false;
5243  if (vclIndex.size() > 0) {
5244  FitVtx(ivnew);
5245  goodVtx = (vtx[ivnew].ChiDOF < fVertex3DCut);
5246  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5247  }
5248  if (goodVtx) {
5249  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5250  vtx3[ivx].Wire = -1;
5251  }
5252  else {
5253  // clobber the vertex
5254  vtx.pop_back();
5255  for (unsigned short ii = 0; ii < vclIndex.size(); ++ii) {
5256  unsigned short icl = vclIndex[ii];
5257  if (tcl[icl].BeginVtx == ivnew) tcl[icl].BeginVtx = -99;
5258  if (tcl[icl].EndVtx == ivnew) tcl[icl].EndVtx = -99;
5259  } // ii
5260  }
5261  } // ivx
5262  } // Vtx3ClusterMatch
std::vector< ClusterStore > tcl
the clusters we are creating
void FitVtx(unsigned short iv)
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
CTP_t clCTP
Cryostat/TPC/Plane code.
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:69
std::vector< VtxStore > vtx
the endpoints we are reconstructing
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
void cluster::ClusterCrawlerAlg::Vtx3ClusterSplit ( detinfo::DetectorPropertiesData const &  det_prop,
geo::TPCID const &  tpcid 
)
private

Definition at line 5265 of file ClusterCrawlerAlg.cxx.

References util::abs(), detinfo::DetectorPropertiesData::ConvertXToTicks(), geo::CryostatID::Cryostat, cluster::ClusterCrawlerAlg::VtxStore::CTP, util::empty(), tca::EncodeCTP(), cluster::ClusterCrawlerAlg::VtxStore::Fixed, cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::TimeErr, cluster::ClusterCrawlerAlg::VtxStore::Topo, geo::TPCID::TPC, cluster::ClusterCrawlerAlg::VtxStore::Wire, cluster::ClusterCrawlerAlg::VtxStore::WireErr, and X.

5267  {
5268  // Try to split clusters in a view in which there is no 2D vertex
5269  // assigned to a 3D vertex
5270  if (empty(vtx3)) return;
5271 
5272  const unsigned int cstat = tpcid.Cryostat;
5273  const unsigned int tpc = tpcid.TPC;
5274 
5275  vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5276 
5277  unsigned int lastplane = 5, kcl, kclID;
5278  float theTime;
5279  unsigned int thePlane, theWire, plane;
5280  unsigned int loWire, hiWire;
5281 
5282  for (unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5283  if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc) continue;
5284  // Complete 3D vertex with matching 2D vertices in all planes?
5285  if (vtxprt)
5286  mf::LogVerbatim("CC") << "Vtx3ClusterSplit ivx " << ivx << " Ptr2D " << vtx3[ivx].Ptr2D[0]
5287  << " " << vtx3[ivx].Ptr2D[1] << " " << vtx3[ivx].Ptr2D[2] << " wire "
5288  << vtx3[ivx].Wire;
5289  if (vtx3[ivx].Wire < 0) continue;
5290  // find the plane that needs to be studied
5291  thePlane = 3;
5292  theWire = vtx3[ivx].Wire;
5293  for (plane = 0; plane < 3; ++plane) {
5294  if (vtx3[ivx].Ptr2D[plane] >= 0) continue;
5295  thePlane = plane;
5296  break;
5297  } // plane
5298  if (thePlane > 2) continue;
5299  theTime = det_prop.ConvertXToTicks(
5300  (double)vtx3[ivx].X, (int)thePlane, (int)tpcid.TPC, (int)tpcid.Cryostat);
5301  // get the hit range if necessary
5302  if (thePlane != lastplane) {
5303  clCTP = EncodeCTP(tpcid.Cryostat, tpcid.TPC, thePlane);
5304  GetHitRange(clCTP);
5305  lastplane = thePlane;
5306  }
5307  // make a list of clusters that have hits near this point on nearby wires
5308  std::vector<short> clIDs;
5309  if (theWire > fFirstWire + 5) { loWire = theWire - 5; }
5310  else {
5311  loWire = fFirstWire;
5312  }
5313  if (theWire < fLastWire - 5) { hiWire = theWire + 5; }
5314  else {
5315  hiWire = fLastWire;
5316  }
5317  if (vtxprt)
5318  mf::LogVerbatim("CC") << "3DVtx " << ivx << " look for cluster hits near P:W:T " << thePlane
5319  << ":" << theWire << ":" << (int)theTime << " Wire range " << loWire
5320  << " to " << hiWire;
5321  for (unsigned int wire = loWire; wire < hiWire; ++wire) {
5322  // ignore dead wires or wires with no hits
5323  if (WireHitRange[wire].first < 0) continue;
5324  unsigned int firsthit = WireHitRange[wire].first;
5325  unsigned int lasthit = WireHitRange[wire].second;
5326  for (unsigned int khit = firsthit; khit < lasthit; ++khit) {
5327  // ignore obsolete and un-assigned hits
5328  if (inClus[khit] <= 0) continue;
5329  if ((unsigned int)inClus[khit] > tcl.size() + 1) {
5330  mf::LogError("CC") << "Invalid hit InClus. " << khit << " " << inClus[khit];
5331  continue;
5332  }
5333  // check an expanded time range
5334  if (theTime < fHits[khit].StartTick() - 20) continue;
5335  if (theTime > fHits[khit].EndTick() + 20) continue;
5336  kclID = inClus[khit];
5337  kcl = kclID - 1;
5338  // ignore obsolete clusters
5339  if (tcl[kcl].ID < 0) continue;
5340  // ignore short clusters
5341  if (tcl[kcl].tclhits.size() < 6) continue;
5342  // ignore long straight clusters
5343  if (tcl[kcl].tclhits.size() > 100 && std::abs(tcl[kcl].BeginAng - tcl[kcl].EndAng) < 0.1)
5344  continue;
5345  // put the cluster in the list if it's not there already
5346  if (vtxprt)
5347  mf::LogVerbatim("CC") << "Bingo " << ivx << " plane " << thePlane << " wire " << wire
5348  << " hit " << fHits[khit].WireID().Wire << ":"
5349  << (int)fHits[khit].PeakTime() << " inClus " << inClus[khit]
5350  << " P:W:T " << thePlane << ":" << tcl[kcl].BeginWir << ":"
5351  << (int)tcl[kcl].BeginTim;
5352  if (std::find(clIDs.begin(), clIDs.end(), kclID) == clIDs.end()) {
5353  clIDs.push_back(kclID);
5354  } // std::find
5355  } // khit
5356  } // wire
5357  if (clIDs.size() == 0) continue;
5358  if (vtxprt)
5359  for (unsigned int ii = 0; ii < clIDs.size(); ++ii)
5360  mf::LogVerbatim("CC") << " clIDs " << clIDs[ii];
5361 
5362  unsigned short ii, icl, jj;
5363  unsigned int iht;
5364  short nhitfit;
5365  bool didit;
5366  // find a reasonable time error using the 2D vertices that comprise this
5367  // incomplete 3D vertex
5368  float tErr = 1;
5369  unsigned short i2Dvx = 0;
5370  for (ii = 0; ii < 3; ++ii) {
5371  if (ii == thePlane) continue;
5372  i2Dvx = vtx3[ivx].Ptr2D[ii];
5373  if (i2Dvx > vtx.size() - 1) {
5374  mf::LogError("CC") << "Vtx3ClusterSplit: Coding error";
5375  return;
5376  }
5377  if (vtx[i2Dvx].TimeErr > tErr) tErr = vtx[i2Dvx].TimeErr;
5378  } // ii -> plane
5379 
5380  // do a local fit near the crossing point and make a tighter cut
5381  for (ii = 0; ii < clIDs.size(); ++ii) {
5382  icl = clIDs[ii] - 1;
5383  didit = false;
5384  for (jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5385  iht = tcl[icl].tclhits[jj];
5386  if (fHits[iht].WireID().Wire < theWire) {
5387  nhitfit = 3;
5388  if (jj > 3) nhitfit = -3;
5389  FitClusterMid(icl, iht, nhitfit);
5390  float doca = DoCA(-1, 1, theWire, theTime);
5391  if (vtxprt)
5392  mf::LogVerbatim("CC") << " cls " << icl << " DoCA " << doca << " tErr " << tErr;
5393  if ((doca / tErr) > 2) clIDs[ii] = -1;
5394  didit = true;
5395  break;
5396  } // fHits[iht].WireID().Wire < theWire
5397  if (didit) break;
5398  } // jj
5399  if (didit) break;
5400  } // ii
5401  if (vtxprt) {
5402  mf::LogVerbatim("CC") << "clIDs after fit " << clIDs.size();
5403  for (ii = 0; ii < clIDs.size(); ++ii)
5404  mf::LogVerbatim("CC") << " clIDs " << clIDs[ii];
5405  }
5406 
5407  // see if any candidates remain
5408  unsigned short nok = 0;
5409  for (ii = 0; ii < clIDs.size(); ++ii)
5410  if (clIDs[ii] >= 0) ++nok;
5411  if (nok == 0) continue;
5412 
5413  // make a new 2D vertex
5414  VtxStore vnew;
5415  vnew.Wire = theWire;
5416  vnew.WireErr = 1;
5417  vnew.Time = theTime;
5418  vnew.TimeErr = 1;
5419  vnew.Topo = 8;
5420  vnew.CTP = clCTP;
5421  vnew.Fixed = false;
5422  vtx.push_back(vnew);
5423  // update the 2D -> 3D vertex pointer
5424  unsigned short ivnew = vtx.size() - 1;
5425  if (vtxprt)
5426  mf::LogVerbatim("CC") << "Make new 2D vtx " << ivnew << " in plane " << thePlane
5427  << " from 3D vtx " << ivx;
5428  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5429  // either split or attach clusters to this vertex
5430  for (ii = 0; ii < clIDs.size(); ++ii) {
5431  if (clIDs[ii] < 0) continue;
5432  icl = clIDs[ii] - 1;
5433  // find the split position
5434  // split the cluster. Find the split position
5435  unsigned short pos = 0;
5436  for (unsigned short jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5437  iht = tcl[icl].tclhits[jj];
5438  if (fHits[iht].WireID().Wire < theWire) {
5439  pos = jj;
5440  break;
5441  }
5442  } // jj
5443  if (pos == 0) {
5444  // vertex is DS of the cluster Begin
5445  tcl[icl].BeginVtx = ivnew;
5446  if (vtxprt) mf::LogVerbatim("CC") << "Attach to Begin " << icl;
5447  }
5448  else if (pos > tcl[icl].tclhits.size()) {
5449  // vertex is US of the cluster Eend
5450  tcl[icl].EndVtx = ivnew;
5451  if (vtxprt) mf::LogVerbatim("CC") << "Attach to End " << icl;
5452  }
5453  else {
5454  // vertex is in the middle of the cluster
5455  if (vtxprt) mf::LogVerbatim("CC") << "Split cluster " << clIDs[ii] << " at pos " << pos;
5456  if (!SplitCluster(icl, pos, ivnew)) {
5457  if (vtxprt) mf::LogVerbatim("CC") << "SplitCluster failed";
5458  continue;
5459  }
5460  tcl[icl].ProcCode += 10000;
5461  tcl[tcl.size() - 1].ProcCode += 10000;
5462  } // pos check
5463  } // ii
5464  // Fit the vertex position
5465  FitVtx(ivnew);
5466  if (vtx[ivnew].ChiDOF < 5 && vtx[ivnew].WireErr < fVertex2DWireErrCut) {
5467  // mark the 3D vertex as complete
5468  vtx3[ivx].Wire = -1;
5469  }
5470  else {
5471  if (vtxprt)
5472  mf::LogVerbatim("CC") << "Bad vtx fit " << ivnew << " ChiDOF " << vtx[ivnew].ChiDOF
5473  << " WireErr " << vtx[ivnew].WireErr;
5474  // Recover (partially) from a bad fit. Leave the ProcCode as-is to trace this problem
5475  vtx.pop_back();
5476  vtx3[ivx].Ptr2D[thePlane] = -1;
5477  // find the cluster - vertex associations
5478  for (jj = 0; jj < tcl.size(); ++jj) {
5479  if (tcl[jj].BeginVtx == ivnew) tcl[jj].BeginVtx = -99;
5480  if (tcl[jj].EndVtx == ivnew) tcl[jj].EndVtx = -99;
5481  } // jj
5482  }
5483  } // ivx
5484 
5485  } // Vtx3ClusterSplit()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< std::pair< int, int > > WireHitRange
void FitVtx(unsigned short iv)
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
constexpr auto abs(T v)
Returns the absolute value of the argument.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
CTP_t clCTP
Cryostat/TPC/Plane code.
float DoCA(short icl, unsigned short end, float vwire, float vtick)
int fDebugHit
out detailed information while crawling
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
unsigned int fFirstWire
the first wire with a hit
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
bool cluster::ClusterCrawlerAlg::VtxClusterSplit ( )
private

Definition at line 1409 of file ClusterCrawlerAlg.cxx.

1410  {
1411 
1412  // split clusters that cross vertices
1413 
1414  vtxprt = (fDebugPlane >= 0 && fDebugWire == 5555);
1415 
1416  if (vtxprt) mf::LogVerbatim("CC") << "VtxClusterSplit ";
1417 
1418  if (vtx.size() == 0) return false;
1419  unsigned short tclsize = tcl.size();
1420  if (tclsize < 2) return false;
1421 
1422  bool didit;
1423  bool didSomething = false;
1424 
1425  for (unsigned short icl = 0; icl < tclsize; ++icl) {
1426  if (tcl[icl].ID < 0) continue;
1427  if (tcl[icl].CTP != clCTP) continue;
1428  // ignore short clusters
1429  if (tcl[icl].tclhits.size() < 5) continue;
1430  // check vertices
1431  didit = false;
1432  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
1433  if (vtx[ivx].CTP != clCTP) continue;
1434  // abandoned vertex?
1435  if (vtx[ivx].NClusters == 0) continue;
1436  // already assigned to this vertex?
1437  if (tcl[icl].BeginVtx == ivx) continue;
1438  if (tcl[icl].EndVtx == ivx) continue;
1439  // vertex wire in-between the cluster ends?
1440  if (vtx[ivx].Wire < tcl[icl].EndWir) continue;
1441  if (vtx[ivx].Wire > tcl[icl].BeginWir) continue;
1442  // vertex time in-between the cluster ends?
1443  float hiTime = tcl[icl].BeginTim;
1444  if (tcl[icl].EndTim > hiTime) hiTime = tcl[icl].EndTim;
1445  if (vtx[ivx].Time > hiTime + 5) continue;
1446  float loTime = tcl[icl].BeginTim;
1447  if (tcl[icl].EndTim < loTime) loTime = tcl[icl].EndTim;
1448  if (vtx[ivx].Time < loTime - 5) continue;
1449  // find the hit on the cluster that is closest to the vertex on the
1450  // DS side
1451  if (vtxprt)
1452  mf::LogVerbatim("CC") << " Chk cluster ID " << tcl[icl].ID << " with vertex " << ivx;
1453  short ihvx = -99;
1454  // nSplit is the index of the hit in the cluster where we will
1455  // split it if all requirements are met
1456  unsigned short nSplit = 0;
1457  unsigned short nLop = 0;
1458  unsigned int iht;
1459  for (unsigned short ii = tcl[icl].tclhits.size() - 1; ii > 0; --ii) {
1460  iht = tcl[icl].tclhits[ii];
1461  ++nLop;
1462  if (fHits[iht].WireID().Wire >= vtx[ivx].Wire) {
1463  nSplit = ii;
1464  if (vtxprt)
1465  mf::LogVerbatim("CC") << "Split cluster " << tcl[icl].ID << " at wire "
1466  << fHits[iht].WireID().Wire << " nSplit " << nSplit;
1467  ihvx = iht;
1468  break;
1469  }
1470  } // ii
1471  // found the wire. Now make a rough time cut
1472  if (ihvx < 0) continue;
1473  if (fabs(fHits[ihvx].PeakTime() - vtx[ivx].Time) > 10) continue;
1474  // check the angle between the crossing cluster icl and the
1475  // clusters that comprise the vertex.
1476  // First decide which end of cluster icl to use to define the angle
1477  float iclAng = 0.;
1478  if (nSplit > tcl[icl].tclhits.size() / 2) { iclAng = tcl[icl].EndAng; }
1479  else {
1480  iclAng = tcl[icl].BeginAng;
1481  }
1482  if (vtxprt) mf::LogVerbatim("CC") << " iclAng " << iclAng;
1483  // check angle wrt the the vertex clusters
1484  bool angOK = false;
1485  for (unsigned short jcl = 0; jcl < tclsize; ++jcl) {
1486  if (tcl[jcl].ID < 0) continue;
1487  if (tcl[jcl].CTP != clCTP) continue;
1488  if (tcl[jcl].BeginVtx == ivx) {
1489  if (fabs(tcl[jcl].BeginAng - iclAng) > 0.4) {
1490  // large angle difference. Set the flag
1491  angOK = true;
1492  break;
1493  }
1494  } // tcl[jcl].BeginVtx == ivx
1495  if (tcl[jcl].EndVtx == ivx) {
1496  if (fabs(tcl[jcl].EndAng - iclAng) > 0.4) {
1497  // large angle difference. Set the flag
1498  angOK = true;
1499  break;
1500  }
1501  } // tcl[jcl].EndVtx == ivx
1502  } // jcl
1503  // time to split or chop
1504  if (angOK) {
1505  if (vtxprt) mf::LogVerbatim("CC") << "Split/Chop at pos " << nLop;
1506  if (nLop < 3) {
1507  // lop off hits at the US end
1508  // Put the cluster in the local arrays
1509  TmpGet(icl);
1510  for (unsigned short ii = 0; ii < nLop; ++ii) {
1511  unsigned int iht = fcl2hits[fcl2hits.size() - 1];
1512  inClus[iht] = 0;
1513  fcl2hits.pop_back();
1514  }
1515  // store it
1516  clProcCode += 1000;
1517  // declare this cluster obsolete
1518  MakeClusterObsolete(icl);
1519  // store the new one
1520  if (!TmpStore()) continue;
1521  unsigned short newcl = tcl.size() - 1;
1522  tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1523  tcl[newcl].EndVtx = ivx;
1524  }
1525  else {
1526  // split the cluster into two
1527  // correct the split position
1528  ++nSplit;
1529  if (SplitCluster(icl, nSplit, ivx)) {
1530  tcl[tcl.size() - 1].ProcCode += 1000;
1531  tcl[tcl.size() - 2].ProcCode += 1000;
1532  }
1533  }
1534  didit = true;
1535  didSomething = true;
1536  } // angOK
1537  if (didit) break;
1538  } // ivx
1539  } // icl
1540 
1541  return didSomething;
1542 
1543  } // VtxClusterSplit()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< ClusterStore > tcl
the clusters we are creating
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
void MakeClusterObsolete(unsigned short icl)
Marks the cluster as obsolete and frees hits still associated with it.
void TmpGet(unsigned short it1)
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::VtxConstraint ( unsigned int  iwire,
unsigned int  ihit,
unsigned int  jwire,
unsigned int &  useHit,
bool &  doConstrain 
)
private

Definition at line 1207 of file ClusterCrawlerAlg.cxx.

References util::abs(), recob::Hit::PeakTime(), geo::WireID::Wire, and recob::Hit::WireID().

1212  {
1213  // checks hits on wire jwire to see if one is on a line between a US vertex
1214  // and the hit ihit on wire iwire. If one is found, doConstrain is set true
1215  // and the hit index is returned.
1216  doConstrain = false;
1217  if (vtx.size() == 0) return;
1218  // no vertices made yet on the first pass
1219  if (pass == 0) return;
1220  // skip if vertices were not requested to be made on the previous pass
1221  if (!fFindVertices[pass - 1]) return;
1222 
1223  if (jwire > WireHitRange.size() - 1) {
1224  mf::LogError("CC") << "VtxConstraint fed bad jwire " << jwire << " WireHitRange size "
1225  << WireHitRange.size();
1226  return;
1227  }
1228 
1229  unsigned int jfirsthit = WireHitRange[jwire].first;
1230  unsigned int jlasthit = WireHitRange[jwire].second;
1231  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1232  if (vtx[iv].CTP != clCTP) continue;
1233  // vertex must be US of the cluster
1234  if (vtx[iv].Wire > jwire) continue;
1235  // but not too far US
1236  if (vtx[iv].Wire < jwire - 10) continue;
1237  recob::Hit const& hit = fHits[ihit];
1238  clpar[0] = hit.PeakTime();
1239  clpar[1] = (vtx[iv].Time - hit.PeakTime()) / (vtx[iv].Wire - iwire);
1240  clpar[2] = hit.WireID().Wire;
1241  float prtime = clpar[0] + clpar[1] * (jwire - iwire);
1242  for (unsigned int jhit = jfirsthit; jhit < jlasthit; ++jhit) {
1243  if (inClus[jhit] != 0) continue;
1244  const float tdiff = std::abs(fHits[jhit].TimeDistanceAsRMS(prtime));
1245  if (tdiff < 2.5) {
1246  useHit = jhit;
1247  doConstrain = true;
1248  return;
1249  }
1250  } // jhit
1251  } // iv
1252  } // VtxConstraint()
std::vector< std::pair< int, int > > WireHitRange
constexpr auto abs(T v)
Returns the absolute value of the argument.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:290
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< bool > fFindVertices
run vertexing code after clustering?
Detector simulation of raw signals on wires.
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
std::vector< VtxStore > vtx
the endpoints we are reconstructing
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
void cluster::ClusterCrawlerAlg::VtxMatch ( detinfo::DetectorPropertiesData const &  det_prop,
geo::TPCID const &  tpcid 
)
private

Definition at line 5679 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorPropertiesData::ConvertTicksToX(), geo::CryostatID::Cryostat, cluster::ClusterCrawlerAlg::Vtx3Store::CStat, tca::DecodeCTP(), e, geo::TPCGeo::GetCenter(), geo::TPCGeo::HalfHeight(), evd::kWire, geo::kX, geo::TPCGeo::Length(), geo::PlaneID::Plane, cluster::ClusterCrawlerAlg::Vtx3Store::ProcCode, cluster::ClusterCrawlerAlg::Vtx3Store::Ptr2D, geo::InvalidWireError::suggestedWireID(), cluster::ClusterCrawlerAlg::Vtx3Store::TPC, geo::TPCID::TPC, cluster::ClusterCrawlerAlg::Vtx3Store::Wire, geo::WireID::Wire, cluster::ClusterCrawlerAlg::Vtx3Store::X, cluster::ClusterCrawlerAlg::Vtx3Store::XErr, y, cluster::ClusterCrawlerAlg::Vtx3Store::Y, cluster::ClusterCrawlerAlg::Vtx3Store::YErr, cluster::ClusterCrawlerAlg::Vtx3Store::Z, z, and cluster::ClusterCrawlerAlg::Vtx3Store::ZErr.

5681  {
5682  // Create 3D vertices from 2D vertices. 3D vertices that are matched
5683  // in all three planes have Ptr2D >= 0 for all planes
5684 
5685  geo::TPCGeo const& TPC = geom->TPC(tpcid);
5686  unsigned int nplanes = wireReadoutGeom->Nplanes(tpcid);
5687 
5688  // Y,Z limits of the detector
5689  auto const world = TPC.GetCenter();
5690 
5691  // reduce the active area of the TPC by 1 cm to prevent wire boundary issues
5692  float YLo = world.Y() - TPC.HalfHeight() + 1;
5693  float YHi = world.Y() + TPC.HalfHeight() - 1;
5694  float ZLo = world.Z() - TPC.Length() / 2 + 1;
5695  float ZHi = world.Z() + TPC.Length() / 2 - 1;
5696 
5697  vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5698 
5699  if (vtxprt) {
5700  mf::LogVerbatim("CC") << "Inside VtxMatch";
5701  PrintVertices();
5702  }
5703 
5704  // wire spacing in cm
5705  float wirePitch = wireReadoutGeom->FirstPlane(tpcid).WirePitch();
5706 
5707  // fill temp vectors of 2D vertex X and X errors
5708  std::vector<float> vX(vtx.size());
5709  std::vector<float> vXsigma(vtx.size());
5710  float vXp;
5711  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5712  if (vtx[ivx].NClusters == 0) continue;
5713  geo::PlaneID iplID = DecodeCTP(vtx[ivx].CTP);
5714  if (iplID.TPC != tpc || iplID.Cryostat != cstat) continue;
5715  // Convert 2D vertex time error to X error
5716  vX[ivx] =
5717  det_prop.ConvertTicksToX((double)vtx[ivx].Time, (int)iplID.Plane, (int)tpc, (int)cstat);
5718  vXp = det_prop.ConvertTicksToX(
5719  (double)(vtx[ivx].Time + vtx[ivx].TimeErr), (int)iplID.Plane, (int)tpc, (int)cstat);
5720  vXsigma[ivx] = fabs(vXp - vX[ivx]);
5721  } // ivx
5722 
5723  // create a array/vector of 2D vertex indices in each plane
5724  std::array<std::vector<unsigned short>, 3> vIndex;
5725  unsigned short indx, ipl;
5726  for (unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5727  if (vtx[ivx].NClusters == 0) continue;
5728  geo::PlaneID iplID = DecodeCTP(vtx[ivx].CTP);
5729  if (iplID.TPC != tpc || iplID.Cryostat != cstat) continue;
5730  ipl = iplID.Plane;
5731  if (ipl > 2) continue;
5732  indx = vIndex[ipl].size();
5733  vIndex[ipl].resize(indx + 1);
5734  vIndex[ipl][indx] = ivx;
5735  }
5736 
5737  // vector of 2D vertices -> 3D vertices.
5738  std::vector<short> vPtr;
5739  for (unsigned short ii = 0; ii < vtx.size(); ++ii)
5740  vPtr.push_back(-1);
5741 
5742  // temp vector of all 2D vertex matches
5743  std::vector<Vtx3Store> v3temp;
5744 
5745  geo::Point_t WPos{0, 0, 0};
5746  // i, j, k indicates 3 different wire planes
5747  unsigned short ii, jpl, jj, kpl, kk, ivx, jvx, kvx;
5748  unsigned int iWire, jWire;
5749  unsigned short v3dBest = 0;
5750  float xbest = 0, ybest = 0, zbest = 0;
5751  float kX, kWire;
5752  // compare vertices in each view
5753  bool gotit = false;
5754  for (ipl = 0; ipl < 2; ++ipl) {
5755  geo::PlaneID const plane_i{tpcid, ipl};
5756  for (ii = 0; ii < vIndex[ipl].size(); ++ii) {
5757  ivx = vIndex[ipl][ii];
5758  if (ivx > vtx.size() - 1) {
5759  mf::LogError("CC") << "VtxMatch: bad ivx " << ivx;
5760  return;
5761  }
5762  // vertex has been matched already
5763  if (vPtr[ivx] >= 0) continue;
5764  iWire = vtx[ivx].Wire;
5765  float best = fVertex3DCut;
5766  // temp array of 2D vertex indices in each plane
5767  // BUG the double brace syntax is required to work around clang bug 21629
5768  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
5769  std::array<short, 3> t2dIndex = {{-1, -1, -1}};
5770  std::array<short, 3> tmpIndex = {{-1, -1, -1}};
5771  for (jpl = ipl + 1; jpl < 3; ++jpl) {
5772  geo::PlaneID const plane_j{tpcid, jpl};
5773  for (jj = 0; jj < vIndex[jpl].size(); ++jj) {
5774  jvx = vIndex[jpl][jj];
5775  if (jvx > vtx.size() - 1) {
5776  mf::LogError("CC") << "VtxMatch: bad jvx " << jvx;
5777  return;
5778  }
5779  // vertex has been matched already
5780  if (vPtr[jvx] >= 0) continue;
5781  jWire = vtx[jvx].Wire;
5782  // new stuff
5783  float dX = fabs(vX[ivx] - vX[jvx]);
5784  float dXSigma = sqrt(vXsigma[ivx] * vXsigma[ivx] + vXsigma[jvx] * vXsigma[jvx]);
5785  float dXChi = dX / dXSigma;
5786 
5787  if (vtxprt)
5788  mf::LogVerbatim("CC")
5789  << "VtxMatch: ipl " << ipl << " ivx " << ivx << " ivX " << vX[ivx] << " jpl " << jpl
5790  << " jvx " << jvx << " jvX " << vX[jvx] << " W:T " << (int)vtx[jvx].Wire << ":"
5791  << (int)vtx[jvx].Time << " dXChi " << dXChi << " fVertex3DCut " << fVertex3DCut;
5792 
5793  if (dXChi > fVertex3DCut) continue;
5794  auto const intersection = wireReadoutGeom->WireIDsIntersect(
5795  geo::WireID{plane_i, iWire}, geo::WireID{plane_j, jWire});
5796  if (!intersection) continue;
5797  auto const [y, z] = std::make_pair(intersection->y, intersection->z);
5798  if (y < YLo || y > YHi || z < ZLo || z > ZHi) continue;
5799  WPos.SetY(y);
5800  WPos.SetZ(z);
5801  kpl = 3 - ipl - jpl;
5802  kX = 0.5 * (vX[ivx] + vX[jvx]);
5803  kWire = -1;
5804  if (nplanes) {
5805  try {
5806  kWire = wireReadoutGeom->Plane({cstat, tpc, kpl}).NearestWireID(WPos).Wire;
5807  }
5808  catch (geo::InvalidWireError const& e) {
5809  kWire = e.suggestedWireID().Wire; // pick the closest valid wire
5810  }
5811  }
5812  kpl = 3 - ipl - jpl;
5813  // save this incomplete 3D vertex
5814  Vtx3Store v3d;
5815  v3d.ProcCode = 1;
5816  tmpIndex[ipl] = ivx;
5817  tmpIndex[jpl] = jvx;
5818  tmpIndex[kpl] = -1;
5819  v3d.Ptr2D = tmpIndex;
5820  v3d.X = kX;
5821  v3d.XErr = dXSigma;
5822  v3d.Y = y;
5823  float yzSigma = wirePitch * sqrt(vtx[ivx].WireErr * vtx[ivx].WireErr +
5824  vtx[jvx].WireErr * vtx[jvx].WireErr);
5825  v3d.YErr = yzSigma;
5826  v3d.Z = z;
5827  v3d.ZErr = yzSigma;
5828  v3d.Wire = kWire;
5829  v3d.CStat = cstat;
5830  v3d.TPC = tpc;
5831  v3temp.push_back(v3d);
5832 
5833  if (vtxprt)
5834  mf::LogVerbatim("CC")
5835  << "VtxMatch: 2 Plane match ivx " << ivx << " P:W:T " << ipl << ":"
5836  << (int)vtx[ivx].Wire << ":" << (int)vtx[ivx].Time << " jvx " << jvx << " P:W:T "
5837  << jpl << ":" << (int)vtx[jvx].Wire << ":" << (int)vtx[jvx].Time << " dXChi "
5838  << dXChi << " yzSigma " << yzSigma;
5839 
5840  if (nplanes == 2) continue;
5841  // look for a 3 plane match
5842  best = fVertex3DCut;
5843  for (kk = 0; kk < vIndex[kpl].size(); ++kk) {
5844  kvx = vIndex[kpl][kk];
5845  if (vPtr[kvx] >= 0) continue;
5846  // Wire difference error
5847  float dW = wirePitch * (vtx[kvx].Wire - kWire) / yzSigma;
5848  // X difference error
5849  float dX = (vX[kvx] - kX) / dXSigma;
5850  float kChi = 0.5 * sqrt(dW * dW + dX * dX);
5851  if (kChi < best) {
5852  best = kChi;
5853  xbest = (vX[kvx] + 2 * kX) / 3;
5854  ybest = y;
5855  zbest = z;
5856  t2dIndex[ipl] = ivx;
5857  t2dIndex[jpl] = jvx;
5858  t2dIndex[kpl] = kvx;
5859  v3dBest = v3temp.size() - 1;
5860  }
5861 
5862  if (vtxprt)
5863  mf::LogVerbatim("CC")
5864  << " kvx " << kvx << " kpl " << kpl << " wire " << (int)vtx[kvx].Wire << " kTime "
5865  << (int)vtx[kvx].Time << " kChi " << kChi << " best " << best << " dW "
5866  << vtx[kvx].Wire - kWire;
5867 
5868  } // kk
5869  if (vtxprt)
5870  mf::LogVerbatim("CC") << " done best = " << best << " fVertex3DCut " << fVertex3DCut;
5871  if (nplanes > 2 && best < fVertex3DCut) {
5872  // create a real 3D vertex using the previously entered incomplete 3D vertex as a template
5873  if (v3dBest > v3temp.size() - 1) {
5874  mf::LogError("CC") << "VtxMatch: bad v3dBest " << v3dBest;
5875  return;
5876  }
5877  Vtx3Store v3d = v3temp[v3dBest];
5878  v3d.Ptr2D = t2dIndex;
5879  v3d.Wire = -1;
5880  // TODO need to average ybest and zbest here with error weighting
5881  v3d.X = xbest;
5882  v3d.Y = ybest;
5883  v3d.Z = zbest;
5884  vtx3.push_back(v3d);
5885  gotit = true;
5886  // mark the 2D vertices as used
5887  for (unsigned short jj = 0; jj < 3; ++jj)
5888  if (t2dIndex[jj] >= 0) vPtr[t2dIndex[jj]] = vtx3.size() - 1;
5889 
5890  if (vtxprt)
5891  mf::LogVerbatim("CC")
5892  << "New 3D vtx " << vtx3.size() << " X " << v3d.X << " Y " << v3d.Y << " Z "
5893  << v3d.Z << " t2dIndex " << t2dIndex[0] << " " << t2dIndex[1] << " "
5894  << t2dIndex[2] << " best Chi " << best;
5895 
5896  } // best < dRCut
5897  if (gotit) break;
5898  } // jj
5899  if (gotit) break;
5900  } // jpl
5901  if (gotit) break;
5902  } // ii
5903  } // ipl
5904 
5905  // Store incomplete 3D vertices but ignore those that are part of a complete 3D vertex
5906  unsigned short vsize = vtx3.size();
5907  for (unsigned short it = 0; it < v3temp.size(); ++it) {
5908  bool keepit = true;
5909  for (unsigned short i3d = 0; i3d < vsize; ++i3d) {
5910  for (unsigned short plane = 0; plane < 3; ++plane) {
5911  if (v3temp[it].Ptr2D[plane] == vtx3[i3d].Ptr2D[plane]) {
5912  keepit = false;
5913  break;
5914  }
5915  } // plane
5916  if (!keepit) break;
5917  } // i3d
5918 
5919  if (keepit) vtx3.push_back(v3temp[it]);
5920  } // it
5921 
5922  // Modify Ptr2D for 2-plane detector
5923  if (nplanes == 2) {
5924  for (unsigned short iv3 = 0; iv3 < vtx3.size(); ++iv3) {
5925  vtx3[iv3].Ptr2D[2] = 666;
5926  } //iv3
5927  } // 2 planes
5928 
5929  if (vtxprt) {
5930  for (unsigned short it = 0; it < vtx3.size(); ++it) {
5931  mf::LogVerbatim("CC") << "vtx3 " << it << " Ptr2D " << vtx3[it].Ptr2D[0] << " "
5932  << vtx3[it].Ptr2D[1] << " " << vtx3[it].Ptr2D[2] << " wire "
5933  << vtx3[it].Wire;
5934  }
5935  }
5936 
5937  } // VtxMatch
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
static unsigned int kWire
WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:85
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:276
Planes which measure X direction.
Definition: geo_types.h:136
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
Geometry information for a single TPC.
Definition: TPCGeo.h:33
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:403
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:195
for(Int_t i=0;i< nentries;i++)
Definition: comparison.C:30
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
art::ServiceHandle< geo::Geometry const > geom
static geo::PlaneID DecodeCTP(CTP_t CTP)
double Length() const
Length is associated with z coordinate [cm].
Definition: TPCGeo.h:110
int fDebugHit
out detailed information while crawling
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
Point_t GetCenter() const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.h:132
if(nlines<=0)
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
geo::WireReadoutGeom const * wireReadoutGeom
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:373
unsigned int Nplanes(TPCID const &tpcid=details::tpc_zero) const
Returns the total number of planes in the specified TPC.
double HalfHeight() const
Height is associated with y coordinate [cm].
Definition: TPCGeo.h:106
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
PlaneGeo const & FirstPlane(TPCID const &tpcid) const
Returns the first plane of the specified TPC.
Exception thrown on invalid wire number.
Definition: Exceptions.h:37
std::vector< VtxStore > vtx
the endpoints we are reconstructing
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:315
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:448
Float_t e
Definition: plot.C:35
ROOT libraries.
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:312
std::vector<recob::Hit>&& cluster::ClusterCrawlerAlg::YieldHits ( )
inline

Returns (and loses) the collection of reconstructed hits.

Definition at line 121 of file ClusterCrawlerAlg.h.

Referenced by cluster::LineCluster::produce(), and cluster::ClusterCrawler::produce().

121 { return std::move(fHits); }
std::vector< recob::Hit > fHits
our version of the hits

Member Data Documentation

std::vector<float> cluster::ClusterCrawlerAlg::chgNear
private

charge near a cluster on each wire

Definition at line 290 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::chifits
private

fit chisq for monitoring kinks, etc

Definition at line 286 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginAng
private

Definition at line 230 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginChg
private

begin average charge

Definition at line 234 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginChgNear
private

nearby charge

Definition at line 235 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginSlp
private

begin slope (= DS end = high wire number)

Definition at line 229 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginSlpErr
private

Definition at line 231 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginTim
private

begin time

Definition at line 233 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::clBeginWir
private

begin wire

Definition at line 232 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clChisq
private

chisq of the current fit

Definition at line 206 of file ClusterCrawlerAlg.h.

CTP_t cluster::ClusterCrawlerAlg::clCTP
private

Cryostat/TPC/Plane code.

Definition at line 265 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndAng
private

Definition at line 237 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndChg
private

end average charge

Definition at line 241 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndChgNear
private

nearby charge

Definition at line 242 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndSlp
private

slope at the end (= US end = low wire number)

Definition at line 236 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndSlpErr
private

Definition at line 238 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndTim
private

begin time

Definition at line 240 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::clEndWir
private

begin wire

Definition at line 239 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::clLA
private

using Large Angle crawling code

Definition at line 266 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clpar[3]
private

cluster parameters for the current fit with origin at the US wire on the cluster (in clpar[2])

Definition at line 203 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clparerr[2]
private

cluster parameter errors

Definition at line 205 of file ClusterCrawlerAlg.h.

short cluster::ClusterCrawlerAlg::clProcCode
private

Processor code = pass number

  • 10 ChkMerge
  • 20 ChkMerge with overlapping hits
  • 100 ChkMerge12
  • 200 ClusterFix
  • 300 LACrawlUS
  • 500 MergeOverlap
  • 666 KillGarbageClusters
  • 1000 VtxClusterSplit
  • 2000 failed pass N cuts but passes pass N=1 cuts
  • 5000 ChkClusterDS +10000 Vtx3ClusterSplit

Definition at line 253 of file ClusterCrawlerAlg.h.

short cluster::ClusterCrawlerAlg::clStopCode
private

code for the reason for stopping cluster tracking 0 = no signal on the next wire 1 = skipped too many occupied/dead wires 2 = failed the fMinWirAfterSkip cut 3 = ended on a kink. Fails fKinkChiRat 4 = failed the fChiCut cut 5 = cluster split by VtxClusterSplit 6 = stop at a vertex 7 = LA crawl stopped due to slope cut 8 = SPECIAL CODE FOR STEP CRAWLING

Definition at line 243 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::cstat
private

Definition at line 271 of file ClusterCrawlerAlg.h.

constexpr unsigned int cluster::ClusterCrawlerAlg::CTPpad = 1000
static

Definition at line 38 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fAllowNoHitWire
private

Definition at line 190 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveChg
private

average charge at leading edge of cluster

Definition at line 207 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveHitWidth
private

average width (EndTick - StartTick) of hits

Definition at line 210 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fChgCut
private

charge difference cut for adding a hit to a cluster

Definition at line 156 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgNearCut
private

cut on ratio of nearby/cluster charge to to define a shower-like cluster

Definition at line 292 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgNearWindow
private

window (ticks) for finding nearby charge

Definition at line 291 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgSlp
private

slope of the charge vs wire

Definition at line 209 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fChiCut
private

stop adding hits to clusters if chisq too high

Definition at line 152 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fChkClusterDS
private

Definition at line 173 of file ClusterCrawlerAlg.h.

std::vector<unsigned int> cluster::ClusterCrawlerAlg::fcl2hits
private

vector of hits used in the cluster

Definition at line 285 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fClProjErrFac
private

cluster projection error factor

Definition at line 181 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugHit
private

out detailed information while crawling

Definition at line 197 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugPlane
private

Definition at line 195 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugWire
private

set to the Begin Wire and Hit of a cluster to print

Definition at line 196 of file ClusterCrawlerAlg.h.

std::vector<bool> cluster::ClusterCrawlerAlg::fDoMerge
private

try to merge clusters?

Definition at line 161 of file ClusterCrawlerAlg.h.

std::vector<geo::WireID> cluster::ClusterCrawlerAlg::fFilteredWires
private

Definition at line 200 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindHammerClusters
private

look for hammer type clusters

Definition at line 166 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindStarVertices
private

Definition at line 175 of file ClusterCrawlerAlg.h.

std::vector<bool> cluster::ClusterCrawlerAlg::fFindVertices
private

run vertexing code after clustering?

Definition at line 164 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fFirstHit
private

first hit used

Definition at line 269 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fFirstWire
private

the first wire with a hit

Definition at line 268 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitErrFac
private

hit time error = fHitErrFac * hit RMS used for cluster fit

Definition at line 179 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitMergeChiCut
private

Merge cluster hit-multiplets if the separation chisq is < cut. Set < 0 for no merging

Definition at line 187 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitMinAmp
private

< ignore hits with Amp < this value

Definition at line 180 of file ClusterCrawlerAlg.h.

std::vector<recob::Hit> cluster::ClusterCrawlerAlg::fHits
private

our version of the hits

Definition at line 220 of file ClusterCrawlerAlg.h.

std::string cluster::ClusterCrawlerAlg::fhitsModuleLabel
private

Definition at line 295 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fKillGarbageClusters
private

Definition at line 172 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fKinkAngCut
private

kink angle cut made after fKinkChiRat

Definition at line 155 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fKinkChiRat
private

Max consecutive chisq increase for the last 3 hits on the cluster

Definition at line 153 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusAngleCut
private

call Large Angle Clustering code if > 0

Definition at line 183 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fLAClusMaxHitsFit
private

max hits fitted on a Large Angle cluster

Definition at line 184 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusSlopeCut
private

Definition at line 185 of file ClusterCrawlerAlg.h.

std::vector<bool> cluster::ClusterCrawlerAlg::fLACrawl
private

Crawl Large Angle clusters on pass?

Definition at line 165 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fLastWire
private

the last wire with a hit

Definition at line 270 of file ClusterCrawlerAlg.h.

trkf::LinFitAlg cluster::ClusterCrawlerAlg::fLinFitAlg
private

Definition at line 227 of file ClusterCrawlerAlg.h.

std::vector<unsigned short> cluster::ClusterCrawlerAlg::fMaxHitsFit
private

Max number of hits fitted.

Definition at line 148 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fMaxTime
private

Definition at line 275 of file ClusterCrawlerAlg.h.

std::vector<unsigned short> cluster::ClusterCrawlerAlg::fMaxWirSkip
private

max number of wires that can be skipped while crawling

Definition at line 158 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fMergeAllHits
private

Definition at line 186 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fMergeChgCut
private

max charge ratio for matching

Definition at line 163 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMergeOverlapAngCut
private

angle cut for merging overlapping clusters

Definition at line 189 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fMinAmp
private

expected minimum signal in each wire plane

Definition at line 170 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMinHitFrac
private

Definition at line 182 of file ClusterCrawlerAlg.h.

std::vector<unsigned short> cluster::ClusterCrawlerAlg::fMinHits
private

Min number of hits to make a cluster.

Definition at line 149 of file ClusterCrawlerAlg.h.

std::vector<unsigned short> cluster::ClusterCrawlerAlg::fMinWirAfterSkip
private

minimum number of hits on consecutive wires after skipping

Definition at line 159 of file ClusterCrawlerAlg.h.

std::vector<unsigned short> cluster::ClusterCrawlerAlg::fNHitsAve
private

number of US hits used to compute fAveChg set to > 2 to do a charge fit using fNHitsAve hits

Definition at line 150 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fNumPass
private

number of passes over the hit collection

Definition at line 147 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fNumWires
private

Definition at line 274 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fRefineVertexClusters
private

Definition at line 168 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fScaleF
private

scale factor from Tick/Wire to dx/du

Definition at line 276 of file ClusterCrawlerAlg.h.

std::vector<float> cluster::ClusterCrawlerAlg::fTimeDelta
private

max time difference for matching

Definition at line 162 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DCut
private

2D vtx -> cluster matching cut (chisq/dof)

Definition at line 191 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DWireErrCut
private

Definition at line 192 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex3DCut
private

2D vtx -> 3D vtx matching cut (chisq/dof)

Definition at line 193 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fVtxClusterSplit
private

Definition at line 174 of file ClusterCrawlerAlg.h.

art::ServiceHandle<geo::Geometry const> cluster::ClusterCrawlerAlg::geom
private

Definition at line 216 of file ClusterCrawlerAlg.h.

std::vector<short> cluster::ClusterCrawlerAlg::hitNear
private

Number of nearby hits that were merged have hitnear < 0

Definition at line 287 of file ClusterCrawlerAlg.h.

std::vector<short> cluster::ClusterCrawlerAlg::inClus
private

Hit used in cluster (-1 = obsolete, 0 = free)

Definition at line 221 of file ClusterCrawlerAlg.h.

std::vector<bool> cluster::ClusterCrawlerAlg::mergeAvailable
private

set true if hit is with HitMergeChiCut of a neighbor hit

Definition at line 222 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::NClusters
private

Definition at line 214 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::pass
private

Definition at line 278 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::plane
private

Definition at line 273 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::prt
private

Definition at line 212 of file ClusterCrawlerAlg.h.

std::vector<ClusterStore> cluster::ClusterCrawlerAlg::tcl
private

the clusters we are creating

Definition at line 223 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::tpc
private

Definition at line 272 of file ClusterCrawlerAlg.h.

std::vector<VtxStore> cluster::ClusterCrawlerAlg::vtx
private

the endpoints we are reconstructing

Definition at line 224 of file ClusterCrawlerAlg.h.

std::vector<Vtx3Store> cluster::ClusterCrawlerAlg::vtx3
private

the 3D vertices we are reconstructing

Definition at line 225 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::vtxprt
private

Definition at line 213 of file ClusterCrawlerAlg.h.

std::vector<std::pair<int, int> > cluster::ClusterCrawlerAlg::WireHitRange
private

Definition at line 283 of file ClusterCrawlerAlg.h.

geo::WireReadoutGeom const* cluster::ClusterCrawlerAlg::wireReadoutGeom
private
Initial value:

Definition at line 217 of file ClusterCrawlerAlg.h.


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