LArSoft  v09_90_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 4726 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().

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

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

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

References util::abs().

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

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

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

Definition at line 4347 of file ClusterCrawlerAlg.cxx.

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

References tca::DeadWireCount().

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

References hits().

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

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

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

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

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

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

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

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

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

References util::abs(), and bin.

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

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

References lar::util::absDiff().

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

References util::abs().

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

References E.

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

References util::abs().

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

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

References tmp.

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

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

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

References util::abs().

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

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

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

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

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

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

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

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

Definition at line 4235 of file ClusterCrawlerAlg.cxx.

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

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

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

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

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

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

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

1711  {
1712  //
1713  // Resets multiplicity and local index of the hits in the range.
1714  // All hits are assumed to be in the same multiplet.
1715  // All hits that are not obsolete are given a multiplicity equal to the
1716  // number of non-obsolete hits in the multiplet, and the local index is
1717  // assigned as an increasing number starting from 0 with the first
1718  // non-obsolete hit on.
1719  //
1720 
1721  // first pass: determine the actual number of hits in the multiplet
1722  if (multiplicity < 0) {
1723  multiplicity = 0;
1724  for (size_t iHit = begin; iHit < end; ++iHit) {
1725  if (inClus[iHit] < 0) continue;
1726  ++multiplicity;
1727  } // for
1728  } // if no valid multiplicity is given
1729 
1730  // second pass: assign the correct multiplicity
1731  short int local_index = 0;
1732  for (size_t iHit = begin; iHit < end; ++iHit) {
1733  if (inClus[iHit] < 0) continue;
1734 
1735  // copy everything but overwrite the local index and multiplicity
1736  // TODO use a write wrapper!
1737  recob::Hit const& hit = fHits[iHit];
1738  fHits[iHit] = recob::Hit(hit.Channel(),
1739  hit.StartTick(),
1740  hit.EndTick(),
1741  hit.PeakTime(),
1742  hit.SigmaPeakTime(),
1743  hit.RMS(),
1744  hit.PeakAmplitude(),
1745  hit.SigmaPeakAmplitude(),
1746  hit.SummedADC(),
1747  hit.Integral(),
1748  hit.SigmaIntegral(),
1749  multiplicity, // multiplicity
1750  local_index, // local index
1751  hit.GoodnessOfFit(),
1752  hit.DegreesOfFreedom(),
1753  hit.View(),
1754  hit.SignalType(),
1755  hit.WireID());
1756 
1757  ++local_index;
1758  } // for
1759 
1760  } // FixMultipletLocalIndices()
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:272
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:228
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:236
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:248
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:264
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:244
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:276
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:280
float GoodnessOfFit() const
Degrees of freedom in the determination of the hit signal shape (-1 by default)
Definition: Hit.h:260
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:232
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:212
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:216
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:220
float SummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:240
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:224
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:268
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 5937 of file ClusterCrawlerAlg.cxx.

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

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

References util::abs().

3541  {
3542  // Crawl a large angle cluster upstream. Similar to CrawlUS but require
3543  // that a hit be added on each wire
3544 
3545  unsigned int dhit = fcl2hits[0];
3546  short dwir = fHits[dhit].WireID().Wire;
3547  clLA = true;
3548  prt = false;
3549  if (fDebugPlane == (short)plane && dwir == fDebugWire && fDebugHit > 0)
3550  prt = std::abs(fHits[dhit].PeakTime() - fDebugHit) < 40;
3551 
3552  if (prt) {
3553  mf::LogVerbatim myprt("CC");
3554  myprt << "******************* LACrawlUS PASS " << pass << " Hits ";
3555  for (unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3556  unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3557  myprt << fHits[iht].WireID().Wire << ":" << (int)fHits[iht].PeakTime() << " ";
3558  }
3559  }
3560 
3561  bool SigOK = true;
3562  bool HitOK = true;
3563  short nmissed = 0;
3564  // count the number of kinks encountered. Hits US of the kink are removed
3565  // and crawling continues unless another kink is encountered
3566  unsigned short kinkOnWire = 0;
3567  unsigned int it = fcl2hits.size() - 1;
3568  unsigned int lasthit = fcl2hits[it];
3569  unsigned int lastwire = fHits[lasthit].WireID().Wire;
3570  unsigned int prevHit, prevWire;
3571  bool ChkCharge = false;
3572  for (unsigned int nextwire = lastwire - 1; nextwire >= fFirstWire; --nextwire) {
3573  if (prt)
3574  mf::LogVerbatim("CC") << "LACrawlUS: next wire " << nextwire << " HitRange "
3575  << WireHitRange[nextwire].first;
3576  // stop crawling if there is a nearby vertex
3577  if (CrawlVtxChk(nextwire)) {
3578  if (prt) mf::LogVerbatim("CC") << "LACrawlUS: stop at vertex";
3579  clStopCode = 6;
3580  break;
3581  }
3582  // AddLAHit will merge the hit on nextwire if necessary
3583  AddLAHit(nextwire, ChkCharge, HitOK, SigOK);
3584  if (prt)
3585  mf::LogVerbatim("CC") << "LACrawlUS: HitOK " << HitOK << " SigOK " << SigOK
3586  << " nmissed SigOK " << nmissed << " cut " << fAllowNoHitWire;
3587  if (SigOK) nmissed = 0;
3588  if (!SigOK) {
3589  ++nmissed;
3590  if (nmissed > fAllowNoHitWire) {
3591  clStopCode = 1;
3592  break;
3593  }
3594  continue;
3595  }
3596  // If a hit was added after a gap, check to see if there is indeed
3597  // a wire signal in the gap
3598  if (HitOK) {
3599  prevHit = fcl2hits[fcl2hits.size() - 2];
3600  prevWire = fHits[prevHit].WireID().Wire;
3601  if (prevWire > nextwire + 2) {
3602  if (!ChkSignal(fcl2hits[fcl2hits.size() - 1], fcl2hits[fcl2hits.size() - 2])) {
3603  // no hit so trim the last hit and quit
3604  FclTrimUS(1);
3605  break;
3606  } // no signal
3607  } // prevWire > nextwire + 2
3608  } // HitOK
3609  // Merge all of the hit multiplets in the fcl2hits array into single
3610  // hits when enough hits have been found to call this a credible large
3611  // angle cluster. The last hit was already merged in AddHit
3612  if (fcl2hits.size() == 4) {
3613  bool didMerge;
3614  for (unsigned short kk = 0; kk < fcl2hits.size() - 1; ++kk) {
3615  unsigned int hit = fcl2hits[kk];
3616  if (mergeAvailable[hit]) MergeHits(hit, didMerge);
3617  }
3618  // update the fit
3619  FitCluster();
3620  clBeginSlp = clpar[1];
3621  // start checking the charge ratio when adding new hits
3622  ChkCharge = true;
3623  continue;
3624  } // fcl2hits.size() == 4
3625  unsigned short chsiz = chifits.size() - 1;
3626  // chsiz is fcl2hits.size() - 1...
3627  if (chsiz < 6) continue;
3628  if (fKinkChiRat[pass] <= 0) continue;
3629  if (chifits.size() != fcl2hits.size()) {
3630  mf::LogError("CC") << "LACrawlUS: chifits size error " << chifits.size() << " "
3631  << fcl2hits.size();
3632  return;
3633  }
3634  if (prt)
3635  mf::LogVerbatim("CC") << "Kink chk " << chifits[chsiz] << " " << chifits[chsiz - 1] << " "
3636  << chifits[chsiz - 2] << " " << chifits[chsiz - 3];
3637  if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3638  chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3639  // find the kink angle (crudely) from the 0th and 2nd hit
3640  unsigned int ih0 = fcl2hits.size() - 1;
3641  unsigned int hit0 = fcl2hits[ih0];
3642  unsigned int ih2 = ih0 - 2;
3643  unsigned int hit2 = fcl2hits[ih2];
3644  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3645  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3646  float th02 = std::atan(fScaleF * dt02 / dw02);
3647  // and the 3rd and 5th hit
3648  unsigned int ih3 = ih2 - 1;
3649  unsigned int hit3 = fcl2hits[ih3];
3650  unsigned int ih5 = ih3 - 2;
3651  unsigned int hit5 = fcl2hits[ih5];
3652  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
3653  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
3654  float th35 = std::atan(fScaleF * dt35 / dw35);
3655  float dth = std::abs(th02 - th35);
3656  if (prt)
3657  mf::LogVerbatim("CC") << " Kink angle " << std::setprecision(3) << dth << " cut "
3658  << fKinkAngCut[pass];
3659  if (dth > fKinkAngCut[pass]) {
3660  // hit a kink. Lop of the first 3 hits, refit and keep crawling?
3661  FclTrimUS(3);
3662  FitCluster();
3663  // See if this is a second kink and it is close to the first
3664  // kink (which had hits removed).
3665  if (kinkOnWire > 0) {
3666  if (kinkOnWire - nextwire < 4) {
3667  if (prt)
3668  mf::LogVerbatim("CC")
3669  << "Hit a second kink. kinkOnWire = " << kinkOnWire << " Stopping";
3670  // set the kink stop code
3671  clStopCode = 3;
3672  break;
3673  }
3674  }
3675  kinkOnWire = nextwire;
3676  if (prt) mf::LogVerbatim("CC") << "Removed kink hits";
3677  } // kinkang check
3678  } // chifits test
3679  } // nextwire
3680 
3682 
3683  clProcCode += 300;
3684  if (prt) mf::LogVerbatim("CC") << "LACrawlUS done. Nhits = " << fcl2hits.size();
3685  prt = false;
3686  } // 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::Integral(), recob::Hit::Multiplicity(), recob::Hit::PeakAmplitude(), recob::Hit::PeakTime(), recob::Hit::PeakTimeMinusRMS(), recob::Hit::PeakTimePlusRMS(), geo::PlaneID::Plane, recob::Hit::RMS(), recob::Hit::SigmaIntegral(), recob::Hit::SigmaPeakAmplitude(), recob::Hit::SigmaPeakTime(), recob::Hit::SignalType(), recob::Hit::StartTick(), recob::Hit::SummedADC(), 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.SummedADC(),
1693  chgsum, // hit_integral
1694  hit.SigmaIntegral(),
1695  NewMultiplicity, // multiplicity
1696  0, // local index
1697  6666, // GoodnessOfFit (flag for merged hit)
1698  hit.DegreesOfFreedom(),
1699  hit.View(),
1700  hit.SignalType(),
1701  hit.WireID());
1702  FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1703  didMerge = true;
1704 
1705  } // MergeHits()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:272
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:228
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:236
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:248
constexpr auto abs(T v)
Returns the absolute value of the argument.
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:264
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:244
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:276
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:280
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:252
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:232
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:212
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:290
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:216
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:220
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
float SummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:240
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:224
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:285
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:268
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 6238 of file ClusterCrawlerAlg.cxx.

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

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

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

References util::to_string().

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

References art::right().

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

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

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

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

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

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

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

Definition at line 5679 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorPropertiesData::ConvertTicksToX(), geo::CryostatID::Cryostat, cluster::ClusterCrawlerAlg::Vtx3Store::CStat, tca::DecodeCTP(), e, geo::TPCGeo::GetCenter(), geo::TPCGeo::HalfHeight(), evd::kWire, geo::kX, geo::TPCGeo::Length(), geo::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.

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