LArSoft  v09_93_00
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
 
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 35 of file ClusterCrawlerAlg.h.

Member Typedef Documentation

typedef unsigned int cluster::ClusterCrawlerAlg::CTP_t

Definition at line 38 of file ClusterCrawlerAlg.h.

Constructor & Destructor Documentation

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

Definition at line 54 of file ClusterCrawlerAlg.cxx.

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

55  {
56  fNumPass = pset.get<unsigned short>("NumPass", 0);
57  fMaxHitsFit = pset.get<std::vector<unsigned short>>("MaxHitsFit");
58  fMinHits = pset.get<std::vector<unsigned short>>("MinHits");
59  fNHitsAve = pset.get<std::vector<unsigned short>>("NHitsAve");
60  fChgCut = pset.get<std::vector<float>>("ChgCut");
61  fChiCut = pset.get<std::vector<float>>("ChiCut");
62  fMaxWirSkip = pset.get<std::vector<unsigned short>>("MaxWirSkip");
63  fMinWirAfterSkip = pset.get<std::vector<unsigned short>>("MinWirAfterSkip");
64  fKinkChiRat = pset.get<std::vector<float>>("KinkChiRat");
65  fKinkAngCut = pset.get<std::vector<float>>("KinkAngCut");
66  fDoMerge = pset.get<std::vector<bool>>("DoMerge");
67  fTimeDelta = pset.get<std::vector<float>>("TimeDelta");
68  fMergeChgCut = pset.get<std::vector<float>>("MergeChgCut");
69  fFindVertices = pset.get<std::vector<bool>>("FindVertices");
70  fLACrawl = pset.get<std::vector<bool>>("LACrawl");
71  fMinAmp = pset.get<std::vector<float>>("MinAmp", {5, 5, 5});
72  fChgNearWindow = pset.get<float>("ChgNearWindow");
73  fChgNearCut = pset.get<float>("ChgNearCut");
74 
75  fChkClusterDS = pset.get<bool>("ChkClusterDS", false);
76  fVtxClusterSplit = pset.get<bool>("VtxClusterSplit", false);
77  fFindStarVertices = pset.get<bool>("FindStarVertices", false);
78  if (pset.has_key("HammerCluster")) {
79  mf::LogWarning("CC")
80  << "fcl setting HammerCluster is replaced by FindHammerClusters. Ignoring...";
81  }
82  fFindHammerClusters = pset.get<bool>("FindHammerClusters", false);
83  fKillGarbageClusters = pset.get<float>("KillGarbageClusters", 0);
84  fRefineVertexClusters = pset.get<bool>("RefineVertexClusters", false);
85  fHitErrFac = pset.get<float>("HitErrFac", 0.2);
86  fHitMinAmp = pset.get<float>("HitMinAmp", 0.2);
87  fClProjErrFac = pset.get<float>("ClProjErrFac", 4);
88  fMinHitFrac = pset.get<float>("MinHitFrac", 0.6);
89 
90  fLAClusAngleCut = pset.get<float>("LAClusAngleCut", 45);
91  fLAClusMaxHitsFit = pset.get<unsigned short>("LAClusMaxHitsFit");
92  fMergeAllHits = pset.get<bool>("MergeAllHits", false);
93  fHitMergeChiCut = pset.get<float>("HitMergeChiCut", 2.5);
94  fMergeOverlapAngCut = pset.get<float>("MergeOverlapAngCut");
95  fAllowNoHitWire = pset.get<unsigned short>("AllowNoHitWire", 0);
96  fVertex2DCut = pset.get<float>("Vertex2DCut", 5);
97  fVertex2DWireErrCut = pset.get<float>("Vertex2DWireErrCut", 5);
98  fVertex3DCut = pset.get<float>("Vertex3DCut", 5);
99 
100  fDebugPlane = pset.get<int>("DebugPlane", -1);
101  fDebugWire = pset.get<int>("DebugWire", -1);
102  fDebugHit = pset.get<int>("DebugHit", -1);
103 
104  // some error checking
105  bool badinput = false;
106  if (fNumPass > fMaxHitsFit.size()) badinput = true;
107  if (fNumPass > fMinHits.size()) badinput = true;
108  if (fNumPass > fNHitsAve.size()) badinput = true;
109  if (fNumPass > fChgCut.size()) badinput = true;
110  if (fNumPass > fChiCut.size()) badinput = true;
111  if (fNumPass > fMaxWirSkip.size()) badinput = true;
112  if (fNumPass > fMinWirAfterSkip.size()) badinput = true;
113  if (fNumPass > fKinkChiRat.size()) badinput = true;
114  if (fNumPass > fKinkAngCut.size()) badinput = true;
115  if (fNumPass > fDoMerge.size()) badinput = true;
116  if (fNumPass > fTimeDelta.size()) badinput = true;
117  if (fNumPass > fMergeChgCut.size()) badinput = true;
118  if (fNumPass > fFindVertices.size()) badinput = true;
119  if (fNumPass > fLACrawl.size()) badinput = true;
120 
121  if (badinput)
123  << "ClusterCrawlerAlg: Bad input from fcl file";
124 
125  } // 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 4728 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().

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

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

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

References util::abs().

4337  {
4338  // returns an angle dependent cluster projection error factor for fitting
4339  // and hit finding
4340 
4341  float slp = std::abs(slope);
4342  if (slp > 15) slp = 15;
4343  // return a value between 1 and 4
4344  float angfac = 1 + 0.03 * slp * slp;
4345  return angfac;
4346  }
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 6087 of file ClusterCrawlerAlg.cxx.

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

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

Definition at line 4349 of file ClusterCrawlerAlg.cxx.

4350  {
4351  fAveHitWidth = 0;
4352  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii)
4353  fAveHitWidth += fHits[fcl2hits[ii]].EndTick() - fHits[fcl2hits[ii]].StartTick();
4354  fAveHitWidth /= (float)fcl2hits.size();
4355  } // 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 4061 of file ClusterCrawlerAlg.cxx.

References tca::DeadWireCount().

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

879  {
880  // check hit - cluster associations
881 
882  if (fHits.size() != inClus.size()) {
883  mf::LogError("CC") << "CHCA: Sizes wrong " << fHits.size() << " " << inClus.size();
884  return;
885  }
886 
887  unsigned int iht, nErr = 0;
888  short clID;
889 
890  // check cluster -> hit association
891  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
892  if (tcl[icl].ID < 0) continue;
893  clID = tcl[icl].ID;
894  for (unsigned short ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
895  iht = tcl[icl].tclhits[ii];
896  if (iht > fHits.size() - 1) {
897  mf::LogError("CC") << "CHCA: Bad tclhits index " << iht << " fHits size " << fHits.size();
898  return;
899  } // iht > fHits.size() - 1
900  if (inClus[iht] != clID) {
901  mf::LogError("CC") << "CHCA: Bad cluster -> hit association. clID " << clID
902  << " hit inClus " << inClus[iht] << " ProcCode " << tcl[icl].ProcCode
903  << " CTP " << tcl[icl].CTP;
904  ++nErr;
905  if (nErr > 10) return;
906  }
907  } // ii
908  } // icl
909 
910  // check hit -> cluster association
911  unsigned short icl;
912  for (iht = 0; iht < fHits.size(); ++iht) {
913  if (inClus[iht] <= 0) continue;
914  icl = inClus[iht] - 1;
915  // see if the cluster is obsolete
916  if (tcl[icl].ID < 0) {
917  mf::LogError("CC") << "CHCA: Hit associated with an obsolete cluster. hit W:T "
918  << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime()
919  << " tcl[icl].ID " << tcl[icl].ID;
920  ++nErr;
921  if (nErr > 10) return;
922  }
923  if (std::find(tcl[icl].tclhits.begin(), tcl[icl].tclhits.end(), iht) ==
924  tcl[icl].tclhits.end()) {
925  mf::LogError("CC") << "CHCA: Bad hit -> cluster association. hit index " << iht << " W:T "
926  << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime()
927  << " inClus " << inClus[iht];
928  ++nErr;
929  if (nErr > 10) return;
930  }
931  } // iht
932 
933  } // 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 6106 of file ClusterCrawlerAlg.cxx.

References hits().

6108  {
6109  // currently unused, only for debug
6110  unsigned int nDuplicates = 0;
6111  std::set<unsigned int> hits;
6112  for (unsigned int hit : fcl2hits) {
6113  if (hits.count(hit)) {
6114  ++nDuplicates;
6115  mf::LogProblem log("CC");
6116  log << "Hit #" << hit
6117  << " being included twice in the future cluster (ID=" << (tcl.size() + 1)
6118  << "?) at location: " << location;
6119  if (!marker.empty()) log << " (marker: '" << marker << "')";
6120  }
6121  hits.insert(hit);
6122  } // for
6123  return nDuplicates > 0;
6124  } // 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 976 of file ClusterCrawlerAlg.cxx.

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

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

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

4983  {
4984  // analyze the hitnear vector
4985  // 0 = no nearby hit exists
4986  // 1 = a nearby hit exists but was not merged
4987  // -1 = a nearby hit was merged
4988 
4989  if (fHitMergeChiCut <= 0) return;
4990 
4991  if (hitNear.size() != fcl2hits.size()) {
4992  mf::LogWarning("CC") << "Coding error: hitNear size != fcl2hits";
4993  return;
4994  }
4995 
4996  // Analyze the last 6 hits added but don't consider the first few hits
4997  if (hitNear.size() < 12) return;
4998 
4999  // TODO move into loops
5000  unsigned short ii, indx;
5001  unsigned short merged = 0;
5002  unsigned short notmerged = 0;
5003  for (ii = 0; ii < 6; ++ii) {
5004  indx = hitNear.size() - 1 - ii;
5005  if (hitNear[indx] > 0) ++notmerged;
5006  if (hitNear[indx] < 0) ++merged;
5007  }
5008 
5009  if (prt)
5010  mf::LogVerbatim("CC") << "ChkClusterNearbyHits: nearby hits merged " << merged
5011  << " not merged " << notmerged;
5012 
5013  if (notmerged < 2) return;
5014 
5015  // a number of nearby hits were not merged while crawling, so the
5016  // average charge is probably wrong. Look at the last 6 hits added
5017  // and merge them if they are close
5018  bool didMerge;
5019  for (ii = 0; ii < 6; ++ii) {
5020  indx = fcl2hits.size() - 1 - ii;
5021  const unsigned int iht = fcl2hits[indx];
5022  recob::Hit const& hit = fHits[iht];
5023  if (hit.Multiplicity() == 2) {
5024  // quit if localindex does not make sense.
5025  if (hit.LocalIndex() != 0 && iht == 0) continue;
5026  // hit doublet. Get the index of the other hit
5027  unsigned int oht;
5028  if (hit.LocalIndex() == 0) { oht = iht + 1; }
5029  else {
5030  oht = iht - 1;
5031  } // hit.LocalIndex() == 0
5032  recob::Hit const& other_hit = fHits[oht];
5033  // TODO use Hit::TimeDistanceAsRMS()
5034  float hitSep = std::abs(hit.PeakTime() - other_hit.PeakTime());
5035  hitSep /= hit.RMS();
5036  if (hitSep < fHitMergeChiCut && inClus[oht] == 0) {
5037  if (prt)
5038  mf::LogVerbatim("CC") << "Merging hit doublet " << iht << " W:T "
5039  << fHits[iht].WireID().Wire << ":" << fHits[iht].PeakTime();
5040  MergeHits(iht, didMerge);
5041  if (didMerge) hitNear[indx] = -1;
5042  } // hitSep OK and not in a cluster
5043  } // hit doublet
5044  } // ii
5045 
5046  // now re-fit
5047  FitCluster();
5048  FitClusterChg();
5049 
5050  if (prt) mf::LogVerbatim("CC") << "ChkClusterNearbyHits refit cluster. fAveChg= " << fAveChg;
5051 
5052  } // 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 2789 of file ClusterCrawlerAlg.cxx.

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

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

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

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

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

2569  {
2570  if (iht > fHits.size() - 1) return false;
2571  if (jht > fHits.size() - 1) return false;
2572  unsigned int wire1 = fHits[iht].WireID().Wire;
2573  float time1 = fHits[iht].PeakTime();
2574  unsigned int wire2 = fHits[jht].WireID().Wire;
2575  float time2 = fHits[jht].PeakTime();
2576  return ChkSignal(wire1, time1, wire2, time2);
2577  } // 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 2580 of file ClusterCrawlerAlg.cxx.

References util::abs(), and bin.

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

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

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

146  {
147  fHits.clear();
148  tcl.clear();
149  vtx.clear();
150  vtx3.clear();
151  inClus.clear();
152  } // ClusterCrawlerAlg::ClearResults()
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 4669 of file ClusterCrawlerAlg.cxx.

References lar::util::absDiff().

4670  {
4671  // Check StartTick and EndTick of hits on adjacent wires overlap as illustrated below.
4672  // >>>>>> This is OK
4673  // Wire StartTick EndTick
4674  // n |--------------|
4675  // n+1 |--------------|
4676  // n+2 |--------------|
4677  // >>>>>> This is NOT OK
4678  // n |------|
4679  // n+1 |-----|
4680  // n+2 |------|
4681 
4682  if (fcl2hits.size() == 0) return true;
4683 
4684  unsigned short nHitToChk = fcl2hits.size();
4685  if (nHitChk > 0) nHitToChk = nHitChk + 1;
4686  unsigned short ii, indx;
4687 
4688  // require that they overlap
4689  // add a tolerance to the StartTick - EndTick overlap
4690  raw::TDCtick_t tol = 30;
4691  // expand the tolerance for induction planes
4692  if (plane < geom->TPC(geo::TPCID(cstat, tpc)).Nplanes() - 1) tol = 40;
4693 
4694  bool posSlope =
4695  (fHits[fcl2hits[0]].PeakTime() > fHits[fcl2hits[fcl2hits.size() - 1]].PeakTime());
4696 
4697  if (prt) {
4698  for (ii = 0; ii < nHitToChk; ++ii) {
4699  indx = fcl2hits.size() - 1 - ii;
4700  mf::LogVerbatim("CC") << "ClusterHitsOK chk " << fHits[fcl2hits[indx]].WireID().Wire
4701  << " start " << fHits[fcl2hits[indx]].StartTick() << " peak "
4702  << fHits[fcl2hits[indx]].PeakTime() << " end "
4703  << fHits[fcl2hits[indx]].EndTick() << " posSlope " << posSlope;
4704  }
4705  }
4706 
4707  raw::TDCtick_t hiStartTick, loEndTick;
4708  for (ii = 0; ii < nHitToChk - 1; ++ii) {
4709  indx = fcl2hits.size() - 1 - ii;
4710  // ignore if not on adjacent wires
4711  if (lar::util::absDiff(fHits[fcl2hits[indx]].WireID().Wire,
4712  fHits[fcl2hits[indx - 1]].WireID().Wire) > 1)
4713  continue;
4714  hiStartTick =
4715  std::max(fHits[fcl2hits[indx]].StartTick(), fHits[fcl2hits[indx - 1]].StartTick());
4716  loEndTick = std::min(fHits[fcl2hits[indx]].EndTick(), fHits[fcl2hits[indx - 1]].EndTick());
4717  if (posSlope) {
4718  if (loEndTick + tol < hiStartTick) { return false; }
4719  }
4720  else {
4721  if (loEndTick + tol < hiStartTick) { return false; }
4722  }
4723  } // ii
4724  return true;
4725  } // 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:381
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 187 of file ClusterCrawlerAlg.cxx.

188  {
189  fcl2hits.clear();
190  chifits.clear();
191  hitNear.clear();
192  chgNear.clear();
193  fAveChg = -1.;
194  fAveHitWidth = -1;
195  clEndChg = -1.;
196  clStopCode = 0;
197  clProcCode = pass;
198  }
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 291 of file ClusterCrawlerAlg.cxx.

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

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

References util::abs().

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

References E.

6174  {
6175  // Returns the chisq/DOF between a cluster and a vertex
6176 
6177  if (icl > (short)tcl.size()) return 9999;
6178  if (ivx > vtx.size()) return 9999;
6179 
6180  float cwire, cslp, cslpErr, ctick;
6181  // figure out which cluster to use
6182  if (icl < 0) {
6183  if (fcl2hits.size() == 0) return 9999;
6184  // cluster under construction
6185  if (end == 0) {
6186  cwire = clBeginWir;
6187  cslp = clBeginSlp;
6188  cslpErr = clBeginSlpErr;
6189  ctick = clBeginTim;
6190  }
6191  else {
6192  cwire = clpar[2];
6193  cslp = clpar[1];
6194  cslpErr = clparerr[1];
6195  ctick = clpar[0];
6196  } // end
6197  }
6198  else {
6199  // tcl cluster
6200  if (end == 0) {
6201  cwire = tcl[icl].BeginWir;
6202  cslp = tcl[icl].BeginSlp;
6203  cslpErr = tcl[icl].BeginSlpErr;
6204  ctick = tcl[icl].BeginTim;
6205  }
6206  else {
6207  cwire = tcl[icl].EndWir;
6208  cslp = tcl[icl].EndSlp;
6209  cslpErr = tcl[icl].EndSlpErr;
6210  ctick = tcl[icl].EndTim;
6211  } // end
6212  }
6213 
6214  // Closest approach wire
6215  float docaW =
6216  (vtx[ivx].Wire + cslp * (vtx[ivx].Time - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6217  float dW = docaW - vtx[ivx].Wire;
6218  float chi = dW / vtx[ivx].WireErr;
6219  float totChi = chi * chi;
6220  dW = vtx[ivx].Wire - cwire;
6221  float dT = ctick + dW * cslp - vtx[ivx].Time;
6222  if (cslpErr < 1E-3) cslpErr = 1E-3;
6223  // increase slope error for large angle clusters
6224  cslpErr *= AngleFactor(cslp);
6225  // cluster slope projection error
6226  float dTErr = dW * cslpErr;
6227  // squared
6228  dTErr *= dTErr;
6229  // add the vertex time error^2 to the cluster projection error^2
6230  dTErr += vtx[ivx].TimeErr * vtx[ivx].TimeErr;
6231  if (dTErr < 1E-3) dTErr = 1E-3;
6232  totChi += dT * dT / dTErr;
6233  totChi /= 2;
6234 
6235  return totChi;
6236 
6237  } // 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 155 of file ClusterCrawlerAlg.cxx.

156  {
157  prt = false;
158  vtxprt = false;
159  NClusters = 0;
160  clBeginSlp = 0;
161  clBeginSlpErr = 0;
162  clBeginTim = 0;
163  clBeginWir = 0;
164  clBeginChg = 0;
165  clBeginChgNear = 0;
166  clEndSlp = 0;
167  clEndSlpErr = 0;
168  clEndTim = 0;
169  clEndWir = 0;
170  clEndChg = 0;
171  clEndChgNear = 0;
172  clChisq = 0;
173  clStopCode = 0;
174  clProcCode = 0;
175  fFirstWire = 0;
176  fLastWire = 0;
177  fAveChg = 0.;
178  fChgSlp = 0.;
179  pass = 0;
180  fScaleF = 0;
181  WireHitRange.clear();
182 
183  ClearResults();
184  }
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 3691 of file ClusterCrawlerAlg.cxx.

References util::abs().

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

References util::abs().

1194  {
1195 
1196  // returns true if the cluster is near a vertex on wire kwire
1197  if (vtx.size() == 0) return false;
1198  unsigned int iht = fcl2hits.size() - 1;
1199  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1200  float prtime = clpar[0] + (kwire - wire0) * clpar[1];
1201  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1202  if (vtx[iv].CTP != clCTP) continue;
1203  if ((unsigned int)(0.5 + vtx[iv].Wire) != kwire) continue;
1204  if (std::abs(prtime - vtx[iv].Time) < 10) return true;
1205  }
1206  return false;
1207  } // 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 1158 of file ClusterCrawlerAlg.cxx.

References util::abs().

1159  {
1160  // returns true if the (presumably short) cluster under construction
1161  // resides between a vertex and another cluster that is associated with
1162  // that vertex
1163 
1164  if (vtx.size() == 0) return false;
1165  if (fcl2hits.size() == 0) return false;
1166 
1167  unsigned int iht = fcl2hits.size() - 1;
1168  unsigned short icl;
1169  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1170  float dt;
1171  float thclus = std::atan(fScaleF * clpar[1]);
1172 
1173  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1174  if (vtx[iv].CTP != clCTP) continue;
1175  if (wire0 < vtx[iv].Wire) continue;
1176  if (wire0 > vtx[iv].Wire + 10) continue;
1177  dt = clpar[0] + (vtx[iv].Wire - wire0) * clpar[1] - vtx[iv].Time;
1178  if (std::abs(dt) > 10) continue;
1179  // cluster points to an US vertex. See if the angle is similar to
1180  // cluster associated with this vertex
1181  for (icl = 0; icl < tcl.size(); ++icl) {
1182  if (tcl[icl].CTP != clCTP) continue;
1183  if (tcl[icl].EndVtx != iv) continue;
1184  if (std::abs(tcl[icl].EndAng - thclus) < fKinkAngCut[pass]) return true;
1185  }
1186  }
1187 
1188  return false;
1189 
1190  } // 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 6072 of file ClusterCrawlerAlg.cxx.

6073  {
6074  // Counts the number of dead wires in the range spanned by fcl2hits
6075  if (fcl2hits.size() < 2) return 0;
6076  unsigned int wire, ndead = 0;
6077  unsigned int iht = fcl2hits[fcl2hits.size() - 1];
6078  unsigned int eWire = fHits[iht].WireID().Wire;
6079  iht = fcl2hits[0];
6080  unsigned int bWire = fHits[iht].WireID().Wire + 1;
6081  for (wire = eWire; wire < bWire; ++wire)
6082  if (WireHitRange[wire].first == -1) ++ndead;
6083  return ndead;
6084  } // 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 6056 of file ClusterCrawlerAlg.cxx.

References tmp.

6057  {
6058  if (inWire1 > inWire2) {
6059  // put in increasing order
6060  unsigned int tmp = inWire1;
6061  inWire1 = inWire2;
6062  inWire2 = tmp;
6063  } // inWire1 > inWire2
6064  ++inWire2;
6065  unsigned int wire, ndead = 0;
6066  for (wire = inWire1; wire < inWire2; ++wire)
6067  if (WireHitRange[wire].first == -1) ++ndead;
6068  return ndead;
6069  } // 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 49 of file ClusterCrawlerAlg.h.

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

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

Definition at line 6127 of file ClusterCrawlerAlg.cxx.

6128  {
6129  // Find the Distance of Closest Approach betweeen a cluster and a point (vwire, vtick). The
6130  // DoCA is returned in Tick units.
6131 
6132  if (icl > (short)tcl.size()) return 9999;
6133 
6134  float cwire, cslp, ctick;
6135  // figure out which cluster to use
6136  if (icl < 0) {
6137  if (fcl2hits.size() == 0) return 9999;
6138  // cluster under construction
6139  if (end == 0) {
6140  cwire = clBeginWir;
6141  cslp = clBeginSlp;
6142  ctick = clBeginTim;
6143  }
6144  else {
6145  cwire = clpar[2];
6146  cslp = clpar[1];
6147  ctick = clpar[0];
6148  } // end
6149  }
6150  else {
6151  // tcl cluster
6152  if (end == 0) {
6153  cwire = tcl[icl].BeginWir;
6154  cslp = tcl[icl].BeginSlp;
6155  ctick = tcl[icl].BeginTim;
6156  }
6157  else {
6158  cwire = tcl[icl].EndWir;
6159  cslp = tcl[icl].EndSlp;
6160  ctick = tcl[icl].EndTim;
6161  } // end
6162  }
6163 
6164  // Closest approach wire
6165  float docaW = (vwire + cslp * (vtick - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6166  float dW = docaW - vwire;
6167  float dT = ctick + (vwire - cwire) * cslp - vtick;
6168  return sqrt(dW * dW + dT * dT);
6169 
6170  } // 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 3132 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.

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

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

Definition at line 45 of file ClusterCrawlerAlg.h.

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

46  {
47  return EncodeCTP(planeID.Cryostat, planeID.TPC, planeID.Plane);
48  }
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:211
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:481
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:399
float cluster::ClusterCrawlerAlg::EndKinkAngle ( )
private

Definition at line 3991 of file ClusterCrawlerAlg.cxx.

References util::abs().

3992  {
3993  // find the kink angle (crudely) from the 0th and 2nd hit on the cluster under construction
3994 
3995  unsigned int ih0 = fcl2hits.size() - 1;
3996  unsigned int hit0 = fcl2hits[ih0];
3997  unsigned int ih2 = ih0 - 2;
3998  unsigned int hit2 = fcl2hits[ih2];
3999  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
4000  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
4001  float th02 = std::atan(fScaleF * dt02 / dw02);
4002  // and the 3rd and 5th hit
4003  unsigned int ih3 = ih2 - 1;
4004  unsigned int hit3 = fcl2hits[ih3];
4005  unsigned int ih5 = ih3 - 2;
4006  unsigned int hit5 = fcl2hits[ih5];
4007  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
4008  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
4009  float th35 = std::atan(fScaleF * dt35 / dw35);
4010  return std::abs(th02 - th35);
4011  }
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 859 of file ClusterCrawlerAlg.cxx.

860  {
861 
862  // Trims nTrim hits off the UpStream end of the fcl2hits, etc vectors.
863  if (nTrim == 0) return;
864 
865  if (nTrim >= fcl2hits.size()) nTrim = fcl2hits.size();
866 
867  // RestoreUnMergedClusterHits((short)nTrim);
868  for (unsigned short ii = 0; ii < nTrim; ++ii) {
869  fcl2hits.pop_back();
870  chifits.pop_back();
871  hitNear.pop_back();
872  chgNear.pop_back();
873  } // ii
874 
875  } // 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 5491 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.

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

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

Definition at line 1765 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.

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

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

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

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

Definition at line 4237 of file ClusterCrawlerAlg.cxx.

4238  {
4239  // Fits the hits on the US end of a cluster. This routine assumes that
4240  // wires are numbered from lower (upstream) to higher (downstream) and
4241  // that the hits in the fclhits vector are sorted so that upstream hits
4242  // are at the end of the vector
4243 
4244  clChisq = 999.;
4245 
4246  if (pass > fNumPass - 1) {
4247  mf::LogError("CC") << "FitCluster called on invalid pass " << pass;
4248  return;
4249  }
4250 
4251  unsigned short ii, nht = 0;
4252  // fit all hits or truncate?
4253  nht = fcl2hits.size();
4254  if (clLA) {
4255  // Fit large angle cluster
4256  if (nht > fLAClusMaxHitsFit) nht = fLAClusMaxHitsFit;
4257  }
4258  else {
4259  if (nht > fMaxHitsFit[pass]) nht = fMaxHitsFit[pass];
4260  }
4261  if (nht < 2) return;
4262 
4263  std::vector<float> xwir;
4264  std::vector<float> ytim;
4265  std::vector<float> ytimerr2;
4266  // apply an angle dependent scale factor.
4267  float angfactor = AngleFactor(clpar[1]);
4268 
4269  unsigned int wire;
4270  unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4271  unsigned int ihit;
4272  float terr, qave = 0, qwt;
4273  for (ii = 0; ii < nht; ++ii) {
4274  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4275  qave += fHits[ihit].Integral();
4276  } // ii
4277  qave /= (float)nht;
4278  for (ii = 0; ii < nht; ++ii) {
4279  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4280  wire = fHits[ihit].WireID().Wire;
4281  xwir.push_back(wire - wire0);
4282  ytim.push_back(fHits[ihit].PeakTime());
4283  // Scale error by hit multiplicity to account for bias in hit
4284  // multiplet fitting
4285  terr = fHitErrFac * fHits[ihit].RMS() * fHits[ihit].Multiplicity();
4286  if (fAveChg > 0) {
4287  // increase the error for large charge hits
4288  qwt = (fHits[ihit].Integral() / qave) - 1;
4289  if (qwt < 1) qwt = 1;
4290  terr *= qwt;
4291  }
4292  if (terr < 0.01) terr = 0.01;
4293  ytimerr2.push_back(angfactor * terr * terr);
4294  }
4296  if (prt) {
4297  mf::LogVerbatim myprt("CC");
4298  myprt << "FitCluster W:T ";
4299  unsigned short cnt = 0;
4300  for (std::vector<unsigned int>::reverse_iterator it = fcl2hits.rbegin();
4301  it != fcl2hits.rend();
4302  ++it) {
4303  unsigned int ihit = *it;
4304  unsigned short wire = fHits[ihit].WireID().Wire;
4305  myprt << wire << ":" << (short)fHits[ihit].PeakTime() << " ";
4306  ++cnt;
4307  if (cnt == 8) {
4308  myprt << " .... ";
4309  break;
4310  }
4311  }
4312  } // prt
4313 
4314  if (xwir.size() < 2) return;
4315 
4316  float intcpt = 0.;
4317  float slope = 0.;
4318  float intcpterr = 0.;
4319  float slopeerr = 0.;
4320  float chidof = 0.;
4321  fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4322  clChisq = chidof;
4323  if (chidof > fChiCut[0]) return;
4324  clpar[0] = intcpt;
4325  clpar[1] = slope;
4326  clpar[2] = wire0;
4327  clparerr[0] = intcpterr;
4328  clparerr[1] = slopeerr;
4329 
4330  if (prt)
4331  mf::LogVerbatim("CC") << "nht " << nht << " fitpar " << (int)clpar[0] << "+/-"
4332  << (int)intcpterr << " " << clpar[1] << "+/-" << slopeerr << " clChisq "
4333  << clChisq;
4334  }
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 4358 of file ClusterCrawlerAlg.cxx.

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

4130  {
4131  FitClusterMid(tcl[it1].tclhits, ihtin, nhit);
4132  } // 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 4135 of file ClusterCrawlerAlg.cxx.

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

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

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

1712  {
1713  //
1714  // Resets multiplicity and local index of the hits in the range.
1715  // All hits are assumed to be in the same multiplet.
1716  // All hits that are not obsolete are given a multiplicity equal to the
1717  // number of non-obsolete hits in the multiplet, and the local index is
1718  // assigned as an increasing number starting from 0 with the first
1719  // non-obsolete hit on.
1720  //
1721 
1722  // first pass: determine the actual number of hits in the multiplet
1723  if (multiplicity < 0) {
1724  multiplicity = 0;
1725  for (size_t iHit = begin; iHit < end; ++iHit) {
1726  if (inClus[iHit] < 0) continue;
1727  ++multiplicity;
1728  } // for
1729  } // if no valid multiplicity is given
1730 
1731  // second pass: assign the correct multiplicity
1732  short int local_index = 0;
1733  for (size_t iHit = begin; iHit < end; ++iHit) {
1734  if (inClus[iHit] < 0) continue;
1735 
1736  // copy everything but overwrite the local index and multiplicity
1737  // TODO use a write wrapper!
1738  recob::Hit const& hit = fHits[iHit];
1739  fHits[iHit] = recob::Hit(hit.Channel(),
1740  hit.StartTick(),
1741  hit.EndTick(),
1742  hit.PeakTime(),
1743  hit.SigmaPeakTime(),
1744  hit.RMS(),
1745  hit.PeakAmplitude(),
1746  hit.SigmaPeakAmplitude(),
1747  hit.ROISummedADC(),
1748  hit.HitSummedADC(),
1749  hit.Integral(),
1750  hit.SigmaIntegral(),
1751  multiplicity, // multiplicity
1752  local_index, // local index
1753  hit.GoodnessOfFit(),
1754  hit.DegreesOfFreedom(),
1755  hit.View(),
1756  hit.SignalType(),
1757  hit.WireID());
1758 
1759  ++local_index;
1760  } // for
1761 
1762  } // 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 129 of file ClusterCrawlerAlg.h.

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

129 { 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 132 of file ClusterCrawlerAlg.h.

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

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

Definition at line 5939 of file ClusterCrawlerAlg.cxx.

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

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

126 { 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 120 of file ClusterCrawlerAlg.h.

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

120 { 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 135 of file ClusterCrawlerAlg.h.

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

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

Definition at line 500 of file ClusterCrawlerAlg.cxx.

References util::abs().

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

References util::abs().

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

829  {
830  short& ID = tcl[icl].ID;
831  if (ID <= 0) {
832  mf::LogError("CC") << "Trying to make already-obsolete cluster obsolete ID = " << ID;
833  return; // already obsolete
834  }
835  ID = -ID; // mark the cluster as obsolete
836 
837  // release the hits
838  for (unsigned int iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
839  inClus[tcl[icl].tclhits[iht]] = 0;
840 
841  } // 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 1549 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().

1550  {
1551  // Merge all unused separate hits in the multiplet of which
1552  // theHit is a member into one hit (= theHit).
1553  // Mark the merged hits other than theHit obsolete.
1554  // Hits in the multiplet that are associated with an existing cluster are
1555  // not affected.
1556  // Hit multiplicity is reworked (including all the hits in the multiplet).
1557  // Used hits have the multiplicity and index corrected too; the local
1558  // index reflects the peak time.
1559  // Note that theHit may or may not be marked free (usually, it is not)
1560 
1561  didMerge = false;
1562 
1563  if (theHit > fHits.size() - 1) { return; }
1564 
1565  recob::Hit const& hit = fHits[theHit];
1566 
1567  // don't bother trying to merge an already merged hit
1568  if (fHits[theHit].GoodnessOfFit() == 6666) {
1569  if (prt)
1570  mf::LogVerbatim("CC") << "MergeHits Trying to merge already merged hit "
1571  << hit.WireID().Plane << ":" << hit.WireID().Wire << ":"
1572  << (int)hit.PeakTime() << " Multiplicity " << hit.Multiplicity()
1573  << " theHit " << theHit;
1574  return;
1575  }
1576 
1577  // don't merge if it isn't available
1578  if (!mergeAvailable[theHit]) { return; }
1579 
1580  if (hit.Multiplicity() < 2) return;
1581 
1582  // number of hits in this hit multiplet
1583  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(theHit);
1584 
1585  // ensure that this is a high multiplicity hit:
1586  if (MultipletRange.second <= MultipletRange.first) return;
1587 
1588  // do a quick check to see how many hits are available to be merged
1589  unsigned short nAvailable = 0;
1590  unsigned short nInClus = 0;
1591  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1592  if (jht == theHit) continue;
1593  if (fHits[jht].GoodnessOfFit() == 6666) continue;
1594  if (inClus[jht] != 0) {
1595  ++nInClus;
1596  continue;
1597  }
1598  ++nAvailable;
1599  } // jht
1600  if (nAvailable == 0) return;
1601  // don't merge if any hit is used
1602  if (nInClus > 0) return;
1603 
1604  // calculate the Charge normalization factor using the hit information
1605  // instead of passing CCHitFinder ChgNorms all the way down here
1606  float chgNorm = 2.507 * hit.PeakAmplitude() * hit.RMS() / hit.Integral();
1607 
1608  short loTime = 9999;
1609  short hiTime = 0;
1610  unsigned short nGaus = 1;
1611  float hitSep;
1612  // number of hits that are close to theHit
1613  unsigned short nclose = 0;
1614  // find the time range for the hit multiplet
1615  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1616  if (inClus[jht] < 0) continue;
1617  recob::Hit const& other_hit = fHits[jht];
1618  // error checking
1619  if ((other_hit.StartTick() != hit.StartTick()) || (other_hit.WireID() != hit.WireID())) {
1620  return;
1621  }
1622  if (other_hit.Multiplicity() != hit.Multiplicity()) { return; }
1623  // hit is not used by another cluster
1624  if (inClus[jht] != 0) continue;
1625  short arg = (short)(other_hit.PeakTimeMinusRMS(3));
1626  if (arg < loTime) loTime = arg;
1627  arg = (short)(other_hit.PeakTimePlusRMS(3));
1628  if (arg > hiTime) hiTime = arg;
1629  if (jht != theHit) ++nGaus;
1630  hitSep = std::abs(other_hit.PeakTime() - hit.PeakTime()) / other_hit.RMS();
1631  if (jht != theHit && hitSep < 3) ++nclose;
1632  } // jht
1633  // all hits in the multiplet other than this one used?
1634  if (nGaus < 2) return;
1635 
1636  // the hits in this multiplet will have this multiplicity from now on
1637  const short int NewMultiplicity = hit.Multiplicity() + 1 - nGaus;
1638 
1639  if (loTime < 0) loTime = 0;
1640  ++hiTime;
1641  // define a signal shape, fill it with zeros
1642  std::vector<double> signal(hiTime - loTime, 0.);
1643  // now add the Gaussians for each hit
1644  double chgsum = 0.;
1645  for (size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1646  recob::Hit const& other_hit = fHits[jht];
1647  if (jht != theHit) {
1648  // hit used in another cluster
1649  if (inClus[jht] != 0) continue;
1650  // declare this hit obsolete
1651  inClus[jht] = -1;
1652  } // jht != theHit
1653  // add up the charge
1654  chgsum += other_hit.Integral();
1655  for (unsigned short time = loTime; time < hiTime; ++time) {
1656  unsigned short indx = time - loTime;
1657  double arg = (other_hit.PeakTime() - (double)time) / other_hit.RMS();
1658  signal[indx] += other_hit.PeakAmplitude() * exp(-0.5 * arg * arg);
1659  } // time
1660  } // jj
1661  // find the average weighted time
1662  double sigsum = 0.;
1663  double sigsumt = 0.;
1664  for (unsigned short time = loTime; time < hiTime; ++time) {
1665  sigsum += signal[time - loTime];
1666  sigsumt += signal[time - loTime] * time;
1667  }
1668  if (sigsum == 0.) {
1669  // mf::LogError("CC")<<"MergeHits: bad sum";
1670  return;
1671  }
1672  double aveTime = sigsumt / sigsum;
1673  // find the RMS
1674  sigsumt = 0.;
1675  for (unsigned short time = loTime; time < hiTime; ++time) {
1676  double dtime = time - aveTime;
1677  sigsumt += signal[time - loTime] * dtime * dtime;
1678  }
1679  const float RMS = std::sqrt(sigsumt / sigsum);
1680  // find the amplitude from the integrated charge and the RMS
1681  const float amplitude = chgsum * chgNorm / (2.507 * RMS);
1682  // modify the hit "in place" (actually completely overwrite it...)
1683  // TODO a lot of these quantities need revamp!!
1684  fHits[theHit] = recob::Hit(hit.Channel(),
1685  hit.StartTick(),
1686  hit.EndTick(),
1687  aveTime, // peak_time
1688  hit.SigmaPeakTime(),
1689  RMS, // rms
1690  amplitude, // peak_amplitude
1691  hit.SigmaPeakAmplitude(),
1692  hit.ROISummedADC(),
1693  hit.HitSummedADC(),
1694  chgsum, // hit_integral
1695  hit.SigmaIntegral(),
1696  NewMultiplicity, // multiplicity
1697  0, // local index
1698  6666, // GoodnessOfFit (flag for merged hit)
1699  hit.DegreesOfFreedom(),
1700  hit.View(),
1701  hit.SignalType(),
1702  hit.WireID());
1703  FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1704  didMerge = true;
1705 
1706  } // 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:563
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:481
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 636 of file ClusterCrawlerAlg.cxx.

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

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

6241  {
6242  // Returns the Chisq/DOF between a (Wire, Tick) point and a vertex
6243 
6244  if (ivx > vtx.size()) return 9999;
6245 
6246  float dW = wire - vtx[ivx].Wire;
6247  float chi = dW / vtx[ivx].WireErr;
6248  float totChi = chi * chi;
6249  float dT = tick - vtx[ivx].Time;
6250  chi = dT / vtx[ivx].TimeErr;
6251  totChi += chi * chi;
6252 
6253  return totChi;
6254 
6255  } // 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 3321 of file ClusterCrawlerAlg.cxx.

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

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

References util::to_string().

6259  {
6260 
6261  if (iht > fHits.size() - 1) return "Bad Hit";
6262  return std::to_string(fHits[iht].WireID().Plane) + ":" +
6263  std::to_string(fHits[iht].WireID().Wire) + ":" +
6264  std::to_string((int)fHits[iht].PeakTime());
6265 
6266  } // 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 3257 of file ClusterCrawlerAlg.cxx.

References art::right().

3258  {
3259 
3260  mf::LogVerbatim myprt("CC");
3261 
3262  if (vtx3.size() > 0) {
3263  // print out 3D vertices
3264  myprt
3265  << "****** 3D vertices ******************************************__2DVtx_Indx__*******\n";
3266  myprt
3267  << "Vtx Cstat TPC Proc X Y Z XEr YEr ZEr pln0 pln1 pln2 Wire\n";
3268  for (unsigned short iv = 0; iv < vtx3.size(); ++iv) {
3269  myprt << std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3270  myprt << std::right << std::setw(7) << vtx3[iv].CStat;
3271  myprt << std::right << std::setw(5) << vtx3[iv].TPC;
3272  myprt << std::right << std::setw(5) << vtx3[iv].ProcCode;
3273  myprt << std::right << std::setw(8) << vtx3[iv].X;
3274  myprt << std::right << std::setw(8) << vtx3[iv].Y;
3275  myprt << std::right << std::setw(8) << vtx3[iv].Z;
3276  myprt << std::right << std::setw(5) << vtx3[iv].XErr;
3277  myprt << std::right << std::setw(5) << vtx3[iv].YErr;
3278  myprt << std::right << std::setw(5) << vtx3[iv].ZErr;
3279  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[0];
3280  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[1];
3281  myprt << std::right << std::setw(5) << vtx3[iv].Ptr2D[2];
3282  myprt << std::right << std::setw(5) << vtx3[iv].Wire;
3283  if (vtx3[iv].Wire < 0) { myprt << " Matched in all planes"; }
3284  else {
3285  myprt << " Incomplete";
3286  }
3287  myprt << "\n";
3288  }
3289  } // vtx3.size
3290 
3291  if (vtx.size() > 0) {
3292  // print out 2D vertices
3293  myprt << "************ 2D vertices ************\n";
3294  myprt << "Vtx CTP wire error tick error ChiDOF NCl topo cluster IDs\n";
3295  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
3296  if (fDebugPlane < 3 && fDebugPlane != (int)vtx[iv].CTP) continue;
3297  myprt << std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3298  myprt << std::right << std::setw(6) << vtx[iv].CTP;
3299  myprt << std::right << std::setw(8) << vtx[iv].Wire << " +/- ";
3300  myprt << std::right << std::setw(4) << vtx[iv].WireErr;
3301  myprt << std::right << std::setw(8) << vtx[iv].Time << " +/- ";
3302  myprt << std::right << std::setw(4) << vtx[iv].TimeErr;
3303  myprt << std::right << std::setw(8) << vtx[iv].ChiDOF;
3304  myprt << std::right << std::setw(5) << vtx[iv].NClusters;
3305  myprt << std::right << std::setw(6) << vtx[iv].Topo;
3306  myprt << " ";
3307  // display the cluster IDs
3308  for (unsigned short ii = 0; ii < tcl.size(); ++ii) {
3309  if (fDebugPlane < 3 && fDebugPlane != (int)tcl[ii].CTP) continue;
3310  if (tcl[ii].ID < 0) continue;
3311  if (tcl[ii].BeginVtx == (short)iv) myprt << std::right << std::setw(4) << tcl[ii].ID;
3312  if (tcl[ii].EndVtx == (short)iv) myprt << std::right << std::setw(4) << tcl[ii].ID;
3313  }
3314  myprt << "\n";
3315  } // iv
3316  } // vtx.size
3317 
3318  } // 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 1259 of file ClusterCrawlerAlg.cxx.

References util::abs().

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

References hits().

937  {
938 
939  unsigned int destHit = 0;
940 
941  if (fHits.size() != inClus.size()) {
942  mf::LogError("CC") << "RemoveObsoleteHits size mis-match " << fHits.size() << " "
943  << inClus.size();
944  return;
945  }
946 
947  unsigned short icl;
948  for (unsigned int srcHit = 0; srcHit < fHits.size(); ++srcHit) {
949  if (inClus[srcHit] < 0) continue;
950  if (srcHit != destHit) {
951  fHits[destHit] = std::move(fHits[srcHit]);
952  inClus[destHit] = inClus[srcHit];
953  if (inClus[destHit] > 0) {
954  // hit is in a cluster. Find it and change the index
955  icl = inClus[destHit] - 1;
956  auto& hits = tcl[icl].tclhits;
957  auto iHitIndex = std::find(hits.begin(), hits.end(), srcHit);
958  if (iHitIndex == hits.end()) {
959  mf::LogError("CC") << "RemoveObsoleteHits: Hit #" << srcHit
960  << " not found in cluster ID " << inClus[destHit];
961  }
962  else {
963  *iHitIndex = destHit; // update the index
964  }
965  } // inClus[destHit] > 0
966  }
967  ++destHit;
968  } // srcHit
969 
970  fHits.resize(destHit);
971  inClus.resize(destHit);
972 
973  } // 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 844 of file ClusterCrawlerAlg.cxx.

845  {
846  short& ID = tcl[icl].ID;
847  if (ID > 0) {
848  mf::LogError("CC") << "Trying to restore non-obsolete cluster ID = " << ID;
849  return;
850  }
851  ID = -ID;
852 
853  for (unsigned short iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
854  inClus[tcl[icl].tclhits[iht]] = ID;
855 
856  } // 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 201 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().

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

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

134  {
135  // compare the wire IDs first:
136  int cmp_res = a.WireID().cmp(b.WireID());
137  if (cmp_res != 0) return cmp_res < 0; // order is decided, unless equal
138  // decide by start time
139  if (a.StartTick() != b.StartTick()) return a.StartTick() < b.StartTick();
140  // if still undecided, resolve by local index
141  return a.LocalIndex() < b.LocalIndex(); // if still unresolved, it's a bug!
142  } // ClusterCrawlerAlg::SortByMultiplet()
bool cluster::ClusterCrawlerAlg::SplitCluster ( unsigned short  icl,
unsigned short  pos,
unsigned short  ivx 
)
private

Definition at line 2672 of file ClusterCrawlerAlg.cxx.

2673  {
2674  // split cluster icl into two clusters
2675 
2676  if (tcl[icl].ID < 0) return false;
2677 
2678  // declare icl obsolete
2679  MakeClusterObsolete(icl);
2680 
2681  unsigned short ii, iclnew;
2682  unsigned int iht;
2683 
2684  if (pos > 2) {
2685  // Have enough hits to make a cluster at the Begin end
2686  // Create the first cluster (DS) using the Begin info
2687  clBeginSlp = tcl[icl].BeginSlp;
2688  clBeginSlpErr = tcl[icl].BeginSlpErr;
2689  clBeginAng = tcl[icl].BeginAng;
2690  clBeginWir = tcl[icl].BeginWir;
2691  clBeginTim = tcl[icl].BeginTim;
2692  clBeginChg = tcl[icl].BeginChg;
2693  clStopCode = 5;
2694  clProcCode = tcl[icl].ProcCode;
2695  fcl2hits.clear();
2696  chifits.clear();
2697  hitNear.clear();
2698  chgNear.clear();
2699  for (ii = 0; ii < pos; ++ii) {
2700  iht = tcl[icl].tclhits[ii];
2701  fcl2hits.push_back(iht);
2702  }
2703  // determine the pass in which this cluster was created
2704  pass = tcl[icl].ProcCode - 10 * (tcl[icl].ProcCode / 10);
2705  if (pass > fNumPass - 1) pass = fNumPass - 1;
2706  // fit the end hits
2707  FitCluster();
2708  clEndSlp = clpar[1];
2709  clEndSlpErr = clparerr[1];
2710  clEndAng = std::atan(fScaleF * clEndSlp);
2711  // find the charge at the end
2712  FitClusterChg();
2713  clEndChg = fAveChg;
2714  if (!TmpStore()) {
2716  return false;
2717  }
2718  // associate the End with the supplied vertex
2719  iclnew = tcl.size() - 1;
2720  tcl[iclnew].EndVtx = ivx;
2721  tcl[iclnew].BeginVtx = tcl[icl].BeginVtx;
2722  if (vtxprt)
2723  mf::LogVerbatim("CC") << "SplitCluster made cluster " << iclnew << " attached to Begin vtx "
2724  << ivx;
2725  } // pos > 2
2726 
2727  if (pos < tcl[icl].tclhits.size() - 3) {
2728  // have enough hits to make a cluster at the End
2729  // now create the second cluster (US)
2730  clEndSlp = tcl[icl].EndSlp;
2731  clEndSlpErr = tcl[icl].EndSlpErr;
2732  clEndAng = std::atan(fScaleF * clEndSlp);
2733  clEndWir = tcl[icl].EndWir;
2734  clEndTim = tcl[icl].EndTim;
2735  clEndChg = tcl[icl].EndChg;
2736  clStopCode = 5;
2737  clProcCode = tcl[icl].ProcCode;
2738  fcl2hits.clear();
2739  chifits.clear();
2740  hitNear.clear();
2741  chgNear.clear();
2742  bool didFit = false;
2743  for (ii = pos; ii < tcl[icl].tclhits.size(); ++ii) {
2744  iht = tcl[icl].tclhits[ii];
2745  if (inClus[iht] != 0) {
2747  return false;
2748  }
2749  fcl2hits.push_back(iht);
2750  // define the Begin parameters
2751  if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
2752  FitCluster();
2753  clBeginSlp = clpar[1];
2754  clBeginAng = std::atan(fScaleF * clBeginSlp);
2755  clBeginSlpErr = clparerr[1];
2756  didFit = true;
2757  }
2758  if ((unsigned short)fcl2hits.size() == fNHitsAve[pass] + 1) {
2759  FitClusterChg();
2760  clBeginChg = fAveChg;
2761  didFit = true;
2762  }
2763  } // ii
2764  // do a fit using all hits if one wasn't done
2765  if (!didFit) {
2766  FitCluster();
2767  FitClusterChg();
2768  clBeginChg = fAveChg;
2769  }
2770  if (!TmpStore()) {
2771  // clobber the previously stored cluster
2772  MakeClusterObsolete(tcl.size() - 1);
2774  return false;
2775  }
2776  // associate the End with the supplied vertex
2777  iclnew = tcl.size() - 1;
2778  tcl[iclnew].BeginVtx = ivx;
2779  tcl[iclnew].EndVtx = tcl[icl].EndVtx;
2780  if (vtxprt)
2781  mf::LogVerbatim("CC") << "SplitCluster made cluster " << iclnew << " attached to End vtx "
2782  << ivx;
2783  }
2784 
2785  return true;
2786  } // 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 3422 of file ClusterCrawlerAlg.cxx.

3423  {
3424  // copies temp cluster it1 into the fcl2hits vector, etc. This is
3425  // effectively the inverse of cl2TmpStore
3426 
3427  if (it1 > tcl.size()) return;
3428 
3429  clBeginSlp = tcl[it1].BeginSlp;
3430  clBeginSlpErr = tcl[it1].BeginSlpErr;
3431  clBeginAng = tcl[it1].BeginAng;
3432  clBeginWir = tcl[it1].BeginWir;
3433  clBeginTim = tcl[it1].BeginTim;
3434  clBeginChg = tcl[it1].BeginChg;
3435  clBeginChgNear = tcl[it1].BeginChgNear;
3436  clEndSlp = tcl[it1].EndSlp;
3437  clEndSlpErr = tcl[it1].EndSlpErr;
3438  clEndAng = tcl[it1].EndAng;
3439  clEndWir = tcl[it1].EndWir;
3440  clEndTim = tcl[it1].EndTim;
3441  clEndChg = tcl[it1].EndChg;
3442  clEndChgNear = tcl[it1].EndChgNear;
3443  clStopCode = tcl[it1].StopCode;
3444  clProcCode = tcl[it1].ProcCode;
3445  clCTP = tcl[it1].CTP;
3446  fcl2hits = tcl[it1].tclhits;
3447  }
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 3450 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.

3451  {
3452 
3453  if (fcl2hits.size() < 2) return false;
3454  if (fcl2hits.size() > fHits.size()) return false;
3455 
3456  if (NClusters == SHRT_MAX) return false;
3457 
3458  ++NClusters;
3459 
3460  unsigned int hit0 = fcl2hits[0];
3461  unsigned int hit;
3462  unsigned int tCST = fHits[hit0].WireID().Cryostat;
3463  unsigned int tTPC = fHits[hit0].WireID().TPC;
3464  unsigned int tPlane = fHits[hit0].WireID().Plane;
3465  unsigned int lastWire = 0;
3466 
3467  for (unsigned short it = 0; it < fcl2hits.size(); ++it) {
3468  hit = fcl2hits[it];
3469  if (inClus[hit] != 0) {
3470  --NClusters;
3471  return false;
3472  }
3473  // check for WireID() consistency
3474  if (fHits[hit].WireID().Cryostat != tCST || fHits[hit].WireID().TPC != tTPC ||
3475  fHits[hit].WireID().Plane != tPlane) {
3476  --NClusters;
3477  return false;
3478  }
3479  // check for decreasing wire number
3480  if (clProcCode < 900 && it > 0 && fHits[hit].WireID().Wire >= lastWire) {
3481  --NClusters;
3482  return false;
3483  }
3484  lastWire = fHits[hit].WireID().Wire;
3485  inClus[hit] = NClusters;
3486  }
3487 
3488  // ensure that the cluster begin/end info is correct
3489 
3490  // define the begin/end charge if it wasn't done already
3491  if (clEndChg <= 0) {
3492  // use the next to the last two hits. The End hit may have low charge
3493  unsigned int ih0 = fcl2hits.size() - 2;
3494  hit = fcl2hits[ih0];
3495  clEndChg = fHits[hit].Integral();
3496  hit = fcl2hits[ih0 - 1];
3497  clEndChg += fHits[hit].Integral();
3498  clEndChg = clEndChg / 2.;
3499  }
3500  if (clBeginChg <= 0) {
3501  // use the 2nd and third hit. The Begin hit may have low charge
3502  hit = fcl2hits[1];
3503  clBeginChg = fHits[hit].Integral();
3504  hit = fcl2hits[2];
3505  clBeginChg += fHits[hit].Integral();
3506  clBeginChg = clBeginChg / 2.;
3507  }
3508 
3509  hit0 = fcl2hits[0];
3510  hit = fcl2hits[fcl2hits.size() - 1];
3511 
3512  // store the cluster in the temporary ClusterStore struct
3513  ClusterStore clstr;
3514 
3515  clstr.ID = NClusters;
3516  clstr.BeginSlp = clBeginSlp;
3517  clstr.BeginSlpErr = clBeginSlpErr;
3518  clstr.BeginAng = std::atan(fScaleF * clBeginSlp);
3519  clstr.BeginWir = fHits[hit0].WireID().Wire;
3520  clstr.BeginTim = fHits[hit0].PeakTime();
3521  clstr.BeginChg = clBeginChg;
3522  clstr.BeginChgNear = clBeginChgNear;
3523  clstr.EndSlp = clEndSlp;
3524  clstr.EndSlpErr = clEndSlpErr;
3525  clstr.EndAng = std::atan(fScaleF * clEndSlp);
3526  clstr.EndWir = fHits[hit].WireID().Wire;
3527  clstr.EndTim = fHits[hit].PeakTime();
3528  clstr.EndChg = clEndChg;
3529  clstr.EndChgNear = clEndChgNear;
3530  clstr.StopCode = clStopCode;
3531  clstr.ProcCode = clProcCode;
3532  clstr.BeginVtx = -99;
3533  clstr.EndVtx = -99;
3534  clstr.CTP = EncodeCTP(tCST, tTPC, tPlane);
3535  clstr.tclhits = fcl2hits;
3536  tcl.push_back(clstr);
3537 
3538  return true;
3539  } // 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 1940 of file ClusterCrawlerAlg.cxx.

1941  {
1942  // try to attach clusters to the specified vertex
1943  if (vtx[iv].NClusters == 0) return;
1944 
1945  short dwb, dwe, dtb, dte;
1946  bool sigOK;
1947 
1948  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
1949  if (tcl[icl].ID < 0) continue;
1950  if (tcl[icl].CTP != vtx[iv].CTP) continue;
1951 
1952  dwb = vtx[iv].Wire - tcl[icl].BeginWir;
1953  dtb = vtx[iv].Time - tcl[icl].BeginTim;
1954  dwe = vtx[iv].Wire - tcl[icl].EndWir;
1955  dte = vtx[iv].Time - tcl[icl].EndTim;
1956 
1957  float drb = dwb * dwb + dtb * dtb;
1958  float dre = dwe * dwe + dte * dte;
1959 
1960  bool bCloser = (drb < dre);
1961 
1962  // ignore clusters in showers
1963  if (bCloser) {
1964  if (tcl[icl].BeginChgNear > fChgNearCut) continue;
1965  }
1966  else {
1967  if (tcl[icl].EndChgNear > fChgNearCut) continue;
1968  }
1969 
1970  if (vtxprt)
1971  mf::LogVerbatim("CC") << "VertexCluster: Try icl ID " << tcl[icl].ID << " w vtx " << iv
1972  << " dwb " << dwb << " dwe " << dwe << " drb " << drb << " dre "
1973  << dre << " Begin closer? " << bCloser;
1974 
1975  if (tcl[icl].BeginVtx < 0 && bCloser && dwb > -3 && dwb < 3 && tcl[icl].EndVtx != iv) {
1976  sigOK = ChkSignal(tcl[icl].BeginWir, tcl[icl].BeginTim, vtx[iv].Wire, vtx[iv].Time);
1977  if (vtxprt)
1978  mf::LogVerbatim("CC") << " Attach cluster Begin to vtx? " << iv << " sigOK " << sigOK;
1979  if (sigOK) {
1980  if (vtxprt)
1981  mf::LogVerbatim("CC") << " check ClusterVertexChi " << ClusterVertexChi(icl, 0, iv);
1982  if (ClusterVertexChi(icl, 0, iv) < fVertex2DCut) {
1983  // do a fit and check the vertex error
1984  tcl[icl].BeginVtx = iv;
1985  FitVtx(iv);
1986  if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
1987  tcl[icl].BeginVtx = -99;
1988  FitVtx(iv);
1989  }
1990  } // good DoCA
1991  } // sigOK
1992  } // check BEGIN
1993 
1994  if (tcl[icl].EndVtx < 0 && !bCloser && dwe > -3 && dwe < 3 && tcl[icl].BeginVtx != iv) {
1995  sigOK = ChkSignal(tcl[icl].EndWir, tcl[icl].EndTim, vtx[iv].Wire, vtx[iv].Time);
1996  if (vtxprt)
1997  mf::LogVerbatim("CC") << " Attach cluster End to vtx? " << iv << " sigOK " << sigOK;
1998  if (sigOK) {
1999  if (vtxprt)
2000  mf::LogVerbatim("CC") << " check ClusterVertexChi " << ClusterVertexChi(icl, 1, iv);
2001  if (ClusterVertexChi(icl, 1, iv) < 3) {
2002  // do a fit and check the vertex error
2003  tcl[icl].EndVtx = iv;
2004  FitVtx(iv);
2005  if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2006  tcl[icl].EndVtx = -99;
2007  FitVtx(iv);
2008  }
2009  } // good DoCA
2010  } // sigOK
2011  } // check END
2012  } // icl
2013  } // 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 5184 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.

5186  {
5187  // Look for clusters that end/begin near the expected wire/time
5188  // for incomplete 3D vertices
5189  if (empty(vtx3)) return;
5190 
5191  const unsigned int cstat = tpcid.Cryostat;
5192  const unsigned int tpc = tpcid.TPC;
5193 
5194  unsigned int thePlane, theWire;
5195  float theTime;
5196  int dwb, dwe;
5197 
5198  for (unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5199  // A complete 3D vertex with matching 2D vertices in all planes?
5200  if (vtx3[ivx].Wire < 0) continue;
5201  if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc) continue;
5202  // Find the plane that is missing a 2D vertex
5203  thePlane = 3;
5204  theWire = vtx3[ivx].Wire;
5205  for (plane = 0; plane < 3; ++plane) {
5206  if (vtx3[ivx].Ptr2D[plane] >= 0) continue;
5207  thePlane = plane;
5208  break;
5209  } // plane
5210  if (thePlane > 2) continue;
5211  theTime = det_prop.ConvertXToTicks(vtx3[ivx].X, thePlane, tpc, cstat);
5212  clCTP = EncodeCTP(cstat, tpc, thePlane);
5213  // Create a new 2D vertex and see how many clusters we can attach to it
5214  VtxStore vnew;
5215  vnew.Wire = theWire;
5216  vnew.Time = theTime;
5217  vnew.CTP = clCTP;
5218  vnew.Topo = 7;
5219  vnew.Fixed = false;
5220  vtx.push_back(vnew);
5221  unsigned short ivnew = vtx.size() - 1;
5222  std::vector<short> vclIndex;
5223  for (unsigned short icl = 0; icl < tcl.size(); ++icl) {
5224  if (tcl[icl].ID < 0) continue;
5225  if (tcl[icl].CTP != clCTP) continue;
5226  dwb = lar::util::absDiff(theWire, tcl[icl].BeginWir);
5227  dwe = lar::util::absDiff(theWire, tcl[icl].EndWir);
5228  // rough cut to start
5229  if (dwb > 10 && dwe > 10) continue;
5230  if (dwb < dwe && dwb < 10 && tcl[icl].BeginVtx < 0) {
5231  // cluster begin is closer
5232  if (theWire < tcl[icl].BeginWir + 5) continue;
5233  if (ClusterVertexChi(icl, 0, ivnew) > fVertex3DCut) continue;
5234  tcl[icl].BeginVtx = ivnew;
5235  vclIndex.push_back(icl);
5236  }
5237  else if (dwe < 10 && tcl[icl].EndVtx < 0) {
5238  // cluster end is closer
5239  if (theWire > tcl[icl].EndWir - 5) continue;
5240  if (ClusterVertexChi(icl, 1, ivnew) > fVertex3DCut) continue;
5241  tcl[icl].EndVtx = ivnew;
5242  vclIndex.push_back(icl);
5243  } // dwb/dwe check
5244  } // icl
5245  bool goodVtx = false;
5246  if (vclIndex.size() > 0) {
5247  FitVtx(ivnew);
5248  goodVtx = (vtx[ivnew].ChiDOF < fVertex3DCut);
5249  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5250  }
5251  if (goodVtx) {
5252  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5253  vtx3[ivx].Wire = -1;
5254  }
5255  else {
5256  // clobber the vertex
5257  vtx.pop_back();
5258  for (unsigned short ii = 0; ii < vclIndex.size(); ++ii) {
5259  unsigned short icl = vclIndex[ii];
5260  if (tcl[icl].BeginVtx == ivnew) tcl[icl].BeginVtx = -99;
5261  if (tcl[icl].EndVtx == ivnew) tcl[icl].EndVtx = -99;
5262  } // ii
5263  }
5264  } // ivx
5265  } // 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
Float_t X
Definition: plot.C:37
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 5268 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.

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

Definition at line 1412 of file ClusterCrawlerAlg.cxx.

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

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

1215  {
1216  // checks hits on wire jwire to see if one is on a line between a US vertex
1217  // and the hit ihit on wire iwire. If one is found, doConstrain is set true
1218  // and the hit index is returned.
1219  doConstrain = false;
1220  if (vtx.size() == 0) return;
1221  // no vertices made yet on the first pass
1222  if (pass == 0) return;
1223  // skip if vertices were not requested to be made on the previous pass
1224  if (!fFindVertices[pass - 1]) return;
1225 
1226  if (jwire > WireHitRange.size() - 1) {
1227  mf::LogError("CC") << "VtxConstraint fed bad jwire " << jwire << " WireHitRange size "
1228  << WireHitRange.size();
1229  return;
1230  }
1231 
1232  unsigned int jfirsthit = WireHitRange[jwire].first;
1233  unsigned int jlasthit = WireHitRange[jwire].second;
1234  for (unsigned short iv = 0; iv < vtx.size(); ++iv) {
1235  if (vtx[iv].CTP != clCTP) continue;
1236  // vertex must be US of the cluster
1237  if (vtx[iv].Wire > jwire) continue;
1238  // but not too far US
1239  if (vtx[iv].Wire < jwire - 10) continue;
1240  recob::Hit const& hit = fHits[ihit];
1241  clpar[0] = hit.PeakTime();
1242  clpar[1] = (vtx[iv].Time - hit.PeakTime()) / (vtx[iv].Wire - iwire);
1243  clpar[2] = hit.WireID().Wire;
1244  float prtime = clpar[0] + clpar[1] * (jwire - iwire);
1245  for (unsigned int jhit = jfirsthit; jhit < jlasthit; ++jhit) {
1246  if (inClus[jhit] != 0) continue;
1247  const float tdiff = std::abs(fHits[jhit].TimeDistanceAsRMS(prtime));
1248  if (tdiff < 2.5) {
1249  useHit = jhit;
1250  doConstrain = true;
1251  return;
1252  }
1253  } // jhit
1254  } // iv
1255  } // 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:563
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 5681 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::TPCGeo::Nplanes(), 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.

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

Returns (and loses) the collection of reconstructed hits.

Definition at line 123 of file ClusterCrawlerAlg.h.

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

123 { 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 208 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 205 of file ClusterCrawlerAlg.h.

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

cluster parameter errors

Definition at line 207 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 40 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fAllowNoHitWire
private

Definition at line 192 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveChg
private

average charge at leading edge of cluster

Definition at line 209 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveHitWidth
private

average width (EndTick - StartTick) of hits

Definition at line 212 of file ClusterCrawlerAlg.h.

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

charge difference cut for adding a hit to a cluster

Definition at line 158 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 211 of file ClusterCrawlerAlg.h.

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

stop adding hits to clusters if chisq too high

Definition at line 154 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fChkClusterDS
private

Definition at line 175 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 183 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugHit
private

out detailed information while crawling

Definition at line 199 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugPlane
private

Definition at line 197 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugWire
private

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

Definition at line 198 of file ClusterCrawlerAlg.h.

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

try to merge clusters?

Definition at line 163 of file ClusterCrawlerAlg.h.

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

Definition at line 202 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindHammerClusters
private

look for hammer type clusters

Definition at line 168 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindStarVertices
private

Definition at line 177 of file ClusterCrawlerAlg.h.

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

run vertexing code after clustering?

Definition at line 166 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 181 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 189 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitMinAmp
private

< ignore hits with Amp < this value

Definition at line 182 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 174 of file ClusterCrawlerAlg.h.

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

kink angle cut made after fKinkChiRat

Definition at line 157 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 155 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusAngleCut
private

call Large Angle Clustering code if > 0

Definition at line 185 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fLAClusMaxHitsFit
private

max hits fitted on a Large Angle cluster

Definition at line 186 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusSlopeCut
private

Definition at line 187 of file ClusterCrawlerAlg.h.

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

Crawl Large Angle clusters on pass?

Definition at line 167 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 150 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 160 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fMergeAllHits
private

Definition at line 188 of file ClusterCrawlerAlg.h.

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

max charge ratio for matching

Definition at line 165 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMergeOverlapAngCut
private

angle cut for merging overlapping clusters

Definition at line 191 of file ClusterCrawlerAlg.h.

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

expected minimum signal in each wire plane

Definition at line 172 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMinHitFrac
private

Definition at line 184 of file ClusterCrawlerAlg.h.

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

Min number of hits to make a cluster.

Definition at line 151 of file ClusterCrawlerAlg.h.

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

minimum number of hits on consecutive wires after skipping

Definition at line 161 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 152 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fNumPass
private

number of passes over the hit collection

Definition at line 149 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 170 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 164 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DCut
private

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

Definition at line 193 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DWireErrCut
private

Definition at line 194 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex3DCut
private

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

Definition at line 195 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fVtxClusterSplit
private

Definition at line 176 of file ClusterCrawlerAlg.h.

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

Definition at line 218 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 216 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 214 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 215 of file ClusterCrawlerAlg.h.

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

Definition at line 283 of file ClusterCrawlerAlg.h.


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