LArSoft  v07_13_02
Liquid Argon Software toolkit - http://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)
 
virtual void reconfigure (fhicl::ParameterSet const &pset)
 
void RunCrawler (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 (geo::TPCID const &tpcid)
 
void Vtx3ClusterMatch (geo::TPCID const &tpcid)
 
void Vtx3ClusterSplit (geo::TPCID const &tpcid)
 
void FindHammerClusters ()
 
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
 set to > 2 to do a charge fit using fNHitsAve hits More...
 
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
 after skipping More...
 
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
 is < cut. Set < 0 for no merging More...
 
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::Geometrygeom
 
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
 8 = SPECIAL CODE FOR STEP CRAWLING More...
 
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
 to define a shower-like cluster More...
 
std::string fhitsModuleLabel
 

Detailed Description

Definition at line 36 of file ClusterCrawlerAlg.h.

Member Typedef Documentation

typedef unsigned int cluster::ClusterCrawlerAlg::CTP_t

Definition at line 40 of file ClusterCrawlerAlg.h.

Constructor & Destructor Documentation

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

Definition at line 45 of file ClusterCrawlerAlg.cxx.

46  {
47  reconfigure(pset);
48  }
virtual void reconfigure(fhicl::ParameterSet const &pset)

Member Function Documentation

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

Definition at line 4907 of file ClusterCrawlerAlg.cxx.

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

4908  {
4909  // Add a hit to the cluster if it meets several criteria:
4910  // similar pulse height to the cluster (if fAveChg is defined)
4911  // closest hit to the project cluster position.
4912  // Return SigOK if there is a nearby hit that was missed due to the cuts
4913 
4914  SigOK = false;
4915  HitOK = false;
4916 
4917  // not in the range of wires with hits
4918  if(kwire < fFirstWire || kwire > fLastWire) return;
4919 
4920  unsigned int lastClHit = UINT_MAX;
4921  if(fcl2hits.size() > 0) lastClHit = fcl2hits[fcl2hits.size()-1];
4922 
4923  // the last hit added to the cluster
4924  unsigned int wire0 = clpar[2];
4925 
4926  // return if no signal and no hit
4927  if(fAllowNoHitWire == 0) {
4928  if(WireHitRange[kwire].first == -2) return;
4929  } else {
4930  // allow a number of wires with no hits
4931  if(WireHitRange[kwire].first == -2 &&
4932  (wire0 - kwire) > fAllowNoHitWire) {
4933  SigOK = true;
4934  return;
4935  }
4936  }
4937  // skip bad wire, but assume the track was there
4938  if(WireHitRange[kwire].first == -1) {
4939  SigOK = true;
4940  return;
4941  }
4942 
4943  unsigned int firsthit = WireHitRange[kwire].first;
4944  unsigned int lasthit = WireHitRange[kwire].second;
4945 
4946  // the projected time of the cluster on this wire
4947  float dw = (float)kwire - (float)wire0;
4948  float prtime = clpar[0] + dw * clpar[1];
4949  if(prtime < 0 || (unsigned int)prtime > fMaxTime) return;
4950  // Find the projected time error including the projection error and the
4951  // error from the last hit added
4952  float prtimerr2 = std::abs(dw)*clparerr[1]*clparerr[1];
4953 
4954  // apply an angle dependent scale factor to the hit error. Default is very large error
4955  float hiterr = 10;
4956  if(lastClHit != UINT_MAX) hiterr = 3 * fHitErrFac * fHits[lastClHit].RMS();
4957  float err = std::sqrt(prtimerr2 + hiterr * hiterr);
4958  // Time window for accepting a hit.
4959  float hitWin = fClProjErrFac * err;
4960 
4961  float prtimeLo = prtime - hitWin;
4962  float prtimeHi = prtime + hitWin;
4963  float chgWinLo = prtime - fChgNearWindow;
4964  float chgWinHi = prtime + fChgNearWindow;
4965  if(prt) {
4966  mf::LogVerbatim("CC")<<"AddHit: wire "<<kwire<<" prtime Lo "<<(int)prtimeLo<<" prtime "<<(int)prtime<<" Hi "<<(int)prtimeHi<<" prtimerr "<<sqrt(prtimerr2)<<" hiterr "<<hiterr<<" fAveChg "<<(int)fAveChg<<" fAveHitWidth "<<std::setprecision(3)<<fAveHitWidth;
4967  }
4968  // loop through the hits
4969  unsigned int imbest = INT_MAX;
4970  float best = 9999., dtime;
4971  float cnear = 0;
4972  float hitTime, hitChg, hitStartTick, hitEndTick;
4973  for(unsigned int khit = firsthit; khit < lasthit; ++khit) {
4974  // obsolete hit?
4975  if(inClus[khit] < 0) continue;
4976  hitTime = fHits[khit].PeakTime();
4977  dtime = std::abs(hitTime - prtime);
4978  if(dtime > 1000) continue;
4979  hitStartTick = fHits[khit].StartTick();
4980  hitEndTick = fHits[khit].EndTick();
4981  // weight by the charge difference
4982  if(fAveChg > 0) dtime *= std::abs(fHits[khit].Integral() - fAveChg) / fAveChg;
4983  if(prt && std::abs(dtime) < 100) {
4984  mf::LogVerbatim("CC")
4985  <<" Chk W:T "<<PrintHit(khit)
4986  <<" dT "<<std::fixed<<std::setprecision(1)<<(hitTime - prtime)
4987  <<" InClus "<<inClus[khit]
4988  <<" mult "<<fHits[khit].Multiplicity()
4989  <<" RMS "<<std::fixed<<std::setprecision(1)<<fHits[khit].RMS()
4990  <<" Chi2 "<<std::fixed<<std::setprecision(1)<<fHits[khit].GoodnessOfFit()
4991  <<" Charge "<<(int)fHits[khit].Integral()
4992  <<" Peak "<<std::fixed<<std::setprecision(1)<<fHits[khit].PeakAmplitude()
4993  <<" LoT "<<(int)hitStartTick
4994  <<" HiT "<<(int)hitEndTick
4995  <<" index " << khit;
4996  }
4997  // count charge in the window
4998  if(fHits[khit].StartTick() > chgWinLo && fHits[khit].EndTick() < chgWinHi) cnear += fHits[khit].Integral();
4999  // check for signal
5000  if(prtimeHi < hitStartTick) continue;
5001  if(prtimeLo > hitEndTick) continue;
5002  SigOK = true;
5003  // check for good hit
5004  if(hitTime < prtimeLo) continue;
5005  if(hitTime > prtimeHi) continue;
5006  // hit used?
5007  if(inClus[khit] > 0) continue;
5008  if(dtime < best) {
5009  best = dtime;
5010  imbest = khit;
5011  }
5012  } // khit
5013 
5014  if(!SigOK) {
5015  if(fAllowNoHitWire == 0) return;
5016  if(prt) mf::LogVerbatim("CC")<<" wire0 "<<wire0<<" kwire "<<kwire<<" max "<<fAllowNoHitWire<<" imbest "<<imbest;
5017  if((wire0 - kwire) > fAllowNoHitWire) return;
5018  SigOK = true;
5019  }
5020 
5021  if(imbest == INT_MAX) return;
5022 
5023  recob::Hit const& hit = fHits[imbest];
5024  hitChg = hit.Integral();
5025 
5026  if(prt) mf::LogVerbatim("CC")<<" Best hit time "<<(int)hit.PeakTime();
5027 
5028  short hnear = 0;
5029  // merge hits in a doublet?
5030  bool didMerge = false;
5031  if(lastClHit != UINT_MAX && fAveHitWidth > 0 && fHitMergeChiCut > 0 && hit.Multiplicity() == 2) {
5032  bool doMerge = true;
5033  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5034  if(std::abs(kwire - vtx[ivx].Wire) < 10 &&
5035  std::abs(int(hit.PeakTime() - vtx[ivx].Time)) < 20 )
5036  {
5037  doMerge = false;
5038  break;
5039  }
5040  } // ivx
5041  // quit if localindex does not make sense.
5042  if (hit.LocalIndex() != 0 && imbest == 0) doMerge = false;
5043  if (doMerge) {
5044  // find the neighbor hit
5045  unsigned int oht;
5046  if(hit.LocalIndex() == 0) {
5047  oht = imbest + 1;
5048  } else {
5049  oht = imbest - 1;
5050  } // hit.LocalIndex() == 0
5051  // check the hit time separation
5052  recob::Hit const& other_hit = fHits[oht];
5053  float hitSep = std::abs(hit.PeakTime() - other_hit.PeakTime());
5054  hitSep /= hit.RMS();
5055  // check the the charge similarity
5056  float totChg = hitChg + other_hit.Integral();
5057  float lastHitChg = fAveChg;
5058  if(lastHitChg < 0) lastHitChg = fHits[lastClHit].Integral();
5059  hnear = 1;
5060  if(prt) mf::LogVerbatim("CC")<<" Chk hit merge hitsep "<<hitSep<<" dChg "<<std::abs(totChg - lastHitChg)<<" Cut "<<std::abs(hit.Integral() - lastHitChg);
5061 // if(inClus[oht] == 0 && hitSep < fHitMergeChiCut && std::abs(totChg - lastHitChg) < std::abs(hit.Integral() - lastHitChg)) {
5062  if(inClus[oht] == 0 && hitSep < fHitMergeChiCut) {
5063  if(prt) mf::LogVerbatim("CC")<<" Merging hit doublet "<<imbest;
5064  MergeHits(imbest, didMerge);
5065  if(prt && !didMerge) mf::LogVerbatim("CC")<<" Hit merge failed ";
5066  } // not in a cluster, hitSep OK, total charge OK
5067  } // doMerge
5068  } // fHitMergeChiCut > 0 && hit.Multiplicity() == 2
5069 
5070  // Make a charge similarity cut if the average charge is defined
5071  bool fitChg = true;
5072  if(fAveChg > 0.) {
5073 
5074  float chgrat = (hitChg - fAveChg) / fAveChg;
5075  if(prt) mf::LogVerbatim("CC")<<" Chgrat "<<std::setprecision(2)<<chgrat;
5076 
5077  // charge is way too high?
5078  if(chgrat > 3 * fChgCut[pass]) {
5079  if(prt) mf::LogVerbatim("CC")<<" fails 3 x high charge cut "<<fChgCut[pass]<<" on pass "<<pass;
5080  return;
5081  }
5082 
5083  // Determine if the last hit added was a large (low) charge hit
5084  // This will be used to prevent adding large (low) charge hits on two
5085  // consecutive fits. This cut is only applied to hits on adjacent wires
5086  float bigchgcut = 1.5 * fChgCut[pass];
5087  bool lasthitbig = false;
5088  bool lasthitlow = false;
5089  if(lastClHit != UINT_MAX && util::absDiff(wire0, kwire) == 1) {
5090  float lastchgrat = (fHits[lastClHit].Integral() - fAveChg) / fAveChg;
5091  lasthitbig = ( lastchgrat > bigchgcut);
5092  lasthitlow = ( lastchgrat < -fChgCut[pass]);
5093  }
5094 
5095  // the last hit added was low charge and this one is as well
5096  if(lasthitlow && chgrat < -fChgCut[pass]) {
5097  if(prt) mf::LogVerbatim("CC")<<" fails low charge cut. Stop crawling.";
5098  SigOK = false;
5099  return;
5100  } // lasthitlow
5101 
5102  // the last hit was high charge and this one is also
5103  if(lasthitbig && chgrat > fChgCut[pass]) {
5104  if(prt) mf::LogVerbatim("CC")<<" fails 2nd hit high charge cut. Last hit was high also. ";
5105  return;
5106  } // lasthitbig
5107 
5108 
5109  // require that large charge hits have a very good projection error
5110  if(chgrat > fChgCut[pass]) {
5111  if(best > 2 * err) {
5112  if(prt) mf::LogVerbatim("CC")<<" high charge && bad dT= "<<best<<" err= "<<err;
5113  return;
5114  }
5115  } // chgrat > fChgCut[pass]
5116 
5117  // decide whether to fit the charge
5118  fitChg = (chgrat < std::abs(fChgCut[pass]) );
5119  } // fAveChg > 0
5120 
5121  // we now have a hit that meets all the criteria. Fit it
5122  fcl2hits.push_back(imbest);
5123  // This is strictly only necessary when calling AddHit for seed clusters
5124  if(fcl2hits.size() == 3) std::sort(fcl2hits.begin(), fcl2hits.end(), SortByLowHit);
5125  FitCluster();
5126  chifits.push_back(clChisq);
5127  hitNear.push_back(hnear);
5128  // remove the charge of the just added hit
5129  cnear -= fHits[imbest].Integral();
5130  if(cnear < 0) cnear = 0;
5131  // divide by the just added hit charge
5132  cnear /= fHits[imbest].Integral();
5133  chgNear.push_back(cnear);
5134  // nearby hit check
5135 // ChkClusterNearbyHits(prt);
5136  HitOK = true;
5137 
5138  if(chgNear.size() != fcl2hits.size()) {
5139  mf::LogError("CC")<<"AddHit: Bad length";
5140  return;
5141  }
5142 
5143  if(prt) mf::LogVerbatim("CC")<<" >>ADD"<<pass
5144  <<" W:T "<<PrintHit(imbest)
5145  <<" dT "<<best<<" clChisq "<<clChisq
5146  <<" Chg "<<(int)fHits[imbest].Integral()
5147  <<" AveChg "<<(int)fAveChg
5148  // <<" width "<<(int)hitWidth<<" fAveHitWidth "<<(int)fAveHitWidth
5149  <<" fcl2hits size "<<fcl2hits.size();
5150 
5151  if(!fitChg) return;
5152  if(prt) mf::LogVerbatim("CC")<<" Fit charge ";
5153  FitClusterChg();
5154  } // AddHit()
short int LocalIndex() const
How well do we believe we know this hit?
Definition: Hit.h:228
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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:221
STL namespace.
void MergeHits(const unsigned int theHit, bool &didMerge)
for(int i=0;i< 401;i++)
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
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:227
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
std::vector< VtxStore > vtx
the endpoints we are reconstructing
bool SortByLowHit(unsigned int i, unsigned int j)
std::string PrintHit(unsigned int iht)
Detector simulation of raw signals on wires.
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
float clChisq
chisq of the current fit
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
std::vector< float > chifits
fit chisq for monitoring kinks, etc
float fClProjErrFac
cluster projection error factor
float fHitMergeChiCut
is < cut. Set < 0 for no merging
std::vector< float > chgNear
charge near a cluster on each wire
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
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 4643 of file ClusterCrawlerAlg.cxx.

References tca::PrintHit().

4644  {
4645  // A variant of AddHit for large angle clusters
4646 
4647  SigOK = false;
4648  HitOK = false;
4649 
4650  // not in the range of wires with hits
4651  if(kwire < fFirstWire || kwire > fLastWire) return;
4652 
4653  if(fcl2hits.size() == 0) return;
4654 
4655  // skip bad wire and assume the track was there
4656  if(WireHitRange[kwire].first == -1) {
4657  SigOK = true;
4658  return;
4659  }
4660  // return SigOK false if no hit on a good wire
4661  if(WireHitRange[kwire].first == -2) return;
4662 
4663  unsigned int firsthit = WireHitRange[kwire].first;
4664  unsigned int lasthit = WireHitRange[kwire].second;
4665 
4666  // max allowable time difference between projected cluster and a hit
4667  float timeDiff = 40 * AngleFactor(clpar[1]);
4668  float dtime;
4669 
4670  // the last hit added to the cluster
4671  unsigned int lastClHit = UINT_MAX;
4672  if(fcl2hits.size() > 0) {
4673  lastClHit = fcl2hits[fcl2hits.size()-1];
4674  if(lastClHit == 0) {
4675  fAveChg = fHits[lastClHit].Integral();
4676  fAveHitWidth = fHits[lastClHit].EndTick() - fHits[lastClHit].StartTick();
4677  }
4678  } // fcl2hits.size() > 0
4679 
4680  // the projected time of the cluster on this wire
4681  float prtime = clpar[0] + ((float)kwire - clpar[2]) * clpar[1];
4682  float chgWinLo = prtime - fChgNearWindow;
4683  float chgWinHi = prtime + fChgNearWindow;
4684  float chgrat, hitWidth;
4685  float hitWidthCut = 0.5 * fAveHitWidth;
4686  float cnear = 0;
4687 // float fom;
4688  if(prt) mf::LogVerbatim("CC")<<"AddLAHit: wire "<<kwire<<" prtime "<<prtime<<" max timeDiff "<<timeDiff<<" fAveChg "<<fAveChg;
4689  unsigned int imbest = 0;
4690  unsigned int khit;
4691  for(khit = firsthit; khit < lasthit; ++khit) {
4692  // obsolete hit?
4693  if(inClus[khit] < 0) continue;
4694  dtime = std::abs(fHits[khit].PeakTime() - prtime);
4695 // fom = dtime;
4696  hitWidth = fHits[khit].EndTick() - fHits[khit].StartTick();
4697  chgrat = 1;
4698  if(ChkCharge && fAveChg > 0) {
4699  chgrat = fHits[khit].Integral() / fAveChg;
4700 // fom *= std::abs(chgrat - 1);
4701 // fom *= fAveHitWidth / hitWidth;
4702  }
4703  if(prt) mf::LogVerbatim("CC")
4704  <<" Chk W:T "<<kwire<<":"<<(short)fHits[khit].PeakTime()
4705  <<" dT "<<std::fixed<<std::setprecision(1)<<dtime
4706  <<" InClus "<<inClus[khit]
4707  <<" mult "<<fHits[khit].Multiplicity()
4708  <<" width "<<(int)hitWidth
4709  <<" MergeAvail "<<mergeAvailable[khit]
4710  <<" Chi2 "<<std::fixed<<std::setprecision(2)<<fHits[khit].GoodnessOfFit()
4711  <<" Charge "<<(int)fHits[khit].Integral()
4712  <<" chgrat "<<std::fixed<<std::setprecision(1)<<chgrat
4713 // <<" fom "<<std::fixed<<std::setprecision(1)<<fom
4714 // <<" LoT "<<(int)fHits[khit].StartTick()
4715 // <<" HiT "<<(int)fHits[khit].EndTick()
4716  <<" index "<<khit;
4717  // count charge in the window
4718  if(fHits[khit].PeakTime() > chgWinLo && fHits[khit].PeakTime() < chgWinHi) cnear += fHits[khit].Integral();
4719  // projected time outside the Signal time window?
4720  if(prtime < fHits[khit].StartTick() - timeDiff) continue;
4721  if(prtime > fHits[khit].EndTick() + timeDiff) continue;
4722  SigOK = true;
4723  // hit used?
4724  if(inClus[khit] > 0) continue;
4725  // ignore narrow width hits
4726  if(hitWidth < hitWidthCut) continue;
4727  // ignore very low charge hits
4728  if(chgrat < 0.1) continue;
4729 // dtime = std::abs(prtime - fHits[khit].PeakTime());
4730  if(dtime < timeDiff) {
4731  HitOK = true;
4732  imbest = khit;
4733  timeDiff = dtime;
4734  }
4735  } // khit
4736 
4737  if(prt && !HitOK) mf::LogVerbatim("CC")<<" no hit found ";
4738 
4739  if(!HitOK) return;
4740 
4741  if(prt) mf::LogVerbatim("CC")<<" Pick hit time "<<(int)fHits[imbest].PeakTime()<<" hit index "<<imbest;
4742 
4743  // merge hits in a multiplet?
4744  short hnear = 0;
4745  if(lastClHit != UINT_MAX && fHits[imbest].Multiplicity() > 1) {
4746  bool doMerge = true;
4747  // Standard code
4748  // don't merge if we are close to a vertex
4749  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4750  if(vtx[ivx].CTP != clCTP) continue;
4751  if(prt) mf::LogVerbatim("CC")<<" close vtx chk W:T "<<vtx[ivx].Wire<<":"<<(int)vtx[ivx].Time;
4752  if(std::abs(kwire - vtx[ivx].Wire) < 5 && std::abs(int(fHits[imbest].PeakTime() - vtx[ivx].Time)) < 20 ) {
4753  if(prt) mf::LogVerbatim("CC")<<" Close to a vertex. Don't merge hits";
4754  doMerge = false;
4755  }
4756  } // ivx
4757  // Decide which hits in the multiplet to merge. Hits that are well
4758  // separated from each other should not be merged
4759  if(doMerge) {
4760  unsigned short nused = 0;
4761  // the total charge of the hit multiplet
4762  float multipletChg = 0.;
4763  float chicut = AngleFactor(clpar[1]) * fHitMergeChiCut * fHits[lastClHit].RMS();
4764  // look for a big separation between adjacent hits
4765  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(imbest);
4766  for(size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
4767  if(inClus[jht] < 0) continue;
4768  if(inClus[jht] == 0) multipletChg += fHits[jht].Integral();
4769  else ++nused;
4770  // check the neighbor hit separation
4771  if(jht > MultipletRange.first) {
4772  // pick the larger RMS of the two hits
4773  float hitRMS = fHits[jht].RMS();
4774  if(fHits[jht - 1].RMS() > hitRMS) hitRMS = fHits[jht-1].RMS();
4775  const float tdiff = std::abs(fHits[jht].PeakTime() - fHits[jht-1].PeakTime()) / hitRMS;
4776  if(prt) mf::LogVerbatim("CC")<<" Hit RMS chisq "<<tdiff<<" chicut "<<chicut;
4777  if(tdiff > chicut) doMerge = false;
4778  } // jht > 0
4779  } // jht
4780  if(prt) {
4781  if(!doMerge) mf::LogVerbatim("CC")
4782  <<" Hits are well separated. Don't merge them ";
4783  }
4784  if(doMerge && nused == 0) {
4785  // compare the charge with the last hit added?
4786  if(ChkCharge) {
4787  // there is a nearby hit
4788  hnear = 1;
4789  float chgrat = multipletChg / fHits[lastClHit].Integral();
4790  if(prt) mf::LogVerbatim("CC")<<" merge hits charge check "
4791  <<(int)multipletChg<<" Previous hit charge "<<(int)fHits[lastClHit].Integral();
4792  if(chgrat > 2) doMerge = false;
4793  }
4794  } // doMerge && nused == 0
4795  } // doMerge true
4796  if(doMerge) {
4797  // there is a nearby hit and it will be merged
4798  hnear = -1;
4799  bool didMerge;
4800  MergeHits(imbest, didMerge);
4801  } // doMerge
4802  } // Hits[imbest].Multiplicity() > 1
4803 
4804  // attach to the cluster and fit
4805  fcl2hits.push_back(imbest);
4806  FitCluster();
4807  FitClusterChg();
4808  chifits.push_back(clChisq);
4809  hitNear.push_back(hnear);
4810  // remove the charge of the just added hit
4811  cnear -= fHits[imbest].Integral();
4812  if(cnear < 0) cnear = 0;
4813  // divide by the just added hit charge
4814  cnear /= fHits[imbest].Integral();
4815  chgNear.push_back(cnear);
4816  if(prt) {
4817  hitWidth = fHits[imbest].EndTick() - fHits[imbest].StartTick();
4818  mf::LogVerbatim("CC")
4819  <<" >>LADD"<<pass<<" W:T "<<PrintHit(imbest)
4820  <<" dT "<<timeDiff
4821  <<" clChisq "<<clChisq
4822  <<" Chg "<<(int)fHits[imbest].Integral()
4823  <<" AveChg "<<(int)fAveChg
4824  <<" width "<<(int)hitWidth
4825  <<" AveWidth "<<(int)fAveHitWidth
4826  <<" fcl2hits size "<<fcl2hits.size();
4827  } // prt
4828  // decide what to do with a bad fit
4829  if(clChisq > fChiCut[pass]) {
4830  FclTrimUS(1);
4831  FitCluster();
4832  HitOK = false;
4833 // if(prt) mf::LogVerbatim("CC")<<" LADD- Removed hit. New clChisq "<<std::setprecision(3)<<clChisq<<" nhits "<<fcl2hits.size();
4834  SigOK = false;
4835  if(prt) mf::LogVerbatim("CC")<<" LADD- Removed bad hit. Stopped tracking";
4836  }
4837 /*
4838  // stop tracking if previous chisq values were close to the cut.
4839  // this is an indicator that the track is wandering too much for this pass
4840  if(chifits.size() > 2 &&
4841  chifits[chifits.size()-2] > 0.8 * fChiCut[pass]) SigOK = false;
4842  if(prt) mf::LogVerbatim("CC")<<" Set SigOK = "<<SigOK;
4843 */
4844  } // AddLAHit()
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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::vector< VtxStore > vtx
the endpoints we are reconstructing
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< std::pair< int, int > > WireHitRange
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
float fHitMergeChiCut
is < cut. Set < 0 for no merging
std::vector< float > chgNear
charge near a cluster on each wire
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
float cluster::ClusterCrawlerAlg::AngleFactor ( float  slope)
private

Definition at line 4506 of file ClusterCrawlerAlg.cxx.

4507  {
4508  // returns an angle dependent cluster projection error factor for fitting
4509  // and hit finding
4510 
4511  float slp = std::abs(slope);
4512  if(slp > 15) slp = 15;
4513  // return a value between 1 and 4
4514  float angfac = 1 + 0.03 * slp * slp;
4515  return angfac;
4516  }
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 6219 of file ClusterCrawlerAlg.cxx.

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

6220  {
6221  return (first_hit.StartTick() == second_hit.StartTick())
6222  && (first_hit.WireID() == second_hit.WireID());
6223  } // ClusterCrawlerAlg::areInSameMultiplet()
void cluster::ClusterCrawlerAlg::CalculateAveHitWidth ( )
private

Definition at line 4519 of file ClusterCrawlerAlg.cxx.

4520  {
4521  fAveHitWidth = 0;
4522  for(unsigned short ii = 0; ii < fcl2hits.size(); ++ii)
4523  fAveHitWidth += fHits[fcl2hits[ii]].EndTick() - fHits[fcl2hits[ii]].StartTick();
4524  fAveHitWidth /= (float)fcl2hits.size();
4525  } // 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 4238 of file ClusterCrawlerAlg.cxx.

References tca::DeadWireCount().

4239  {
4240 
4241 
4242  // Find the fraction of the wires on the cluster that have
4243  // hits.
4244  unsigned int iht = fcl2hits[fcl2hits.size() - 1];
4245  clEndWir = fHits[iht].WireID().Wire;
4246  clBeginWir = fHits[fcl2hits[0]].WireID().Wire;
4247  float hitFrac = (float)(fcl2hits.size() + DeadWireCount()) / (float)(clBeginWir - clEndWir + 1);
4248 
4249  if(hitFrac < fMinHitFrac) {
4250 // RestoreUnMergedClusterHits(-1);
4251  if(prt) mf::LogVerbatim("CC")<<"CheckClusterHitFrac: Poor hit fraction "<<hitFrac<<" clBeginWir "<<clBeginWir
4252  <<" clEndWir "<<clEndWir<<" size "<<fcl2hits.size()<<" DeadWireCount "<<DeadWireCount();
4253  fcl2hits.clear();
4254  return;
4255  } // hitFrac
4256 
4257 /* TODO: Does this make sense?
4258  // lop off the last hit if it is part of a hit multiplet
4259  if(fHits[iht].Multiplicity() > 1) {
4260  fcl2hits.resize(fcl2hits.size() - 1);
4261  }
4262 */
4263  // check for short track ghosts
4264  if(fcl2hits.size() < 5) {
4265  unsigned short nsing = 0;
4266  for(unsigned short iht = 0; iht < fcl2hits.size(); ++iht) if(fHits[fcl2hits[iht]].Multiplicity() == 1) ++nsing;
4267  hitFrac = (float)nsing / (float)fcl2hits.size();
4268  if(hitFrac < fMinHitFrac) {
4269 // RestoreUnMergedClusterHits(-1);
4270  fcl2hits.clear();
4271  if(prt) mf::LogVerbatim("CC")<<"CheckClusterHitFrac: Poor short track hit fraction "<<hitFrac;
4272  return;
4273  } // hitFrac
4274  } // short ghost track check
4275 
4276  // analyze the pattern of nearby charge
4277  // will need the cluster charge so calculate it here if it isn't defined yet
4278  if(clBeginChg <= 0) {
4279  unsigned int iht, nht = 0;
4280  for(unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
4281  iht = fcl2hits[ii];
4282  clBeginChg += fHits[iht].Integral();
4283  ++nht;
4284  if(nht == 8) break;
4285  }
4286  clBeginChg /= (float)nht;
4287  } // clBeginChg == 0
4288  // handle short vs long clusters
4289  unsigned short cnt = chgNear.size()/2;
4290  // get the average charge from <= 30 hits at each end
4291  if(chgNear.size() > 60) cnt = 30;
4292  clBeginChgNear = 0;
4293  clEndChgNear = 0;
4294  for(unsigned short ids = 0; ids < cnt; ++ids) {
4295  clBeginChgNear += chgNear[ids];
4296  clEndChgNear += chgNear[chgNear.size() - 1 - ids];
4297  }
4298  clBeginChgNear /= (float)cnt;
4299  clEndChgNear /= (float)cnt;
4300 
4301  } // 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 1006 of file ClusterCrawlerAlg.cxx.

1007  {
1008  // check hit - cluster associations
1009 
1010  if(fHits.size() != inClus.size()) {
1011  mf::LogError("CC")<<"CHCA: Sizes wrong "<<fHits.size()<<" "<<inClus.size();
1012  return;
1013  }
1014 
1015  unsigned int iht, nErr = 0;
1016  short clID;
1017 
1018  // check cluster -> hit association
1019  for(unsigned short icl = 0; icl < tcl.size(); ++icl) {
1020  if(tcl[icl].ID < 0) continue;
1021  clID = tcl[icl].ID;
1022  for(unsigned short ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
1023  iht = tcl[icl].tclhits[ii];
1024  if(iht > fHits.size() - 1) {
1025  mf::LogError("CC")<<"CHCA: Bad tclhits index "<<iht<<" fHits size "<<fHits.size();
1026  return;
1027  } // iht > fHits.size() - 1
1028  if(inClus[iht] != clID) {
1029  mf::LogError("CC")<<"CHCA: Bad cluster -> hit association. clID "<<clID<<" hit inClus "<<inClus[iht]<<" ProcCode "<<tcl[icl].ProcCode<<" CTP "<<tcl[icl].CTP;
1030  ++nErr;
1031  if(nErr > 10) return;
1032  }
1033  } // ii
1034  } // icl
1035 
1036  // check hit -> cluster association
1037  unsigned short icl;
1038  for(iht = 0; iht < fHits.size(); ++iht) {
1039  if(inClus[iht] <= 0) continue;
1040  icl = inClus[iht] - 1;
1041  // see if the cluster is obsolete
1042  if(tcl[icl].ID < 0) {
1043  mf::LogError("CC")<<"CHCA: Hit associated with an obsolete cluster. hit W:T "<<fHits[iht].WireID().Wire<<":"<<(int)fHits[iht].PeakTime()
1044  <<" tcl[icl].ID "<<tcl[icl].ID;
1045  ++nErr;
1046  if(nErr > 10) return;
1047  }
1048  if (std::find(tcl[icl].tclhits.begin(), tcl[icl].tclhits.end(), iht) == tcl[icl].tclhits.end()) {
1049  mf::LogError("CC")<<"CHCA: Bad hit -> cluster association. hit index "<<iht
1050  <<" W:T "<<fHits[iht].WireID().Wire<<":"<<(int)fHits[iht].PeakTime()<<" inClus "<<inClus[iht];
1051  ++nErr;
1052  if(nErr > 10) return;
1053  }
1054  } // iht
1055 
1056  } // CheckHitClusterAssociations()
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< ClusterStore > tcl
the clusters we are creating
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 6257 of file ClusterCrawlerAlg.cxx.

References hits().

6258  {
6259  // currently unused, only for debug
6260  unsigned int nDuplicates = 0;
6261  std::set<unsigned int> hits;
6262  for (unsigned int hit: fcl2hits) {
6263  if (hits.count(hit)) {
6264  ++nDuplicates;
6265  mf::LogProblem log("CC");
6266  log << "Hit #" << hit
6267  << " being included twice in the future cluster (ID="
6268  << (tcl.size() + 1) << "?) at location: " << location;
6269  if (!marker.empty()) log << " (marker: '" << marker << "')";
6270  }
6271  hits.insert(hit);
6272  } // for
6273  return nDuplicates > 0;
6274  } // 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 1095 of file ClusterCrawlerAlg.cxx.

References cluster::SortByLowHit().

1095  {
1096  // Try to extend clusters DS by a few wires.
1097  // DS hits may not have been included in a cluster if they have high
1098  // multiplicity or high charge.
1099  // Ref ClusterLoop cuts for starting a seed cluster.
1100 
1101  prt = (fDebugPlane == 3);
1102 
1103  // use the most generous kink angle cut
1104  float dThCut = fKinkAngCut[fNumPass - 1];
1105 
1106  if(prt) mf::LogVerbatim("CC")<<"ChkClusterDS clCTP "<<clCTP<<" kink angle cut "<<dThCut;
1107 
1108  const unsigned short tclsize = tcl.size();
1109  bool didMerge, skipit;
1110  unsigned short icl, ii, nhm, iv;
1111  unsigned int iht;
1112 
1113  // first merge any hits on the DS end of clusters
1114  for(icl = 0; icl < tclsize; ++icl) {
1115  if(tcl[icl].ID < 0) continue;
1116  if(tcl[icl].CTP != clCTP) continue;
1117  // ignore clusters that have a Begin vertex
1118  if(tcl[icl].BeginVtx >= 0) continue;
1119  // and clusters near a vertex
1120  skipit = false;
1121  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
1122  if(vtx[iv].CTP != clCTP) continue;
1123  if(std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4) continue;
1124  if(std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20) continue;
1125  skipit = true;
1126  break;
1127  }
1128  if(skipit) continue;
1129  // check the first few hits
1130  nhm = 0;
1131  for(ii = 0; ii < 3; ++ii) {
1132  iht = fcl2hits[ii];
1133  if(fHits[iht].Multiplicity() > 1) {
1134  MergeHits(iht, didMerge);
1135  if(didMerge) ++nhm;
1136  }
1137  } // ii
1138  if(nhm > 0) {
1139  // update the Begin parameters in-place
1140  FitClusterMid(icl, 0, 3);
1141  tcl[icl].BeginTim = clpar[0];
1142  tcl[icl].BeginSlp = clpar[1];
1143  tcl[icl].BeginAng = atan(fScaleF * clpar[1]);
1144  tcl[icl].BeginSlpErr = clparerr[1];
1145  tcl[icl].BeginChg = fAveChg;
1146  tcl[icl].ProcCode += 5000;
1147  if(prt) mf::LogVerbatim("CC")<<"ChkClusterDS: Merge hits on cluster "<<tcl[icl].ID;
1148  } // nhm > 0
1149  } // icl
1150 
1151  float thhits, prevth, hitrms, rmsrat;
1152  bool ratOK;
1153  std::vector<unsigned int> dshits;
1154  for(icl = 0; icl < tclsize; ++icl) {
1155  if(tcl[icl].ID < 0) continue;
1156  if(tcl[icl].CTP != clCTP) continue;
1157  // ignore clusters that have a Begin vertex
1158  if(tcl[icl].BeginVtx >= 0) continue;
1159  // and clusters near a vertex
1160  skipit = false;
1161  for(iv = 0; iv < vtx.size(); ++iv) {
1162  if(vtx[iv].CTP != clCTP) continue;
1163  if(std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4) continue;
1164  if(std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20) continue;
1165  skipit = true;
1166  break;
1167  }
1168  if(skipit) continue;
1169  // ignore clusters with lots of nearby charge
1170 // if(tcl[icl].BeginChgNear > fChgNearCut) continue;
1171  // find the angle using the first 2 hits
1172  unsigned int ih0 = tcl[icl].tclhits[1];
1173  unsigned int ih1 = tcl[icl].tclhits[0];
1174  const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1175  (fHits[ih1].WireID().Wire - fHits[ih0].WireID().Wire);
1176  prevth = std::atan(fScaleF * slp);
1177  // move the "origin" to the first hit
1178  ih0 = ih1;
1179  unsigned int wire = fHits[ih0].WireID().Wire;
1180  hitrms = fHits[ih0].RMS();
1181  float time0 = fHits[ih0].PeakTime();
1182  float prtime;
1183  dshits.clear();
1184  // follow DS a few wires. Stop if any encountered
1185  // hit is associated with a cluster
1186  for(ii = 0; ii < 4; ++ii) {
1187  ++wire;
1188  if(wire > fLastWire) break;
1189  prtime = time0 + slp;
1190  if(prt) mf::LogVerbatim("CC")<<"ChkClusterDS: Try to extend "
1191  <<tcl[icl].ID<<" to W:T "<<wire<<" hitrms "<<hitrms<<" prevth "<<prevth<<" prtime "<<(int)prtime;
1192  // stop if no hits on this wire
1193  if(WireHitRange[wire].first == -2) break;
1194  unsigned int firsthit = WireHitRange[wire].first;
1195  unsigned int lasthit = WireHitRange[wire].second;
1196  bool hitAdded = false;
1197  for(ih1 = firsthit; ih1 < lasthit; ++ih1) {
1198  if(inClus[ih1] != 0) continue;
1199  if(prtime < fHits[ih1].PeakTimeMinusRMS(5)) continue;
1200  if(prtime > fHits[ih1].PeakTimePlusRMS(5)) continue;
1201  const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1202  (fHits[ih1].WireID().Wire - fHits[ih0].WireID().Wire);
1203  thhits = std::atan(fScaleF * slp);
1204  if(prt) mf::LogVerbatim("CC")<<" theta "<<thhits<<" prevth "<<prevth<<" cut "<<dThCut;
1205  if(std::abs(thhits - prevth) > dThCut) continue;
1206  // make a hit rms cut for small angle clusters
1207  ratOK = true;
1208  if(std::abs(slp) < fLAClusSlopeCut) {
1209  rmsrat = fHits[ih1].RMS() / hitrms;
1210  ratOK = rmsrat > 0.3 && rmsrat < 3;
1211  } else {
1212  // merge the hits
1213  bool didMerge;
1214  MergeHits(ih1, didMerge);
1215  }
1216  if(prt) mf::LogVerbatim("CC")<<" rmsrat "<<rmsrat<<" OK? "<<ratOK;
1217  // require small angle and not wildly different width compared
1218  // to the first hit in the cluster
1219  // TODO handle hit multiplets here
1220  if(ratOK) {
1221  dshits.push_back(ih1);
1222  hitAdded = true;
1223  prevth = thhits;
1224  ih0 = ih1;
1225  if(prt) mf::LogVerbatim("CC")<<" Add hit "<<fHits[ih1].WireID().Wire
1226  <<":"<<(int)fHits[ih1].PeakTime()<<" rmsrat "<<rmsrat;
1227  break;
1228  }
1229  } // ih1
1230  // stop looking if no hit was added on this wire
1231  if(!hitAdded) break;
1232  } // ii
1233  // Found hits not associated with a different cluster
1234  if(dshits.size() > 0) {
1235  // put the tcl cluster into the working vectors
1236  TmpGet(icl);
1237  // clobber the hits
1238  fcl2hits.clear();
1239  // sort the DS hits
1240  if(dshits.size() > 1) std::sort(dshits.begin(), dshits.end(), SortByLowHit);
1241  // stuff them into fcl2hits
1242  fcl2hits = dshits;
1243  // Append the existing hits
1244  for(ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
1245  // un-assign the hits so that TmpStore will re-assign them
1246  iht = tcl[icl].tclhits[ii];
1247  inClus[iht] = 0;
1248  fcl2hits.push_back(iht);
1249  }
1250  clProcCode += 5000;
1251  pass = fNumPass - 1;
1252  FitClusterChg();
1253  clBeginChg = fAveChg;
1254  // declare the old one obsolete
1255  MakeClusterObsolete(icl);
1256  // add the new one
1257  if(!TmpStore()) {
1258  mf::LogError("CC")<<"ChkClusterDS TmpStore failed while extending cluster ID "<<tcl[icl].ID;
1259  continue;
1260  }
1261  const size_t newcl = tcl.size() -1;
1262  if(prt) { mf::LogVerbatim("CC")<<" Store "<<newcl; }
1263  tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1264  tcl[newcl].EndVtx = tcl[icl].EndVtx;
1265  } // dshits.size() > 0
1266  } // icl
1267  } // 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
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
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
std::vector< ClusterStore > tcl
the clusters we are creating
unsigned short fNumPass
number of passes over the hit collection
std::vector< VtxStore > vtx
the endpoints we are reconstructing
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< 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
void cluster::ClusterCrawlerAlg::ChkClusterNearbyHits ( bool  prt)
private

Definition at line 5158 of file ClusterCrawlerAlg.cxx.

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

5159  {
5160  // analyze the hitnear vector
5161  // 0 = no nearby hit exists
5162  // 1 = a nearby hit exists but was not merged
5163  // -1 = a nearby hit was merged
5164 
5165  if(fHitMergeChiCut <= 0) return;
5166 
5167  if(hitNear.size() != fcl2hits.size()) {
5168  mf::LogWarning("CC")<<"Coding error: hitNear size != fcl2hits";
5169  return;
5170  }
5171 
5172  // Analyze the last 6 hits added but don't consider the first few hits
5173  if(hitNear.size() < 12) return;
5174 
5175  // TODO move into loops
5176  unsigned short ii, indx;
5177  unsigned short merged = 0;
5178  unsigned short notmerged = 0;
5179  for(ii = 0; ii < 6; ++ii) {
5180  indx = hitNear.size() - 1 - ii;
5181  if(hitNear[indx] > 0) ++notmerged;
5182  if(hitNear[indx] < 0) ++merged;
5183  }
5184 
5185  if(prt) mf::LogVerbatim("CC")<<"ChkClusterNearbyHits: nearby hits merged "<<merged<<" not merged "<<notmerged;
5186 
5187  if(notmerged < 2) return;
5188 
5189  // a number of nearby hits were not merged while crawling, so the
5190  // average charge is probably wrong. Look at the last 6 hits added
5191  // and merge them if they are close
5192  bool didMerge;
5193  for(ii = 0; ii < 6; ++ii) {
5194  indx = fcl2hits.size() - 1 - ii;
5195  const unsigned int iht = fcl2hits[indx];
5196  recob::Hit const& hit = fHits[iht];
5197  if(hit.Multiplicity() == 2) {
5198  // quit if localindex does not make sense.
5199  if (hit.LocalIndex() != 0 && iht == 0) continue;
5200  // hit doublet. Get the index of the other hit
5201  unsigned int oht;
5202  if(hit.LocalIndex() == 0) {
5203  oht = iht + 1;
5204  } else {
5205  oht = iht - 1;
5206  } // hit.LocalIndex() == 0
5207  recob::Hit const& other_hit = fHits[oht];
5208  // TODO use Hit::TimeDistanceAsRMS()
5209  float hitSep = std::abs(hit.PeakTime() - other_hit.PeakTime());
5210  hitSep /= hit.RMS();
5211  if(hitSep < fHitMergeChiCut && inClus[oht] == 0) {
5212  if(prt) mf::LogVerbatim("CC")<<"Merging hit doublet "
5213  <<iht<<" W:T "<<fHits[iht].WireID().Wire<<":"<<fHits[iht].PeakTime();
5214  MergeHits(iht, didMerge);
5215  if(didMerge) hitNear[indx] = -1;
5216  } // hitSep OK and not in a cluster
5217  } // hit doublet
5218  } // ii
5219 
5220  // now re-fit
5221  FitCluster();
5222  FitClusterChg();
5223 
5224  if(prt) mf::LogVerbatim("CC")<<"ChkClusterNearbyHits refit cluster. fAveChg= "<<fAveChg;
5225 
5226  } // ChkClusterHitNear()
short int LocalIndex() const
How well do we believe we know this hit?
Definition: Hit.h:228
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:221
void MergeHits(const unsigned int theHit, bool &didMerge)
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:227
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:219
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
float fHitMergeChiCut
is < cut. Set < 0 for no merging
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ChkMerge ( )
private

Definition at line 2954 of file ClusterCrawlerAlg.cxx.

References tca::DeadWireCount().

2955  {
2956  // Try to merge clusters. Clusters that have been subsumed in other
2957  // clusters, i.e. no longer valid, have ID < 0
2958 
2959  if(tcl.size() < 2) return;
2960  // The size of the ClusterStore vector will increase while merging
2961  // is on-going so the upper limit on it1 is fixed tcl.size() - 1
2962  // before merging starts
2963 
2964  prt = (fDebugPlane == (short)plane && fDebugWire < 0);
2965  if(prt) mf::LogVerbatim("CC")<<"ChkMerge on pass "<<pass;
2966 
2967  unsigned short it1, it2, nh1, pass1, pass2;
2968  float bs1, bth1, bt1, bc1, es1, eth1, et1, ec1;
2969  float bs2, bth2, bt2, bc2, es2, eth2, et2, ec2;
2970  int bw1, ew1, bw2, ew2, ndead;
2971  float dth, dw, angcut, chgrat, chgcut, dtim, timecut, bigslp;
2972  bool bothLong, NoVtx;
2973 
2974  int skipcut, tclsize = tcl.size();
2975  int maxOverlap = 3;
2976 
2977  for(it1 = 0; it1 < tclsize - 1; ++it1) {
2978  // ignore already merged clusters
2979  if(tcl[it1].ID < 0) continue;
2980  if(tcl[it1].CTP != clCTP) continue;
2981  bs1 = tcl[it1].BeginSlp;
2982  // convert slope to angle
2983  bth1 = std::atan(fScaleF * bs1);
2984  // more compact notation for begin/end, wire/time/chg/slp/theta, 1/2
2985  bw1 = tcl[it1].BeginWir;
2986  bt1 = tcl[it1].BeginTim;
2987  bc1 = tcl[it1].BeginChg;
2988  es1 = tcl[it1].EndSlp;
2989  eth1 = tcl[it1].EndAng;
2990  ew1 = tcl[it1].EndWir;
2991  et1 = tcl[it1].EndTim;
2992  ec1 = tcl[it1].EndChg;
2993  nh1 = tcl[it1].tclhits.size();
2994  pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2995  if(pass1 > fNumPass) pass1 = fNumPass;
2996  for(it2 = it1 + 1; it2 < tclsize; ++it2) {
2997  // ignore already merged clusters
2998  if(tcl[it1].ID < 0) continue;
2999  if(tcl[it2].ID < 0) continue;
3000  // only merge if they are in the right cryostat/TPC/plane
3001  if(tcl[it2].CTP != clCTP) continue;
3002  // Don't bother if these clusters, if merged, would fail the
3003  // cluster hit fraction cut
3004  if(!ChkMergedClusterHitFrac(it1, it2)) {
3005 // if(prt) mf::LogVerbatim("CC")<<"ID1-2 "<<tcl[it1].ID<<"-"<<tcl[it2].ID<<" fails ChkMergedClusterHitFrac";
3006  continue;
3007  }
3008  bs2 = tcl[it2].BeginSlp;
3009  bth2 = std::atan(fScaleF * bs2);
3010  bw2 = tcl[it2].BeginWir;
3011  bt2 = tcl[it2].BeginTim;
3012  bc2 = tcl[it2].BeginChg;
3013  es2 = tcl[it2].EndSlp;
3014  eth2 = tcl[it2].EndAng;
3015  ew2 = tcl[it2].EndWir;
3016  et2 = tcl[it2].EndTim;
3017  ec2 = tcl[it2].EndChg;
3018  pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
3019  if(pass2 > fNumPass) pass2 = fNumPass;
3020  // use the more promiscuous pass for cuts
3021  angcut = fKinkAngCut[pass1];
3022  if(fKinkAngCut[pass2] > angcut) angcut = fKinkAngCut[pass2];
3023  skipcut = fMaxWirSkip[pass1];
3024  if(fMaxWirSkip[pass2] > skipcut) skipcut = fMaxWirSkip[pass2];
3025  chgcut = fMergeChgCut[pass1];
3026  if(fMergeChgCut[pass2] > chgcut) chgcut = fMergeChgCut[pass2];
3027 /*
3028  timecut = fTimeDelta[pass];
3029  if(fTimeDelta[pass2] > timecut) timecut = fTimeDelta[pass2];
3030  // increase the time cut for large angle clusters
3031  timecut *= AngleFactor(clpar[1]);
3032 */
3033  // tweak the cuts for long straight tracks
3034  bothLong = (nh1 > 100 && tcl[it2].tclhits.size() > 100);
3035 
3036  // look for US and DS broken clusters w similar angle.
3037  // US cluster 2 merge with DS cluster 1?
3038  // This is the most likely occurrence given the order in which
3039  // clusters are created so put it first.
3040  dth = std::abs(bth2 - eth1);
3041  ndead = DeadWireCount(bw2, ew1);
3042  dw = ew1 - bw2 - ndead;
3043  // require no vertex between
3044  NoVtx = (tcl[it1].EndVtx < 0) && (tcl[it2].BeginVtx < 0);
3045  if(prt && bw2 < (ew1 + maxOverlap) ) mf::LogVerbatim("CC")<<"Chk1 ID1-2 "<<tcl[it1].ID<<"-"<<tcl[it2].ID<<" "<<ew1<<":"<<(int)et1<<" "<<bw2<<":"<<(int)bt2<<" dw "<<dw<<" ndead "<<ndead<<" skipcut "<<skipcut<<" dth "<<dth<<" angcut "<<angcut;
3046  if(NoVtx && bw2 < (ew1 + maxOverlap) && dw < skipcut && dth < angcut) {
3047  chgrat = 2 * fabs(bc2 - ec1) / (bc2 + ec1);
3048  // ignore the charge cut for long tracks with small dth
3049  if(bothLong && dth < 0.05) chgrat = 0.;
3050  // project bw2,bt2 to ew1
3051  dtim = fabs(bt2 + (ew1-bw2)*bs2 - et1);
3052  bigslp = std::abs(bs2);
3053  if(std::abs(es1) > bigslp) bigslp = std::abs(es1);
3054  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
3055  if(prt) mf::LogVerbatim("CC")<<" dtim "<<dtim<<" timecut "<<(int)timecut<<" ec1 "<<ec1<<" bc2 "<<bc2<<" chgrat "<<chgrat<<" chgcut "<<chgcut<<" es1 "<<es1<<" ChkSignal "<<ChkSignal(ew1, et1, bw2, bt2);
3056  if(chgrat < chgcut && dtim < timecut) {
3057  // ensure there is a signal between cluster ends
3058  if(ChkSignal(ew1, et1, bw2, bt2)) {
3059  DoMerge(it2, it1, 10);
3060  tclsize = tcl.size();
3061  break;
3062  }
3063  } // chgrat < chgcut ...
3064  } // US cluster 2 merge with DS cluster 1?
3065 
3066  // look for US and DS broken clusters w similar angle
3067  // US cluster 1 merge with DS cluster 2?
3068  dth = fabs(bth1 - eth2);
3069  ndead = DeadWireCount(bw1, ew2);
3070  dw = ew2 - bw1 - ndead;
3071  if(prt && bw1 < (ew2 + maxOverlap) && dw < skipcut) mf::LogVerbatim("CC")<<"Chk2 ID1-2 "<<tcl[it1].ID<<"-"<<tcl[it2].ID<<" "<<bw1<<":"<<(int)bt1<<" "<<bw2<<":"<<(int)et2<<" dw "<<dw<<" ndead "<<ndead<<" skipcut "<<skipcut<<" dth "<<dth<<" angcut "<<angcut;
3072  // require no vertex between
3073  NoVtx = (tcl[it2].EndVtx < 0) && (tcl[it1].BeginVtx < 0);
3074  if(NoVtx && bw1 < (ew2 + maxOverlap) && dw < skipcut && dth < angcut ) {
3075  chgrat = 2 * fabs((bc1 - ec2) / (bc1 + ec2));
3076  // ignore the charge cut for long tracks with small dth
3077  if(bothLong && dth < 0.05) chgrat = 0.;
3078  // project sw1,st1 to ew2
3079  dtim = std::abs(bt1 + (ew2-bw1)*bs1 - et2);
3080  bigslp = std::abs(bs1);
3081  if(std::abs(bs2) > bigslp) bigslp = std::abs(bs2);
3082  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
3083  if(prt) mf::LogVerbatim("CC")<<" dtim "<<dtim<<" err "<<dtim<<" timecut "<<(int)timecut<<" chgrat "<<chgrat<<" chgcut "<<chgcut<<" ChkSignal "<<ChkSignal(bw1, bt1, ew2, et2);
3084  // TODO: we should be checking for a signal here like we did above
3085  if(chgrat < chgcut && dtim < timecut) {
3086  if(ChkSignal(bw1, bt1, ew2, et2)) {
3087  DoMerge(it1, it2, 10);
3088  tclsize = tcl.size();
3089  break;
3090  }
3091  } // chgrat < chgcut ...
3092  } // US cluster 1 merge with DS cluster 2
3093 
3094  if(bw2 < bw1 && ew2 > ew1) {
3095  // look for small cl2 within the wire boundary of cl1
3096  // with similar times and slopes for both clusters
3097  dth = fabs(eth2 - eth1);
3098  dtim = fabs(et1 +(ew2 - ew1 - 1)*es1 - et2);
3099  bigslp = std::abs(es1);
3100  if(std::abs(es1) > bigslp) bigslp = std::abs(es1);
3101  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
3102  // count the number of wires with no hits on cluster 1
3103  short nmiss1 = bw1 - ew1 + 1 - tcl[it1].tclhits.size();
3104  // compare with the number of hits in cluster 2
3105  short nin2 = tcl[it2].tclhits.size();
3106  if(prt) mf::LogVerbatim("CC")<<"cl2: "<<ew2<<":"<<(int)et2<<" - "<<bw2<<":"<<(int)bt2
3107  <<" within cl1 "<<ew1<<":"<<(int)et1<<" - "<<bw1<<":"<<(int)bt1
3108  <<" ? dth "<<dth<<" dtim "<<dtim<<" nmissed "<<nmiss1<<" timecut "<<timecut<<" FIX THIS CODE";
3109  // make rough cuts before calling ChkMerge12
3110  // this may not work well for long wandering clusters
3111  // TODO fix this code
3112  bool didit = false;
3113  if(dth < 1 && dtim < timecut && nmiss1 >= nin2)
3114  ChkMerge12(it1, it2, didit);
3115  if(didit) {
3116  tclsize = tcl.size();
3117  break;
3118  } //didit
3119  } // small cl2 within the wire boundary of cl1
3120 
3121  if(bw1 < bw2 && ew1 > ew2) {
3122  // look for small cl1 within the wire boundary of cl2
3123  // with similar times and slopes for both clusters
3124  dth = std::abs(eth2 - eth1);
3125  dtim = std::abs(et2 +(ew1 - ew2 - 1)*es2 - et1);
3126  bigslp = std::abs(es1);
3127  if(std::abs(es1) > bigslp) bigslp = std::abs(es1);
3128  timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
3129  // count the number of wires with no hits on cluster 2
3130  short nmiss2 = bw2 - ew2 + 1 - tcl[it2].tclhits.size();
3131  // compare with the number of hits in cluster 1
3132  short nin1 = tcl[it1].tclhits.size();
3133  if(prt) mf::LogVerbatim("CC")<<"cl1: "<<ew1<<":"<<(int)et1<<" - "<<bw1<<":"<<(int)bt1
3134  <<" within cl2 "<<ew2<<":"<<(int)et2<<" - "<<bw2<<":"<<(int)bt2
3135  <<" ? dth "<<dth<<" dtim "<<dtim<<" nmissed "<<nmiss2<<" timecut "<<timecut<<" FIX THIS CODE";
3136  // make rough cuts before calling ChkMerge12
3137  // this may not work well for long wandering clusters
3138  bool didit = false;
3139  if(dth < 1 && dtim < timecut && nmiss2 >= nin1) ChkMerge12(it2, it1, didit);
3140  if(didit) {
3141  tclsize = tcl.size();
3142  break;
3143  } // didit
3144  } // small cl1 within the wire boundary of cl2
3145 
3146  if(tcl[it1].ID < 0) break;
3147  } // cluster 2
3148  if(tcl[it1].ID < 0) continue;
3149  } // cluster 1
3150  }
float fScaleF
scale factor from Tick/Wire to dx/du
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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
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)
std::vector< ClusterStore > tcl
the clusters we are creating
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 3153 of file ClusterCrawlerAlg.cxx.

References cluster::ClusterCrawlerAlg::ClusterStore::EndWir, and cluster::ClusterCrawlerAlg::ClusterStore::tclhits.

3154  {
3155  // Calling routine has done a rough check that cluster it2 is a candidate
3156  // for merging with cluster it1. The wire range spanned by it2 lies
3157  // within the wire range of it1 and the clusters are reasonably close
3158  // together in time.
3159 
3160  // assume that no merging was done
3161  didit = false;
3162 
3163  if(prt) mf::LogVerbatim("CC")<<"ChkMerge12 "<<tcl[it1].ID<<" "<<tcl[it2].ID;
3164 
3165  ClusterStore& cl1 = tcl[it1];
3166  // fill a vector spanning the length of cluster 1 and filled with the hit time
3167  int ew1 = tcl[it1].EndWir;
3168  int bw1 = tcl[it1].BeginWir;
3169  unsigned int iht, hit;
3170  int wire;
3171  std::vector<unsigned int> cl1hits(bw1+1-ew1);
3172 /*
3173  // fill the vector with 0s
3174  for(unsigned int wire = ew1; wire <= bw1; ++wire) {
3175  cl1hits.push_back(0);
3176  }
3177 */
3178  // put in the hit IDs
3179  for(iht = 0; iht < cl1.tclhits.size(); ++iht) {
3180  hit = cl1.tclhits[iht];
3181  wire = fHits[hit].WireID().Wire;
3182  if(wire - ew1 < 0 || wire - ew1 > (int)cl1hits.size()) {
3183 // mf::LogError("CC")<<"ChkMerge12 bad wire "<<(wire-ew1);
3184  return;
3185  }
3186  cl1hits[wire - ew1] = hit;
3187  }
3188  unsigned int ew2 = tcl[it2].EndWir;
3189  float et2 = tcl[it2].EndTim;
3190  // look for the closest wire with a hit on cluster 1
3191  unsigned int wiron1 = 0;
3192  // count the number of missing hits
3193  short nmiss = 0;
3194  for(wire = ew2 - 1; wire > ew1; --wire) {
3195  if(cl1hits[wire - ew1] > 0) {
3196  wiron1 = wire;
3197  break;
3198  }
3199  ++nmiss;
3200  } // wire
3201  if(prt) mf::LogVerbatim("CC")<<"chk next US wire "<<wiron1<<" missed "<<nmiss;
3202  if(wiron1 == 0) return;
3203  if(nmiss > fMaxWirSkip[pass]) return;
3204 
3205  // compare the wires with hits on cluster 2 with the gap in cluster 1
3206  // the number of hit wires that fit in the gap
3207  unsigned int hiton2;
3208  int wiron2;
3209  unsigned short nfit = 0;
3210  for(iht = 0; iht < tcl[it2].tclhits.size(); ++iht) {
3211  hiton2 = tcl[it2].tclhits[iht];
3212  wiron2 = fHits[hiton2].WireID().Wire;
3213  if(wiron2 < ew1 || wiron2 > bw1) return;
3214  if(cl1hits[wiron2 - ew1] == 0) ++nfit;
3215  }
3216  // require complete filling of the gap
3217  if(nfit < tcl[it2].tclhits.size()) return;
3218 
3219  // decode the pass for both clusters and select the matching cuts
3220  unsigned short pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
3221  unsigned short pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
3222  unsigned short cpass = pass1;
3223  // use the tighter cuts
3224  if(pass2 < pass1) cpass = pass2;
3225 
3226  // ***** Check End of Cluster 2 matching with middle of cluster 1
3227  if((int) wiron1 - ew1 < 0) return;
3228  unsigned int hiton1 = cl1hits[wiron1 - ew1];
3229  if(hiton1 > fHits.size() - 1) {
3230 // mf::LogError("CC")<<"ChkMerge12 bad hiton1 "<<hiton1;
3231  return;
3232  }
3233  // check the time difference
3234  float timon1 = fHits[hiton1].PeakTime();
3235  float dtim = std::abs(et2 + (wiron1 - ew2) * tcl[it2].EndSlp - timon1);
3236  if(dtim > fTimeDelta[cpass]) return;
3237  // check the slope difference. First do a local fit on cluster 1 near
3238  // the matching point
3239  FitClusterMid(it1, hiton1, 3);
3240  if(clChisq > 20.) return;
3241  // fit parameters are now in clpar.
3242  // check for angle consistency
3243  float dth = std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].EndSlp));
3244  if(prt) mf::LogVerbatim("CC")<<"US dtheta "<<dth<<" cut "<<fKinkAngCut[cpass];
3245  if(dth > fKinkAngCut[cpass]) return;
3246  // make a charge ratio cut. fAveChg was calculated in FitClusterMid
3247  float chgrat = 2 * std::abs(fAveChg - tcl[it2].EndChg) / (fAveChg + tcl[it2].EndChg);
3248  if(prt) mf::LogVerbatim("CC")<<"US chgrat "<<chgrat<<" cut "<<fMergeChgCut[pass];
3249  // ensure that there is a signal on any missing wires at the US end of 1
3250  bool SigOK;
3251  SigOK = ChkSignal(wiron1, timon1, ew2, et2);
3252  if(prt) mf::LogVerbatim("CC")<<"US SigOK? "<<SigOK;
3253  if( !SigOK ) return;
3254 
3255 
3256  // ***** Check Begin of Cluster 2 matching with middle of cluster 1
3257  unsigned int bw2 = tcl[it2].BeginWir;
3258  float bt2 = tcl[it2].BeginTim;
3259  nmiss = 0;
3260  wiron1 = 0;
3261  for(wire = bw2 + 1; wire < bw1; ++wire) {
3262  if(cl1hits[wire - ew1] > 0) {
3263  wiron1 = wire;
3264  break;
3265  }
3266  ++nmiss;
3267  }
3268  if(wiron1 == 0) return;
3269  if(nmiss > fMaxWirSkip[pass]) return;
3270  // fit this section of cluster 1 with 4 hits starting at the hit on the
3271  // closest wire and moving DS
3272  hiton1 = cl1hits[wiron1 - ew1];
3273  if(hiton1 > fHits.size() - 1) {
3274 // mf::LogError("CC")<<"ChkMerge12 bad hiton1 "<<hiton1;
3275  return;
3276  }
3277  timon1 = fHits[hiton1].PeakTime();
3278  dtim = std::abs(bt2 - (wiron1 - bw2) *tcl[it2].BeginSlp - timon1);
3279  if(dtim > fTimeDelta[cpass]) return;
3280  FitClusterMid(it1, hiton1, -3);
3281  if(clChisq > 20.) return;
3282  // check for angle consistency
3283  dth = std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].BeginSlp));
3284  if(prt) mf::LogVerbatim("CC")
3285  <<"DS dtheta "<<dth<<" cut "<<fKinkAngCut[cpass];
3286  if(dth > fKinkAngCut[cpass]) return;
3287  // make a charge ratio cut
3288  chgrat = 2 * std::abs(fAveChg - tcl[it2].BeginChg) / (fAveChg + tcl[it2].BeginChg);
3289  if(prt) mf::LogVerbatim("CC")
3290  <<"DS chgrat "<<chgrat<<" cut "<<fMergeChgCut[pass];
3291  // ensure that there is a signal on any missing wires at the US end of 1
3292  SigOK = ChkSignal(wiron1, timon1, bw2, bt2);
3293  if(prt) mf::LogVerbatim("CC")<<"DS SigOK? "<<SigOK;
3294  if( !SigOK ) return;
3295 
3296  if(prt) mf::LogVerbatim("CC")<<"Merge em";
3297  // success. Merge them
3298  DoMerge(it1, it2, 100);
3299  didit = true;
3300  } // 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
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
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< ClusterStore > tcl
the clusters we are creating
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 4191 of file ClusterCrawlerAlg.cxx.

4192  {
4193  // This routine is called before two tcl clusters, it1 and it2, are slated to be
4194  // merged to see if they will satisfy the minimum hit fraction criterion
4195  if(it1 > tcl.size()-1) return false;
4196  if(it2 > tcl.size()-1) return false;
4197  unsigned int eWire = 99999;
4198  unsigned int bWire = 0, wire;
4199  if(tcl[it1].BeginWir > bWire) bWire = tcl[it1].BeginWir;
4200  if(tcl[it2].BeginWir > bWire) bWire = tcl[it2].BeginWir;
4201  if(tcl[it1].EndWir < eWire) eWire = tcl[it1].EndWir;
4202  if(tcl[it2].EndWir < eWire) eWire = tcl[it2].EndWir;
4203  unsigned int mergedClusterLength = bWire - eWire + 1;
4204  // define a vector of size = length of the wire range
4205  std::vector<bool> cHits(mergedClusterLength, false);
4206  // set the elements true if there is a hit
4207  unsigned int ii, iht, indx;
4208  for(ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
4209  iht = tcl[it1].tclhits[ii];
4210  if(iht > fHits.size()-1) {
4211  mf::LogError("CC")<<"ChkMergedClusterHitFrac bad iht ";
4212  return false;
4213  }
4214  indx = fHits[iht].WireID().Wire - eWire;
4215  cHits[indx] = true;
4216  } // ii
4217  for(ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
4218  iht = tcl[it2].tclhits[ii];
4219  if(iht > fHits.size()-1) {
4220  mf::LogError("CC")<<"ChkMergedClusterHitFrac bad iht ";
4221  return false;
4222  }
4223  indx = fHits[iht].WireID().Wire - eWire;
4224  cHits[indx] = true;
4225  } // ii
4226  // set cHits true if the wire is dead
4227  for(ii = 0; ii < cHits.size(); ++ii) {
4228  wire = eWire + ii;
4229  if(WireHitRange[wire].first == -1) cHits[ii] = true;
4230  }
4231  // count the number of wires with hits
4232  float nhits = std::count(cHits.begin(), cHits.end(), true);
4233  float hitFrac = nhits / (float)cHits.size();
4234  return (hitFrac > fMinHitFrac);
4235  } // ChkMergedClusterHitFrac
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
bool cluster::ClusterCrawlerAlg::ChkSignal ( unsigned int  iht,
unsigned int  jht 
)
private

Definition at line 2735 of file ClusterCrawlerAlg.cxx.

2736  {
2737  if(iht > fHits.size() - 1) return false;
2738  if(jht > fHits.size() - 1) return false;
2739  unsigned int wire1 = fHits[iht].WireID().Wire;
2740  float time1 = fHits[iht].PeakTime();
2741  unsigned int wire2 = fHits[jht].WireID().Wire;
2742  float time2 = fHits[jht].PeakTime();
2743  return ChkSignal(wire1, time1, wire2, time2);
2744  } // 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 2747 of file ClusterCrawlerAlg.cxx.

References bin.

2748  {
2749  // returns true if there is a signal on the line between
2750  // (wire1, time1) and (wire2, time2).
2751  // Be sure to set time1 < time2 if you are checking for signals on a single wire
2752 
2753  // Gaussian amplitude in bins of size 0.15
2754  const float gausAmp[20] = {1, 0.99, 0.96, 0.90, 0.84, 0.75, 0.67, 0.58, 0.49, 0.40, 0.32, 0.26, 0.20, 0.15, 0.11, 0.08, 0.06, 0.04, 0.03, 0.02};
2755 
2756  // return true if fMinAmp is set ignore wire signal checking in this plane
2757  if(fMinAmp[plane] <= 0) return true;
2758 
2759  // get the begin and end right
2760  unsigned int wireb = wire1;
2761  float timeb = time1;
2762  unsigned int wiree = wire2;
2763  float timee = time2;
2764  // swap them?
2765  if(wiree > wireb) {
2766  wireb = wire2;
2767  timeb = time2;
2768  wiree = wire1;
2769  timee = time1;
2770  }
2771  if(wiree < fFirstWire || wiree > fLastWire) return false;
2772  if(wireb < fFirstWire || wireb > fLastWire) return false;
2773 
2774  int wire0 = wiree;
2775  // checking a single wire?
2776  float slope = 0;
2777  bool oneWire = false;
2778  float prTime, prTimeLo = 0, prTimeHi = 0;
2779  if(wireb == wiree) {
2780  oneWire = true;
2781  if(time1 < time2) {
2782  prTimeLo = time1;
2783  prTimeHi = time2;
2784  } else {
2785  prTimeLo = time2;
2786  prTimeHi = time1;
2787  }
2788  } else {
2789  slope = (timeb - timee) / (wireb - wiree);
2790  }
2791 
2792  int bin;
2793  unsigned short nmissed = 0;
2794  for(unsigned int wire = wiree; wire < wireb + 1; ++wire) {
2795  if(oneWire) {
2796  prTime = (prTimeLo + prTimeHi) / 2;
2797  } else {
2798  prTime = timee + (wire - wire0) * slope;
2799  }
2800  // skip dead wires
2801  if(WireHitRange[wire].first == -1) continue;
2802  // no hits on this wire
2803  if(WireHitRange[wire].first == -2) ++nmissed;
2804  unsigned int firsthit = WireHitRange[wire].first;
2805  unsigned int lasthit = WireHitRange[wire].second;
2806  // if(vtxprt) mf::LogVerbatim("CC")<<" wire "<<wire<<" Hit range "<<firsthit<<" "<<lasthit<<" prTime "<<prTime;
2807  float amp = 0;
2808  for(unsigned int khit = firsthit; khit < lasthit; ++khit) {
2809  // if(vtxprt) mf::LogVerbatim("CC")<<" hit time "<<fHits[khit].PeakTime()<<" rms "<<fHits[khit].RMS()<<" amp "<<fHits[khit].PeakAmplitude()<<" StartTick "<<fHits[khit].StartTick()<<" EndTick "<<fHits[khit].EndTick();
2810  if(oneWire) {
2811  // TODO: This sometimes doesn't work with overlapping hits
2812  // if(prTimeHi > fHits[khit].EndTick()) continue;
2813  // if(prTimeLo < fHits[khit].StartTick()) continue;
2814  // A not totally satisfactory solution
2815  if(prTime < fHits[khit].StartTick()) continue;
2816  if(prTime > fHits[khit].EndTick()) continue;
2817  return true;
2818  } else {
2819  // skip checking if we are far away from prTime on the positive side
2820  if(fHits[khit].PeakTime() - prTime > 500) continue;
2821  bin = std::abs(fHits[khit].PeakTime() - prTime) / fHits[khit].RMS();
2822  bin /= 0.15;
2823  if(bin > 19) continue;
2824  if(bin < 0) continue;
2825  // if(vtxprt) mf::LogVerbatim("CC")<<" bin "<<bin<<" add "<<fHits[khit].PeakAmplitude() * gausAmp[bin]<<" to amp "<<amp;
2826  // add amplitude from all hits
2827  amp += fHits[khit].PeakAmplitude() * gausAmp[bin];
2828  }
2829  } // khit
2830  if(amp < fMinAmp[plane]) ++nmissed;
2831  } // wire
2832  if(nmissed > fAllowNoHitWire) return false;
2833  return true;
2834 
2835  } // ChkSignal()
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< std::pair< int, int > > WireHitRange
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 2539 of file ClusterCrawlerAlg.cxx.

References cluster::ClusterCrawlerAlg::VtxStore::CTP, cluster::ClusterCrawlerAlg::VtxStore::Fixed, cluster::ClusterCrawlerAlg::VtxStore::Time, cluster::ClusterCrawlerAlg::VtxStore::Topo, and cluster::ClusterCrawlerAlg::VtxStore::Wire.

2540  {
2541  // Checks the vertex (vw, fvt) against the existing set of vertices.
2542  // If there a match, clusters it1 and/or it2 are associated with it
2543  // if there is signal between the existing vertex and the start of
2544  // the cluster. The topo flag indicates the type of vertex that was
2545  // found: 1 = US of it1 && US of it2, 2 = US of it1 && DS of it2,
2546  // 3 = DS of it1 && US of it2, 4 = DS of it1 and DS of it2.
2547  // didit is set true if a cluster is attached to a (new or old) vertex
2548 
2549  if(vtxprt) mf::LogVerbatim("CC")<<" ChkVertex "
2550  <<tcl[it1].EndWir<<":"<<(int)tcl[it1].EndTim<<" - "<<tcl[it1].BeginWir<<":"<<(int)tcl[it1].BeginTim<<" and "
2551  <<tcl[it2].EndWir<<":"<<(int)tcl[it2].EndTim<<" - "<<tcl[it2].BeginWir<<":"<<(int)tcl[it2].BeginTim
2552  <<" topo "<<topo<<" fvw "<<fvw<<" fvt "<<fvt;
2553 
2554  unsigned int vw = (unsigned int)(0.5 + fvw);
2555  unsigned int iht;
2556 
2557  // don't make vertices using short tracks that are close to
2558  // long straight clusters. These are most likely due to numerous
2559  // short delta ray clusters
2560  if(tcl[it1].tclhits.size() < 10 && tcl[it2].tclhits.size() < 10) {
2561  for(unsigned short it = 0; it < tcl.size(); ++it) {
2562  if(it == it1 || it == it2) continue;
2563  if(tcl[it].ID < 0) continue;
2564  if(tcl[it].CTP != clCTP) continue;
2565  if(tcl[it].tclhits.size() < 100) continue;
2566  if(std::abs(tcl[it].BeginAng - tcl[it].EndAng) > 0.1) continue;
2567  // don't reject because it is near the end of a long cluster
2568  if(vw < tcl[it].EndWir + 5) continue;
2569  if(vw > tcl[it].BeginWir - 5) continue;
2570  for(unsigned short ii = 0; ii < tcl[it].tclhits.size(); ++ii) {
2571  iht = tcl[it].tclhits[ii];
2572  if(fHits[iht].WireID().Wire <= vw) {
2573  if(std::abs(fHits[iht].PeakTime() - fvt) < 60) return;
2574  } // fHits[iht].WireID().Wire <= vWire
2575  } // ii
2576  } // it
2577  }
2578 
2579 // if(vtxprt) mf::LogVerbatim("CC")<<" passed cut1";
2580 
2581  // check vertex and clusters for proximity to existing vertices
2582  unsigned short nFitOK = 0;
2583  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
2584  if(vtx[iv].CTP != clCTP) continue;
2585  // make this a really loose cut since the errors on the prospective vertex aren't known yet
2586  if(PointVertexChi(fvw, fvt, iv) > 300) continue;
2587  if(vtxprt) mf::LogVerbatim("CC")<<" vtx "<<iv<<" PointVertexChi "<<PointVertexChi(fvw, fvt, iv);
2588  // got a match. Check the appropriate cluster end and attach
2589  if( (topo == 1 || topo == 2) && tcl[it1].EndVtx < 0) {
2590  if(ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim)) {
2591  // try to fit
2592  tcl[it1].EndVtx = iv;
2593  FitVtx(iv);
2594  if(vtxprt) mf::LogVerbatim("CC")<<" FitVtx "<<iv<<" WireErr "<<vtx[iv].WireErr<<" ChiDOF "<<vtx[iv].ChiDOF;
2595  if(vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) {
2596  ++nFitOK;
2597  } else {
2598  // bad fit
2599  tcl[it1].EndVtx = -99;
2600  FitVtx(iv);
2601  } // check fit
2602  } // ChkSignal
2603 // if(vtxprt) mf::LogVerbatim("CC")<<" 12 Attach cl "<<tcl[it1].ID<<" to vtx? "<<iv;
2604  } else if( (topo == 3 || topo == 4) && tcl[it1].BeginVtx < 0) {
2605  if(ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim)) {
2606  tcl[it1].BeginVtx = iv;
2607  FitVtx(iv);
2608  if(vtxprt) mf::LogVerbatim("CC")<<" FitVtx "<<iv<<" WireErr "<<vtx[iv].WireErr<<" ChiDOF "<<vtx[iv].ChiDOF;
2609  if(vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) {
2610  ++nFitOK;
2611  } else {
2612  // bad fit
2613  tcl[it1].BeginVtx = -99;
2614  FitVtx(iv);
2615  } // bad fit
2616  } // ChkSignal
2617 // if(vtxprt) mf::LogVerbatim("CC")<<" 34 Attach cl "<<tcl[it1].ID<<" to vtx? "<<iv;
2618  } // cluster it2
2619  if( (topo == 1 || topo == 3) && tcl[it2].EndVtx < 0) {
2620  if(ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim)) {
2621  tcl[it2].EndVtx = iv;
2622  FitVtx(iv);
2623  if(vtxprt) mf::LogVerbatim("CC")<<" FitVtx "<<iv<<" WireErr "<<vtx[iv].WireErr<<" ChiDOF "<<vtx[iv].ChiDOF;
2624  if(vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) {
2625  ++nFitOK;
2626  } else {
2627  // bad fit
2628  tcl[it2].EndVtx = -99;
2629  FitVtx(iv);
2630  } // bad fit
2631  } // ChkSignal
2632  } else if( (topo == 2 || topo == 4) && tcl[it2].BeginVtx < 0) {
2633  if(ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim)) {
2634  tcl[it2].BeginVtx = iv;
2635  FitVtx(iv);
2636  if(vtxprt) mf::LogVerbatim("CC")<<" FitVtx "<<iv<<" WireErr "<<vtx[iv].WireErr<<" ChiDOF "<<vtx[iv].ChiDOF;
2637  if(vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) {
2638  ++nFitOK;
2639  } else {
2640  // bad fit
2641  tcl[it2].BeginVtx = -99;
2642  FitVtx(iv);
2643  } // bad fit
2644  } // ChkSignal
2645  } // cluster it2
2646  if(nFitOK > 0) {
2647  if(vtxprt) mf::LogVerbatim("CC")<<" Attached "<<nFitOK<<" clusters to vertex "<<iv;
2648  return;
2649  }
2650  } // iv
2651 
2652 // if(vtxprt) mf::LogVerbatim("CC")<<" passed cut2";
2653 
2654  // no match to existing vertices. Ensure that there is a wire signal between
2655  // the vertex and the appropriate ends of the clusters
2656  bool SigOK = false;
2657  if(topo == 1 || topo == 2) {
2658  SigOK = ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim);
2659 // if(vtxprt) mf::LogVerbatim("CC")<<" chk1 vtx W:T "<<vw<<":"<<(int)fvt<<" "<<tcl[it1].EndWir<<":"<<(int)tcl[it1].EndTim<<" SigOK "<<SigOK;
2660  } else {
2661  SigOK = ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim);
2662 // if(vtxprt) mf::LogVerbatim("CC")<<" chk1 vtx W:T "<<vw<<":"<<(int)fvt<<" "<<tcl[it1].BeginWir<<":"<<(int)tcl[it1].BeginTim<<" SigOK "<<SigOK;
2663  }
2664 // if(vtxprt) mf::LogVerbatim("CC")<<" SigOK it1 "<<SigOK;
2665  if(!SigOK) return;
2666 
2667  if(topo == 1 || topo == 3) {
2668  SigOK = ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim);
2669 // if(vtxprt) mf::LogVerbatim("CC")<<" chk2 vtx W:T "<<vw<<":"<<(int)fvt<<" "<<tcl[it2].EndWir<<":"<<(int)tcl[it2].EndTim<<" SigOK "<<SigOK;
2670  } else {
2671  SigOK = ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim);
2672 // if(vtxprt) mf::LogVerbatim("CC")<<" chk2 vtx W:T "<<vw<<":"<<(int)fvt<<" "<<tcl[it2].BeginWir<<":"<<(int)tcl[it2].BeginTim<<" SigOK "<<SigOK;
2673  }
2674 // if(vtxprt) mf::LogVerbatim("CC")<<" SigOK it2 "<<SigOK;
2675  if(!SigOK) return;
2676 
2677  VtxStore newvx;
2678  newvx.Wire = vw;
2679  newvx.Time = fvt;
2680  newvx.Topo = topo;
2681  newvx.CTP = clCTP;
2682  newvx.Fixed = false;
2683  vtx.push_back(newvx);
2684  unsigned short iv = vtx.size() - 1;
2685  if(topo == 1 || topo == 2) {
2686  if(tcl[it1].EndVtx >= 0) {
2687 // mf::LogError("CC")<<"ChkVertex: Coding error trying to make new vtx "<<iv<<"\n";
2688  vtx.pop_back();
2689  return;
2690  }
2691  tcl[it1].EndVtx = iv;
2692  } else {
2693  if(tcl[it1].BeginVtx >= 0) {
2694 // mf::LogError("CC")<<"ChkVertex: Coding error trying to make new vtx "<<iv<<"\n";
2695  vtx.pop_back();
2696  return;
2697  }
2698  tcl[it1].BeginVtx = iv;
2699  }
2700  if(topo == 1 || topo == 3) {
2701  if(tcl[it2].EndVtx >= 0) {
2702 // mf::LogError("CC")<<"ChkVertex: Coding error trying to make new vtx "<<iv<<"\n";
2703  vtx.pop_back();
2704  return;
2705  }
2706  tcl[it2].EndVtx = iv;
2707  } else {
2708  if(tcl[it2].BeginVtx >= 0) {
2709 // mf::LogError("CC")<<"ChkVertex: Coding error trying to make new vtx "<<iv<<"\n";
2710  vtx.pop_back();
2711  return;
2712  }
2713  tcl[it2].BeginVtx = iv;
2714  }
2715  // fit it
2716  FitVtx(iv);
2717  // reject it if the fit is bad
2718  if(vtx[iv].ChiDOF < 5 && vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].TimeErr < 20) {
2719  if(vtxprt) mf::LogVerbatim("CC")<<" New vtx "<<iv<<" in plane "<<plane<<" topo "<<topo<<" cls "<<tcl[it1].ID<<" "<<tcl[it2].ID<<" W:T "<<(int)vw<<":"<<(int)fvt<<" NClusters "<<vtx[iv].NClusters;
2720  // Try to refine the cluster hits and vertex position
2722  } else {
2723  if(vtxprt) mf::LogVerbatim("CC")<<" Bad vtx fit "<<vtx[iv].ChiDOF<<" wire err "<<vtx[iv].WireErr<<" TimeErr "<<vtx[iv].TimeErr;
2724  // clobber the vertex and references to it
2725  vtx.pop_back();
2726  if(tcl[it1].BeginVtx == iv) tcl[it1].BeginVtx = -99;
2727  if(tcl[it1].EndVtx == iv) tcl[it1].EndVtx = -99;
2728  if(tcl[it2].BeginVtx == iv) tcl[it2].BeginVtx = -99;
2729  if(tcl[it2].EndVtx == iv) tcl[it2].EndVtx = -99;
2730  } // bad fit
2731 
2732  } // ChkVertex()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< recob::Hit > fHits
our version of the hits
void RefineVertexClusters(unsigned short ivx)
float PointVertexChi(float wire, float tick, unsigned short ivx)
void cluster::ClusterCrawlerAlg::ClearResults ( )

Deletes all the results (might saves memory)

Note
The current implementation typically does NOT save memory.

Definition at line 142 of file ClusterCrawlerAlg.cxx.

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

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

Definition at line 4847 of file ClusterCrawlerAlg.cxx.

References util::absDiff(), max, and min.

4848  {
4849  // Check StartTick and EndTick of hits on adjacent wires overlap as illustrated below.
4850  // >>>>>> This is OK
4851  // Wire StartTick EndTick
4852  // n |--------------|
4853  // n+1 |--------------|
4854  // n+2 |--------------|
4855  // >>>>>> This is NOT OK
4856  // n |------|
4857  // n+1 |-----|
4858  // n+2 |------|
4859 
4860  if(fcl2hits.size() == 0) return true;
4861 // if(fAveHitWidth == 0) return true;
4862 
4863  unsigned short nHitToChk = fcl2hits.size();
4864  if(nHitChk > 0) nHitToChk = nHitChk + 1;
4865  unsigned short ii, indx;
4866 
4867  // require that they overlap
4868  // add a tolerance to the StartTick - EndTick overlap
4869  raw::TDCtick_t tol = 30;
4870  // expand the tolerance for induction planes
4871  if(plane < geom->Cryostat(cstat).TPC(tpc).Nplanes()-1) tol = 40;
4872 
4873  bool posSlope = (fHits[fcl2hits[0]].PeakTime() > fHits[fcl2hits[fcl2hits.size() - 1]].PeakTime());
4874 
4875  if(prt) {
4876  for(ii = 0; ii < nHitToChk; ++ii) {
4877  indx = fcl2hits.size() - 1 - ii;
4878  mf::LogVerbatim("CC")<<"ClusterHitsOK chk "<<fHits[fcl2hits[indx]].WireID().Wire<<" start "<<fHits[fcl2hits[indx]].StartTick()<<" peak "<<fHits[fcl2hits[indx]].PeakTime()<<" end "<<fHits[fcl2hits[indx]].EndTick()<<" posSlope "<<posSlope;
4879  }
4880  }
4881 
4882  raw::TDCtick_t hiStartTick, loEndTick;
4883  for(ii = 0; ii < nHitToChk - 1; ++ii) {
4884  indx = fcl2hits.size() - 1 - ii;
4885  // ignore if not on adjacent wires
4886  if(util::absDiff(fHits[fcl2hits[indx]].WireID().Wire, fHits[fcl2hits[indx-1]].WireID().Wire) > 1) continue;
4887  hiStartTick = std::max(fHits[fcl2hits[indx]].StartTick(), fHits[fcl2hits[indx-1]].StartTick());
4888  loEndTick = std::min(fHits[fcl2hits[indx]].EndTick(), fHits[fcl2hits[indx-1]].EndTick());
4889  if(posSlope) {
4890  if(loEndTick + tol < hiStartTick) {
4891 // if(prt) mf::LogVerbatim("CC")<<" bad overlap pos Slope "<<loEndTick<<" > "<<hiStartTick;
4892  return false;
4893  }
4894  } else {
4895  if(loEndTick + tol < hiStartTick) {
4896 // if(prt) mf::LogVerbatim("CC")<<" bad overlap neg Slope "<<loEndTick<<" < "<<hiStartTick;
4897  return false;
4898  }
4899  }
4900  } // ii
4901 // if(prt) mf::LogVerbatim("CC")<<" Cluster hits are OK";
4902  return true;
4903  } // ClusterHitsOK
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
int TDCtick_t
Type representing a TDC tick.
Definition: RawTypes.h:24
Int_t max
Definition: plot.C:27
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
std::vector< recob::Hit > fHits
our version of the hits
Int_t min
Definition: plot.C:26
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::ClusterInit ( )
private

Definition at line 166 of file ClusterCrawlerAlg.cxx.

167  {
168  fcl2hits.clear();
169  chifits.clear();
170  hitNear.clear();
171  chgNear.clear();
172  fAveChg = -1.;
173  fAveHitWidth = -1;
174 // unMergedHits.clear();
175  clEndChg = -1.;
176  clStopCode = 0;
177  clProcCode = pass;
178  }
std::vector< short > hitNear
float fAveChg
average charge at leading edge of cluster
float fAveHitWidth
average width (EndTick - StartTick) of hits
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
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 329 of file ClusterCrawlerAlg.cxx.

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

330  {
331  // looks for seed clusters in a plane and crawls along a trail of hits
332 
333  unsigned int nHitsUsed = 0, iwire, jwire, kwire;
334  bool AllDone = false, SigOK = false, HitOK = false;
335  unsigned int ihit, jhit;
336  for(unsigned short thispass = 0; thispass < fNumPass; ++thispass) {
337  pass = thispass;
338  // look for a starting cluster that spans a block of wires
339  unsigned int span = 3;
340  if(fMinHits[pass] < span) span = fMinHits[pass];
341  for(iwire = fLastWire; iwire > fFirstWire + span; --iwire) {
342  // skip bad wires or no hits on the wire
343  if(WireHitRange[iwire].first < 0) continue;
344  auto ifirsthit = (unsigned int)WireHitRange[iwire].first;
345  auto ilasthit = (unsigned int)WireHitRange[iwire].second;
346  for(ihit = ifirsthit; ihit < ilasthit; ++ihit) {
347  bool ClusterAdded = false;
348  recob::Hit const& hit = fHits[ihit];
349  // skip used hits
350  if(ihit > fHits.size()-1) {
351  mf::LogError("CC")<<"ClusterLoop bad ihit "<<ihit<<" fHits size "<<fHits.size();
352  return;
353  }
354  // skip used and obsolete hits
355  if(inClus[ihit] != 0) continue;
356  // skip narrow hits
357  if(fHits[ihit].PeakAmplitude() < fHitMinAmp) continue;
358 // prt = (fDebugPlane == (int)plane && (int)iwire == fDebugWire && std::abs((int)hit.PeakTime() - fDebugHit) < 20);
359  if((iwire + 1) < span) continue;
360  jwire = iwire - span + 1;
361  if(prt) mf::LogVerbatim("CC")<<"Found debug hit "<<PrintHit(ihit)<<" on pass"<<pass;
362  // skip if good wire and no hit
363  if(WireHitRange[jwire].first == -2) continue;
364  if(WireHitRange[jwire].first == -1) {
365  // Found a dead jwire. Keep looking upstream until we find a good wire
366  unsigned int nmissed = 0;
367  while(WireHitRange[jwire].first == -1 && jwire > 1 && nmissed < fMaxWirSkip[pass]) {
368  --jwire;
369  ++nmissed;
370  }
371  if(prt) mf::LogVerbatim("CC")<<" new jwire "<<jwire<<" dead? "<<WireHitRange[jwire].first;
372  if(WireHitRange[jwire].first < 0) continue;
373  } // dead jwire
374  // Find the hit on wire jwire that best matches a line between
375  // a nearby vertex and hit ihit. No constraint if useHit < 0
376  unsigned int useHit = 0;
377  bool doConstrain = false;
378  VtxConstraint(iwire, ihit, jwire, useHit, doConstrain);
379  unsigned int jfirsthit = (unsigned int)WireHitRange[jwire].first;
380  unsigned int jlasthit = (unsigned int)WireHitRange[jwire].second;
381  if(jfirsthit > fHits.size()-1 || jfirsthit > fHits.size()-1) throw art::Exception(art::errors::LogicError)
382  <<"ClusterLoop jwire "<<jwire<<" bad firsthit "<<jfirsthit<<" lasthit "<<jlasthit<<" fhits size "<<fHits.size();
383  // if(prt) mf::LogVerbatim("CC")<<" jhit range "<<jfirsthit<<" "<<jlasthit;
384  for(jhit = jfirsthit; jhit < jlasthit; ++jhit) {
385  if(jhit > fHits.size()-1) throw art::Exception(art::errors::LogicError)
386  <<"ClusterLoop bad jhit "<<jhit<<" firsthit "<<jfirsthit<<" lasthit "<<jlasthit<<" fhits size"<<fHits.size();
387  // Constraint?
388  if(doConstrain && jhit != useHit) continue;
389  recob::Hit const& other_hit = fHits[jhit];
390  // skip used and obsolete hits
391  if(inClus[jhit] != 0) continue;
392  // skip narrow hits
393  if(fHits[jhit].PeakAmplitude() < fHitMinAmp) continue;
394  // start a cluster with these two hits
395  ClusterInit();
396  fcl2hits.push_back(ihit);
397  chifits.push_back(0.);
398  hitNear.push_back(0);
399  chgNear.push_back(0); // These will be defined if the cluster survives the cuts
400  // enter the jhit
401  fcl2hits.push_back(jhit);
402  chifits.push_back(0.);
403  hitNear.push_back(0);
404  chgNear.push_back(0);
405  clLA = false;
406  clpar[0] = other_hit.PeakTime();
407  clpar[1] = (hit.PeakTime() - other_hit.PeakTime()) / (iwire - jwire);
408  // increase slope errors for large angle clusters
409  clparerr[1] = 0.2 * std::abs(clpar[1]);
410  clpar[2] = fHits[jhit].WireID().Wire;
411  clChisq = 0;
412  // now look for hits to add on the intervening wires
413  bool clok = false;
414  for(kwire = jwire+1; kwire < iwire; ++kwire) {
415  // ensure this cluster doesn't cross a vertex
416  if(CrawlVtxChk(kwire)) {
417  clok = false;
418  break;
419  }
420  AddHit(kwire, HitOK, SigOK);
421  if(prt) mf::LogVerbatim("CC")<<" HitOK "<<HitOK<<" clChisq "<<clChisq<<" cut "<<fChiCut[pass]<<" ClusterHitsOK "<<ClusterHitsOK(-1);
422  // No hit found
423  if(!HitOK) break;
424  // This should be a really good chisq
425  if(clChisq > 2) break;
426  // hit widths & overlap not consistent
427  if(!ClusterHitsOK(-1)) continue;
428  clok = true;
429  }
430  // drop it?
431  if(!clok) continue;
432  prt = (fDebugPlane == (int)plane && (int)iwire == fDebugWire && std::abs((int)hit.PeakTime() - fDebugHit) < 20);
433  if(prt) mf::LogVerbatim("CC")<<"ADD >>>>> Starting cluster with hits "<<PrintHit(fcl2hits[0])<<" "<<PrintHit(fcl2hits[1])<<" "<<PrintHit(fcl2hits[2])<<" on pass "<<pass;
434  // save the cluster begin info
435  clBeginWir = iwire;
436  clBeginTim = hit.PeakTime();
437  clBeginSlp = clpar[1];
438  // don't do a small angle crawl if the cluster slope is too large
439  // and Large Angle crawling is NOT requested on this pass
440  if(!fLACrawl[pass] && std::abs(clBeginSlp) > fLAClusSlopeCut) continue;
441  // See if we are trying to start a cluster between a vertex
442  // and a cluster that is associated to that vertex. If so, skip it
443  if(CrawlVtxChk2()) continue;
444  clBeginSlpErr = clparerr[1];
445  clBeginChg = 0;
446  // Calculate the average width
447  fAveHitWidth = 0;
448  float chg = 0;
449  for(unsigned short kk = 0; kk < fcl2hits.size(); ++kk) {
450  fAveHitWidth += fHits[fcl2hits[kk]].EndTick() - fHits[fcl2hits[kk]].StartTick();
451  chg += fHits[fcl2hits[kk]].Integral();
452  }
453  fAveHitWidth /= (float)fcl2hits.size();
454  // decide whether to crawl a large angle cluster. Requirements are:
455  // 1) the user has set the LACluster angle cut > 0, AND
456  // 2) the cluster slope exceeds the cut
457  // Note that if condition 1 is met, normal cluster crawling is done
458  // only if the slope is less than the cut
459  if(fLACrawl[pass] && fLAClusSlopeCut > 0) {
460  // LA cluster crawling requested
461  if(std::abs(clBeginSlp) > fLAClusSlopeCut) {
462  LACrawlUS();
463  } else {
464  CrawlUS();
465  } // std::abs(clBeginSlp) > fLAClusAngleCut
466  } else {
467  // allow clusters of any angle
468  CrawlUS();
469  } // fLAClusSlopeCut > 0
470  if(fcl2hits.size() >= fMinHits[pass]) {
471  // it's long enough so save it
472  clEndSlp = clpar[1]; // save the slope at the end
473  clEndSlpErr = clparerr[1];
474  // store the cluster
475  if(!TmpStore()) {
476  mf::LogError("CC")<<"Failed to store cluster in plane "<<plane;
477  continue;
478  }
479  ClusterAdded = true;
480  nHitsUsed += fcl2hits.size();
481  AllDone = (nHitsUsed == fHits.size());
482  break;
483  } else {
484  // abandon it
485  if(prt) mf::LogVerbatim("CC")<<"ClusterLoop: dropped the cluster";
486  }
487  if(ClusterAdded || AllDone) break;
488  } // jhit
489  if(AllDone) break;
490  } // ihit
491  if(AllDone) break;
492  } // iwire
493 
494  // try to merge clusters
495  if(fDoMerge[pass]) ChkMerge();
496  // form 2D vertices
497  if(fFindVertices[pass]) FindVertices();
498 
499  if(AllDone) break;
500 
501  } // pass
502 
503  // Kill Garbage clusters
504  if(fKillGarbageClusters > 0 && !tcl.empty()) KillGarbageClusters();
505  // Merge overlapping clusters
507  // Check the DS end of clusters
509  // split clusters using vertices
510  if(fVtxClusterSplit) {
511  bool didSomething = VtxClusterSplit();
512  // iterate once to handle the case where a cluster crosses two vertices
513  if(didSomething) VtxClusterSplit();
514  }
515  // Look for 2D vertices with star topology - short, back-to-back clusters
517 
518  if(fDebugPlane == (int)plane) {
519  mf::LogVerbatim("CC")<<"Clustering done in plane "<<plane;
520  PrintClusters();
521  }
522 
523 // if(unMergedHits.size() > 0) mf::LogError("CC")<<"Found unMergedHits > 0 after post-pass processing";
524 
526 
527  } // ClusterLoop()
std::vector< short > hitNear
bool ClusterHitsOK(short nHitChk)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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)
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
std::vector< ClusterStore > tcl
the clusters we are creating
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
std::vector< std::pair< int, int > > WireHitRange
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:219
std::vector< unsigned short > fMinHits
Min number of hits to make a cluster.
std::vector< float > chifits
fit chisq for monitoring kinks, etc
unsigned int clBeginWir
begin wire
void AddHit(unsigned int kwire, bool &HitOK, bool &SigOK)
std::vector< float > chgNear
charge near a cluster on each wire
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
std::vector< bool > fDoMerge
try to merge clusters?
void cluster::ClusterCrawlerAlg::ClusterVertex ( unsigned short  it2)
private

Definition at line 2456 of file ClusterCrawlerAlg.cxx.

2457  {
2458  // try to attach cluster it to an existing vertex
2459 
2460  if(vtx.size() == 0) return;
2461 
2462  unsigned short iv, jv;
2463  short dwib, dwjb, dwie, dwje;
2464  bool matchEnd, matchBegin;
2465 
2466 // if(vtxprt) mf::LogVerbatim("CC")<<"ClusterVertex: Try to attach cluster "<<tcl[it].ID<<" to existing vertices";
2467 
2468  for(iv = 0; iv < vtx.size(); ++iv) {
2469  // ignore vertices in the wrong cryostat/TPC/Plane
2470  if(vtx[iv].CTP != clCTP) continue;
2471  // ignore deleted vertices
2472  if(vtx[iv].NClusters == 0) continue;
2473  // determine which end to match - begin or end. Handle short tracks
2474  matchEnd = false; matchBegin = false;
2475  if(tcl[it].tclhits.size() < 6) {
2476  // See which end is closer to this vertex vs other vertices
2477  dwib = std::abs(vtx[iv].Wire - tcl[it].BeginWir);
2478  if(dwib > 2) dwib = 2;
2479  dwie = std::abs(vtx[iv].Wire - tcl[it].EndWir);
2480  if(dwie > 2) dwie = 2;
2481  dwjb = 999; dwje = 999;
2482  for(jv = 0; jv < vtx.size(); ++jv) {
2483  if(iv == jv) continue;
2484  if(std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50) {
2485  if(std::abs(vtx[jv].Wire - tcl[it].BeginWir) < dwjb)
2486  dwjb = std::abs(vtx[jv].Wire - tcl[it].BeginWir);
2487  } // std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50
2488  if(std::abs(vtx[jv].Time - tcl[it].EndTim) < 50) {
2489  if(std::abs(vtx[jv].Wire - tcl[it].EndWir) < dwje)
2490  dwje = std::abs(vtx[jv].Wire - tcl[it].EndWir);
2491  } // std::abs(vtx[jv].Time - tcl[it].EndTim) < 50
2492  } // jv
2493  matchEnd = tcl[it].EndVtx != iv &&
2494  dwie < 3 && dwie < dwje && dwie < dwib;
2495  matchBegin = tcl[it].BeginVtx != iv &&
2496  dwib < 3 && dwib < dwjb && dwib < dwie;
2497 // if(vtxprt) mf::LogVerbatim("CC")<<" dwib "<<dwib<<" dwie " <<dwie<<" dwjb "<<dwjb<<" dwje "<<dwje;
2498  } else {
2499  matchEnd = tcl[it].EndVtx < 0 && vtx[iv].Wire <= tcl[it].EndWir + 2;
2500  matchBegin = tcl[it].BeginVtx < 0 && vtx[iv].Wire >= tcl[it].BeginWir - 2;
2501  }
2502  if(matchEnd) {
2503  if(vtxprt) mf::LogVerbatim("CC")<<" Match End chi "<<ClusterVertexChi(it, 1, iv)<<" to vtx "<<iv
2504  <<" signalOK "<<ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim);
2505  if(ClusterVertexChi(it, 1, iv) < fVertex2DCut && ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim)) {
2506  // good match
2507  tcl[it].EndVtx = iv;
2508  // re-fit it
2509  FitVtx(iv);
2510  if(vtxprt) mf::LogVerbatim("CC")<<" Add End "<<tcl[it].ID<<" to vtx "<<iv<<" NClusters "<<vtx[iv].NClusters;
2511  if(vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut) return;
2512  if(vtxprt) mf::LogVerbatim("CC")<<" Bad fit. ChiDOF "<<vtx[iv].ChiDOF<<" WireErr "<<vtx[iv].WireErr<<" Undo it";
2513  tcl[it].EndVtx = -99;
2514  FitVtx(iv);
2515  } // tChi < 3
2516  } // matchEnd
2517 
2518  if(matchBegin) {
2519  if(vtxprt) mf::LogVerbatim("CC")<<" Match Begin chi "<<ClusterVertexChi(it, 0, iv)<<" to vtx "<<iv
2520  <<" signalOK "<<ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].BeginWir, tcl[it].BeginTim);
2521  if(ClusterVertexChi(it, 0, iv) < fVertex2DCut && ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].BeginWir, tcl[it].BeginTim)) {
2522  // good match
2523  tcl[it].BeginVtx = iv;
2524  // re-fit it
2525  FitVtx(iv);
2526  if(vtxprt) mf::LogVerbatim("CC")<<" Add Begin "<<tcl[it].ID<<" to vtx "<<iv<<" NClusters "<<vtx[iv].NClusters;
2527  if(vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut) return;
2528  if(vtxprt) mf::LogVerbatim("CC")<<" Bad fit. ChiDOF "<<vtx[iv].ChiDOF<<" WireErr "<<vtx[iv].WireErr<<" Undo it";
2529  tcl[it].BeginVtx = -99;
2530  FitVtx(iv);
2531  } // tChi < 3
2532  } // matchBegin
2533  } // iv
2534  } // ClusterVertex()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
CTP_t clCTP
Cryostat/TPC/Plane code.
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
std::vector< ClusterStore > tcl
the clusters we are creating
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 6320 of file ClusterCrawlerAlg.cxx.

References E.

6321  {
6322  // Returns the chisq/DOF between a cluster and a vertex
6323 
6324  if(icl > (short)tcl.size()) return 9999;
6325  if(ivx > vtx.size()) return 9999;
6326 
6327  float cwire, cslp, cslpErr, ctick;
6328  // figure out which cluster to use
6329  if(icl < 0) {
6330  if(fcl2hits.size() == 0) return 9999;
6331  // cluster under construction
6332  if(end == 0) {
6333  cwire = clBeginWir;
6334  cslp = clBeginSlp;
6335  cslpErr = clBeginSlpErr;
6336  ctick = clBeginTim;
6337  } else {
6338  cwire = clpar[2];
6339  cslp = clpar[1];
6340  cslpErr = clparerr[1];
6341  ctick = clpar[0];
6342  } // end
6343  } else {
6344  // tcl cluster
6345  if(end == 0) {
6346  cwire = tcl[icl].BeginWir;
6347  cslp = tcl[icl].BeginSlp;
6348  cslpErr = tcl[icl].BeginSlpErr;
6349  ctick = tcl[icl].BeginTim;
6350  } else {
6351  cwire = tcl[icl].EndWir;
6352  cslp = tcl[icl].EndSlp;
6353  cslpErr = tcl[icl].EndSlpErr;
6354  ctick = tcl[icl].EndTim;
6355  } // end
6356  }
6357 
6358  // Closest approach wire
6359  float docaW = (vtx[ivx].Wire + cslp * (vtx[ivx].Time - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6360  float dW = docaW - vtx[ivx].Wire;
6361  float chi = dW / vtx[ivx].WireErr;
6362  float totChi = chi * chi;
6363  dW = vtx[ivx].Wire - cwire;
6364  float dT = ctick + dW * cslp - vtx[ivx].Time;
6365  if(cslpErr < 1E-3) cslpErr = 1E-3;
6366  // increase slope error for large angle clusters
6367  cslpErr *= AngleFactor(cslp);
6368  // cluster slope projection error
6369  float dTErr = dW * cslpErr;
6370  // squared
6371  dTErr *= dTErr;
6372  // add the vertex time error^2 to the cluster projection error^2
6373  dTErr += vtx[ivx].TimeErr * vtx[ivx].TimeErr;
6374  if(dTErr < 1E-3) dTErr = 1E-3;
6375  totChi += dT * dT / dTErr;
6376  totChi /= 2;
6377 
6378  return totChi;
6379 
6380  } // ClusterVertexChi
Float_t E
Definition: plot.C:23
float clparerr[2]
cluster parameter errors
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
float clBeginSlp
begin slope (= DS end = high wire number)
unsigned int clBeginWir
begin wire
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::CrawlInit ( )
private

Definition at line 152 of file ClusterCrawlerAlg.cxx.

152  {
153  prt = false; vtxprt = false;
154  NClusters = 0; clBeginSlp = 0; clBeginSlpErr = 0; clBeginTim = 0;
155  clBeginWir = 0; clBeginChg = 0; clBeginChgNear = 0; clEndSlp = 0; clEndSlpErr = 0;
156  clEndTim = 0; clEndWir = 0; clEndChg = 0; clEndChgNear = 0; clChisq = 0;
157  clStopCode = 0; clProcCode = 0; fFirstWire = 0;
158  fLastWire = 0; fAveChg = 0.; fChgSlp = 0.; pass = 0;
159  fScaleF = 0; WireHitRange.clear();
160  // unMergedHits.clear();
161 
162  ClearResults();
163  }
float fScaleF
scale factor from Tick/Wire to dx/du
float fAveChg
average charge at leading edge of cluster
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)
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
float clChisq
chisq of the current fit
std::vector< std::pair< int, int > > WireHitRange
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 3876 of file ClusterCrawlerAlg.cxx.

3877  {
3878  // Crawl along a trail of hits moving upstream
3879 
3880  if(fcl2hits.size() < 2) return;
3881 
3882  unsigned int dhit = fcl2hits[0];
3883  int dwir = fHits[dhit].WireID().Wire;
3884  clLA = false;
3885 
3886  prt = false;
3887  if(fDebugPlane == (short)plane && dwir == fDebugWire && fDebugHit > 0)
3888  prt = std::abs(fHits[dhit].PeakTime() - fDebugHit) < 20;
3889 
3890  if(prt) {
3891  mf::LogVerbatim myprt("CC");
3892  myprt<<"******************* Start CrawlUS on pass "<<pass<<" Hits: ";
3893  for(unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3894  unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3895  myprt<<fHits[iht].WireID().Wire<<":"<<(int)fHits[iht].PeakTime()<<" ";
3896  }
3897  myprt<<"\n";
3898  }
3899 
3900  // SigOK = true if there is a ADC signal near the projected cluster position
3901  bool SigOK = true;
3902  bool HitOK = true;
3903  // count the number of missed hits on adjacent wires
3904  short nmissed = 0;
3905  // count the number of added hits after skipping
3906  short nHitAfterSkip = 0;
3907  bool DidaSkip = false;
3908  bool PostSkip = false;
3909  unsigned int it = fcl2hits.size() - 1;
3910  unsigned int lasthit = fcl2hits[it];
3911  if(lasthit > fHits.size() - 1) {
3912  mf::LogError("CC")<<"CrawlUS bad lasthit "<<lasthit;
3913  return;
3914  }
3915  unsigned int lastwire = fHits[lasthit].WireID().Wire;
3916  if(prt) mf::LogVerbatim("CC")<<"CrawlUS: last wire "<<lastwire<<" hit "<<lasthit;
3917 
3918  unsigned int lastWireWithSignal = lastwire;
3919  unsigned short nDroppedHit = 0;
3920 
3921  for(unsigned int nextwire = lastwire-1; nextwire > fFirstWire; --nextwire) {
3922  if(prt) mf::LogVerbatim("CC")<<"CrawlUS: next wire "<<nextwire<<" HitRange "<<WireHitRange[nextwire].first;
3923  // stop crawling if there is a nearby vertex
3924  if(CrawlVtxChk(nextwire)) {
3925  if(prt) mf::LogVerbatim("CC")<<"CrawlUS: stop at vertex";
3926  clStopCode = 6;
3927  break;
3928  }
3929  // Switch to large angle crawling?
3930  if(std::abs(clpar[1]) > fLAClusSlopeCut) {
3931  if(prt) mf::LogVerbatim("CC")<<">>>>> CrawlUS: Switching to LACrawlUS";
3932  LACrawlUS();
3933  return;
3934  }
3935  // add hits and check for PH and width consistency
3936  AddHit(nextwire, HitOK, SigOK);
3937  if(prt) mf::LogVerbatim("CC")<<"CrawlUS: HitOK "<<HitOK<<" SigOK "<<SigOK<<" nmissed "<<nmissed;
3938  if(SigOK) lastWireWithSignal = nextwire;
3939  if(!HitOK) {
3940  // no hit on this wire. Was there a signal or dead wire?
3941  if(SigOK) {
3942  // no hit on the wire but there is a signal
3943  ++nmissed;
3944 /*
3945  // stop if too many missed wires
3946  if(prt) mf::LogVerbatim("CC")<<" nmissed "<<nmissed<<" cut "<<fMaxWirSkip[pass];
3947  if(nmissed > fMaxWirSkip[pass]) {
3948  clStopCode = 1;
3949  break;
3950  }
3951 */
3952  // see if we are in the PostSkip phase and missed more than 1 wire
3953  if(PostSkip && nmissed > fMinWirAfterSkip[pass]) {
3954  // cluster is really short
3955  if((int)(fcl2hits.size() - nHitAfterSkip) < 4) {
3956 // RestoreUnMergedClusterHits(-1);
3957  fcl2hits.clear();
3958  return;
3959  }
3960  if(prt) mf::LogVerbatim("CC")<<" PostSkip && nmissed = "<<nmissed;
3961  clStopCode = 2;
3962  FclTrimUS(nHitAfterSkip);
3963  FitCluster();
3964  if(clChisq > 90.) {
3965 // RestoreUnMergedClusterHits(-1);
3966  fcl2hits.clear();
3967  return;
3968  }
3969  FitCluster();
3970  return;
3971  } // PostSkip && nmissed >
3972  if(nmissed > 1) {
3973  DidaSkip = true;
3974  PostSkip = false;
3975  }
3976  } // SigOK
3977  else {
3978  // SigOK is false
3979  clStopCode = 0;
3980  lasthit = fcl2hits[fcl2hits.size() - 1];
3981  if((lastWireWithSignal - nextwire) > fAllowNoHitWire) {
3982  if(prt) mf::LogVerbatim("CC")<<"No hit or signal on wire "<<nextwire<<" last wire with signal "<<lastWireWithSignal<<" exceeding fAllowNoHitWire "<<fAllowNoHitWire<<" Break!";
3983  break;
3984  }
3985  } // else SigOK false
3986  } // !HitOK
3987  else {
3988  if(prt) mf::LogVerbatim("CC")<<" CrawlUS check clChisq "<<clChisq<<" cut "<<fChiCut[pass];
3989  if(clChisq > fChiCut[pass]) {
3990  if(fcl2hits.size() < 3) {
3991  fcl2hits.clear();
3992  return;
3993  }
3994  // a fit error occurred. Lop off the leading hit and refit
3995  if(prt) mf::LogVerbatim("CC")<<"ADD- Bad clChisq "<<clChisq<<" dropping hit";
3996  FclTrimUS(1);
3997  FitCluster();
3998  ++nDroppedHit;
3999  if(nDroppedHit > 4) {
4000  if(prt) mf::LogVerbatim("CC")<<" Too many dropped hits: "<<nDroppedHit<<" Stop crawling";
4001  break;
4002  } // too many dropped hits
4003  if(clChisq > fChiCut[pass]) {
4004  if(prt) mf::LogVerbatim("CC")<<" Bad clChisq "<<clChisq<<" after dropping hit. Stop crawling";
4005  break;
4006  }
4007  FitClusterChg();
4008 /*
4009  // bail out if we have had repeated failures
4010  lasthit = fcl2hits[fcl2hits.size() - 1];
4011  if((fHits[lasthit].WireID().Wire - nextwire) > fMinWirAfterSkip[pass]) {
4012  if(prt) mf::LogVerbatim("CC")<<" Too many missed wires "<<(fHits[lasthit].WireID().Wire - nextwire)<<" cut "<<fMinWirAfterSkip[pass];
4013  break;
4014  }
4015 */
4016  continue;
4017  } // clChisq > fChiCut[0]
4018  // monitor the onset of a kink. Look for a progressive increase
4019  // in chisq for the previous 0 - 2 hits.
4020  if(chifits.size() > 5 && fKinkChiRat[pass] > 0) {
4021  if(chifits.size() != fcl2hits.size()) {
4022  mf::LogError("CC")<<"CrawlUS: chifits size error "<<chifits.size()<<" "<<fcl2hits.size();
4023  return;
4024  }
4025  unsigned short chsiz = chifits.size()-1;
4026  if(prt) mf::LogVerbatim("CC")<<"Kink chk "<<chifits[chsiz]<<" "<<chifits[chsiz-1]<<" "<<chifits[chsiz-2]<<" "<<chifits[chsiz-3];
4027  if( chifits[chsiz-1] > fKinkChiRat[pass] * chifits[chsiz-2] &&
4028  chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz-1]) {
4029  if(fcl2hits.size() != chifits.size()) {
4030  mf::LogError("CC")<<"bad kink check size "<<chifits.size()<<" "<<fcl2hits.size()<<" plane "<<plane<<" cluster "<<dwir<<":"<<dhit;
4031  continue;
4032  }
4033  if(EndKinkAngle() > fKinkAngCut[pass]) {
4034  if(prt) mf::LogVerbatim("CC")<<"******************* Stopped tracking - kink angle "<<EndKinkAngle()
4035  <<" > "<<fKinkAngCut[pass]<<" Removing 3 hits";
4036  // kill the last 3 hits and refit
4037  FclTrimUS(3);
4038  FitCluster();
4039  FitClusterChg();
4040  // set the kink stop code and quit
4041 // clStopCode = 3;
4042 // break;
4043  } // kinkang check
4044  } // chifits check
4045  } // chifits.size() > 5
4046  // done with kink check
4047  // update the cluster Begin information?
4048  if(fcl2hits.size() == fMaxHitsFit[pass] ||
4049  fcl2hits.size() == fMinHits[pass]) {
4050  clBeginSlp = clpar[1];
4051  clBeginSlpErr = clparerr[1];
4052  }
4053  // define the begin cluster charge if it's not defined yet
4054  if(clBeginChg <= 0 && fAveChg > 0) {
4055  clBeginChg = fAveChg;
4056  if(prt) mf::LogVerbatim("CC")<<" Set clBeginChg "<<clBeginChg;
4057  }
4058  // reset nmissed
4059  nmissed = 0;
4060  // start counting hits added after skipping
4061  if(DidaSkip) {
4062  // start PostSkip phase
4063  PostSkip = true;
4064  DidaSkip = false;
4065  nHitAfterSkip = 0;
4066  } // DidaSkip
4067  // check for PostSkip phase
4068  if(PostSkip) {
4069  // end the PostSkip phase if there are enough hits
4070  ++nHitAfterSkip;
4071  if(nHitAfterSkip == fMinWirAfterSkip[pass]) PostSkip = false;
4072  }
4073  // check for bad chisq
4074  if(clChisq > fChiCut[pass]) {
4075  if(prt) mf::LogVerbatim("CC")<<"<<ADD- Bad chisq "<<clChisq;
4076  // remove the last few hits if there is a systematic increase in chisq and re-fit
4077  float chirat;
4078  unsigned short lopped = 0;
4079  for(unsigned short nlop = 0; nlop < 4; ++nlop) {
4080  unsigned short cfsize = chifits.size() - 1;
4081  chirat = chifits[cfsize] / chifits[cfsize - 1];
4082  if(prt) mf::LogVerbatim("CC")<<"chirat "<<chirat<<" last hit "<<fcl2hits[fcl2hits.size()-1];
4083  if(chirat < 1.2) break;
4084  if(prt) mf::LogVerbatim("CC")<<"<<ADD- Bad chisq. Bad chirat "<<chirat;
4085  FclTrimUS(1);
4086  ++lopped;
4087  if(fcl2hits.size() < 6) break;
4088  if(chifits.size() < 6) break;
4089  } // nlop
4090  if(fcl2hits.size() < 6) {
4091  clStopCode = 4;
4092  if(prt) mf::LogVerbatim("CC")<<"Bad fit chisq - short cluster. Break";
4093  break;
4094  }
4095  if(lopped == 0 && fcl2hits.size() > 5) {
4096  if(prt) mf::LogVerbatim("CC")<<"<<ADD- Bad chisq. remove 1 hit";
4097  FclTrimUS(1);
4098  ++lopped;
4099  }
4100  FitCluster();
4101  FitClusterChg();
4102  if(prt) mf::LogVerbatim("CC")<<"Bad fit chisq - removed "<<lopped<<" hits. Continue";
4103  } // clChisq > fChiCut[pass]
4104  } // !HitOK check
4105  } // nextwire
4106  if(prt) mf::LogVerbatim("CC")<<"******************* CrawlUS normal stop. size "<<fcl2hits.size();
4107 
4108  bool reFit = false;
4109  // end kink angle check
4110  if(fcl2hits.size() > 5) {
4111  // check for a kink at the US end
4112  if(prt) mf::LogVerbatim("CC")<<"EndKinkAngle check "<<EndKinkAngle()<<" cut "<<fKinkAngCut[pass];
4113  if(EndKinkAngle() > fKinkAngCut[pass]) {
4114  if(prt) mf::LogVerbatim("CC")<<"EndKinkAngle removes 3 hits ";
4115  FclTrimUS(3);
4116  reFit = true;
4117  }
4118  } // fcl2hits.size() > 5
4119 
4120  // count the number of hits on adjacent wires at the leading edge and
4121  // ensure that the count is consistent with fMinWirAfterSkip
4122  if((unsigned short)fcl2hits.size() > fMinWirAfterSkip[pass] + 3) {
4123  unsigned int ih0 = fcl2hits.size() - 1;
4124  unsigned int hit0 = fcl2hits[ih0];
4125  unsigned int uswir = fHits[hit0].WireID().Wire;
4126  unsigned int nxtwir;
4127  unsigned short nAdjHit = 0;
4128  for(unsigned short ii = ih0 - 1; ii > 0; --ii) {
4129  nxtwir = fHits[ fcl2hits[ii] ].WireID().Wire;
4130  ++nAdjHit;
4131  if(nxtwir != uswir + 1) break;
4132  // break if there are enough hits
4133  if( nAdjHit == fMinWirAfterSkip[pass] ) break;
4134  uswir = nxtwir;
4135  } // ii
4136  // lop off hits?
4137  if(nAdjHit < fMinWirAfterSkip[pass]) {
4138  if(prt) mf::LogVerbatim("CC")<<"fMinWirAfterSkip removes "<<nAdjHit<<" hits ";
4139  FclTrimUS(nAdjHit);
4140  reFit = true;
4141  }
4142  } // fcl2hits.size() > fMinWirAfterSkip[pass] + 3
4143 
4144  // check for a bad hit on the end
4145  if(!reFit && fcl2hits.size() > 3) {
4146  float chirat = chifits[chifits.size()-1] / chifits[chifits.size()-2];
4147  if(prt) mf::LogVerbatim("CC")<<"Last hit chirat "<<chirat<<" cut "<<fKinkChiRat[pass];
4148  if(prt) mf::LogVerbatim("CC")<<"Check "<<clChisq<<" "<<chifits[chifits.size()-1]<<" "<<chifits[chifits.size()-2];
4149  if(chirat > fKinkChiRat[pass]) {
4150  if(prt) mf::LogVerbatim("CC")<<"<<ADD- at end";
4151  FclTrimUS(1);
4152  reFit = true;
4153  }
4154  } // !reFit
4155 
4156  if(reFit) {
4157  FitCluster();
4158  FitClusterChg();
4159  }
4161  if(prt) mf::LogVerbatim("CC")<<"******************* CrawlUS done. Size "
4162  <<fcl2hits.size()<<" min length for this pass "<<fMinHits[pass];
4163 
4164  prt = false;
4165  } // CrawlUS()
float fAveChg
average charge at leading edge of cluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
float clparerr[2]
cluster parameter errors
float clBeginChg
begin average charge
std::vector< unsigned short > fMinWirAfterSkip
after skipping
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
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.
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
float clChisq
chisq of the current fit
std::vector< std::pair< int, int > > WireHitRange
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 1306 of file ClusterCrawlerAlg.cxx.

1307  {
1308 
1309  // returns true if the cluster is near a vertex on wire kwire
1310  if(vtx.size() == 0) return false;
1311  unsigned int iht = fcl2hits.size() - 1;
1312  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1313  float prtime = clpar[0] + (kwire - wire0) * clpar[1];
1314  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
1315  if(vtx[iv].CTP != clCTP) continue;
1316  if((unsigned int)(0.5 + vtx[iv].Wire) != kwire) continue;
1317  if(std::abs(prtime - vtx[iv].Time) < 10) return true;
1318  }
1319  return false;
1320  } // CrawlVtxChk()
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< recob::Hit > fHits
our version of the hits
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
bool cluster::ClusterCrawlerAlg::CrawlVtxChk2 ( )
private

Definition at line 1271 of file ClusterCrawlerAlg.cxx.

1272  {
1273  // returns true if the (presumably short) cluster under construction
1274  // resides between a vertex and another cluster that is associated with
1275  // that vertex
1276 
1277  if(vtx.size() == 0) return false;
1278  if(fcl2hits.size() == 0) return false;
1279 
1280  unsigned int iht = fcl2hits.size() - 1;
1281  unsigned short icl;
1282  float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1283  float dt;
1284  float thclus = std::atan(fScaleF * clpar[1]);
1285 
1286  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
1287  if(vtx[iv].CTP != clCTP) continue;
1288  if(wire0 < vtx[iv].Wire) continue;
1289  if(wire0 > vtx[iv].Wire + 10) continue;
1290  dt = clpar[0] + (vtx[iv].Wire - wire0) * clpar[1] - vtx[iv].Time;
1291  if(std::abs(dt) > 10) continue;
1292  // cluster points to an US vertex. See if the angle is similar to
1293  // cluster associated with this vertex
1294  for(icl = 0; icl < tcl.size(); ++icl) {
1295  if(tcl[icl].CTP != clCTP) continue;
1296  if(tcl[icl].EndVtx != iv) continue;
1297  if(std::abs(tcl[icl].EndAng - thclus) < fKinkAngCut[pass]) return true;
1298  }
1299  }
1300 
1301  return false;
1302 
1303  } // CrawlVtxChk2()
float fScaleF
scale factor from Tick/Wire to dx/du
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
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 ( )
private

Definition at line 6204 of file ClusterCrawlerAlg.cxx.

6205  {
6206  // Counts the number of dead wires in the range spanned by fcl2hits
6207  if(fcl2hits.size() < 2) return 0;
6208  unsigned int wire, ndead = 0;
6209  unsigned int iht = fcl2hits[fcl2hits.size()-1];
6210  unsigned int eWire = fHits[iht].WireID().Wire;
6211  iht = fcl2hits[0];
6212  unsigned int bWire = fHits[iht].WireID().Wire + 1;
6213  for(wire = eWire; wire < bWire; ++wire) if(WireHitRange[wire].first == -1) ++ndead;
6214  return ndead;
6215  } // 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 6189 of file ClusterCrawlerAlg.cxx.

References tmp.

6190  {
6191  if(inWire1 > inWire2) {
6192  // put in increasing order
6193  unsigned int tmp = inWire1;
6194  inWire1 = inWire2;
6195  inWire2 = tmp;
6196  } // inWire1 > inWire2
6197  ++inWire2;
6198  unsigned int wire, ndead = 0;
6199  for(wire = inWire1; wire < inWire2; ++wire) if(WireHitRange[wire].first == -1) ++ndead;
6200  return ndead;
6201  } // DeadWireCount
Float_t tmp
Definition: plot.C:37
std::vector< std::pair< int, int > > WireHitRange
static geo::PlaneID cluster::ClusterCrawlerAlg::DecodeCTP ( CTP_t  CTP)
inlinestatic

Definition at line 48 of file ClusterCrawlerAlg.h.

References CTPpad.

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

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

Definition at line 6277 of file ClusterCrawlerAlg.cxx.

6278  {
6279  // Find the Distance of Closest Approach betweeen a cluster and a point (vwire, vtick). The
6280  // DoCA is returned in Tick units.
6281 
6282  if(icl > (short)tcl.size()) return 9999;
6283 
6284  float cwire, cslp, ctick;
6285  // figure out which cluster to use
6286  if(icl < 0) {
6287  if(fcl2hits.size() == 0) return 9999;
6288  // cluster under construction
6289  if(end == 0) {
6290  cwire = clBeginWir;
6291  cslp = clBeginSlp;
6292  ctick = clBeginTim;
6293  } else {
6294  cwire = clpar[2];
6295  cslp = clpar[1];
6296  ctick = clpar[0];
6297  } // end
6298  } else {
6299  // tcl cluster
6300  if(end == 0) {
6301  cwire = tcl[icl].BeginWir;
6302  cslp = tcl[icl].BeginSlp;
6303  ctick = tcl[icl].BeginTim;
6304  } else {
6305  cwire = tcl[icl].EndWir;
6306  cslp = tcl[icl].EndSlp;
6307  ctick = tcl[icl].EndTim;
6308  } // end
6309  }
6310 
6311  // Closest approach wire
6312  float docaW = (vwire + cslp * (vtick - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6313  float dW = docaW - vwire;
6314  float dT = ctick + (vwire - cwire) * cslp - vtick;
6315  return sqrt(dW * dW + dT * dT);
6316 
6317  } // DoCA
std::vector< ClusterStore > tcl
the clusters we are creating
float clBeginSlp
begin slope (= DS end = high wire number)
unsigned int clBeginWir
begin wire
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
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 3303 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.

3304  {
3305  // Merge clusters.
3306 
3307  ClusterStore& cl1 = tcl[it1];
3308  ClusterStore& cl2 = tcl[it2];
3309 
3310  if(cl1.tclhits.size() < 3) return;
3311  if(cl2.tclhits.size() < 3) return;
3312 /*
3313  bool myprt = false;
3314  if(plane == 1 && cl1.ID == 84 && cl2.ID == 63) myprt = true;
3315 */
3316 
3317  unsigned int lowire, hiwire, whsize, ii, iht, indx;
3318  // do a fit across the boundary between cl1 and cl2 to
3319  // ensure that they truly should be merged
3320  unsigned int fithit;
3321  // Find the low and high wire for both clusters.
3322  // Assume that cluster 1 is DS
3323  bool cl1DS = true;
3324  hiwire = cl1.BeginWir;
3325  fithit = cl1.tclhits[cl1.tclhits.size() - 2];
3326  if(cl2.BeginWir > hiwire) {
3327  hiwire = cl2.BeginWir;
3328  fithit = cl2.tclhits[cl2.tclhits.size() - 2];
3329  cl1DS = false;
3330  }
3331  lowire = cl1.EndWir;
3332  if(cl2.EndWir < lowire) lowire = cl2.EndWir;
3333 
3334  // make a vector of wire hits
3335  whsize = hiwire + 2 - lowire;
3336  std::vector<int> wirehit(whsize, -1);
3337  // put in the hit IDs for cluster 2
3338  for(ii = 0; ii < cl2.tclhits.size(); ++ii) {
3339  iht = cl2.tclhits[ii];
3340  indx = fHits[iht].WireID().Wire - lowire;
3341  wirehit[indx] = iht;
3342  } // iht
3343  // now cluster 1
3344  for(ii = 0; ii < cl1.tclhits.size(); ++ii) {
3345  iht = cl1.tclhits[ii];
3346  indx = fHits[iht].WireID().Wire - lowire;
3347  wirehit[indx] = iht;
3348 /*
3349  if(myprt) mf::LogVerbatim("CC")
3350  <<"Cl1 hit "<<wire<<":"<<(int)fHits[hit].PeakTime()
3351  <<" wire index "<<index<<" hit index "<<hit;
3352 */
3353  } // iht
3354  // make the new cluster
3355  fcl2hits.clear();
3356  for(std::vector<int>::reverse_iterator rit = wirehit.rbegin(); rit != wirehit.rend(); ++rit) {
3357  if(*rit < 0) continue;
3358  fcl2hits.push_back(*rit);
3359  } // rit
3360 
3361  // fit the 6 hits that are near the merging point
3362  short nhitfit = 6;
3363  FitClusterMid(fcl2hits, fithit, nhitfit);
3364 // std::cout<<"Merge "<<cl1.ID<<" "<<cl2.ID<<" clChisq "<<clChisq<<"\n";
3365  if(clChisq > 5) return;
3366 
3367  // mark cl1 and cl2 obsolete
3368  MakeClusterObsolete(it1);
3369  MakeClusterObsolete(it2);
3370 
3371  short endVtx = 0;
3372  short begVtx = 0;
3373  short del1Vtx = -99;
3374  short del2Vtx = -99;
3375  if(cl1DS) {
3376  // use cluster 1 Begin info
3377  clBeginSlp = cl1.BeginSlp;
3378  clBeginSlpErr = cl1.BeginSlpErr;
3379  clBeginAng = cl1.BeginAng;
3380  clBeginWir = cl1.BeginWir;
3381  clBeginTim = cl1.BeginTim;
3382  clBeginChg = cl1.BeginChg;
3383  clBeginChgNear = cl1.BeginChgNear;
3384  begVtx = cl1.BeginVtx;
3385  del1Vtx = cl1.EndVtx;
3386  // and cluster 2 End info
3387  clEndSlp = cl2.EndSlp;
3388  clEndSlpErr = cl2.EndSlpErr;
3389  clEndAng = cl2.EndAng;
3390  clEndWir = cl2.EndWir;
3391  clEndTim = cl2.EndTim;
3392  clEndChg = cl2.EndChg;
3393  clEndChgNear = cl2.EndChgNear;
3394  endVtx = cl2.EndVtx;
3395  del2Vtx = cl2.BeginVtx;
3396  clStopCode = cl2.StopCode;
3397  } else {
3398  // use cluster 2 Begin info
3399  clBeginSlp = cl2.BeginSlp;
3400  clBeginSlpErr = cl2.BeginSlpErr;
3401  clBeginAng = cl2.BeginAng;
3402  clBeginWir = cl2.BeginWir;
3403  clBeginTim = cl2.BeginTim;
3404  clBeginChg = cl2.BeginChg;
3405  clBeginChgNear = cl2.BeginChgNear;
3406  begVtx = cl2.BeginVtx;
3407  del2Vtx = cl2.EndVtx;
3408  // and cluster 1 End info
3409  clEndSlp = cl1.EndSlp;
3410  clEndSlpErr = cl1.EndSlpErr;
3411  clEndWir = cl1.EndWir;
3412  clEndTim = cl1.EndTim;
3413  clEndChg = cl1.EndChg;
3414  clEndChgNear = cl1.EndChgNear;
3415  endVtx = cl1.EndVtx;
3416  del1Vtx = cl1.BeginVtx;
3417  clStopCode = cl1.StopCode;
3418  }
3419 
3420  // append it to the tcl vector
3421  clCTP = cl1.CTP;
3422  if(!TmpStore()) return;
3423  unsigned short itnew = tcl.size()-1;
3424  if(prt) mf::LogVerbatim("CC")<<"DoMerge "<<cl1.ID<<" "<<cl2.ID<<" -> "<<tcl[itnew].ID;
3425  // stuff the processor code with the current pass
3426  tcl[itnew].ProcCode = inProcCode + pass;
3427  // transfer the vertex info
3428  // delete a vertex between these two?
3429  if(del1Vtx >= 0 && del1Vtx == del2Vtx) vtx[del1Vtx].NClusters = 0;
3430  // preserve the vertex assignments
3431  tcl[itnew].BeginVtx = begVtx;
3432  tcl[itnew].EndVtx = endVtx;
3433  } // DoMerge
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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.
std::vector< ClusterStore > tcl
the clusters we are creating
unsigned int clEndWir
begin wire
std::vector< VtxStore > vtx
the endpoints we are reconstructing
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)
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
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
static CTP_t cluster::ClusterCrawlerAlg::EncodeCTP ( unsigned int  cryo,
unsigned int  tpc,
unsigned int  plane 
)
inlinestatic

Definition at line 44 of file ClusterCrawlerAlg.h.

References plane.

Referenced by EncodeCTP().

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

Definition at line 46 of file ClusterCrawlerAlg.h.

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

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

Definition at line 4168 of file ClusterCrawlerAlg.cxx.

4169  {
4170  // find the kink angle (crudely) from the 0th and 2nd hit on the cluster under construction
4171 
4172  unsigned int ih0 = fcl2hits.size() - 1;
4173  unsigned int hit0 = fcl2hits[ih0];
4174  unsigned int ih2 = ih0 - 2;
4175  unsigned int hit2 = fcl2hits[ih2];
4176  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
4177  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
4178  float th02 = std::atan( fScaleF * dt02 / dw02);
4179  // and the 3rd and 5th hit
4180  unsigned int ih3 = ih2 - 1;
4181  unsigned int hit3 = fcl2hits[ih3];
4182  unsigned int ih5 = ih3 - 2;
4183  unsigned int hit5 = fcl2hits[ih5];
4184  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
4185  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
4186  float th35 = std::atan(fScaleF * dt35 / dw35);
4187  return std::abs(th02 - th35);
4188  }
float fScaleF
scale factor from Tick/Wire to dx/du
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 882 of file ClusterCrawlerAlg.cxx.

883  {
884 
885  // Trims nTrim hits off the UpStream end of the fcl2hits, etc vectors.
886  if(nTrim == 0) return;
887 
888  if(nTrim >= fcl2hits.size()) nTrim = fcl2hits.size();
889 
890 // RestoreUnMergedClusterHits((short)nTrim);
891  for(unsigned short ii = 0; ii < nTrim; ++ii) {
892  fcl2hits.pop_back();
893  chifits.pop_back();
894  hitNear.pop_back();
895  chgNear.pop_back();
896  } // ii
897 
898  } // 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 ( )
private

Definition at line 5638 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorProperties::ConvertTicksToX(), cluster::ClusterCrawlerAlg::Vtx3Store::CStat, cluster::ClusterCrawlerAlg::VtxStore::CTP, e, tca::EncodeCTP(), cluster::ClusterCrawlerAlg::VtxStore::Fixed, geo::TPCGeo::LocalToWorld(), cluster::ClusterCrawlerAlg::Vtx3Store::ProcCode, cluster::ClusterCrawlerAlg::Vtx3Store::Ptr2D, 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.

5639  {
5640  // look for a long cluster that stops at a short cluster in two views. This can occur in a CCmu
5641  // interaction where two protons are emitted back-to-back and are therefore reconstructed as one cluster
5642  // This routine looks for this signature, and if found, splits the short clusters and creates a new 3D vertex.
5643  // This routine only considers the case where the long cluster intersects the short cluster at the US (End) end.
5644 
5645  unsigned int nPln = geom->Cryostat(cstat).TPC(tpc).Nplanes();
5646  if(nPln != 3) return;
5647 
5648  float ew1, ew2, bw2, fvw;
5649 
5650  struct Hammer {
5651  bool Used;
5652  unsigned int Wire; // intersection point of the long cluster and the short cluster
5653  float Tick; // intersection point of the long cluster and the short cluster
5654  float X;
5655  unsigned short longClIndex;
5656  unsigned short shortClIndex;
5657  unsigned short splitPos;
5658  };
5659  std::array< std::vector<Hammer>, 3> hamrVec;
5660 
5661  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
5662 
5663  unsigned int ipl;
5664  bool useit = false;
5665  for(ipl = 0; ipl < 3; ++ipl) {
5666  clCTP = EncodeCTP(cstat, tpc, ipl);
5667  for(unsigned short ic1 = 0; ic1 < tcl.size(); ++ic1) {
5668  if(tcl[ic1].ID < 0) continue;
5669  // require a long cluster
5670  if(tcl[ic1].tclhits.size() < 20) continue;
5671  if(tcl[ic1].CTP != clCTP) continue;
5672  // ignore long clusters with an End vertex assignment
5673  if(tcl[ic1].EndVtx >= 0) continue;
5674  ew1 = tcl[ic1].EndWir;
5675  for(unsigned short ic2 = 0; ic2 < tcl.size(); ++ic2) {
5676  if(tcl[ic2].ID < 0) continue;
5677  // require a short cluster
5678  if(tcl[ic2].tclhits.size() > 20) continue;
5679  // but not too short cluster
5680  if(tcl[ic2].tclhits.size() < 6) continue;
5681  if(tcl[ic2].CTP != clCTP) continue;
5682  ew2 = tcl[ic2].EndWir;
5683  bw2 = tcl[ic2].BeginWir;
5684  // check the US end. The End of the long cluster must lie between the Begin and End wire of the
5685  // short cluster
5686  if(ew1 < ew2 || ew1 > bw2 ) continue;
5687  // look for intersection of the two clusters
5688  float best = 10;
5689  short ibst = -1;
5690  unsigned short spos = 0;
5691  for(unsigned short ii = 0; ii < tcl[ic2].tclhits.size(); ++ii) {
5692  unsigned int iht = tcl[ic2].tclhits[ii];
5693  float dw = fHits[iht].WireID().Wire - tcl[ic1].EndWir;
5694  float dt = fabs(fHits[iht].PeakTime() - tcl[ic1].EndTim - tcl[ic1].EndSlp * dw);
5695  if(dt < best) {
5696  best = dt;
5697  ibst = iht;
5698  spos = ii;
5699  }
5700  } // ii
5701  if(ibst < 0) continue;
5702  fvw = 0.5 + fHits[ibst].WireID().Wire;
5703  Hammer aHam;
5704  aHam.Used = false;
5705  aHam.Wire = (0.5 + fvw);
5706  aHam.Tick = fHits[ibst].PeakTime();
5707  aHam.X = detprop->ConvertTicksToX((double)aHam.Tick, (int)ipl, (int)tpc, (int)cstat);
5708 // std::cout<<"aHam "<<" fvw "<<fvw<<" X "<<aHam.X<<" ic1 ID "<<tcl[ic1].ID<<" ic2 ID "<<tcl[ic2].ID<<"\n";
5709  aHam.longClIndex = ic1;
5710  aHam.shortClIndex = ic2;
5711  aHam.splitPos = spos;
5712  unsigned short indx = hamrVec[ipl].size();
5713  hamrVec[ipl].resize(indx + 1);
5714  hamrVec[ipl][indx] = aHam;
5715 // hamrVec[ipl].push_back(aHam);
5716  useit = true;
5717  } // ic2
5718  if(useit) break;
5719  } // ic1
5720  } // ipl
5721 
5722  unsigned short noham = 0;
5723  for(ipl = 0; ipl < 3; ++ipl) if(hamrVec[ipl].size() == 0) ++noham;
5724  if(noham > 1) return;
5725 
5726  // Y,Z limits of the detector
5727  double local[3] = {0.,0.,0.};
5728  double world[3] = {0.,0.,0.};
5729 
5730  const geo::TPCGeo &thetpc = geom->TPC(tpc, cstat);
5731  thetpc.LocalToWorld(local,world);
5732  float YLo = world[1]-geom->DetHalfHeight(tpc,cstat) + 1;
5733  float YHi = world[1]+geom->DetHalfHeight(tpc,cstat) - 1;
5734  float ZLo = world[2]-geom->DetLength(tpc,cstat)/2 + 1;
5735  float ZHi = world[2]+geom->DetLength(tpc,cstat)/2 - 1;
5736 
5737  // Match in 3D
5738  float dX;
5739  double y, z;
5740  unsigned short icl, jpl, jcl, kpl, splitPos;
5741  for(ipl = 0; ipl < 3; ++ipl) {
5742  if(hamrVec[ipl].size() == 0) continue;
5743  jpl = (ipl + 1) % nPln;
5744  kpl = (jpl + 1) % nPln;
5745  for(unsigned short ii = 0; ii < hamrVec[ipl].size(); ++ii) {
5746  if(hamrVec[ipl][ii].Used) continue;
5747  for(unsigned short jj = 0; jj < hamrVec[jpl].size(); ++jj) {
5748  if(hamrVec[jpl][jj].Used) continue;
5749  dX = hamrVec[ipl][ii].X - hamrVec[jpl][jj].X;
5750  if(fabs(dX) > fVertex3DCut) continue;
5751  geom->IntersectionPoint(hamrVec[ipl][ii].Wire, hamrVec[jpl][jj].Wire, ipl, jpl, cstat, tpc, y, z);
5752  if(y < YLo || y > YHi || z < ZLo || z > ZHi) continue;
5753  // mark them used
5754  hamrVec[ipl][ii].Used = true;
5755  hamrVec[jpl][jj].Used = true;
5756  // make a new 3D vertex
5757  Vtx3Store newVtx3;
5758  newVtx3.ProcCode = 7;
5759  newVtx3.X = 0.5 * (hamrVec[ipl][ii].X + hamrVec[jpl][jj].X);
5760  // TODO: do this correctly;
5761  newVtx3.XErr = fabs(hamrVec[ipl][ii].X - hamrVec[jpl][jj].X);
5762  newVtx3.Y = y;
5763  newVtx3.YErr = 1; // TODO
5764  newVtx3.Z = z;
5765  newVtx3.ZErr = 1; // TODO
5766  newVtx3.CStat = cstat;
5767  newVtx3.TPC = tpc;
5768 
5769  // make 2D vertex in ipl
5770  VtxStore newVtx2;
5771  newVtx2.Wire = hamrVec[ipl][ii].Wire;
5772  newVtx2.WireErr = 2;
5773  newVtx2.Time = hamrVec[ipl][ii].Tick;
5774  newVtx2.TimeErr = 5;
5775  newVtx2.Topo = 6;
5776  newVtx2.Fixed = false;
5777  icl = hamrVec[ipl][ii].longClIndex;
5778  newVtx2.CTP = tcl[icl].CTP;
5779  vtx.push_back(newVtx2);
5780  unsigned short ivnew = vtx.size() - 1;
5781  // associate the new vertex with the long cluster
5782  tcl[icl].EndVtx = ivnew;
5783  FitVtx(ivnew);
5784  // stash the index in newVtx3
5785  newVtx3.Ptr2D[ipl] = (short)ivnew;
5786  // split the short cluster and associate the new clusters with the new vtx
5787  icl = hamrVec[ipl][ii].shortClIndex;
5788  splitPos = hamrVec[ipl][ii].splitPos;
5789  if(!SplitCluster(icl, splitPos, ivnew)) return;
5790 
5791  // make 2D vertex in jpl
5792  newVtx2.Wire = hamrVec[jpl][jj].Wire;
5793  newVtx2.Time = hamrVec[jpl][jj].Tick;
5794  newVtx2.Topo = 6;
5795  jcl = hamrVec[jpl][jj].longClIndex;
5796  newVtx2.CTP = tcl[jcl].CTP;
5797  vtx.push_back(newVtx2);
5798  ivnew = vtx.size() - 1;
5799 // std::cout<<"newVtx2 jpl index "<<vtx.size()-1<<" CTP "<<newVtx2.CTP<<"\n";
5800  // associate the new vertex with the long cluster
5801  tcl[jcl].EndVtx = ivnew;
5802  // stash the index in newVtx3
5803  newVtx3.Ptr2D[jpl] = (short)(vtx.size() - 1);
5804  // split the short cluster and associate the new clusters with the new vtx
5805  jcl = hamrVec[jpl][jj].shortClIndex;
5806  splitPos = hamrVec[jpl][jj].splitPos;
5807  if(!SplitCluster(jcl, splitPos, vtx.size() - 1)) return;
5808  FitVtx(ivnew);
5809 // std::cout<<"Split jpl "<<jpl<<" cl ID "<<tcl[jcl].ID<<" pos "<<splitPos<<" vtx "<<vtx.size()-1<<"\n";
5810 
5811  // set the kpl 2D vertex index < 0. Let follow-on code find the 3rd plane vertex
5812  newVtx3.Ptr2D[kpl] = -1;
5813  double WPos[3] = {0, y, z};
5814  try{
5815  newVtx3.Wire = geom->NearestWire(WPos, kpl, tpc, cstat);
5816  }
5817  catch(geo::InvalidWireError const& e) {
5818  newVtx3.Wire = e.suggestedWireID().Wire; // pick the closest valid wire
5819  }
5820 // std::cout<<"3D Vtx "<<ipl<<":"<<ii<<" "<<jpl<<":"<<jj<<" kpl "<<kpl<<" wire "<<newVtx3.Wire<<"\n";
5821  vtx3.push_back(newVtx3);
5822  } // jj
5823  } // ii
5824  }
5825 
5826  } // FindHammerClusters
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
void FitVtx(unsigned short iv)
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
Geometry information for a single TPC.
Definition: TPCGeo.h:37
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
art::ServiceHandle< geo::Geometry > geom
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< ClusterStore > tcl
the clusters we are creating
geo::Length_t DetHalfHeight(geo::TPCID const &tpcid) const
Returns the half height of the active volume of the specified TPC.
std::vector< VtxStore > vtx
the endpoints we are reconstructing
geo::WireID::WireID_t NearestWire(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the index of wire closest to position in the specified TPC.
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
bool IntersectionPoint(geo::WireID const &wid1, geo::WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
std::vector< recob::Hit > fHits
our version of the hits
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
Float_t e
Definition: plot.C:34
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
Float_t X
Definition: plot.C:39
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
Definition: TPCGeo.h:490
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 6227 of file ClusterCrawlerAlg.cxx.

6228  {
6229  std::pair<size_t, size_t> range{ iHit, iHit };
6230 
6231  range.first = iHit - fHits[iHit].LocalIndex();
6232  range.second = range.first + fHits[iHit].Multiplicity();
6233 
6234  return range;
6235 /*
6236  const raw::TDCtick_t MultipletStartTime = fHits[iHit].StartTick();
6237  geo::WireID const& wid = fHits[iHit].WireID();
6238 
6239  // detect the first hit with the same start time as the reference hit
6240  while (range.first > 0) {
6241  if (fHits[range.first - 1].StartTick() != MultipletStartTime) break;
6242  if (fHits[range.first - 1].WireID() != wid) break;
6243  --range.first;
6244  } // while
6245 
6246  // detect the last hit with the same start time as the reference hit
6247  while (++range.second < fHits.size()) {
6248  if (fHits[range.second].StartTick() != MultipletStartTime) break;
6249  if (fHits[range.second].WireID() != wid) break;
6250  } // while
6251  return range;
6252  */
6253  } // ClusterCrawlerAlg::FindHitMultiplet()
std::vector< recob::Hit > fHits
our version of the hits
void cluster::ClusterCrawlerAlg::FindStarVertices ( )
private

Definition at line 1916 of file ClusterCrawlerAlg.cxx.

References 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.

1917  {
1918  // Make 2D vertices with a star topology with short back-to-back
1919  // clusters. Vertices must reside on the US end of the longest
1920  // cluster, so vertex finding uses the End information only.
1921  // This routine is called after all passes are completed
1922  // in the current CTP
1923  if(tcl.size() < 2) return;
1924 
1925  // This code has some issues...
1926  return;
1927 
1928  vtxprt = (fDebugPlane == (int)plane && fDebugHit < 0);
1929  if(vtxprt) {
1930  mf::LogVerbatim("CC")<<"FindStarVertices";
1931  PrintClusters();
1932  }
1933 
1934  unsigned short vtxSizeIn = vtx.size();
1935 
1936  float fvw = 0.;
1937  float fvt = 0.;
1938  float dsl = 0, dth = 0;
1939  float es1 = 0, es2 = 0;
1940  float eth1 = 0, eth2 = 0;
1941  float bt1 = 0, bt2 = 0;
1942  float et1 = 0, et2 = 0;
1943  float bw1 = 0, bw2 = 0;
1944  float ew1 = 0, ew2 = 0;
1945  float lotime = 0, hitime = 0, nwirecut = 0;
1946  unsigned short tclsize = tcl.size();
1947  for(unsigned short it1 = 0; it1 < tclsize - 1; ++it1) {
1948  // ignore obsolete clusters
1949  if(tcl[it1].ID < 0) continue;
1950  if(tcl[it1].CTP != clCTP) continue;
1951  // long dead-straight cluster?
1952  if(tcl[it1].tclhits.size() > 100) {
1953  dth = tcl[it1].BeginAng - tcl[it1].EndAng;
1954  if(std::abs(dth) < 0.1) continue;
1955  }
1956  es1 = tcl[it1].EndSlp;
1957  eth1 = tcl[it1].EndAng;
1958  ew1 = tcl[it1].EndWir;
1959  et1 = tcl[it1].EndTim;
1960  bw1 = tcl[it1].BeginWir;
1961  bt1 = tcl[it1].BeginTim;
1962  for(unsigned short it2 = it1 + 1; it2 < tclsize; ++it2) {
1963  if(tcl[it2].ID < 0) continue;
1964  if(tcl[it2].CTP != clCTP) continue;
1965  // long dead-straight cluster?
1966  if(tcl[it2].tclhits.size() > 100) {
1967  dth = tcl[it2].BeginAng - tcl[it2].EndAng;
1968  if(std::abs(dth) < 0.05) continue;
1969  }
1970  es2 = tcl[it2].EndSlp;
1971  eth2 = tcl[it2].EndAng;
1972  ew2 = tcl[it2].EndWir;
1973  et2 = tcl[it2].EndTim;
1974  bw2 = tcl[it2].BeginWir;
1975  bt2 = tcl[it2].BeginTim;
1976  // require angle difference
1977  dth = std::abs(eth1 - eth2);
1978  if(dth < 0.3) continue;
1979  dsl = es2 - es1;
1980  fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
1981  // intersection within the wire boundaries
1982  if(fvw < ew1 || fvw > bw1) continue;
1983  if(fvw < ew2 || fvw > bw2) continue;
1984  if(vtxprt) mf::LogVerbatim("CC")<<"Chk clusters "<<tcl[it1].ID<<" "<<tcl[it2].ID<<" topo5 vtx wire "<<fvw;
1985  // ensure that the intersection is close to the US end of the longer
1986  // cluster if it is more than 20 hits long
1987  if(tcl[it1].tclhits.size() > tcl[it2].tclhits.size()) {
1988  if(tcl[it1].tclhits.size() > 20) {
1989  nwirecut = 0.5 * tcl[it1].tclhits.size();
1990  if((fvw - ew1) > nwirecut) continue;
1991  }
1992  } else {
1993  if(tcl[it2].tclhits.size() > 20) {
1994  nwirecut = 0.5 * tcl[it2].tclhits.size();
1995  if((fvw - ew2) > nwirecut) continue;
1996  }
1997  }
1998  fvt = et1 + (fvw - ew1) * es1;
1999  // and time boundaries
2000  lotime = 9999;
2001  if(et1 < lotime) lotime = et1;
2002  if(bt1 < lotime) lotime = bt1;
2003  if(et2 < lotime) lotime = et2;
2004  if(bt2 < lotime) lotime = bt2;
2005  hitime = 0;
2006  if(et1 > hitime) hitime = et1;
2007  if(bt1 > hitime) hitime = bt1;
2008  if(et2 > hitime) hitime = et2;
2009  if(bt2 > hitime) hitime = bt2;
2010  if(fvt < lotime || fvt > hitime) continue;
2011  if(vtxprt) mf::LogVerbatim("CC")<<" vertex time "<<fvt<<" lotime "<<lotime<<" hitime "<<hitime;
2012  unsigned int vw = (0.5 + fvw);
2013  // ensure that the vertex is near a hit on both clusters
2014  unsigned int pos1 = 0;
2015  for(unsigned short ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
2016  if(fHits[tcl[it1].tclhits[ii]].WireID().Wire <= vw) {
2017  if(std::abs(int(fHits[tcl[it1].tclhits[ii]].PeakTime() - fvt)) < 10) pos1 = ii;
2018  break;
2019  }
2020  } // ii
2021  // vertex is not near a hit on cluster 1
2022  if(pos1 == 0) continue;
2023  unsigned short pos2 = 0;
2024  for(unsigned short ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
2025  if(fHits[tcl[it2].tclhits[ii]].WireID().Wire <= vw) {
2026  if(std::abs(int(fHits[tcl[it2].tclhits[ii]].PeakTime() - fvt)) < 10) pos2 = ii;
2027  break;
2028  }
2029  } // ii
2030  // vertex is not near a hit on cluster 2
2031  if(pos2 == 0) continue;
2032  // ensure we aren't near an existing vertex
2033  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
2034  if(std::abs(fvw - vtx[iv].Wire) < 2 &&
2035  std::abs(fvt - vtx[iv].Time) < 10) continue;
2036  }
2037  // make a new vertex
2038  VtxStore newvx;
2039  newvx.Wire = fvw;
2040  newvx.WireErr = 1;
2041  newvx.Time = fvt;
2042  newvx.TimeErr = 1;
2043  newvx.Topo = 5;
2044  newvx.CTP = clCTP;
2045  newvx.Fixed = false;
2046  vtx.push_back(newvx);
2047  unsigned short ivx = vtx.size() - 1;
2048  if(vtxprt) mf::LogVerbatim("CC")<<" new vertex "<<ivx<<" cluster "<<tcl[it1].ID<<" split pos "<<pos1;
2049  if(!SplitCluster(it1, pos1, ivx)) continue;
2050  tcl[tcl.size()-1].ProcCode += 1000;
2051  tcl[tcl.size()-2].ProcCode += 1000;
2052  if(vtxprt) mf::LogVerbatim("CC")<<" new vertex "<<ivx<<" cluster "<<tcl[it2].ID<<" split pos "<<pos2;
2053  if(!SplitCluster(it2, pos2, ivx)) continue;
2054  tcl[tcl.size()-1].ProcCode += 1000;
2055  tcl[tcl.size()-2].ProcCode += 1000;
2056  FitVtx(ivx);
2057  break;
2058  } // it2
2059  } // it1
2060 
2061  if(vtx.size() > vtxSizeIn) {
2062  // try to split other clusters
2063  VtxClusterSplit();
2064  // try to attach other clusters to it
2065  VertexCluster(vtx.size() - 1);
2066  FitAllVtx(clCTP);
2067  } // new vertex
2068 
2069  if(vtxprt) {
2070  mf::LogVerbatim("CC")<<"Vertices "<<vtx.size();
2071  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
2072  if(vtx[iv].CTP != clCTP) continue;
2073  mf::LogVerbatim("CC")
2074  <<"vtx "<<iv<<" wire "<<vtx[iv].Wire<<" time "<<(int)vtx[iv].Time
2075  <<" NClusters "<<vtx[iv].NClusters<<" topo "<<vtx[iv].Topo;
2076  }
2077  PrintClusters();
2078  }
2079 
2080  } // FindStarVertices()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void FitVtx(unsigned short iv)
CTP_t clCTP
Cryostat/TPC/Plane code.
int fDebugHit
out detailed information while crawling
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
void VertexCluster(unsigned short ivx)
void cluster::ClusterCrawlerAlg::FindVertices ( )
private

Definition at line 2217 of file ClusterCrawlerAlg.cxx.

References greaterThan(), CluLen::index, CluLen::length, and tca::PrintClusters().

2218  {
2219  // try to make 2D vertices
2220 
2221  if(tcl.size() < 2) return;
2222 
2223  // sort clusters starting with the longest
2224  std::vector<CluLen> clulens;
2225  CluLen clulen;
2226  for(unsigned short icl = 0; icl < tcl.size(); ++icl) {
2227  if(tcl[icl].ID < 0) continue;
2228  if(tcl[icl].CTP != clCTP) continue;
2229  if(tcl[icl].BeginVtx >= 0 && tcl[icl].EndVtx >= 0) continue;
2230  clulen.index = icl;
2231  clulen.length = tcl[icl].tclhits.size();
2232  clulens.push_back(clulen);
2233  }
2234  if(clulens.size() == 0) return;
2235  std::sort (clulens.begin(),clulens.end(), greaterThan);
2236 
2237  float nwires = fNumWires;
2238  float maxtime = fMaxTime;
2239 
2240  unsigned short vtxSizeIn = vtx.size();
2241 
2242  vtxprt = (fDebugPlane == (short)plane && fDebugHit < 0);
2243  if(vtxprt) {
2244  mf::LogVerbatim("CC")<<"FindVertices plane "<<plane<<" pass "<<pass;
2245  PrintClusters();
2246  }
2247 
2248  float es1 = 0, eth1 = 0, ew1 = 0, et1 = 0;
2249  float bs1 = 0, bth1 = 0, bw1 = 0, bt1 = 0;
2250  float es2 = 0, eth2 = 0, ew2 = 0, et2 = 0;
2251  float bs2 = 0, bth2 = 0, bw2 = 0, bt2 = 0;
2252  float dth = 0, dsl = 0, fvw = 0, fvt = 0;
2253  float angcut = 0;
2254  unsigned int vw = 0, pass1, pass2, ii1, it1, ii2, it2;
2255  bool SigOK = false;
2256  for(ii1 = 0; ii1 < clulens.size() - 1; ++ii1) {
2257  it1 = clulens[ii1].index;
2258  es1 = tcl[it1].EndSlp;
2259  eth1 = tcl[it1].EndAng;
2260  ew1 = tcl[it1].EndWir;
2261  et1 = tcl[it1].EndTim;
2262  bs1 = tcl[it1].BeginSlp;
2263  bth1 = tcl[it1].BeginAng;
2264  bw1 = tcl[it1].BeginWir;
2265  bt1 = tcl[it1].BeginTim;
2266  pass1 = tcl[it1].ProcCode - 10 *(tcl[it1].ProcCode / 10);
2267  for(ii2 = ii1 + 1; ii2 < clulens.size(); ++ii2) {
2268  it2 = clulens[ii2].index;
2269  // try to attach cluster to existing vertices at either end
2270  ClusterVertex(it2);
2271  // ignore if both clusters are short
2272  if(tcl[it1].tclhits.size() < 5 &&
2273  tcl[it2].tclhits.size() < 5) continue;
2274  es2 = tcl[it2].EndSlp;
2275  eth2 = tcl[it2].EndAng;
2276  ew2 = tcl[it2].EndWir;
2277  et2 = tcl[it2].EndTim;
2278  bs2 = tcl[it2].BeginSlp;
2279  bth2 = tcl[it2].BeginAng;
2280  bw2 = tcl[it2].BeginWir;
2281  bt2 = tcl[it2].BeginTim;
2282  pass2 = tcl[it2].ProcCode - 10 *(tcl[it2].ProcCode / 10);
2283  if(pass1 < pass2) {
2284  angcut = fKinkAngCut[pass2];
2285  } else {
2286  angcut = fKinkAngCut[pass1];
2287  }
2288  // topo 1: check for vtx US of the ends of both clusters
2289  dth = fabs(eth1 - eth2);
2290  if(tcl[it1].EndVtx < 0 && tcl[it2].EndVtx < 0 && dth > 0.1) {
2291  dsl = es2 - es1;
2292  // find vertex wire and vertex time in float precision (fvw, fvt)
2293  fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
2294  // vertex wire in the detector?
2295  if(fvw > 0. && fvw < nwires) {
2296  // require vtx in the range of wires with hits AND
2297  vw = (0.5 + fvw);
2298  // vtx US of both clusters AND
2299  // vtx not too far US of both clusters
2300  if(vw >= fFirstWire - 1 &&
2301  fvw <= ew1 + 3 && fvw <= ew2 + 3 &&
2302  fvw > (ew1 - 10) && fvw > (ew2 - 10) ) {
2303  fvt = et1 + (fvw - ew1) * es1;
2304  if(vtxprt) mf::LogVerbatim("CC")<<"Chk clusters topo1 "<<tcl[it1].ID<<" "<<tcl[it2].ID<<" vtx wire "<<vw<<" time "<<(int)fvt<<" dth "<<dth;
2305  if(fvt > 0 && fvt < maxtime) {
2306  // Vertex wire US of cluster ends and time in the detector.
2307  // Check for signal at the vertex position and adjust the vertex by 1 wire
2308  // if necessary
2309  SigOK = ChkSignal(vw, fvt, vw, fvt);
2310  if(!SigOK) {
2311  fvw += 1.;
2312  vw = (0.5 + fvw);
2313  SigOK = ChkSignal(vw, fvt, vw, fvt);
2314  }
2315  // Check this against existing vertices and update
2316  if(SigOK) ChkVertex(fvw, fvt, it1, it2, 1);
2317  } // fvt in detector
2318  } // vw topo 1 check
2319  } // fvw in detector
2320  } // topo 1
2321  // topo 2: check for vtx US of it1 and DS of it2
2322  dth = std::abs(eth1 - bth2);
2323  if(tcl[it1].EndVtx < 0 && tcl[it2].BeginVtx < 0 && dth > angcut) {
2324  dsl = bs2 - es1;
2325  if(fabs(ew1 - bw2) < 3 && fabs(et1 - bt2) < 500) {
2326  fvw = 0.5 * (ew1 + bw2);
2327  } else {
2328  fvw = (et1 - ew1 * es1 - bt2 + bw2 * bs2) / dsl;
2329  }
2330  if(fvw > 0 && fvw < nwires) {
2331  // vertex wire in the detector
2332  vw = (0.5 + fvw);
2333  // require vtx US of cluster 1 End AND
2334  // vtx DS of cluster 2 Begin
2335  if(fvw <= ew1 + 2 && fvw >= bw2 - 2) {
2336  fvt = et1 + (vw - ew1) * es1;
2337  fvt += bt2 + (vw - bw2) * bs2;
2338  fvt /= 2;
2339  if(vtxprt) mf::LogVerbatim("CC")<<"Chk clusters topo2 "<<tcl[it1].ID<<" "<<tcl[it2].ID<<" vtx wire "<<vw<<" time "<<(int)fvt<<" dth "<<dth;
2340  if(fvt > 0. && fvt < maxtime) {
2341  ChkVertex(fvw, fvt, it1, it2, 2);
2342  } // fvt in detector
2343  } // vw topo 2 check
2344  } // fvw in detector
2345  } // topo 2
2346  // topo 3: check for vtx DS of it1 and US of it2
2347  dth = std::abs(bth1 - eth2);
2348  if(tcl[it1].BeginVtx < 0 && tcl[it2].EndVtx < 0 && dth > angcut) {
2349  dsl = bs1 - es2;
2350  if(fabs(bw1 - ew2) < 3 && fabs(bt1 - et2) < 500) {
2351  fvw = 0.5 * (bw1 + ew2);
2352  } else {
2353  fvw = (et2 - ew2 * es2 - bt1 + bw1 * bs1) / dsl;
2354  }
2355  if(fvw > 0 && fvw < nwires) {
2356  vw = (0.5 + fvw);
2357  // require vtx US of cluster 2 Begin AND
2358  // vtx DS of cluster 1 End
2359  if(fvw <= ew2 + 2 && fvw >= bw1 - 2) {
2360  fvt = et2 + (fvw - ew2) * es2;
2361  fvt += bt1 + (fvw - bw1) * es1;
2362  fvt /= 2;
2363  if(vtxprt) mf::LogVerbatim("CC")<<"Chk clusters topo3 "<<tcl[it1].ID<<" "<<tcl[it2].ID<<" vtx wire "<<vw<<" time "<<(int)fvt<<" dth "<<dth;
2364  if(fvt > 0. && fvt < maxtime) {
2365  ChkVertex(fvw, fvt, it1, it2, 3);
2366  } // fvt in detector
2367  } // vw topo 3 check
2368  } // fvw in detector
2369  } // topo 3
2370  // topo 4: check for vtx DS of it1 and DS of it2
2371  dth = std::abs(bth1 - bth2);
2372  if(tcl[it1].BeginVtx < 0 && tcl[it2].BeginVtx < 0 && dth > 0.1) {
2373  dsl = bs2 - bs1;
2374  // find vertex wire and vertex time in float precision (fvw, fvt)
2375  // convert to integer if within the detector (vw, vt)
2376  fvw = (bt1 - bw1 * bs1 - bt2 + bw2 * bs2) / dsl;
2377  if(vtxprt) mf::LogVerbatim("CC")<<"Chk clusters topo4 "<<bw1<<":"<<(int)bt1<<" "<<bw2<<":"<<(int)bt2<<" fvw "<<fvw<<" nwires "<<nwires;
2378  if(fvw > 0 && fvw < nwires) {
2379  // vertex wire in the detector
2380  vw = (0.5 + fvw);
2381  // require vtx in the range of wires with hits AND vtx DS of both clusters AND
2382  // vtx not too far DS of both clusters
2383  float dwcut = 10;
2384  if(tcl[it1].tclhits.size() < 2 * dwcut) dwcut = tcl[it1].tclhits.size()/2;
2385  if(tcl[it2].tclhits.size() < 2 * dwcut) dwcut = tcl[it2].tclhits.size()/2;
2386  if(fvw <= fLastWire + 1 &&
2387  fvw >= bw1 - dwcut && fvw <= bw1 + dwcut &&
2388  fvw >= bw2 - dwcut && fvw <= bw1 + dwcut) {
2389  fvt = bt1 + (fvw - bw1) * bs1;
2390  if(vtxprt) mf::LogVerbatim("CC")<<" vtx wire "<<vw<<" time "<<fvt<<" dth "<<dth<<" dwcut "<<dwcut;
2391  if(fvt > 0. && fvt < maxtime) {
2392  // vertex wire US of cluster ends and time in the detector
2393  // Check for signal at the vertex position and adjust the vertex by 1 wire
2394  // if necessary
2395  SigOK = ChkSignal(vw, fvt, vw, fvt);
2396  if(!SigOK) {
2397  fvw -= 1.;
2398  vw = (0.5 + fvw);
2399  SigOK = ChkSignal(vw, fvt, vw, fvt);
2400  }
2401  // Check this against existing vertices and update
2402  if(SigOK) ChkVertex(fvw, fvt, it1, it2, 4);
2403  } // fvt in detector
2404  } // vw topo 4 check
2405  } // fvw in detector
2406  } // topo4
2407  } // it2
2408  } // it1
2409 
2410  // Fix vertices where both ends of a cluster are assigned to the
2411  // same vertex. This can happen with short clusters
2412  for(unsigned short it = 0; it < tcl.size(); ++it) {
2413  if(tcl[it].ID < 0) continue;
2414  if(tcl[it].CTP != clCTP) continue;
2415  if(tcl[it].BeginVtx > -1 && tcl[it].BeginVtx == tcl[it].EndVtx ) {
2416  unsigned short iv = tcl[it].BeginVtx;
2417  float dwir = tcl[it].BeginWir - vtx[iv].Wire;
2418  float dtim = tcl[it].BeginTim - vtx[iv].Time;
2419  float rbeg = dwir * dwir + dtim * dtim;
2420  dwir = tcl[it].EndWir - vtx[iv].Wire;
2421  dtim = tcl[it].EndTim - vtx[iv].Time;
2422  float rend = dwir * dwir + dtim * dtim;
2423  if(rend < rbeg) {
2424  tcl[it].EndVtx = -99;
2425  } else {
2426  tcl[it].BeginVtx = -99;
2427  }
2428  } // tcl[it].BeginVtx == tcl[it].EndVtx
2429  } // it
2430 
2431  if(vtx.size() > vtxSizeIn) FitAllVtx(clCTP);
2432 
2433  // "delete" any vertices that have only one cluster
2434  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
2435  if(vtx[ivx].CTP != clCTP) continue;
2436  if(vtx[ivx].NClusters == 1) {
2437  vtx[ivx].NClusters = 0;
2438  for(unsigned short icl = 0; icl < tcl.size(); ++icl) {
2439  if(tcl[icl].CTP != clCTP) continue;
2440  if(tcl[icl].BeginVtx == ivx) {
2441  tcl[icl].BeginVtx = -99;
2442  break;
2443  }
2444  if(tcl[icl].EndVtx == ivx) {
2445  tcl[icl].EndVtx = -99;
2446  break;
2447  }
2448  } // icl
2449  } // vtx[ivx].NClusters == 1
2450  } // ivx
2451 
2452 
2453  } // FindVertices()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
bool ChkSignal(unsigned int iht, unsigned int jht)
CTP_t clCTP
Cryostat/TPC/Plane code.
int fDebugHit
out detailed information while crawling
unsigned int fLastWire
the last wire with a hit
std::vector< ClusterStore > tcl
the clusters we are creating
if(nlines<=0)
unsigned int fFirstWire
the first wire with a hit
std::vector< VtxStore > vtx
the endpoints we are reconstructing
std::vector< float > fKinkAngCut
kink angle cut made after fKinkChiRat
bool greaterThan(CluLen c1, CluLen c2)
void ClusterVertex(unsigned short it2)
void ChkVertex(float fvw, float fvt, unsigned short it1, unsigned short it2, short topo)
void cluster::ClusterCrawlerAlg::FitAllVtx ( CTP_t  inCTP)
private

Definition at line 2153 of file ClusterCrawlerAlg.cxx.

2154  {
2155 
2156  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
2157  if(vtx[iv].CTP != inCTP) continue;
2158  FitVtx(iv);
2159  }
2160 
2161  } // FitAllVtx
void FitVtx(unsigned short iv)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::FitCluster ( )
private

Definition at line 4410 of file ClusterCrawlerAlg.cxx.

4411  {
4412  // Fits the hits on the US end of a cluster. This routine assumes that
4413  // wires are numbered from lower (upstream) to higher (downstream) and
4414  // that the hits in the fclhits vector are sorted so that upstream hits
4415  // are at the end of the vector
4416 
4417 
4418  clChisq = 999.;
4419 
4420  if(pass > fNumPass - 1) {
4421  mf::LogError("CC")<<"FitCluster called on invalid pass "<<pass;
4422  return;
4423  }
4424 
4425  unsigned short ii, nht = 0;
4426  // fit all hits or truncate?
4427  nht = fcl2hits.size();
4428  if(clLA) {
4429  // Fit large angle cluster
4430  if(nht > fLAClusMaxHitsFit) nht = fLAClusMaxHitsFit;
4431  } else {
4432  if(nht > fMaxHitsFit[pass]) nht = fMaxHitsFit[pass];
4433  }
4434  if(nht < 2) return;
4435 
4436  std::vector<float> xwir;
4437  std::vector<float> ytim;
4438  std::vector<float> ytimerr2;
4439  // apply an angle dependent scale factor.
4440  float angfactor = AngleFactor(clpar[1]);
4441 
4442  unsigned int wire;
4443  unsigned int wire0 = fHits[fcl2hits[fcl2hits.size()-1]].WireID().Wire;
4444  unsigned int ihit;
4445  float terr, qave = 0, qwt;
4446  for(ii = 0; ii < nht; ++ii) {
4447  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4448  qave += fHits[ihit].Integral();
4449  } // ii
4450  qave /= (float)nht;
4451  for(ii = 0; ii < nht; ++ii) {
4452  ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4453  wire = fHits[ihit].WireID().Wire;
4454  xwir.push_back(wire - wire0);
4455  ytim.push_back(fHits[ihit].PeakTime());
4456  // Scale error by hit multiplicity to account for bias in hit
4457  // multiplet fitting
4458  terr = fHitErrFac * fHits[ihit].RMS() * fHits[ihit].Multiplicity();
4459  if(fAveChg > 0) {
4460  // increase the error for large charge hits
4461  qwt = (fHits[ihit].Integral() / qave) - 1;
4462  if(qwt < 1) qwt = 1;
4463  terr *= qwt;
4464  }
4465  if(terr < 0.01) terr = 0.01;
4466  ytimerr2.push_back(angfactor * terr * terr);
4467  }
4469  if(prt) {
4470  mf::LogVerbatim myprt("CC");
4471  myprt<<"FitCluster W:T ";
4472  unsigned short cnt = 0;
4473  for(std::vector<unsigned int>::reverse_iterator it = fcl2hits.rbegin(); it != fcl2hits.rend(); ++it) {
4474  unsigned int ihit = *it;
4475  unsigned short wire = fHits[ihit].WireID().Wire;
4476  myprt<<wire<<":"<<(short)fHits[ihit].PeakTime()<<" ";
4477  ++cnt;
4478  if(cnt == 8) {
4479  myprt<<" .... ";
4480  break;
4481  }
4482  }
4483  } // prt
4484 
4485  if(xwir.size() < 2) return;
4486 
4487  float intcpt = 0.;
4488  float slope = 0.;
4489  float intcpterr = 0.;
4490  float slopeerr = 0.;
4491  float chidof = 0.;
4492  fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4493  clChisq = chidof;
4494  if(chidof > fChiCut[0]) return;
4495  clpar[0] = intcpt;
4496  clpar[1] = slope;
4497  clpar[2] = wire0;
4498  clparerr[0] = intcpterr;
4499  clparerr[1] = slopeerr;
4500 
4501  if(prt) mf::LogVerbatim("CC")<<"nht "<<nht<<" fitpar "<<(int)clpar[0]<<"+/-"<<(int)intcpterr
4502  <<" "<<clpar[1]<<"+/-"<<slopeerr<<" clChisq "<<clChisq;
4503 
4504  }
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
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
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF)
Definition: LinFitAlg.cxx:26
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
void cluster::ClusterCrawlerAlg::FitClusterChg ( )
private

Definition at line 4528 of file ClusterCrawlerAlg.cxx.

4529  {
4530  // Fits the charge of hits on the fcl2hits vector to a line, or simply
4531  // uses the average of 1 or 2 hits as determined by NHitsAve
4532 
4533  if(fcl2hits.size() == 0) return;
4534  unsigned int ih0 = fcl2hits.size() - 1;
4535 
4536  if(pass >= fNumPass) {
4537  mf::LogError("CC")<<"FitClusterChg bad pass "<<pass;
4538  return;
4539  }
4540 
4541  // Handle Large Angle clusters
4542  if(clLA) {
4543  // simple average of the charge (and the hit width
4544  // while we are here)
4545  unsigned short nhave = fLAClusMaxHitsFit;
4546  if(nhave > fcl2hits.size()) nhave = fcl2hits.size();
4547  fAveChg = 0;
4548  fChgSlp = 0;
4549  fAveHitWidth = 0;
4550  unsigned int iht;
4551  for(unsigned short ii = 0; ii < nhave; ++ii) {
4552  iht = fcl2hits[fcl2hits.size() - 1 - ii];
4553  fAveChg += fHits[iht].Integral();
4554  fAveHitWidth += (fHits[iht].EndTick() - fHits[iht].StartTick());
4555  } // ii
4556  fAveChg /= (float)fcl2hits.size();
4557  fAveHitWidth /= (float)fcl2hits.size();
4558  return;
4559  } // clLA
4560 
4561  // number of hits at the leading edge that we will fit
4562  unsigned short fitLen = fNHitsAve[pass];
4563  // start fitting charge when there are at least 6 hits if we are tracking
4564  // long clusters
4565  if(fitLen > 5 && // Fit 6 hits when tracking long clusters AND
4566  fcl2hits.size() > 5 && // there are at least 6 hits AND
4567  fcl2hits.size() < fitLen) // there are less than fNHitsAve[pass]
4568  fitLen = 5;
4569 
4570  // don't find the average charge --> no charge cut is made
4571  if(fNHitsAve[pass] < 1) return;
4572 
4573  if(fNHitsAve[pass] == 1) {
4574  // simply use the charge and width the last hit
4575  fAveChg = fHits[fcl2hits[ih0]].Integral();
4576  fChgSlp = 0.;
4577  } else if(fNHitsAve[pass] == 2) {
4578  // average the last two points if requested
4579  fAveChg = (fHits[fcl2hits[ih0]].Integral() +
4580  fHits[fcl2hits[ih0 - 1]].Integral()) / 2.;
4581  fChgSlp = 0.;
4582  } else if((unsigned short)fcl2hits.size() > fitLen){
4583  // do a real fit
4584  std::vector<float> xwir;
4585  std::vector<float> ychg;
4586  std::vector<float> ychgerr2;
4587  // origin of the fit
4588  unsigned int wire0 = fHits[fcl2hits[fcl2hits.size()-1]].WireID().Wire;
4589  // find the mean and rms of the charge
4590  unsigned short npt = 0;
4591  unsigned short imlast = 0;
4592  float ave = 0.;
4593  float rms = 0.;
4594  // this loop intentionally ignores the Begin hit
4595  for(unsigned int ii = fcl2hits.size() - 1; ii > 0; --ii) {
4596  ++npt;
4597  float chg = fHits[fcl2hits[ii]].Integral();
4598  ave += chg;
4599  rms += chg * chg;
4600  if(npt == fitLen) {
4601  imlast = ii;
4602  break;
4603  }
4604  }
4605  float fnpt = npt;
4606  ave /= fnpt;
4607  rms = std::sqrt((rms - fnpt * ave * ave) / (fnpt - 1));
4608  float chgcut = ave + rms;
4609  float chg;
4610  unsigned int wire;
4611  for(unsigned short ii = fcl2hits.size() - 1; ii > imlast; --ii) {
4612  wire = fHits[fcl2hits[ii]].WireID().Wire;
4613  chg = fHits[fcl2hits[ii]].Integral();
4614  if(chg > chgcut) continue;
4615  xwir.push_back((float)(wire - wire0));
4616  ychg.push_back(chg);
4617  ychgerr2.push_back(chg);
4618  }
4619  if(ychg.size() < 3) return;
4620  float intcpt; float slope; float intcpterr;
4621  float slopeerr; float chidof;
4622  fLinFitAlg.LinFit(xwir, ychg, ychgerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4623  if(prt) mf::LogVerbatim("CC")<<"FitClusterChg wire "<<wire0
4624  <<" chidof "<<(int)chidof<<" npt "<<xwir.size()
4625  <<" charge = "<<(int)intcpt<<" slope = "<<(int)slope
4626  <<" first ave "<<(int)ave<<" rms "<<(int)rms;
4627  if(chidof > 100.) return;
4628  // fit must have gone wrong if the fStepCrawlChgRatCut average is greater than
4629  // the average using all points
4630  if(intcpt > ave) return;
4631  // ensure that change does not exceed 30%
4632  if(fAveChg > 0) {
4633  ave = intcpt / fAveChg;
4634  if(ave > 1.3) return;
4635  if(ave < 0.77) return;
4636  }
4637  fAveChg = intcpt;
4638  fChgSlp = slope;
4639  }
4640  } // 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
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
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF)
Definition: LinFitAlg.cxx:26
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
set to > 2 to do a charge fit using fNHitsAve hits
void cluster::ClusterCrawlerAlg::FitClusterMid ( unsigned short  it1,
unsigned int  iht,
short  nhit 
)
private

Definition at line 4304 of file ClusterCrawlerAlg.cxx.

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

Definition at line 4310 of file ClusterCrawlerAlg.cxx.

4311  {
4312  // Fits hits on temp cluster it1 to a line starting at hit ihtin and including
4313  // nhit hits incrementing towards the hit vector End when nhit > 0 and
4314  // decrementing towards the hit vector Begin when nhit < 0.
4315  // The fit params are stashed in the clpar and clparerr arrays.
4316  // fAveChg is re-calculated as well.
4317 
4318 
4319  // set chisq bad in case something doesn't work out
4320  clChisq = 99.;
4321 
4322  if(hitVec.size() < 3) return;
4323 
4324  std::vector<float> xwir;
4325  std::vector<float> ytim;
4326  std::vector<float> ytimerr2;
4327 
4328  unsigned short ii, hitcnt = 0, nht = 0, usnhit;
4329  float wire0 = 0;
4330  unsigned int iht;
4331  bool UseEm = false;
4332  fAveChg = 0.;
4333  fChgSlp = 0.;
4334 
4335  if(nhit > 0) {
4336  usnhit = nhit;
4337  // find the first desired hit and move towards the End
4338  for(ii = 0; ii < hitVec.size(); ++ii) {
4339  iht = hitVec[ii];
4340  if(iht > fHits.size()-1) {
4341  mf::LogError("CC")<<"FitClusterMid bad iht "<<iht;
4342  return;
4343  }
4344  // look for the desired first hit. Use this as the origin wire
4345  if(iht == ihtin) {
4346  UseEm = true;
4347  wire0 = fHits[iht].WireID().Wire;
4348  }
4349  // use hits after finding the first desired hit
4350  if(UseEm) {
4351  xwir.push_back((float)fHits[iht].WireID().Wire - wire0);
4352  ytim.push_back(fHits[iht].PeakTime());
4353  // pass the error^2 to the fitter
4354  float terr = fHitErrFac * fHits[iht].RMS();
4355  ytimerr2.push_back(terr * terr);
4356  fAveChg += fHits[iht].Integral();
4357  ++hitcnt;
4358  if(hitcnt == usnhit) break;
4359  }
4360  }
4361  nht = hitcnt;
4362  } else {
4363  usnhit = -nhit;
4364  // find the first desired hit and move towards the Begin
4365  for(auto ii = hitVec.crbegin(); ii != hitVec.crend(); ++ii) {
4366  iht = *ii;
4367  if(iht > fHits.size()-1) {
4368  mf::LogVerbatim("CC")<<"FitClusterMid bad iht "<<iht;
4369  return;
4370  }
4371  // look for the desired first hit. Use this as the origin wire
4372  if(iht == ihtin) {
4373  UseEm = true;
4374  wire0 = fHits[iht].WireID().Wire;
4375  }
4376  // use hits after finding the first desired hit
4377  if(UseEm) {
4378  xwir.push_back((float)fHits[iht].WireID().Wire - wire0);
4379  ytim.push_back(fHits[iht].PeakTime());
4380  float terr = fHitErrFac * fHits[iht].RMS();
4381  ytimerr2.push_back(terr * terr);
4382  fAveChg += fHits[iht].Integral();
4383  ++hitcnt;
4384  if(hitcnt == usnhit) break;
4385  }
4386  }
4387  nht = hitcnt;
4388  }
4389 
4390  if(nht < 2) return;
4391  fAveChg = fAveChg / (float)nht;
4392  fChgSlp = 0.;
4393 
4394  float intcpt = 0.;
4395  float slope = 0.;
4396  float intcpterr = 0.;
4397  float slopeerr = 0.;
4398  float chidof = 0.;
4399  fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4400  clChisq = chidof;
4401  if(clChisq > fChiCut[0]) return;
4402  clpar[0] = intcpt;
4403  clpar[1] = slope;
4404  clpar[2] = wire0;
4405  clparerr[0] = intcpterr;
4406  clparerr[1] = slopeerr;
4407  }
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
float clChisq
chisq of the current fit
std::vector< recob::Hit > fHits
our version of the 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)
Definition: LinFitAlg.cxx:26
float fChgSlp
slope of the charge vs wire
void cluster::ClusterCrawlerAlg::FitVtx ( unsigned short  iv)
private

Definition at line 5229 of file ClusterCrawlerAlg.cxx.

References geo::CryostatID::Cryostat, tca::DecodeCTP(), min, geo::PlaneID::Plane, geo::TPCID::TPC, x, and y.

5230  {
5231  std::vector<float> x;
5232  std::vector<float> y;
5233  std::vector<float> ey2;
5234  float arg;
5235 
5236  // don't fit fixed vertices
5237  if(vtx[iv].Fixed) return;
5238 
5239  // Set this large in case something bad happens
5240  vtx[iv].ChiDOF = 99;
5241 
5242  // make a list of clusters
5243  unsigned short icl;
5244  std::vector<unsigned short> vcl;
5245  for(icl = 0; icl < tcl.size(); ++icl) {
5246  if(tcl[icl].ID < 0) continue;
5247  if(tcl[icl].CTP != vtx[iv].CTP) continue;
5248  if(tcl[icl].EndVtx == iv) vcl.push_back(icl);
5249  if(tcl[icl].BeginVtx == iv) vcl.push_back(icl);
5250  }
5251 
5252  vtx[iv].NClusters = vcl.size();
5253 
5254  if(vcl.size() == 0) return;
5255 
5256  // don't let the time error be less than the expected
5257  // time error of hits on a cluster. This is crude by
5258  // probably good enough
5259  icl = vcl[0];
5260  unsigned short indx = tcl[icl].tclhits.size() - 1;
5261  unsigned int hit = tcl[icl].tclhits[indx];
5262  float minTimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5263 
5264  if(vcl.size() == 1) {
5265  icl = vcl[0];
5266  // Put the vertex at the appropriate end of the cluster
5267  if(tcl[icl].EndVtx == iv) {
5268  vtx[iv].Wire = tcl[icl].EndWir;
5269  vtx[iv].WireErr = 1;
5270  vtx[iv].Time = tcl[icl].EndTim;
5271  // set the vertex time error to the hit error used for fitting
5272  indx = tcl[icl].tclhits.size() - 1;
5273  hit = tcl[icl].tclhits[indx];
5274  vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5275  vtx[iv].ChiDOF = 0;
5276  }
5277  if(tcl[icl].BeginVtx == iv) {
5278  vtx[iv].Wire = tcl[icl].BeginWir;
5279  vtx[iv].WireErr = 1;
5280  vtx[iv].Time = tcl[icl].BeginTim;
5281  // set the vertex time error to the hit error used for fitting
5282  hit = tcl[icl].tclhits[0];
5283  vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5284  vtx[iv].ChiDOF = 0;
5285  }
5286  return;
5287  } // size 1
5288 
5289  std::vector<double> slps;
5290  std::vector<double> slperrs;
5291  for(unsigned short ii = 0; ii < vcl.size(); ++ii) {
5292  icl = vcl[ii];
5293  if(tcl[icl].EndVtx == iv) {
5294  x.push_back(tcl[icl].EndSlp);
5295  slps.push_back(tcl[icl].EndSlp);
5296  slperrs.push_back(tcl[icl].EndSlpErr);
5297  arg = tcl[icl].EndSlp * tcl[icl].EndWir - tcl[icl].EndTim;
5298  y.push_back(arg);
5299  if(tcl[icl].EndSlpErr > 0.) {
5300  arg = tcl[icl].EndSlpErr * tcl[icl].EndWir;
5301  } else {
5302  arg = .1 * tcl[icl].EndWir;
5303  }
5304  ey2.push_back(arg * arg);
5305  } else if(tcl[icl].BeginVtx == iv) {
5306  x.push_back(tcl[icl].BeginSlp);
5307  slps.push_back(tcl[icl].BeginSlp);
5308  slperrs.push_back(tcl[icl].BeginSlpErr);
5309  arg = tcl[icl].BeginSlp * tcl[icl].BeginWir - tcl[icl].BeginTim;
5310  y.push_back(arg);
5311  if(tcl[icl].BeginSlpErr > 0.) {
5312  arg = tcl[icl].BeginSlpErr * tcl[icl].BeginWir;
5313  } else {
5314  arg = .1 * tcl[icl].BeginWir;
5315  }
5316  ey2.push_back(arg * arg);
5317  }
5318  } // ii
5319  if(x.size() < 2) return;
5320 
5321  // calculate error
5322  double sumerr = 0, cnt = 0;
5323  for(unsigned short ii = 0; ii < slps.size() - 1; ++ii) {
5324  for(unsigned short jj = ii + 1; jj < slps.size(); ++jj) {
5325  arg = std::min(slperrs[ii], slperrs[jj]);
5326  arg /= (slps[ii] - slps[jj]);
5327  sumerr += arg * arg;
5328  ++cnt;
5329  } // jj
5330  } // ii
5331  sumerr /= cnt;
5332 
5333  float vTime = 0.;
5334  float vTimeErr = 0.;
5335  float vWire = 0.;
5336  float vWireErr = 0.;
5337  float chiDOF;
5338  fLinFitAlg.LinFit(x, y, ey2, vTime, vWire, vTimeErr, vWireErr, chiDOF);
5339  if(chiDOF > 900) return;
5340  vTime = -vTime;
5341  // a crazy time from the fit?
5342  if(vTime < 0 || vTime > fMaxTime) return;
5343  // a crazy wire from the fit?
5344  geo::PlaneID iplID = DecodeCTP(vtx[iv].CTP);
5345  if(vWire < 0 || vWire > geom->Nwires(iplID.Plane, iplID.TPC, iplID.Cryostat)) return;
5346  vtx[iv].ChiDOF = chiDOF;
5347  vtx[iv].Wire = vWire;
5348  vtx[iv].Time = vTime;
5349  vtx[iv].WireErr = vWire * sqrt(sumerr);
5350  vtx[iv].TimeErr = vTime * fabs(sumerr);
5351 // std::cout<<"vWire "<<vWire<<" Err "<<vtx[iv].WireErr<<" vTime "<<vTime<<" Err "<<vtx[iv].TimeErr
5352 // <<" sumerr "<<sumerr<<" nclusters "<<x.size()<<"\n";
5353  // set minimum wire error
5354  if(vtx[iv].WireErr < 1) vtx[iv].WireErr = 2;
5355  // set minimum time error
5356  if(vtx[iv].TimeErr < minTimeErr) vtx[iv].TimeErr = minTimeErr;
5357 
5358  } // FitVtx
Float_t x
Definition: compare.C:6
Float_t y
Definition: compare.C:6
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
art::ServiceHandle< geo::Geometry > geom
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
static geo::PlaneID DecodeCTP(CTP_t CTP)
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
Detector simulation of raw signals on wires.
std::vector< recob::Hit > fHits
our version of the hits
Int_t min
Definition: plot.C:26
void LinFit(std::vector< float > &x, std::vector< float > &y, std::vector< float > &ey2, float &Intercept, float &Slope, float &InterceptError, float &SlopeError, float &ChiDOF)
Definition: LinFitAlg.cxx:26
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
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 1859 of file ClusterCrawlerAlg.cxx.

References recob::Hit::Channel(), recob::Hit::DegreesOfFreedom(), evd::details::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().

1860  {
1861  //
1862  // Resets multiplicity and local index of the hits in the range.
1863  // All hits are assumed to be in the same multiplet.
1864  // All hits that are not obsolete are given a multiplicity equal to the
1865  // number of non-obsolete hits in the multiplet, and the local index is
1866  // assigned as an increasing number starting from 0 with the first
1867  // non-obsolete hit on.
1868  //
1869 
1870  // first pass: determine the actual number of hits in the multiplet
1871  if (multiplicity < 0) {
1872  multiplicity = 0;
1873  for (size_t iHit = begin; iHit < end; ++iHit) {
1874  if(inClus[iHit] < 0) continue;
1875  // if (!isHitPresent(iHit)) continue;
1876  ++multiplicity;
1877  } // for
1878  } // if no valid multiplicity is given
1879 
1880  // second pass: assign the correct multiplicity
1881  short int local_index = 0;
1882  for (size_t iHit = begin; iHit < end; ++iHit) {
1883  if(inClus[iHit] < 0) continue;
1884  // if (!isHitPresent(iHit)) continue;
1885 
1886  // copy everything but overwrite the local index and multiplicity
1887  // TODO use a write wrapper!
1888  recob::Hit const& hit = fHits[iHit];
1889  fHits[iHit] = recob::Hit(
1890  hit.Channel(),
1891  hit.StartTick(),
1892  hit.EndTick(),
1893  hit.PeakTime(),
1894  hit.SigmaPeakTime(),
1895  hit.RMS(),
1896  hit.PeakAmplitude(),
1897  hit.SigmaPeakAmplitude(),
1898  hit.SummedADC(),
1899  hit.Integral(),
1900  hit.SigmaIntegral(),
1901  multiplicity, // multiplicity
1902  local_index, // local index
1903  hit.GoodnessOfFit(),
1904  hit.DegreesOfFreedom(),
1905  hit.View(),
1906  hit.SignalType(),
1907  hit.WireID()
1908  );
1909 
1910  ++local_index;
1911  } // for
1912 
1913  } // FixMultipletLocalIndices()
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:232
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:221
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:223
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:226
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:230
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:233
float GoodnessOfFit() const
Degrees of freedom in the determination of the hit signal shape (-1 by default)
Definition: Hit.h:229
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:222
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:217
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:218
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
float SummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:224
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:220
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
std::vector<ClusterStore> const& cluster::ClusterCrawlerAlg::GetClusters ( ) const
inline

Returns a constant reference to the clusters found.

Definition at line 125 of file ClusterCrawlerAlg.h.

References tcl.

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

125 { 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 128 of file ClusterCrawlerAlg.h.

References vtx.

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

Definition at line 6075 of file ClusterCrawlerAlg.cxx.

References geo::CryostatID::Cryostat, tca::DecodeCTP(), art::errors::LogicError, max, geo::PlaneID::Plane, and geo::TPCID::TPC.

6076  {
6077  // fills the WireHitRange vector for the supplied Cryostat/TPC/Plane code
6078  // Hits must have been sorted by increasing wire number
6079  fFirstHit = 0;
6080  geo::PlaneID planeID = DecodeCTP(CTP);
6081  unsigned int nwires = geom->Nwires(planeID.Plane, planeID.TPC, planeID.Cryostat);
6082  WireHitRange.resize(nwires + 1);
6083 
6084  // These will be re-defined later
6085  fFirstWire = 0;
6086  fLastWire = 0;
6087 
6088  unsigned int wire, iht;
6089  unsigned int nHitInPlane;
6090  std::pair<int, int> flag;
6091 
6092  // Define the "no hits on wire" condition
6093  flag.first = -2; flag.second = -2;
6094  for(auto& apair : WireHitRange) apair = flag;
6095 
6096  nHitInPlane = 0;
6097 
6098  std::vector<bool> firsthit;
6099  firsthit.resize(nwires+1, true);
6100  bool firstwire = true;
6101  for(iht = 0; iht < fHits.size(); ++iht) {
6102  if(fHits[iht].WireID().TPC != planeID.TPC) continue;
6103  if(fHits[iht].WireID().Cryostat != planeID.Cryostat) continue;
6104  if(fHits[iht].WireID().Plane != planeID.Plane) continue;
6105  wire = fHits[iht].WireID().Wire;
6106  // define the first hit start index in this TPC, Plane
6107  if(firsthit[wire]) {
6108  WireHitRange[wire].first = iht;
6109  firsthit[wire] = false;
6110  }
6111  if(firstwire){
6112  fFirstWire = wire;
6113  firstwire = false;
6114  }
6115  WireHitRange[wire].second = iht+1;
6116  fLastWire = wire+1;
6117  ++nHitInPlane;
6118  }
6119  // overwrite with the "dead wires" condition
6120  lariov::ChannelStatusProvider const& channelStatus
6122 
6123  flag.first = -1; flag.second = -1;
6124  unsigned int nbad = 0;
6125  for(wire = 0; wire < nwires; ++wire) {
6126  raw::ChannelID_t chan = geom->PlaneWireToChannel((int)planeID.Plane,(int)wire,(int)planeID.TPC,(int)planeID.Cryostat);
6127  if(!channelStatus.IsGood(chan)) {
6128  WireHitRange[wire] = flag;
6129  ++nbad;
6130  }
6131  } // wire
6132 // std::cout<<nbad<<" bad wires in plane "<<planeID.Plane<<"\n";
6133 
6134  // define the MergeAvailable vector and check for errors
6135  if(mergeAvailable.size() < fHits.size()) throw art::Exception(art::errors::LogicError)
6136  <<"GetHitRange: Invalid mergeAvailable vector size "<<mergeAvailable.size()<<fHits.size();
6137  unsigned int firstHit, lastHit;
6138  unsigned int cnt;
6139  cnt = 0;
6140  float maxRMS, chiSep, peakCut;
6141  for(wire = 0; wire < nwires; ++wire) {
6142  // ignore dead wires and wires with no hits
6143  if(WireHitRange[wire].first < 0) continue;
6144  firstHit = WireHitRange[wire].first;
6145  lastHit = WireHitRange[wire].second;
6146  for(iht = firstHit; iht < lastHit; ++iht) {
6147  if(fHits[iht].WireID().Wire != wire)
6148  throw art::Exception(art::errors::LogicError)<<"Bad WireHitRange on wire "<<wire<<"\n";
6149  ++cnt;
6150  if(fHits[iht].Multiplicity() > 1) {
6151  peakCut = 0.6 * fHits[iht].PeakAmplitude();
6152  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(iht);
6153  for(size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
6154  if(jht == iht) continue;
6155  // require that the j hit be similar in magnitude to the i hit
6156  if(fHits[jht].PeakAmplitude() < peakCut) continue;
6157  maxRMS = std::max(fHits[iht].RMS(), fHits[jht].RMS());
6158  chiSep = std::abs(fHits[iht].PeakTime() - fHits[jht].PeakTime()) / maxRMS;
6159  if(chiSep < fHitMergeChiCut) {
6160  mergeAvailable[iht] = true;
6161  break;
6162  }
6163  } // jht
6164  } // fHits[iht].Multiplicity() > 1
6165  } // iht
6166  } // wire
6167  if(cnt != nHitInPlane) mf::LogWarning("CC")<<"Bad WireHitRange count "<<cnt<<" "<<nHitInPlane<<"\n";
6168 
6169  if(!fMergeAllHits) return;
6170 
6171  // Merge all of the hits
6172  bool didMerge;
6173  for(wire = 0; wire < nwires; ++wire) {
6174  if(WireHitRange[wire].first < 0) continue;
6175  firstHit = WireHitRange[wire].first;
6176  lastHit = WireHitRange[wire].second;
6177  for(iht = firstHit; iht < lastHit; ++iht) {
6178  if(!mergeAvailable[iht]) continue;
6179  // already merged?
6180  if(fHits[iht].GoodnessOfFit() == 6666) continue;
6181  MergeHits(iht, didMerge);
6182  mergeAvailable[iht] = false;
6183  } // iht
6184  } // wire
6185 
6186  } // GetHitRange()
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
void MergeHits(const unsigned int theHit, bool &didMerge)
art::ServiceHandle< geo::Geometry > geom
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
static geo::PlaneID DecodeCTP(CTP_t CTP)
unsigned int fLastWire
the last wire with a hit
Int_t max
Definition: plot.C:27
unsigned int fFirstWire
the first wire with a hit
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
std::pair< size_t, size_t > FindHitMultiplet(size_t iHit) const
std::vector< std::pair< int, int > > WireHitRange
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 fFirstHit
first hit used
float fHitMergeChiCut
is < cut. Set < 0 for no merging
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
std::vector<recob::Hit> cluster::ClusterCrawlerAlg::GetHits ( void  )
inline

Returns the collection of reconstructed hits.

Definition at line 122 of file ClusterCrawlerAlg.h.

References fHits.

122 { 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 116 of file ClusterCrawlerAlg.h.

References inClus.

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

116 {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 131 of file ClusterCrawlerAlg.h.

References ClearResults(), SortByMultiplet(), and vtx3.

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

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

Definition at line 530 of file ClusterCrawlerAlg.cxx.

531  {
532  // Ghost Clusters:
533 
534  if(tcl.size() < 2) return;
535 
536  unsigned short icl, jcl;
537  // This code preferentially selects icl clusters that were
538  // reconstructed on an early pass (unless they were split)
539  std::vector<float> iHits, jHits;
540  unsigned int indx;
541  // find the average hit width on the first pass and construct
542  // a hit separation cut
543  float sepcut = 0, iFrac, jFrac;
544  bool first = true;
545  unsigned short iLoIndx, jLoIndx, olapSize, iop, ii, jj;
546  unsigned short nclose;
547  float iChg, jChg;
548  // vecrtor of clusters that will be killed after all is done
549  std::vector<unsigned short> killMe;
550  bool doKill;
551  for(icl = 0; icl < tcl.size() - 1; ++icl) {
552  if(tcl[icl].ID < 0) continue;
553  if(tcl[icl].CTP != clCTP) continue;
554 // if(tcl[icl].ProcCode < 300) continue;
555  // put the hits into a wire ordered vector
556  iHits.clear();
557  // initialize to a large positive value
558  iHits.resize(tcl[icl].BeginWir - tcl[icl].EndWir + 1, 1000);
559  iChg = 0;
560  for(auto iht : tcl[icl].tclhits) {
561  indx = fHits[iht].WireID().Wire - tcl[icl].EndWir;
562  if(indx > iHits.size() - 1) {
563  mf::LogWarning("CC")<<"KillGarbageClusters: icl ID "<<tcl[icl].ID<<" Bad indx "<<indx<<" "<<iHits.size()<<"\n";
564  continue;
565  }
566  iHits[indx] = fHits[iht].PeakTime();
567  iChg += fHits[iht].Integral();
568  if(first) sepcut += fHits[iht].RMS();
569  } // iht
570  if(first) {
571  sepcut /= (float)tcl[icl].tclhits.size();
572  // clusters are consider ghost candidates if many hits
573  // are within sepcut of each other on the same wire
574  sepcut *= 10;
575  first = false;
576  } // first
577  for(jcl = icl + 1; jcl < tcl.size(); ++jcl) {
578  if(tcl[jcl].ID < 0) continue;
579  if(tcl[jcl].CTP != clCTP) continue;
580 // if(tcl[jcl].ProcCode < 300) continue;
581  // ignore if there is no overlap
582  if(tcl[icl].BeginWir < tcl[jcl].EndWir) continue;
583  if(tcl[icl].EndWir > tcl[jcl].BeginWir) continue;
584  // require similar angle
585  if(std::abs(tcl[icl].BeginAng - tcl[jcl].BeginAng) > fKillGarbageClusters) continue;
586  // find the overlap region
587  if(tcl[icl].EndWir < tcl[jcl].EndWir) {
588  // icl E-----------....
589  // jcl E----------....
590  // olap xxxxxxxxxx...
591  iLoIndx = tcl[jcl].EndWir - tcl[icl].EndWir;
592  jLoIndx = 0;
593  if(tcl[icl].BeginWir < tcl[jcl].BeginWir) {
594  // icl E-----------B
595  // jcl E------------B
596  // olap xxxxxxxxxx
597  olapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
598  } else {
599  // icl E-----------B
600  // jcl E-----B
601  // olap xxxxxxx
602  olapSize = tcl[jcl].BeginWir - tcl[jcl].EndWir + 1;
603  } // iBegin
604  } // iEnd < jEnd
605  else {
606  // icl E-----------....
607  // jcl E----------....
608  // olap xxxxxxxxxx...
609  iLoIndx = 0;
610  jLoIndx = tcl[icl].EndWir - tcl[icl].EndWir;
611  if(tcl[icl].BeginWir < tcl[jcl].BeginWir) {
612  // icl E-----B
613  // jcl E-----------B
614  // olap xxxxxxx
615  olapSize = tcl[icl].BeginWir - tcl[icl].EndWir + 1;
616  } else {
617  // icl E-----------B
618  // jcl E----------B
619  // olap xxxxxxxxx
620  olapSize = tcl[jcl].BeginWir - tcl[icl].EndWir + 1;
621  }
622  } // iEnd > jEnd
623  jHits.clear();
624  // initialize to a large negative value
625  jHits.resize(tcl[jcl].BeginWir - tcl[jcl].EndWir + 1, -1000);
626  jChg = 0;
627  for(auto jht : tcl[jcl].tclhits) {
628  indx = fHits[jht].WireID().Wire - tcl[jcl].EndWir;
629  if(indx > jHits.size() - 1) {
630  mf::LogWarning("CC")<<"KillGarbageClusters: jcl ID "<<tcl[jcl].ID<<" Bad indx "<<indx<<" "<<jHits.size()<<"\n";
631  continue;
632  }
633  jHits[indx] = fHits[jht].PeakTime();
634  jChg += fHits[jht].Integral();
635  } // jht
636 /*
637  mf::LogVerbatim myprt("CC");
638  myprt<<"Check icl ID "<<tcl[icl].ID<<" size "<<iHits.size()<<" iLoIndx "<<iLoIndx;
639  myprt<<" wire range "<<tcl[icl].EndWir<<"-"<<tcl[icl].BeginWir;
640  myprt<<" jcl ID "<<tcl[jcl].ID<<" size "<<jHits.size()<<" jLoIndx "<<jLoIndx;
641  myprt<<" wire range "<<tcl[jcl].EndWir<<"-"<<tcl[jcl].BeginWir;
642  myprt<<" olapSize "<<olapSize;
643 */
644  // count the number of close hits
645  nclose = 0;
646  for(iop = 0; iop < olapSize; ++iop) {
647  ii = iLoIndx + iop;
648  if(ii > iHits.size() - 1) continue;
649  jj = jLoIndx + iop;
650  if(jj > jHits.size() - 1) continue;
651  if(std::abs(iHits[ii] - jHits[jj]) < sepcut) ++nclose;
652  } // iop
653  iFrac = (float)nclose / (float)iHits.size();
654  jFrac = (float)nclose / (float)jHits.size();
655  if(iFrac < 0.5 && jFrac < 0.5) continue;
656  doKill = (iFrac < jFrac && iChg > jChg);
657 /*
658  mf::LogVerbatim myprt("CC");
659  myprt<<"Check icl ID "<<tcl[icl].ID<<" size "<<iHits.size()<<" iFrac "<<iFrac<<" iChg "<<(int)iChg;
660  myprt<<" jcl ID "<<tcl[jcl].ID<<" size "<<jHits.size()<<" jFrac "<<jFrac<<" jChg "<<(int)jChg<<" doKill? "<<doKill;
661 */
662  if(doKill) killMe.push_back(jcl);
663  } // jcl
664  } // icl
665 
666  if(killMe.size() == 0) return;
667  for(auto icl : killMe) {
668  // killing time
669  if(tcl[icl].ID < 0) continue;
670  tcl[icl].ProcCode = 666;
671  MakeClusterObsolete(icl);
672  } // icl
673 
674 
675  } // KillGarbageClusters
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< ClusterStore > tcl
the clusters we are creating
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 3736 of file ClusterCrawlerAlg.cxx.

3736  {
3737  // Crawl a large angle cluster upstream. Similar to CrawlUS but require
3738  // that a hit be added on each wire
3739 
3740 
3741  unsigned int dhit = fcl2hits[0];
3742  short dwir = fHits[dhit].WireID().Wire;
3743  clLA = true;
3744  prt = false;
3745  if(fDebugPlane == (short)plane && dwir == fDebugWire && fDebugHit > 0)
3746  prt = std::abs(fHits[dhit].PeakTime() - fDebugHit) < 40;
3747 
3748  if(prt) {
3749  mf::LogVerbatim myprt("CC");
3750  myprt<<"******************* LACrawlUS PASS "<<pass<<" Hits ";
3751  for(unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3752  unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3753  myprt<<fHits[iht].WireID().Wire<<":"<<(int)fHits[iht].PeakTime()<<" ";
3754  }
3755  }
3756 
3757  bool SigOK = true;
3758  bool HitOK = true;
3759  short nmissed = 0;
3760  // count the number of kinks encountered. Hits US of the kink are removed
3761  // and crawling continues unless another kink is encountered
3762  unsigned short kinkOnWire = 0;
3763  unsigned int it = fcl2hits.size() - 1;
3764  unsigned int lasthit = fcl2hits[it];
3765  unsigned int lastwire = fHits[lasthit].WireID().Wire;
3766  unsigned int prevHit, prevWire;
3767  bool ChkCharge = false;
3768  for(unsigned int nextwire = lastwire-1; nextwire >= fFirstWire; --nextwire) {
3769  if(prt) mf::LogVerbatim("CC")<<"LACrawlUS: next wire "<<nextwire<<" HitRange "<<WireHitRange[nextwire].first;
3770  // stop crawling if there is a nearby vertex
3771  if(CrawlVtxChk(nextwire)) {
3772  if(prt) mf::LogVerbatim("CC")<<"LACrawlUS: stop at vertex";
3773  clStopCode = 6;
3774  break;
3775  }
3776  // AddLAHit will merge the hit on nextwire if necessary
3777  AddLAHit(nextwire, ChkCharge, HitOK, SigOK);
3778  if(prt) mf::LogVerbatim("CC")<<"LACrawlUS: HitOK "<<HitOK<<" SigOK "<<SigOK<<" nmissed SigOK "<<nmissed<<" cut "<<fAllowNoHitWire;
3779  if(SigOK) nmissed = 0;
3780  if(!SigOK) {
3781  ++nmissed;
3782  if(nmissed > fAllowNoHitWire) {
3783  clStopCode = 1;
3784  break;
3785  }
3786  continue;
3787  }
3788  // If a hit was added after a gap, check to see if there is indeed
3789  // a wire signal in the gap
3790  if(HitOK) {
3791  prevHit = fcl2hits[fcl2hits.size() - 2];
3792  prevWire = fHits[prevHit].WireID().Wire;
3793  if(prevWire > nextwire + 2) {
3794  if(!ChkSignal(fcl2hits[fcl2hits.size()-1], fcl2hits[fcl2hits.size()-2])) {
3795  // no hit so trim the last hit and quit
3796  FclTrimUS(1);
3797  break;
3798  } // no signal
3799  } // prevWire > nextwire + 2
3800  } // HitOK
3801  // Merge all of the hit multiplets in the fcl2hits array into single
3802  // hits when enough hits have been found to call this a credible large
3803  // angle cluster. The last hit was already merged in AddHit
3804  if(fcl2hits.size() == 4) {
3805  bool didMerge;
3806  for(unsigned short kk = 0; kk< fcl2hits.size()-1; ++kk) {
3807  unsigned int hit = fcl2hits[kk];
3808  if(mergeAvailable[hit]) MergeHits(hit, didMerge);
3809  }
3810  // update the fit
3811  FitCluster();
3812  clBeginSlp = clpar[1];
3813  // start checking the charge ratio when adding new hits
3814  ChkCharge = true;
3815  continue;
3816  } // fcl2hits.size() == 4
3817  unsigned short chsiz = chifits.size()-1;
3818  // chsiz is fcl2hits.size() - 1...
3819  if(chsiz < 6) continue;
3820  if(fKinkChiRat[pass] <= 0) continue;
3821  if(chifits.size() != fcl2hits.size()) {
3822  mf::LogError("CC")
3823  <<"LACrawlUS: chifits size error "<<chifits.size()<<" "<<fcl2hits.size();
3824  return;
3825  }
3826  if(prt) mf::LogVerbatim("CC") <<"Kink chk "<<chifits[chsiz]<<" "<<chifits[chsiz-1]
3827  <<" "<<chifits[chsiz-2]<<" "<<chifits[chsiz-3];
3828  if( chifits[chsiz-1] > fKinkChiRat[pass] * chifits[chsiz-2] &&
3829  chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz-1]) {
3830  // find the kink angle (crudely) from the 0th and 2nd hit
3831  unsigned int ih0 = fcl2hits.size() - 1;
3832  unsigned int hit0 = fcl2hits[ih0];
3833  unsigned int ih2 = ih0 - 2;
3834  unsigned int hit2 = fcl2hits[ih2];
3835  float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3836  float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3837  float th02 = std::atan( fScaleF * dt02 / dw02);
3838  // and the 3rd and 5th hit
3839  unsigned int ih3 = ih2 - 1;
3840  unsigned int hit3 = fcl2hits[ih3];
3841  unsigned int ih5 = ih3 - 2;
3842  unsigned int hit5 = fcl2hits[ih5];
3843  float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
3844  float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
3845  float th35 = std::atan(fScaleF * dt35 / dw35);
3846  float dth = std::abs(th02 - th35);
3847  if(prt) mf::LogVerbatim("CC")<<" Kink angle "<<std::setprecision(3)<<dth<<" cut "<<fKinkAngCut[pass];
3848  if(dth > fKinkAngCut[pass]) {
3849  // hit a kink. Lop of the first 3 hits, refit and keep crawling?
3850  FclTrimUS(3);
3851  FitCluster();
3852  // See if this is a second kink and it is close to the first
3853  // kink (which had hits removed).
3854  if(kinkOnWire > 0) {
3855  if(kinkOnWire - nextwire < 4) {
3856  if(prt) mf::LogVerbatim("CC") <<"Hit a second kink. kinkOnWire = "<<kinkOnWire<<" Stopping";
3857  // set the kink stop code
3858  clStopCode = 3;
3859  break;
3860  }
3861  }
3862  kinkOnWire = nextwire;
3863  if(prt) mf::LogVerbatim("CC")<<"Removed kink hits";
3864  } // kinkang check
3865  } // chifits test
3866  } // nextwire
3867 
3869 
3870  clProcCode += 300;
3871  if(prt) mf::LogVerbatim("CC")<<"LACrawlUS done. Nhits = "<<fcl2hits.size();
3872  prt = false;
3873  } // LACrawlUS
float fScaleF
scale factor from Tick/Wire to dx/du
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
bool ChkSignal(unsigned int iht, unsigned int jht)
int fDebugWire
set to the Begin Wire and Hit of a cluster to print
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.
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
std::vector< std::pair< int, int > > WireHitRange
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 854 of file ClusterCrawlerAlg.cxx.

854  {
855  short& ID = tcl[icl].ID;
856  if (ID <= 0) {
857  mf::LogError("CC")<<"Trying to make already-obsolete cluster obsolete ID = "<<ID;
858  return; // already obsolete
859  }
860  ID = -ID; // mark the cluster as obsolete
861 
862  // release the hits
863  for(unsigned int iht = 0; iht < tcl[icl].tclhits.size(); ++iht) inClus[tcl[icl].tclhits[iht]] = 0;
864 
865  } // ClusterCrawlerAlg::MakeClusterObsolete()
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< ClusterStore > tcl
the clusters we are creating
void cluster::ClusterCrawlerAlg::MergeHits ( const unsigned int  theHit,
bool &  didMerge 
)
private

Definition at line 1654 of file ClusterCrawlerAlg.cxx.

References 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().

1654  {
1655  // Merge all unused separate hits in the multiplet of which
1656  // theHit is a member into one hit (= theHit).
1657  // Mark the merged hits other than theHit obsolete.
1658  // Hits in the multiplet that are associated with an existing cluster are
1659  // not affected.
1660  // Hit multiplicity is reworked (including all the hits in the multiplet).
1661  // Used hits have the multiplicity and index corrected too; the local
1662  // index reflects the peak time.
1663  // Note that theHit may or may not be marked free (usually, it is not)
1664 
1665  didMerge = false;
1666 
1667  if(theHit > fHits.size() - 1) {
1668 // mf::LogError("CC")<<"Bad theHit";
1669  return;
1670  }
1671 
1672  recob::Hit const& hit = fHits[theHit];
1673 
1674  // don't bother trying to merge an already merged hit
1675  if(fHits[theHit].GoodnessOfFit() == 6666) {
1676  if(prt) mf::LogVerbatim("CC")<<"MergeHits Trying to merge already merged hit "
1677  <<hit.WireID().Plane<<":"<<hit.WireID().Wire<<":"<<(int)hit.PeakTime()
1678  <<" Multiplicity "<<hit.Multiplicity()<<" theHit "<<theHit;
1679  return;
1680  }
1681 
1682  // don't merge if it isn't available
1683  if(!mergeAvailable[theHit]) {
1684 // if(prt) mf::LogVerbatim("CC")<<"MergeHits "<<hit.WireID().Plane<<":"<<hit.WireID().Wire<<":"<<(int)hit.PeakTime()<<" Multiplicity "<<hit.Multiplicity()<<" theHit "<<theHit<<" is not available";
1685  return;
1686  }
1687 
1688  if(hit.Multiplicity() < 2) return;
1689 
1690 // if(prt) mf::LogVerbatim("CC")<<"MergeHits "<<hit.WireID().Plane<<":"<<hit.WireID().Wire<<":"<<(int)hit.PeakTime()<<" Multiplicity "<<hit.Multiplicity()<<" theHit "<<theHit;
1691 // if(prt && fcl2hits.size() > 0)mf::LogVerbatim("CC")<<" Seed hit "<<fHits[fcl2hits[0]].WireID().Wire<<":"<<(int)fHits[fcl2hits[0]].PeakTime();
1692 
1693  // number of hits in this hit multiplet
1694  std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(theHit);
1695 
1696  // ensure that this is a high multiplicity hit:
1697  if (MultipletRange.second <= MultipletRange.first) return;
1698 
1699  // do a quick check to see how many hits are available to be merged
1700  unsigned short nAvailable = 0;
1701  unsigned short nInClus = 0;
1702  for(size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1703  if(jht == theHit) continue;
1704  if(fHits[jht].GoodnessOfFit() == 6666) continue;
1705  if(inClus[jht] != 0) {
1706  ++nInClus;
1707  continue;
1708  }
1709  ++nAvailable;
1710  } // jht
1711  if(nAvailable == 0) return;
1712  // don't merge if any hit is used
1713  if(nInClus > 0) return;
1714 
1715  // calculate the Charge normalization factor using the hit information
1716  // instead of passing CCHitFinder ChgNorms all the way down here
1717  float chgNorm = 2.507 * hit.PeakAmplitude() * hit.RMS() / hit.Integral();
1718 
1719  short loTime = 9999;
1720  short hiTime = 0;
1721  unsigned short nGaus = 1;
1722  float hitSep;
1723  // number of hits that are close to theHit
1724  unsigned short nclose = 0;
1725  // find the time range for the hit multiplet
1726  for(size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1727  if(inClus[jht] < 0) continue;
1728  recob::Hit const& other_hit = fHits[jht];
1729 /*
1730  if(prt) {
1731  mf::LogVerbatim("CC")
1732  <<" P:W:T "<<plane<<":"<<other_hit.WireID().Wire<<":"<<(int)other_hit.PeakTime()
1733  <<" Amp "<<(int)other_hit.PeakAmplitude()
1734  <<" RMS "<<other_hit.RMS()
1735  <<" Charge "<<(int)other_hit.Integral()
1736  <<" inClus "<<inClus[jht];
1737  }
1738 */
1739  // error checking
1740  if((other_hit.StartTick() != hit.StartTick())
1741  || (other_hit.WireID() != hit.WireID()))
1742  {
1743 /*
1744  mf::LogError("CC")<<"Hit multiplet ID error "
1745  << other_hit.WireID() << " @" << other_hit.StartTick()
1746  << " " << other_hit.LocalIndex() << "/" << other_hit.Multiplicity()
1747  << " vs. " << hit.WireID() << " @" << hit.StartTick()
1748  << " " << hit.LocalIndex() << "/" << hit.Multiplicity()
1749  ;
1750 */
1751  return;
1752  }
1753  if (other_hit.Multiplicity() != hit.Multiplicity()) {
1754 /*
1755  mf::LogError("CC")
1756  << " hit #" << jht << " in the same multiplet as #" << theHit
1757  << " has different multiplicity!"
1758  << "\n hit #" << theHit << ": " << hit
1759  << "\n hit #" << jht << ": " << other_hit;
1760 */
1761  return;
1762  }
1763  // hit is not used by another cluster
1764  if(inClus[jht] != 0) continue;
1765  short arg = (short)(other_hit.PeakTimeMinusRMS(3));
1766  if(arg < loTime) loTime = arg;
1767  arg = (short)(other_hit.PeakTimePlusRMS(3));
1768  if(arg > hiTime) hiTime = arg;
1769  if(jht != theHit) ++nGaus;
1770  hitSep = std::abs(other_hit.PeakTime() - hit.PeakTime()) / other_hit.RMS();
1771  if(jht != theHit && hitSep < 3) ++nclose;
1772  } // jht
1773  // all hits in the multiplet other than this one used?
1774  if(nGaus < 2) return;
1775 
1776  // the hits in this multiplet will have this multiplicity from now on
1777  const short int NewMultiplicity = hit.Multiplicity() + 1 - nGaus;
1778 
1779  if(loTime < 0) loTime = 0;
1780  ++hiTime;
1781  // define a signal shape, fill it with zeros
1782  std::vector<double> signal(hiTime - loTime, 0.);
1783  // now add the Gaussians for each hit
1784  double chgsum = 0.;
1785  for(size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1786  recob::Hit const& other_hit = fHits[jht];
1787  if(jht != theHit) {
1788  // hit used in another cluster
1789  if(inClus[jht] != 0) continue;
1790  // declare this hit obsolete
1791  inClus[jht] = -1;
1792  } // jht != theHit
1793  // add up the charge
1794  chgsum += other_hit.Integral();
1795  for(unsigned short time = loTime; time < hiTime; ++time) {
1796  unsigned short indx = time - loTime;
1797  double arg = (other_hit.PeakTime() - (double)time) / other_hit.RMS();
1798  signal[indx] += other_hit.PeakAmplitude() * exp(-0.5 * arg * arg);
1799  } // time
1800  } // jj
1801  // find the average weighted time
1802  double sigsum = 0.;
1803  double sigsumt = 0.;
1804  for(unsigned short time = loTime; time < hiTime; ++time) {
1805  sigsum += signal[time - loTime];
1806  sigsumt += signal[time - loTime] * time;
1807  }
1808  if(sigsum == 0.) {
1809 // mf::LogError("CC")<<"MergeHits: bad sum";
1810  return;
1811  }
1812  double aveTime = sigsumt / sigsum;
1813  // find the RMS
1814  sigsumt = 0.;
1815  for(unsigned short time = loTime; time < hiTime; ++time) {
1816  double dtime = time - aveTime;
1817  sigsumt += signal[time - loTime] * dtime * dtime;
1818  }
1819  const float RMS = std::sqrt(sigsumt / sigsum);
1820  // find the amplitude from the integrated charge and the RMS
1821  const float amplitude = chgsum * chgNorm/ (2.507 * RMS);
1822  // modify the hit "in place" (actually completely overwrite it...)
1823  // TODO a lot of these quantities need revamp!!
1824  fHits[theHit] = recob::Hit(
1825  hit.Channel(),
1826  hit.StartTick(),
1827  hit.EndTick(),
1828  aveTime, // peak_time
1829  hit.SigmaPeakTime(),
1830  RMS, // rms
1831  amplitude, // peak_amplitude
1832  hit.SigmaPeakAmplitude(),
1833  hit.SummedADC(),
1834  chgsum, // hit_integral
1835  hit.SigmaIntegral(),
1836  NewMultiplicity, // multiplicity
1837  0, // local index
1838  6666, // GoodnessOfFit (flag for merged hit)
1839  hit.DegreesOfFreedom(),
1840  hit.View(),
1841  hit.SignalType(),
1842  hit.WireID()
1843  );
1844 /*
1845  if(prt) {
1846  mf::LogVerbatim("CC")
1847  <<" theHit "<<fHits[theHit].WireID().Wire<<":"<<(int)aveTime
1848  <<" RMS "<<std::setprecision(1)<<fHits[theHit].RMS()
1849  <<" chg "<<(int)chgsum<<" Amp "<<(int)fHits[theHit].PeakAmplitude();
1850  }
1851 */
1852  FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1853  didMerge = true;
1854 
1855  } // MergeHits()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
Definition: Hit.h:232
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:221
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:223
float SigmaIntegral() const
Initial tdc tick for hit.
Definition: Hit.h:226
int DegreesOfFreedom() const
Initial tdc tick for hit.
Definition: Hit.h:230
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:233
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
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[.
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:227
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:222
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:258
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:217
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:240
Detector simulation of raw signals on wires.
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:218
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
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:224
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:220
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:237
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
void cluster::ClusterCrawlerAlg::MergeOverlap ( )
private

Definition at line 679 of file ClusterCrawlerAlg.cxx.

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

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

6384  {
6385  // Returns the Chisq/DOF between a (Wire, Tick) point and a vertex
6386 
6387  if(ivx > vtx.size()) return 9999;
6388 
6389  float dW = wire - vtx[ivx].Wire;
6390  float chi = dW / vtx[ivx].WireErr;
6391  float totChi = chi * chi;
6392  float dT = tick - vtx[ivx].Time;
6393  chi = dT / vtx[ivx].TimeErr;
6394  totChi += chi * chi;
6395 
6396  return totChi;
6397 
6398  } // PointVertexChi
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::PrintClusters ( )
private

Definition at line 3499 of file ClusterCrawlerAlg.cxx.

References art::right().

3500  {
3501 
3502  // prints clusters to the screen for code development
3503  mf::LogVerbatim myprt("CC");
3504 
3505  PrintVertices();
3506 
3507  float aveRMS, aveRes;
3508  myprt<<"*************************************** Clusters *********************************************************************\n";
3509  myprt<<" ID CTP nht Stop Proc beg_W:T bAng bSlp Err bChg end_W:T eAng eSlp Err eChg bVx eVx aveRMS Qual cnt\n";
3510  for(unsigned short ii = 0; ii < tcl.size(); ++ii) {
3511  // print clusters in all planes (fDebugPlane = 3) or in a selected plane
3512  if(fDebugPlane < 3 && fDebugPlane != (int)tcl[ii].CTP) continue;
3513  myprt<<std::right<<std::setw(4)<<tcl[ii].ID;
3514  myprt<<std::right<<std::setw(3)<<tcl[ii].CTP;
3515  myprt<<std::right<<std::setw(5)<<tcl[ii].tclhits.size();
3516  myprt<<std::right<<std::setw(4)<<tcl[ii].StopCode;
3517  myprt<<std::right<<std::setw(6)<<tcl[ii].ProcCode;
3518  unsigned int iTime = tcl[ii].BeginTim;
3519  myprt<<std::right<<std::setw(6)<<tcl[ii].BeginWir<<":"<<iTime;
3520  if(iTime < 10) {
3521  myprt<<" ";
3522  } else if(iTime < 100) {
3523  myprt<<" ";
3524  } else if(iTime < 1000) myprt<<" ";
3525  myprt<<std::right<<std::setw(7)<<std::fixed<<std::setprecision(2)<<tcl[ii].BeginAng;
3526  if(std::abs(tcl[ii].BeginSlp) < 100) {
3527  myprt<<std::right<<std::setw(6)<<std::fixed<<std::setprecision(2)<<tcl[ii].BeginSlp;
3528  } else {
3529  myprt<<std::right<<std::setw(6)<<(int)tcl[ii].BeginSlp;
3530  }
3531  myprt<<std::right<<std::setw(6)<<std::fixed<<std::setprecision(2)<<tcl[ii].BeginSlpErr;
3532  myprt<<std::right<<std::setw(5)<<(int)tcl[ii].BeginChg;
3533 // myprt<<std::right<<std::setw(5)<<std::fixed<<std::setprecision(1)<<tcl[ii].BeginChgNear;
3534  iTime = tcl[ii].EndTim;
3535  myprt<<std::right<<std::setw(6)<<tcl[ii].EndWir<<":"<<iTime;
3536  if(iTime < 10) {
3537  myprt<<" ";
3538  } else if(iTime < 100) {
3539  myprt<<" ";
3540  } else if(iTime < 1000) myprt<<" ";
3541  myprt<<std::right<<std::setw(7)<<std::fixed<<std::setprecision(2)<<tcl[ii].EndAng;
3542  if(std::abs(tcl[ii].EndSlp) < 100) {
3543  myprt<<std::right<<std::setw(6)<<std::fixed<<std::setprecision(2)<<tcl[ii].EndSlp;
3544  } else {
3545  myprt<<std::right<<std::setw(6)<<(int)tcl[ii].EndSlp;
3546  }
3547  myprt<<std::right<<std::setw(6)<<std::fixed<<std::setprecision(2)<<tcl[ii].EndSlpErr;
3548  myprt<<std::right<<std::setw(5)<<(int)tcl[ii].EndChg;
3549 // myprt<<std::right<<std::setw(5)<<std::fixed<<std::setprecision(1)<<tcl[ii].EndChgNear;
3550  myprt<<std::right<<std::setw(5)<<tcl[ii].BeginVtx;
3551  myprt<<std::right<<std::setw(5)<<tcl[ii].EndVtx;
3552  aveRMS = 0;
3553  unsigned int iht = 0;
3554  for(unsigned short jj = 0; jj < tcl[ii].tclhits.size(); ++jj) {
3555  iht = tcl[ii].tclhits[jj];
3556  aveRMS += fHits[iht].RMS();
3557  }
3558  aveRMS /= (float)tcl[ii].tclhits.size();
3559  myprt<<std::right<<std::setw(5)<<std::fixed<<std::setprecision(1)<<aveRMS;
3560  aveRes = 0;
3561  // find cluster tracking resolution
3562  unsigned int hit0, hit1, hit2, cnt = 0;
3563  float arg;
3564  for(unsigned short iht = 1; iht < tcl[ii].tclhits.size()-1; ++iht) {
3565  hit1 = tcl[ii].tclhits[iht];
3566  hit0 = tcl[ii].tclhits[iht-1];
3567  hit2 = tcl[ii].tclhits[iht+1];
3568  // require hits on adjacent wires
3569  if(fHits[hit1].WireID().Wire + 1 != fHits[hit0].WireID().Wire) continue;
3570  if(fHits[hit2].WireID().Wire + 1 != fHits[hit1].WireID().Wire) continue;
3571  arg = (fHits[hit0].PeakTime() + fHits[hit2].PeakTime())/2 - fHits[hit1].PeakTime();
3572  aveRes += arg * arg;
3573  ++cnt;
3574  }
3575  if(cnt > 1) {
3576  aveRes /= (float)cnt;
3577  aveRes = sqrt(aveRes);
3578  // convert to a quality factor
3579  aveRes /= (aveRMS * fHitErrFac);
3580  myprt<<std::right<<std::setw(6)<<std::fixed<<std::setprecision(1)<<aveRes;
3581  myprt<<std::right<<std::setw(5)<<std::fixed<<cnt;
3582  } else {
3583  myprt<<" NA";
3584  myprt<<std::right<<std::setw(5)<<std::fixed<<cnt;
3585  }
3586  myprt<<"\n";
3587  // TEMP
3588 // if(tcl[ii].BeginVtx >= 0) myprt<<"Begin vtx Chi "<<ClusterVertexChi(ii, 0, tcl[ii].BeginVtx)<<"\n";
3589 // if(tcl[ii].EndVtx >= 0) myprt<<"End vtx Chi "<<ClusterVertexChi(ii, 1, tcl[ii].EndVtx)<<"\n";
3590  } // ii
3591 
3592  } // PrintClusters()
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
float fHitErrFac
hit time error = fHitErrFac * hit RMS used for cluster fit
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< recob::Hit > fHits
our version of the hits
std::string cluster::ClusterCrawlerAlg::PrintHit ( unsigned int  iht)
private

Definition at line 6402 of file ClusterCrawlerAlg.cxx.

References util::flags::to_string().

6403  {
6404 
6405  if(iht > fHits.size() - 1) return "Bad Hit";
6406  return std::to_string(fHits[iht].WireID().Plane) + ":" +std::to_string(fHits[iht].WireID().Wire) + ":" + std::to_string((int)fHits[iht].PeakTime());
6407 
6408  } // PrintHit
std::vector< recob::Hit > fHits
our version of the hits
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
recob::tracking::Plane Plane
Definition: TrackState.h:17
void cluster::ClusterCrawlerAlg::PrintVertices ( )
private

Definition at line 3436 of file ClusterCrawlerAlg.cxx.

References art::right().

3437  {
3438 
3439  mf::LogVerbatim myprt("CC");
3440 
3441  if(vtx3.size() > 0) {
3442  // print out 3D vertices
3443  myprt<<"****** 3D vertices ******************************************__2DVtx_Indx__*******\n";
3444  myprt<<"Vtx Cstat TPC Proc X Y Z XEr YEr ZEr pln0 pln1 pln2 Wire\n";
3445  for(unsigned short iv = 0; iv < vtx3.size(); ++iv) {
3446  myprt<<std::right<<std::setw(3)<<std::fixed<<iv<<std::setprecision(1);
3447  myprt<<std::right<<std::setw(7)<<vtx3[iv].CStat;
3448  myprt<<std::right<<std::setw(5)<<vtx3[iv].TPC;
3449  myprt<<std::right<<std::setw(5)<<vtx3[iv].ProcCode;
3450  myprt<<std::right<<std::setw(8)<<vtx3[iv].X;
3451  myprt<<std::right<<std::setw(8)<<vtx3[iv].Y;
3452  myprt<<std::right<<std::setw(8)<<vtx3[iv].Z;
3453  myprt<<std::right<<std::setw(5)<<vtx3[iv].XErr;
3454  myprt<<std::right<<std::setw(5)<<vtx3[iv].YErr;
3455  myprt<<std::right<<std::setw(5)<<vtx3[iv].ZErr;
3456  myprt<<std::right<<std::setw(5)<<vtx3[iv].Ptr2D[0];
3457  myprt<<std::right<<std::setw(5)<<vtx3[iv].Ptr2D[1];
3458  myprt<<std::right<<std::setw(5)<<vtx3[iv].Ptr2D[2];
3459  myprt<<std::right<<std::setw(5)<<vtx3[iv].Wire;
3460  if(vtx3[iv].Wire < 0) {
3461  myprt<<" Matched in all planes";
3462  } else {
3463  myprt<<" Incomplete";
3464  }
3465  myprt<<"\n";
3466  }
3467  } // vtx3.size
3468 
3469  if(vtx.size() > 0) {
3470  // print out 2D vertices
3471  myprt<<"************ 2D vertices ************\n";
3472  myprt<<"Vtx CTP wire error tick error ChiDOF NCl topo cluster IDs\n";
3473  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
3474  if(fDebugPlane < 3 && fDebugPlane != (int)vtx[iv].CTP) continue;
3475  myprt<<std::right<<std::setw(3)<<std::fixed<<iv<<std::setprecision(1);
3476  myprt<<std::right<<std::setw(6)<<vtx[iv].CTP;
3477  myprt<<std::right<<std::setw(8)<<vtx[iv].Wire<<" +/- ";
3478  myprt<<std::right<<std::setw(4)<<vtx[iv].WireErr;
3479  myprt<<std::right<<std::setw(8)<<vtx[iv].Time<<" +/- ";
3480  myprt<<std::right<<std::setw(4)<<vtx[iv].TimeErr;
3481  myprt<<std::right<<std::setw(8)<<vtx[iv].ChiDOF;
3482  myprt<<std::right<<std::setw(5)<<vtx[iv].NClusters;
3483  myprt<<std::right<<std::setw(6)<<vtx[iv].Topo;
3484  myprt<<" ";
3485  // display the cluster IDs
3486  for(unsigned short ii = 0; ii < tcl.size(); ++ii) {
3487  if(fDebugPlane < 3 && fDebugPlane != (int)tcl[ii].CTP) continue;
3488  if(tcl[ii].ID < 0) continue;
3489  if(tcl[ii].BeginVtx == (short)iv) myprt<<std::right<<std::setw(4)<<tcl[ii].ID;
3490  if(tcl[ii].EndVtx == (short)iv) myprt<<std::right<<std::setw(4)<<tcl[ii].ID;
3491  }
3492  myprt<<"\n";
3493  } // iv
3494  } // vtx.size
3495 
3496  } // PrintVertices
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
void cluster::ClusterCrawlerAlg::reconfigure ( fhicl::ParameterSet const &  pset)
virtual

Definition at line 51 of file ClusterCrawlerAlg.cxx.

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

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

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

Definition at line 1366 of file ClusterCrawlerAlg.cxx.

1367  {
1368 
1369  // Try to attach or remove hits on the ends of vertex clusters
1370 
1371  std::vector<unsigned short> begClusters;
1372  std::vector<short> begdW;
1373  std::vector<unsigned short> endClusters;
1374  std::vector<short> enddW;
1375 
1376  unsigned int vWire = (unsigned int)(vtx[iv].Wire + 0.5);
1377  unsigned int vWireErr = (unsigned int)(2 * vtx[iv].WireErr);
1378  unsigned int vWireLo = vWire - vWireErr;
1379  unsigned int vWireHi = vWire + vWireErr;
1380 
1381  unsigned short icl, ii;
1382  short dW;
1383  bool needsWork = false;
1384  short maxdW = -100;
1385  short mindW = 100;
1386  for(icl = 0; icl < tcl.size(); ++icl) {
1387  if(tcl[icl].ID < 0) continue;
1388  if(tcl[icl].CTP != vtx[iv].CTP) continue;
1389  if(tcl[icl].BeginVtx == iv) {
1390  dW = vWire - tcl[icl].BeginWir;
1391  if(dW > maxdW) maxdW = dW;
1392  if(dW < mindW) mindW = dW;
1393  if(std::abs(dW) > 1) needsWork = true;
1394  // TODO: Check dTime also?
1395  begClusters.push_back(icl);
1396  begdW.push_back(dW);
1397  }
1398  if(tcl[icl].EndVtx == iv) {
1399  dW = vWire - tcl[icl].EndWir;
1400  if(dW > maxdW) maxdW = dW;
1401  if(dW < mindW) mindW = dW;
1402  if(std::abs(dW) > 1) needsWork = true;
1403  endClusters.push_back(icl);
1404  enddW.push_back(dW);
1405  }
1406  } // icl
1407 
1408  if(vtxprt) mf::LogVerbatim("CC")<<"RefineVertexClusters: vertex "<<iv<<" needsWork "<<needsWork
1409  <<" mindW "<<mindW<<" maxdW "<<maxdW<<" vWireErr "<<vWireErr;
1410 
1411  if(!needsWork) return;
1412 
1413  // See if we can move the vertex within errors to reconcile the differences
1414  // without altering the clusters
1415  if( ((unsigned int)std::abs(mindW) < vWireErr) && ((unsigned int)std::abs(maxdW) < vWireErr) && std::abs(maxdW - mindW) < 2) {
1416  if(vtxprt) mf::LogVerbatim("CC")<<" Move vtx wire "<<vtx[iv].Wire;
1417  vtx[iv].Wire -= (float)(maxdW + mindW)/2;
1418  if(vtxprt) mf::LogVerbatim("CC")<<" to "<<vtx[iv].Wire;
1419  // TODO: Fix the vertex time here if necessary
1420  vtx[iv].Fixed = true;
1421  // try to attach other clusters
1422  VertexCluster(iv);
1423  return;
1424  }
1425 
1426  // Check the vertex End clusters
1427  unsigned short newSize;
1428  for(ii = 0; ii < endClusters.size(); ++ii) {
1429  icl = endClusters[ii];
1430  if(vtxprt) mf::LogVerbatim("CC")<<" endCluster "<<tcl[icl].ID<<" dW "<<enddW[ii]<<" vWire "<<vWire;
1431  if(tcl[icl].EndWir < vWire) {
1432  // vertex is DS of the cluster end -> remove hits
1433  TmpGet(icl);
1434  newSize = fcl2hits.size();
1435  for(auto hiter = fcl2hits.rbegin(); hiter < fcl2hits.rend(); ++hiter) {
1436  if(fHits[*hiter].WireID().Wire > vWire) break;
1437  --newSize;
1438  }
1439  // release the hits
1440  for(auto hiter = fcl2hits.begin(); hiter < fcl2hits.end(); ++hiter) inClus[*hiter] = 0;
1441  // shorten the cluster
1442  fcl2hits.resize(newSize);
1443  MakeClusterObsolete(icl);
1444  // fit
1445  FitCluster();
1446  clProcCode += 700;
1447  // store it
1448  TmpStore();
1449  tcl[tcl.size()-1].EndVtx = iv;
1450  // update the vertex association
1451  if(vtxprt) mf::LogVerbatim("CC")<<" modified cluster "<<tcl[icl].ID<<" -> "<<tcl[tcl.size()-1].ID;
1452  } // tcl[icl].EndWir < vWire
1453  else if(tcl[icl].EndWir > vWire) {
1454  mf::LogVerbatim("CC")<<"RefineVertexClusters: Write some EndVtx code";
1455  } //
1456  } // ii endClusters
1457 
1458  if(begClusters.size() > 0) mf::LogVerbatim("CC")<<"RefineVertexClusters: Write some BeginVtx code";
1459 
1460  if(mindW < 0 && maxdW > 0) {
1461  // vertex wire is in between the ends of the clusters
1462  // inspect the hits on both clusters near the vertex. The vertex should probably be on the hit
1463  // with the highest charge
1464  int vtxHit = -1;
1465  unsigned short clsBigChg = 0;
1466  float bigChg = 0;
1467  unsigned int iht;
1468  unsigned int ihit;
1469  // check the begClusters
1470  for(ii = 0; ii < begClusters.size(); ++ii) {
1471  icl = begClusters[ii];
1472  for(iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1473  ihit = tcl[icl].tclhits[iht];
1474  if(fHits[ihit].Integral() > bigChg) {
1475  bigChg = fHits[ihit].Integral();
1476  vtxHit = ihit;
1477  clsBigChg = icl;
1478  }
1479  if(fHits[ihit].WireID().Wire < vWireLo) break;
1480  } // iht
1481  } // ii
1482  // now check the endClusters
1483  for(ii = 0; ii < endClusters.size(); ++ii) {
1484  icl = endClusters[ii];
1485  for(iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1486  ihit = tcl[icl].tclhits[tcl[icl].tclhits.size() - 1 - iht];
1487  if(fHits[ihit].Integral() > bigChg) {
1488  bigChg = fHits[ihit].Integral();
1489  vtxHit = ihit;
1490  clsBigChg = icl;
1491  }
1492  if(fHits[ihit].WireID().Wire > vWireHi) break;
1493  } // iht
1494  } // ii
1495  if(vtxHit > 0) {
1496  if(vtxprt) mf::LogVerbatim("CC")<<" moving vertex location to hit "
1497  <<fHits[vtxHit].WireID().Wire<<":"<<(int)fHits[vtxHit].PeakTime()<<" on cluster "<<tcl[clsBigChg].ID;
1498  vtx[iv].Wire = fHits[vtxHit].WireID().Wire;
1499  vtx[iv].Time = fHits[vtxHit].PeakTime();
1500  vtx[iv].Fixed = true;
1501  } // vtxHit > 0
1502  } // mindW < 0 && maxdW > 0
1503 
1504  FitVtx(iv);
1505 
1506  } // RefineVertexClusters
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void FitVtx(unsigned short iv)
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
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
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 1059 of file ClusterCrawlerAlg.cxx.

References hits().

1059  {
1060 
1061  unsigned int destHit = 0;
1062 
1063  if(fHits.size() != inClus.size()) {
1064  mf::LogError("CC")<<"RemoveObsoleteHits size mis-match "<<fHits.size()<<" "<<inClus.size();
1065  return;
1066  }
1067 
1068  unsigned short icl;
1069  for(unsigned int srcHit = 0; srcHit < fHits.size(); ++srcHit) {
1070  if(inClus[srcHit] < 0) continue;
1071  if(srcHit != destHit) {
1072  fHits[destHit] = std::move(fHits[srcHit]);
1073  inClus[destHit] = inClus[srcHit];
1074  if(inClus[destHit] > 0) {
1075  // hit is in a cluster. Find it and change the index
1076  icl = inClus[destHit] - 1;
1077  auto& hits = tcl[icl].tclhits;
1078  auto iHitIndex = std::find(hits.begin(), hits.end(), srcHit);
1079  if (iHitIndex == hits.end()) {
1080  mf::LogError("CC")<< "RemoveObsoleteHits: Hit #" << srcHit << " not found in cluster ID "<< inClus[destHit];
1081  } else {
1082  *iHitIndex = destHit; // update the index
1083  }
1084  } // inClus[destHit] > 0
1085  }
1086  ++destHit;
1087  } // srcHit
1088 
1089  fHits.resize(destHit);
1090  inClus.resize(destHit);
1091 
1092  } // RemoveObsoleteHits()
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< ClusterStore > tcl
the clusters we are creating
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 868 of file ClusterCrawlerAlg.cxx.

868  {
869  short& ID = tcl[icl].ID;
870  if(ID > 0) {
871  mf::LogError("CC")<<"Trying to restore non-obsolete cluster ID = "<<ID;
872  return;
873  }
874  ID = -ID;
875 
876  for(unsigned short iht = 0; iht < tcl[icl].tclhits.size(); ++iht) inClus[tcl[icl].tclhits[iht]] = ID;
877 
878  } // RestoreObsoleteCluster()
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
std::vector< ClusterStore > tcl
the clusters we are creating
void cluster::ClusterCrawlerAlg::RunCrawler ( std::vector< recob::Hit > const &  srchits)

Definition at line 181 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorProperties::DriftVelocity(), detinfo::DetectorProperties::Efield(), tca::EncodeCTP(), geo::TPCGeo::Nplanes(), detinfo::DetectorProperties::NumberTimeSamples(), tca::PrintClusters(), detinfo::DetectorProperties::SamplingRate(), and detinfo::DetectorProperties::Temperature().

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

182  {
183  // Run the ClusterCrawler algorithm - creating seed clusters and crawling upstream.
184 
185  CrawlInit();
186 
187  fHits = srchits; // plain copy of the sources; it's the base of our hit result
188 
189  if(fHits.size() < 3) return;
190  if(fHits.size() > UINT_MAX) {
191  mf::LogWarning("CC")<<"Too many hits for ClusterCrawler "<<fHits.size();
192  return;
193  }
194 
195  // don't do anything...
196  if(fNumPass == 0) return;
197 
198  // sort it as needed;
199  // that is, sorted by wire ID number,
200  // then by start of the region of interest in time, then by the multiplet
201  std::sort(fHits.begin(), fHits.end(), &SortByMultiplet);
202 
203  inClus.resize(fHits.size());
204  mergeAvailable.resize(fHits.size());
205  for(unsigned int iht = 0; iht < inClus.size(); ++iht) {
206  inClus[iht] = 0;
207  mergeAvailable[iht] = false;
208  }
209 
210  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
211 
212  for (geo::TPCID const& tpcid: geom->IterateTPCIDs()) {
213  geo::TPCGeo const& TPC = geom->TPC(tpcid);
214  for(plane = 0; plane < TPC.Nplanes(); ++plane){
215  WireHitRange.clear();
216  // define a code to ensure clusters are compared within the same plane
217  clCTP = EncodeCTP(tpcid.Cryostat, tpcid.TPC, plane);
218  cstat = tpcid.Cryostat;
219  tpc = tpcid.TPC;
220  // fill the WireHitRange vector with first/last hit on each wire
221  // dead wires and wires with no hits are flagged < 0
223 
224 // sanity check
225 /*
226  std::cout<<"Plane "<<plane<<" sanity check. Wire range "<<fFirstWire<<" "<<fLastWire;
227  unsigned int nhts = 0;
228  for(unsigned int wire = fFirstWire; wire < fLastWire; ++wire) {
229  if(WireHitRange[wire].first < 0) continue;
230  unsigned int fhit = WireHitRange[wire].first;
231  unsigned int lhit = WireHitRange[wire].second;
232  for(unsigned int hit = fhit; hit < lhit; ++hit) {
233  ++nhts;
234  if(fHits[hit].WireID().Wire != wire) {
235  std::cout<<"Bad wire "<<hit<<" "<<fHits[hit].WireID().Wire<<" "<<wire<<"\n";
236  return;
237  } // check wire
238  if(fHits[hit].WireID().Plane != plane) {
239  std::cout<<"Bad plane "<<hit<<" "<<fHits[hit].WireID().Plane<<" "<<plane<<"\n";
240  return;
241  } // check plane
242  if(fHits[hit].WireID().TPC != tpc) {
243  std::cout<<"Bad tpc "<<hit<<" "<<fHits[hit].WireID().TPC<<" "<<tpc<<"\n";
244  return;
245  } // check tpc
246  } // hit
247  } // wire
248  std::cout<<" is OK. nhits "<<nhts<<"\n";
249 */
250  if (WireHitRange.empty()||(fFirstWire == fLastWire)) continue;
251  raw::ChannelID_t channel = fHits[fFirstHit].Channel();
252  // get the scale factor to convert dTick/dWire to dX/dU. This is used
253  // to make the kink and merging cuts
254  float wirePitch = geom->WirePitch(geom->View(channel));
255  float tickToDist = detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
256  tickToDist *= 1.e-3 * detprop->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
257  fScaleF = tickToDist / wirePitch;
258  // convert Large Angle Cluster crawling cut to a slope cut
259  if(fLAClusAngleCut > 0)
260  fLAClusSlopeCut = std::tan(3.142 * fLAClusAngleCut / 180.) / fScaleF;
261  fMaxTime = detprop->NumberTimeSamples();
263  // look for clusters
264  if(fNumPass > 0) ClusterLoop();
265  } // plane
266  if(fVertex3DCut > 0) {
267  // Match vertices in 3 planes
268  VtxMatch(tpcid);
269  Vtx3ClusterMatch(tpcid);
271  // split clusters using 3D vertices
272  Vtx3ClusterSplit(tpcid);
273  }
274  if(fDebugPlane >= 0) {
275  mf::LogVerbatim("CC")<<"Clustering done in TPC ";
276  PrintClusters();
277  }
278  } // for all tpcs
279 
280  // clean up
281  WireHitRange.clear();
282  fcl2hits.clear();
283  chifits.clear();
284  hitNear.clear();
285  chgNear.clear();
286 
287 /*
288  // TEMP. Print out cluster info for tuning
289  std::array<unsigned int, 3> ncl;
290  std::array<unsigned int, 3> nht;
291  std::array<unsigned int, 3> nhtTot;
292  std::array<unsigned int, 3> nhtNotMerged;
293  unsigned int ipl;
294  for(ipl = 0; ipl < 3; ++ipl) {
295  ncl[ipl] = 0;
296  nht[ipl] = 0;
297  nhtTot[ipl] = 0;
298  nhtNotMerged[ipl] = 0;
299  }
300  // hits in clusters
301  for(unsigned int icl = 0; icl < tcl.size(); ++icl) {
302  if(tcl[icl].ID < 0) continue;
303  geo::PlaneID iplID = DecodeCTP(tcl[icl].CTP);
304  ipl = iplID.Plane;
305  ++ncl[ipl];
306  nht[ipl] += tcl[icl].tclhits.size();
307  }
308  // total number of hits
309  for(unsigned int iht = 0; iht < fHits.size(); ++iht) {
310  ipl = fHits[iht].WireID().Plane;
311  ++nhtTot[ipl];
312  if(inClus[iht] >= 0) ++nhtNotMerged[ipl];
313  }
314  int frc1, frc2;
315  for(ipl = 0; ipl < 3; ++ipl) {
316  frc1 = 0; frc2 = 0;
317  if(nhtNotMerged[ipl] > 0) frc1 = 100 * (float)nht[ipl] / (float)nhtNotMerged[ipl];
318  if(nhtTot[ipl] > 0) frc2 = 100 * (float)nhtNotMerged[ipl] / (float)nhtTot[ipl];
319  frc2 = 100 - frc2;
320  std::cout<<"plane "<<ipl<<" num clusters "<<ncl[ipl]<<" Hits in clusters "<<frc1<<"%. Hits merged "<<frc2<<"%\n";
321  }
322 */
323  // remove the hits that have become obsolete
325 
326  } // RunCrawler
float fScaleF
scale factor from Tick/Wire to dx/du
std::vector< short > hitNear
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void RemoveObsoleteHits()
Removes obsolete hits from hits, updating the indices.
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Geometry information for a single TPC.
Definition: TPCGeo.h:37
static bool SortByMultiplet(recob::Hit const &a, recob::Hit const &b)
Comparison for sorting hits by wire and hit multiplet.
virtual double SamplingRate() const =0
Returns the period of the TPC readout electronics clock.
art::ServiceHandle< geo::Geometry > geom
CTP_t clCTP
Cryostat/TPC/Plane code.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
IteratorBox< TPC_id_iterator,&GeometryCore::begin_TPC_id,&GeometryCore::end_TPC_id > IterateTPCIDs() const
Enables ranged-for loops on all TPC IDs of the detector.
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
void Vtx3ClusterMatch(geo::TPCID const &tpcid)
std::vector< short > inClus
Hit used in cluster (-1 = obsolete, 0 = free)
unsigned int fLastWire
the last wire with a hit
void VtxMatch(geo::TPCID const &tpcid)
unsigned short fNumPass
number of passes over the hit collection
unsigned int fFirstWire
the first wire with a hit
virtual double Temperature() const =0
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
virtual unsigned int NumberTimeSamples() const =0
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
std::vector< float > chifits
fit chisq for monitoring kinks, etc
virtual double DriftVelocity(double efield=0., double temperature=0.) const =0
void Vtx3ClusterSplit(geo::TPCID const &tpcid)
float fLAClusAngleCut
call Large Angle Clustering code if > 0
std::vector< bool > mergeAvailable
set true if hit is with HitMergeChiCut of a neighbor hit
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
unsigned int fFirstHit
first hit used
std::vector< float > chgNear
charge near a cluster on each wire
bool fFindHammerClusters
look for hammer type clusters
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
std::vector< unsigned int > fcl2hits
vector of hits used in the cluster
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 129 of file ClusterCrawlerAlg.cxx.

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

Referenced by GetVertices().

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

Definition at line 2838 of file ClusterCrawlerAlg.cxx.

2839  {
2840  // split cluster icl into two clusters
2841 
2842  if(tcl[icl].ID < 0) return false;
2843 
2844 // if(pos < 3 || pos > tcl[icl].tclhits.size() - 3) return false;
2845 
2846  // declare icl obsolete
2847  MakeClusterObsolete(icl);
2848 
2849  unsigned short ii, iclnew;
2850  unsigned int iht;
2851 
2852  if(pos > 2) {
2853  // Have enough hits to make a cluster at the Begin end
2854  // Create the first cluster (DS) using the Begin info
2855  clBeginSlp = tcl[icl].BeginSlp;
2856  clBeginSlpErr = tcl[icl].BeginSlpErr;
2857  clBeginAng = tcl[icl].BeginAng;
2858  clBeginWir = tcl[icl].BeginWir;
2859  clBeginTim = tcl[icl].BeginTim;
2860  clBeginChg = tcl[icl].BeginChg;
2861  clStopCode = 5;
2862  clProcCode = tcl[icl].ProcCode;
2863  fcl2hits.clear();
2864  chifits.clear();
2865  hitNear.clear();
2866  chgNear.clear();
2867  for(ii = 0; ii < pos; ++ii) {
2868  iht = tcl[icl].tclhits[ii];
2869  fcl2hits.push_back(iht);
2870  }
2871  // determine the pass in which this cluster was created
2872  pass = tcl[icl].ProcCode - 10 * (tcl[icl].ProcCode / 10);
2873  if(pass > fNumPass-1) pass = fNumPass-1;
2874  // fit the end hits
2875  FitCluster();
2876  clEndSlp = clpar[1];
2877  clEndSlpErr = clparerr[1];
2878  clEndAng = std::atan(fScaleF * clEndSlp);
2879  // find the charge at the end
2880  FitClusterChg();
2881  clEndChg = fAveChg;
2882  if(!TmpStore()) {
2884  return false;
2885  }
2886  // associate the End with the supplied vertex
2887  iclnew = tcl.size() - 1;
2888  tcl[iclnew].EndVtx = ivx;
2889  tcl[iclnew].BeginVtx = tcl[icl].BeginVtx;
2890  if(vtxprt) mf::LogVerbatim("CC")<<"SplitCluster made cluster "<<iclnew<<" attached to Begin vtx "<<ivx;
2891  } // pos > 2
2892 
2893  if(pos < tcl[icl].tclhits.size() - 3) {
2894  // have enough hits to make a cluster at the End
2895  // now create the second cluster (US)
2896  clEndSlp = tcl[icl].EndSlp;
2897  clEndSlpErr = tcl[icl].EndSlpErr;
2898  clEndAng = std::atan(fScaleF * clEndSlp);
2899  clEndWir = tcl[icl].EndWir;
2900  clEndTim = tcl[icl].EndTim;
2901  clEndChg = tcl[icl].EndChg;
2902  clStopCode = 5;
2903  clProcCode = tcl[icl].ProcCode;
2904  fcl2hits.clear();
2905  chifits.clear();
2906  hitNear.clear();
2907  chgNear.clear();
2908  bool didFit = false;
2909  for(ii = pos; ii < tcl[icl].tclhits.size(); ++ii) {
2910  iht = tcl[icl].tclhits[ii];
2911  if(inClus[iht] != 0) {
2913  return false;
2914  }
2915  fcl2hits.push_back(iht);
2916  // define the Begin parameters
2917  if(fcl2hits.size() == fMaxHitsFit[pass] ||
2918  fcl2hits.size() == fMinHits[pass]) {
2919  FitCluster();
2920  clBeginSlp = clpar[1];
2921  clBeginAng = std::atan(fScaleF * clBeginSlp);
2922  clBeginSlpErr = clparerr[1];
2923  didFit = true;
2924  }
2925  if((unsigned short)fcl2hits.size() == fNHitsAve[pass] + 1) {
2926  FitClusterChg();
2927  clBeginChg = fAveChg;
2928  didFit = true;
2929  }
2930  } // ii
2931  // do a fit using all hits if one wasn't done
2932  if(!didFit) {
2933  FitCluster();
2934  FitClusterChg();
2935  clBeginChg = fAveChg;
2936  }
2937  if(!TmpStore()) {
2938  // clobber the previously stored cluster
2939  MakeClusterObsolete(tcl.size() - 1);
2941  return false;
2942  }
2943  // associate the End with the supplied vertex
2944  iclnew = tcl.size() - 1;
2945  tcl[iclnew].BeginVtx = ivx;
2946  tcl[iclnew].EndVtx = tcl[icl].EndVtx;
2947  if(vtxprt) mf::LogVerbatim("CC")<<"SplitCluster made cluster "<<iclnew<<" attached to End vtx "<<ivx;
2948  }
2949 
2950  return true;
2951  } // 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
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)
std::vector< ClusterStore > tcl
the clusters we are creating
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.
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
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
set to > 2 to do a charge fit using fNHitsAve hits
void cluster::ClusterCrawlerAlg::TmpGet ( unsigned short  it1)
private

Definition at line 3595 of file ClusterCrawlerAlg.cxx.

3596  {
3597  // copies temp cluster it1 into the fcl2hits vector, etc. This is
3598  // effectively the inverse of cl2TmpStore
3599 
3600  if(it1 > tcl.size()) return;
3601 
3602 
3603  clBeginSlp = tcl[it1].BeginSlp;
3604  clBeginSlpErr = tcl[it1].BeginSlpErr;
3605  clBeginAng = tcl[it1].BeginAng;
3606  clBeginWir = tcl[it1].BeginWir;
3607  clBeginTim = tcl[it1].BeginTim;
3608  clBeginChg = tcl[it1].BeginChg;
3609  clBeginChgNear = tcl[it1].BeginChgNear;
3610  clEndSlp = tcl[it1].EndSlp;
3611  clEndSlpErr = tcl[it1].EndSlpErr;
3612  clEndAng = tcl[it1].EndAng;
3613  clEndWir = tcl[it1].EndWir;
3614  clEndTim = tcl[it1].EndTim;
3615  clEndChg = tcl[it1].EndChg;
3616  clEndChgNear = tcl[it1].EndChgNear;
3617  clStopCode = tcl[it1].StopCode;
3618  clProcCode = tcl[it1].ProcCode;
3619  clCTP = tcl[it1].CTP;
3620  fcl2hits = tcl[it1].tclhits;
3621  }
float clBeginChg
begin average charge
float clEndSlp
slope at the end (= US end = low wire number)
CTP_t clCTP
Cryostat/TPC/Plane code.
std::vector< ClusterStore > tcl
the clusters we are creating
unsigned int clEndWir
begin wire
float clBeginSlp
begin slope (= DS end = high wire number)
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
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 3625 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.

3626  {
3627 
3628  if(fcl2hits.size() < 2) return false;
3629  if(fcl2hits.size() > fHits.size()) return false;
3630 
3631  if(NClusters == SHRT_MAX) return false;
3632 
3633  ++NClusters;
3634 
3635  unsigned int hit0 = fcl2hits[0];
3636  unsigned int hit;
3637  unsigned int tCST = fHits[hit0].WireID().Cryostat;
3638  unsigned int tTPC = fHits[hit0].WireID().TPC;
3639  unsigned int tPlane = fHits[hit0].WireID().Plane;
3640  unsigned int lastWire = 0;
3641 
3642  for(unsigned short it = 0; it < fcl2hits.size(); ++it) {
3643  hit = fcl2hits[it];
3644  if(inClus[hit] != 0) {
3645 /*
3646  mf::LogError("CC")<<"TmpStore: Trying to use obsolete/used hit "<<hit<<" inClus "<<inClus[hit]
3647  <<" on wire "<<fHits[hit].WireID().Wire<<" on cluster "<<NClusters
3648  <<" in plane "<<plane<<" ProcCode "<<clProcCode;
3649 */
3650  --NClusters;
3651  return false;
3652  }
3653  // check for WireID() consistency
3654  if(fHits[hit].WireID().Cryostat != tCST || fHits[hit].WireID().TPC != tTPC || fHits[hit].WireID().Plane != tPlane) {
3655 /*
3656  mf::LogError("CC")<<"TmpStore: CTP mis-match "<<hit<<" WireID().TPC "<<fHits[hit].WireID().TPC
3657  <<" WireID().Plane "<<fHits[hit].WireID().Plane<<" tCST "<<tCST<<" tTPC "<<tTPC<<" tPlane "<<tPlane
3658  <<" on cluster "<<NClusters<<" ProcCode "<<clProcCode;
3659 */
3660  --NClusters;
3661  return false;
3662  }
3663  // check for decreasing wire number
3664  if(clProcCode < 900 && it > 0 && fHits[hit].WireID().Wire >= lastWire) {
3665 /*
3666  mf::LogError("CC")<<"TmpStore: Hits not in correct wire order. Seed hit "<<fHits[fcl2hits[0]].WireID().Plane<<":"
3667  <<fHits[fcl2hits[0]].WireID().Wire<<":"<<(int)fHits[fcl2hits[0]].PeakTime()<<" it "<<it<<" hit wire "<<fHits[hit].WireID().Wire
3668  <<" ProcCode "<<clProcCode;
3669 */
3670  --NClusters;
3671 /*
3672  for(unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3673  mf::LogVerbatim("CC")<<ii<<" "<<fcl2hits[ii]<<" "<<fHits[fcl2hits[ii]].WireID().Plane<<":"<<fHits[fcl2hits[ii]].WireID().Wire<<":"<<(int)fHits[fcl2hits[ii]].PeakTime();
3674  }
3675 */
3676  return false;
3677  }
3678  lastWire = fHits[hit].WireID().Wire;
3679  inClus[hit] = NClusters;
3680  }
3681 
3682  // ensure that the cluster begin/end info is correct
3683 
3684  // define the begin/end charge if it wasn't done already
3685  if(clEndChg <= 0) {
3686  // use the next to the last two hits. The End hit may have low charge
3687  unsigned int ih0 = fcl2hits.size() - 2;
3688  hit = fcl2hits[ih0];
3689  clEndChg = fHits[hit].Integral();
3690  hit = fcl2hits[ih0 - 1];
3691  clEndChg += fHits[hit].Integral();
3692  clEndChg = clEndChg / 2.;
3693  }
3694  if(clBeginChg <= 0) {
3695  // use the 2nd and third hit. The Begin hit may have low charge
3696  hit = fcl2hits[1];
3697  clBeginChg = fHits[hit].Integral();
3698  hit = fcl2hits[2];
3699  clBeginChg += fHits[hit].Integral();
3700  clBeginChg = clBeginChg / 2.;
3701  }
3702 
3703  hit0 = fcl2hits[0];
3704  hit = fcl2hits[fcl2hits.size()-1];
3705 
3706  // store the cluster in the temporary ClusterStore struct
3707  ClusterStore clstr;
3708 
3709  clstr.ID = NClusters;
3710  clstr.BeginSlp = clBeginSlp;
3711  clstr.BeginSlpErr = clBeginSlpErr;
3712  clstr.BeginAng = std::atan(fScaleF * clBeginSlp);
3713  clstr.BeginWir = fHits[hit0].WireID().Wire;
3714  clstr.BeginTim = fHits[hit0].PeakTime();
3715  clstr.BeginChg = clBeginChg;
3716  clstr.BeginChgNear = clBeginChgNear;
3717  clstr.EndSlp = clEndSlp;
3718  clstr.EndSlpErr = clEndSlpErr;
3719  clstr.EndAng = std::atan(fScaleF * clEndSlp);
3720  clstr.EndWir = fHits[hit].WireID().Wire;
3721  clstr.EndTim = fHits[hit].PeakTime();
3722  clstr.EndChg = clEndChg;
3723  clstr.EndChgNear = clEndChgNear;
3724  clstr.StopCode = clStopCode;
3725  clstr.ProcCode = clProcCode;
3726  clstr.BeginVtx = -99;
3727  clstr.EndVtx = -99;
3728  clstr.CTP = EncodeCTP(tCST, tTPC, tPlane);
3729  clstr.tclhits = fcl2hits;
3730  tcl.push_back(clstr);
3731 
3732  return true;
3733  } // TmpStore()
float fScaleF
scale factor from Tick/Wire to dx/du
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)
std::vector< ClusterStore > tcl
the clusters we are creating
float clBeginSlp
begin slope (= DS end = high wire number)
Detector simulation of raw signals on wires.
short clStopCode
8 = SPECIAL CODE FOR STEP CRAWLING
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 2083 of file ClusterCrawlerAlg.cxx.

2084  {
2085  // try to attach clusters to the specified vertex
2086  if(vtx[iv].NClusters == 0) return;
2087 
2088  short dwb, dwe, dtb, dte;
2089  bool sigOK;
2090 
2091 // vtxprt = (fDebugPlane >= 0 && fDebugWire == 3333);
2092 
2093  for(unsigned short icl = 0; icl < tcl.size(); ++icl) {
2094  if(tcl[icl].ID < 0) continue;
2095  if(tcl[icl].CTP != vtx[iv].CTP) continue;
2096 
2097  dwb = vtx[iv].Wire - tcl[icl].BeginWir;
2098  dtb = vtx[iv].Time - tcl[icl].BeginTim;
2099  dwe = vtx[iv].Wire - tcl[icl].EndWir;
2100  dte = vtx[iv].Time - tcl[icl].EndTim;
2101 
2102  float drb = dwb * dwb + dtb * dtb;
2103  float dre = dwe * dwe + dte * dte;
2104 
2105  bool bCloser = (drb < dre);
2106 
2107  // ignore clusters in showers
2108  if(bCloser) {
2109  if(tcl[icl].BeginChgNear > fChgNearCut) continue;
2110  } else {
2111  if(tcl[icl].EndChgNear > fChgNearCut) continue;
2112  }
2113 
2114  if(vtxprt) mf::LogVerbatim("CC")<<"VertexCluster: Try icl ID "<<tcl[icl].ID<<" w vtx "<<iv<<" dwb "<<dwb<<" dwe "<<dwe<<" drb "<<drb<<" dre "<<dre<<" Begin closer? "<<bCloser;
2115 
2116  if(tcl[icl].BeginVtx < 0 && bCloser && dwb > -3 && dwb < 3 && tcl[icl].EndVtx != iv) {
2117  sigOK = ChkSignal(tcl[icl].BeginWir, tcl[icl].BeginTim, vtx[iv].Wire, vtx[iv].Time);
2118  if(vtxprt) mf::LogVerbatim("CC")<<" Attach cluster Begin to vtx? "<<iv<<" sigOK "<<sigOK;
2119  if(sigOK) {
2120  if(vtxprt) mf::LogVerbatim("CC")<<" check ClusterVertexChi "<<ClusterVertexChi(icl, 0, iv);
2121  if(ClusterVertexChi(icl, 0, iv) < fVertex2DCut) {
2122  // do a fit and check the vertex error
2123  tcl[icl].BeginVtx = iv;
2124  FitVtx(iv);
2125  if(vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2126  tcl[icl].BeginVtx = -99;
2127  FitVtx(iv);
2128  }
2129  } // good DoCA
2130  } // sigOK
2131  } // check BEGIN
2132 
2133  if(tcl[icl].EndVtx < 0 && !bCloser && dwe > -3 && dwe < 3 && tcl[icl].BeginVtx != iv) {
2134  sigOK = ChkSignal(tcl[icl].EndWir, tcl[icl].EndTim, vtx[iv].Wire, vtx[iv].Time);
2135  if(vtxprt) mf::LogVerbatim("CC")<<" Attach cluster End to vtx? "<<iv<<" sigOK "<<sigOK;
2136  if(sigOK) {
2137  if(vtxprt) mf::LogVerbatim("CC")<<" check ClusterVertexChi "<<ClusterVertexChi(icl, 1, iv);
2138  if(ClusterVertexChi(icl, 1, iv) < 3) {
2139  // do a fit and check the vertex error
2140  tcl[icl].EndVtx = iv;
2141  FitVtx(iv);
2142  if(vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2143  tcl[icl].EndVtx = -99;
2144  FitVtx(iv);
2145  }
2146  } // good DoCA
2147  } // sigOK
2148  } // check END
2149  } // icl
2150  } // VertexCluster
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void FitVtx(unsigned short iv)
bool ChkSignal(unsigned int iht, unsigned int jht)
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
std::vector< ClusterStore > tcl
the clusters we are creating
float fVertex2DCut
2D vtx -> cluster matching cut (chisq/dof)
std::vector< VtxStore > vtx
the endpoints we are reconstructing
float fChgNearCut
to define a shower-like cluster
void cluster::ClusterCrawlerAlg::Vtx3ClusterMatch ( geo::TPCID const &  tpcid)
private

Definition at line 5361 of file ClusterCrawlerAlg.cxx.

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

5362  {
5363  // Look for clusters that end/begin near the expected wire/time
5364  // for incomplete 3D vertices
5365  if(vtx3.size() == 0) return;
5366 
5367  const unsigned int cstat = tpcid.Cryostat;
5368  const unsigned int tpc = tpcid.TPC;
5369 
5370  unsigned int thePlane, theWire;
5371  float theTime;
5372  int dwb, dwe;
5373 
5374  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
5375 
5376  for(unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5377  // A complete 3D vertex with matching 2D vertices in all planes?
5378  if(vtx3[ivx].Wire < 0) continue;
5379  if(vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc) continue;
5380  // Find the plane that is missing a 2D vertex
5381  thePlane = 3;
5382  theWire = vtx3[ivx].Wire;
5383  for(plane = 0; plane < 3; ++plane) {
5384  if(vtx3[ivx].Ptr2D[plane] >= 0) continue;
5385  thePlane = plane;
5386  break;
5387  } // plane
5388  if(thePlane > 2) continue;
5389  theTime = detprop->ConvertXToTicks(vtx3[ivx].X, thePlane, tpc, cstat);
5390  clCTP = EncodeCTP(cstat, tpc, thePlane);
5391  // Create a new 2D vertex and see how many clusters we can attach to it
5392  VtxStore vnew;
5393  vnew.Wire = theWire;
5394  vnew.Time = theTime;
5395  vnew.CTP = clCTP;
5396  vnew.Topo = 7;
5397  vnew.Fixed = false;
5398  vtx.push_back(vnew);
5399  unsigned short ivnew = vtx.size() -1;
5400  std::vector<short> vclIndex;
5401  for(unsigned short icl = 0; icl < tcl.size(); ++icl) {
5402  if(tcl[icl].ID < 0) continue;
5403  if(tcl[icl].CTP != clCTP) continue;
5404  dwb = util::absDiff(theWire, tcl[icl].BeginWir);
5405  dwe = util::absDiff(theWire, tcl[icl].EndWir);
5406  // rough cut to start
5407  if(dwb > 10 && dwe > 10) continue;
5408  if(dwb < dwe && dwb < 10 && tcl[icl].BeginVtx < 0) {
5409  // cluster begin is closer
5410  if(theWire < tcl[icl].BeginWir + 5) continue;
5411  if(ClusterVertexChi(icl, 0, ivnew) > fVertex3DCut) continue;
5412  tcl[icl].BeginVtx = ivnew;
5413  vclIndex.push_back(icl);
5414  } else if(dwe < 10 && tcl[icl].EndVtx < 0) {
5415  // cluster end is closer
5416  if(theWire > tcl[icl].EndWir - 5) continue;
5417  if(ClusterVertexChi(icl, 1, ivnew) > fVertex3DCut) continue;
5418  tcl[icl].EndVtx = ivnew;
5419  vclIndex.push_back(icl);
5420  } // dwb/dwe check
5421  } // icl
5422  bool goodVtx = false;
5423  if(vclIndex.size() > 0) {
5424  FitVtx(ivnew);
5425  goodVtx = (vtx[ivnew].ChiDOF < fVertex3DCut);
5426  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5427  }
5428  if(goodVtx) {
5429  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5430  vtx3[ivx].Wire = -1;
5431  } else {
5432  // clobber the vertex
5433  vtx.pop_back();
5434  for(unsigned short ii = 0; ii < vclIndex.size(); ++ii) {
5435  unsigned short icl = vclIndex[ii];
5436  if(tcl[icl].BeginVtx == ivnew) tcl[icl].BeginVtx = -99;
5437  if(tcl[icl].EndVtx == ivnew) tcl[icl].EndVtx = -99;
5438  } // ii
5439  }
5440  } // ivx
5441  } // Vtx3ClusterMatch
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
void FitVtx(unsigned short iv)
CTP_t clCTP
Cryostat/TPC/Plane code.
virtual double ConvertXToTicks(double X, int p, int t, int c) const =0
float ClusterVertexChi(short icl, unsigned short end, unsigned short ivx)
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
Float_t X
Definition: plot.C:39
void cluster::ClusterCrawlerAlg::Vtx3ClusterSplit ( geo::TPCID const &  tpcid)
private

Definition at line 5444 of file ClusterCrawlerAlg.cxx.

References detinfo::DetectorProperties::ConvertXToTicks(), geo::CryostatID::Cryostat, cluster::ClusterCrawlerAlg::VtxStore::CTP, 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.

5445  {
5446  // Try to split clusters in a view in which there is no 2D vertex
5447  // assigned to a 3D vertex
5448  if(vtx3.size() == 0) return;
5449  const unsigned int cstat = tpcid.Cryostat;
5450  const unsigned int tpc = tpcid.TPC;
5451 
5452  vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5453 
5454  unsigned int lastplane = 5, kcl, kclID;
5455  float dth, theTime;
5456  unsigned int thePlane, theWire, plane;
5457  unsigned int loWire, hiWire;
5458 
5459  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
5460 
5461  for(unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5462  if(vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc) continue;
5463  // Complete 3D vertex with matching 2D vertices in all planes?
5464  if(vtxprt) mf::LogVerbatim("CC")<<"Vtx3ClusterSplit ivx "<<ivx<<" Ptr2D "<<vtx3[ivx].Ptr2D[0]<<" "<<vtx3[ivx].Ptr2D[1]<<" "<<vtx3[ivx].Ptr2D[2]<<" wire "<<vtx3[ivx].Wire;
5465  if(vtx3[ivx].Wire < 0) continue;
5466  // find the plane that needs to be studied
5467  thePlane = 3;
5468  theWire = vtx3[ivx].Wire;
5469  for(plane = 0; plane < 3; ++plane) {
5470  if(vtx3[ivx].Ptr2D[plane] >= 0) continue;
5471  thePlane = plane;
5472  break;
5473  } // plane
5474  if(thePlane > 2) continue;
5475  theTime = detprop->ConvertXToTicks((double)vtx3[ivx].X,
5476  (int)thePlane, (int)tpcid.TPC, (int)tpcid.Cryostat);
5477  // get the hit range if necessary
5478  if(thePlane != lastplane) {
5479  clCTP = EncodeCTP(tpcid.Cryostat, tpcid.TPC, thePlane);
5480  GetHitRange(clCTP);
5481  lastplane = thePlane;
5482  }
5483  // make a list of clusters that have hits near this point on nearby wires
5484  std::vector<short> clIDs;
5485  if(theWire > fFirstWire + 5) { loWire = theWire - 5; } else { loWire = fFirstWire; }
5486  if(theWire < fLastWire - 5) { hiWire = theWire + 5; } else { hiWire = fLastWire; }
5487  if(vtxprt) mf::LogVerbatim("CC")<<"3DVtx "<<ivx<<" look for cluster hits near P:W:T "<<thePlane<<":"<<theWire<<":"<<(int)theTime<<" Wire range "<<loWire<<" to "<<hiWire;
5488  for(unsigned int wire = loWire; wire < hiWire; ++wire) {
5489  // ignore dead wires or wires with no hits
5490  if(WireHitRange[wire].first < 0) continue;
5491  unsigned int firsthit = WireHitRange[wire].first;
5492  unsigned int lasthit = WireHitRange[wire].second;
5493  for(unsigned int khit = firsthit; khit < lasthit; ++khit) {
5494  // ignore obsolete and un-assigned hits
5495  if(inClus[khit] <= 0) continue;
5496  if((unsigned int)inClus[khit] > tcl.size() + 1) {
5497  mf::LogError("CC")<<"Invalid hit InClus. "<<khit<<" "<<inClus[khit];
5498  continue;
5499  }
5500  // check an expanded time range
5501  if(theTime < fHits[khit].StartTick() - 20) continue;
5502  if(theTime > fHits[khit].EndTick() + 20) continue;
5503  kclID = inClus[khit];
5504  kcl = kclID - 1;
5505  // ignore obsolete clusters
5506  if(tcl[kcl].ID < 0) continue;
5507  // ignore short clusters
5508  if(tcl[kcl].tclhits.size() < 6) continue;
5509  // ignore long straight clusters
5510  if(tcl[kcl].tclhits.size() > 100 && std::abs(tcl[kcl].BeginAng - tcl[kcl].EndAng) < 0.1) continue;
5511  // put the cluster in the list if it's not there already
5512  if(vtxprt) mf::LogVerbatim("CC")<<"Bingo "<<ivx<<" plane "<<thePlane<<" wire "<<wire<<" hit "<<fHits[khit].WireID().Wire<<":"<<(int)fHits[khit].PeakTime()<<" inClus "<<inClus[khit]<<" P:W:T "<<thePlane<<":"<<tcl[kcl].BeginWir<<":"<<(int)tcl[kcl].BeginTim;
5513  if(std::find(clIDs.begin(), clIDs.end(), kclID) == clIDs.end()) {
5514  clIDs.push_back(kclID);
5515  } // std::find
5516  } // khit
5517  } // wire
5518  if(clIDs.size() == 0) continue;
5519  if(vtxprt) for(unsigned int ii = 0; ii < clIDs.size(); ++ii) mf::LogVerbatim("CC")<<" clIDs "<<clIDs[ii];
5520 
5521  unsigned short ii, icl, jj;
5522  unsigned int iht;
5523  short nhitfit;
5524  bool didit;
5525  // find a reasonable time error using the 2D vertices that comprise this
5526  // incomplete 3D vertex
5527  float tErr = 1;
5528  unsigned short i2Dvx = 0;
5529  for(ii = 0; ii < 3; ++ii) {
5530  if(ii == thePlane) continue;
5531  i2Dvx = vtx3[ivx].Ptr2D[ii];
5532  if(i2Dvx > vtx.size() - 1) {
5533  mf::LogError("CC")<<"Vtx3ClusterSplit: Coding error";
5534  return;
5535  }
5536  if(vtx[i2Dvx].TimeErr > tErr) tErr = vtx[i2Dvx].TimeErr;
5537  } // ii -> plane
5538 
5539  // do a local fit near the crossing point and make a tighter cut
5540  for(ii = 0; ii < clIDs.size(); ++ii) {
5541  icl = clIDs[ii] - 1;
5542  didit = false;
5543  for(jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5544  iht = tcl[icl].tclhits[jj];
5545  if(fHits[iht].WireID().Wire < theWire) {
5546  nhitfit = 3;
5547  if(jj > 3) nhitfit = -3;
5548  FitClusterMid(icl, iht, nhitfit);
5549  float doca = DoCA(-1, 1, theWire, theTime);
5550  if(vtxprt) mf::LogVerbatim("CC")<<" cls "<<icl<<" dth "<<dth<<" DoCA "<<doca<<" tErr "<<tErr;
5551  if((doca / tErr) > 2) clIDs[ii] = -1;
5552  didit = true;
5553  break;
5554  } // fHits[iht].WireID().Wire < theWire
5555  if(didit) break;
5556  } // jj
5557  if(didit) break;
5558  } // ii
5559  if(vtxprt) {
5560  mf::LogVerbatim("CC")<<"clIDs after fit "<<clIDs.size();
5561  for(ii = 0; ii < clIDs.size(); ++ii) mf::LogVerbatim("CC")<<" clIDs "<<clIDs[ii];
5562  }
5563 
5564  // see if any candidates remain
5565  unsigned short nok = 0;
5566  for(ii = 0; ii < clIDs.size(); ++ii) if(clIDs[ii] >= 0) ++nok;
5567  if(nok == 0) continue;
5568 
5569  // make a new 2D vertex
5570  VtxStore vnew;
5571  vnew.Wire = theWire;
5572  vnew.WireErr = 1;
5573  vnew.Time = theTime;
5574  vnew.TimeErr = 1;
5575  vnew.Topo = 8;
5576  vnew.CTP = clCTP;
5577  vnew.Fixed = false;
5578  vtx.push_back(vnew);
5579  // update the 2D -> 3D vertex pointer
5580  unsigned short ivnew = vtx.size() - 1;
5581  if(vtxprt) mf::LogVerbatim("CC")<<"Make new 2D vtx "<<ivnew<<" in plane "<<thePlane<<" from 3D vtx "<<ivx;
5582  vtx3[ivx].Ptr2D[thePlane] = ivnew;
5583  // either split or attach clusters to this vertex
5584  for(ii = 0; ii < clIDs.size(); ++ii) {
5585  if(clIDs[ii] < 0) continue;
5586  icl = clIDs[ii] - 1;
5587  // find the split position
5588  // split the cluster. Find the split position
5589  unsigned short pos = 0;
5590  for(unsigned short jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5591  iht = tcl[icl].tclhits[jj];
5592  if(fHits[iht].WireID().Wire < theWire) {
5593  pos = jj;
5594  break;
5595  }
5596  } // jj
5597  if(pos == 0) {
5598  // vertex is DS of the cluster Begin
5599  tcl[icl].BeginVtx = ivnew;
5600  if(vtxprt) mf::LogVerbatim("CC")<<"Attach to Begin "<<icl;
5601  } else if(pos > tcl[icl].tclhits.size()) {
5602  // vertex is US of the cluster Eend
5603  tcl[icl].EndVtx = ivnew;
5604  if(vtxprt) mf::LogVerbatim("CC")<<"Attach to End "<<icl;
5605  } else {
5606  // vertex is in the middle of the cluster
5607  if(vtxprt) mf::LogVerbatim("CC")<<"Split cluster "<<clIDs[ii]<<" at pos "<<pos;
5608  if(!SplitCluster(icl, pos, ivnew)) {
5609  if(vtxprt) mf::LogVerbatim("CC")<<"SplitCluster failed";
5610  continue;
5611  }
5612  tcl[icl].ProcCode += 10000;
5613  tcl[tcl.size()-1].ProcCode += 10000;
5614  } // pos check
5615  } // ii
5616  // Fit the vertex position
5617  FitVtx(ivnew);
5618  if(vtx[ivnew].ChiDOF < 5 && vtx[ivnew].WireErr < fVertex2DWireErrCut) {
5619  // mark the 3D vertex as complete
5620  vtx3[ivx].Wire = -1;
5621  } else {
5622  if(vtxprt) mf::LogVerbatim("CC")<<"Bad vtx fit "<<ivnew<<" ChiDOF "<<vtx[ivnew].ChiDOF<<" WireErr "<<vtx[ivnew].WireErr;
5623  // Recover (partially) from a bad fit. Leave the ProcCode as-is to trace this problem
5624  vtx.pop_back();
5625  vtx3[ivx].Ptr2D[thePlane] = -1;
5626  // find the cluster - vertex associations
5627  for(jj = 0; jj < tcl.size(); ++jj) {
5628  if(tcl[jj].BeginVtx == ivnew) tcl[jj].BeginVtx = -99;
5629  if(tcl[jj].EndVtx == ivnew) tcl[jj].EndVtx = -99;
5630  } // jj
5631  }
5632  } // ivx
5633 
5634  } // Vtx3ClusterSplit()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
void FitVtx(unsigned short iv)
void FitClusterMid(unsigned short it1, unsigned int iht, short nhit)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
CTP_t clCTP
Cryostat/TPC/Plane code.
float DoCA(short icl, unsigned short end, float vwire, float vtick)
virtual double ConvertXToTicks(double X, int p, int t, int c) const =0
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
std::vector< ClusterStore > tcl
the clusters we are creating
unsigned int fFirstWire
the first wire with a hit
std::vector< VtxStore > vtx
the endpoints we are reconstructing
static CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
bool SplitCluster(unsigned short icl, unsigned short pos, unsigned short ivx)
Float_t X
Definition: plot.C:39
bool cluster::ClusterCrawlerAlg::VtxClusterSplit ( )
private

Definition at line 1509 of file ClusterCrawlerAlg.cxx.

1510  {
1511 
1512  // split clusters that cross vertices
1513 
1514  vtxprt = (fDebugPlane >= 0 && fDebugWire == 5555);
1515 
1516  if(vtxprt) mf::LogVerbatim("CC")<<"VtxClusterSplit ";
1517 
1518  if(vtx.size() == 0) return false;
1519  unsigned short tclsize = tcl.size();
1520  if(tclsize < 2) return false;
1521 
1522 // float dth;
1523  bool didit;
1524  bool didSomething = false;
1525 
1526  for(unsigned short icl = 0; icl < tclsize; ++icl) {
1527  if(tcl[icl].ID < 0) continue;
1528  if(tcl[icl].CTP != clCTP) continue;
1529  // ignore short clusters
1530  if(tcl[icl].tclhits.size() < 5) continue;
1531  // check vertices
1532  didit = false;
1533  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
1534  if(vtx[ivx].CTP != clCTP) continue;
1535  // abandoned vertex?
1536  if(vtx[ivx].NClusters == 0) continue;
1537  // already assigned to this vertex?
1538  if(tcl[icl].BeginVtx == ivx) continue;
1539  if(tcl[icl].EndVtx == ivx) continue;
1540 /*
1541  // long dead-straight cluster?
1542  if(tcl[icl].tclhits.size() > 100) {
1543  dth = tcl[icl].BeginAng - tcl[icl].EndAng;
1544  if(fabs(dth) < 0.1) continue;
1545  }
1546 */
1547  // vertex wire in-between the cluster ends?
1548  if(vtx[ivx].Wire < tcl[icl].EndWir) continue;
1549  if(vtx[ivx].Wire > tcl[icl].BeginWir) continue;
1550  // vertex time in-between the cluster ends?
1551  float hiTime = tcl[icl].BeginTim;
1552  if(tcl[icl].EndTim > hiTime) hiTime = tcl[icl].EndTim;
1553  if(vtx[ivx].Time > hiTime + 5) continue;
1554  float loTime = tcl[icl].BeginTim;
1555  if(tcl[icl].EndTim < loTime) loTime = tcl[icl].EndTim;
1556  if(vtx[ivx].Time < loTime - 5) continue;
1557  // find the hit on the cluster that is closest to the vertex on the
1558  // DS side
1559  if(vtxprt) mf::LogVerbatim("CC")<<" Chk cluster ID "<<tcl[icl].ID<<" with vertex "<<ivx;
1560  short ihvx = -99;
1561  // nSplit is the index of the hit in the cluster where we will
1562  // split it if all requirements are met
1563  unsigned short nSplit = 0;
1564  unsigned short nLop = 0;
1565  unsigned int iht;
1566  for(unsigned short ii = tcl[icl].tclhits.size()-1; ii > 0 ; --ii) {
1567  iht = tcl[icl].tclhits[ii];
1568  ++nLop;
1569  if(fHits[iht].WireID().Wire >= vtx[ivx].Wire) {
1570  nSplit = ii;
1571  if(vtxprt) mf::LogVerbatim("CC")<<"Split cluster "<<tcl[icl].ID<<" at wire "<<fHits[iht].WireID().Wire
1572  <<" nSplit "<<nSplit;
1573  ihvx = iht;
1574  break;
1575  }
1576  } // ii
1577  // found the wire. Now make a rough time cut
1578  if(ihvx < 0) continue;
1579 // short dtime = std::abs(short(fHits[ihvx].PeakTime() - vtx[ivx].Time));
1580 // if(vtxprt) mf::LogVerbatim("CC")<<" Delta time "<<dtime;
1581  if(fabs(fHits[ihvx].PeakTime() - vtx[ivx].Time) > 10) continue;
1582  // check the angle between the crossing cluster icl and the
1583  // clusters that comprise the vertex.
1584  // First decide which end of cluster icl to use to define the angle
1585  float iclAng = 0.;
1586  if(nSplit > tcl[icl].tclhits.size() / 2) {
1587  iclAng = tcl[icl].EndAng;
1588  } else {
1589  iclAng = tcl[icl].BeginAng;
1590  }
1591  if(vtxprt) mf::LogVerbatim("CC")<<" iclAng "<<iclAng;
1592  // check angle wrt the the vertex clusters
1593  bool angOK = false;
1594  for(unsigned short jcl = 0; jcl < tclsize; ++jcl) {
1595  if(tcl[jcl].ID < 0) continue;
1596  if(tcl[jcl].CTP != clCTP) continue;
1597  if(tcl[jcl].BeginVtx == ivx) {
1598  if(fabs(tcl[jcl].BeginAng - iclAng) > 0.4) {
1599  // large angle difference. Set the flag
1600  angOK = true;
1601  break;
1602  }
1603  } // tcl[jcl].BeginVtx == ivx
1604  if(tcl[jcl].EndVtx == ivx) {
1605  if(fabs(tcl[jcl].EndAng - iclAng) > 0.4) {
1606  // large angle difference. Set the flag
1607  angOK = true;
1608  break;
1609  }
1610  } // tcl[jcl].EndVtx == ivx
1611  } // jcl
1612  // time to split or chop
1613  if(angOK) {
1614  if(vtxprt) mf::LogVerbatim("CC")<<"Split/Chop at pos "<<nLop;
1615  if(nLop < 3) {
1616  // lop off hits at the US end
1617  // Put the cluster in the local arrays
1618  TmpGet(icl);
1619  for(unsigned short ii = 0; ii < nLop; ++ii) {
1620  unsigned int iht = fcl2hits[fcl2hits.size()-1];
1621  inClus[iht] = 0;
1622  fcl2hits.pop_back();
1623  }
1624  // store it
1625  clProcCode += 1000;
1626  // declare this cluster obsolete
1627  MakeClusterObsolete(icl);
1628  // store the new one
1629  if(!TmpStore()) continue;
1630  unsigned short newcl = tcl.size() - 1;
1631  tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1632  tcl[newcl].EndVtx = ivx;
1633  } else {
1634  // split the cluster into two
1635  // correct the split position
1636  ++nSplit;
1637  if(SplitCluster(icl, nSplit, ivx)) {
1638  tcl[tcl.size()-1].ProcCode += 1000;
1639  tcl[tcl.size()-2].ProcCode += 1000;
1640  }
1641  }
1642  didit = true;
1643  didSomething = true;
1644  } // angOK
1645  if(didit) break;
1646  } // ivx
1647  } // icl
1648 
1649  return didSomething;
1650 
1651  } // VtxClusterSplit()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
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)
std::vector< ClusterStore > tcl
the clusters we are creating
std::vector< VtxStore > vtx
the endpoints we are reconstructing
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< 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 1322 of file ClusterCrawlerAlg.cxx.

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

1323  {
1324  // checks hits on wire jwire to see if one is on a line between a US vertex
1325  // and the hit ihit on wire iwire. If one is found, doConstrain is set true
1326  // and the hit index is returned.
1327  doConstrain = false;
1328  if(vtx.size() == 0) return;
1329  // no vertices made yet on the first pass
1330  if(pass == 0) return;
1331  // skip if vertices were not requested to be made on the previous pass
1332  if( !fFindVertices[pass - 1] ) return;
1333 
1334  if(jwire > WireHitRange.size() - 1) {
1335  mf::LogError("CC")<<"VtxConstraint fed bad jwire "<<jwire<<" WireHitRange size "<<WireHitRange.size();
1336  return;
1337  }
1338 
1339  unsigned int jfirsthit = WireHitRange[jwire].first;
1340  unsigned int jlasthit = WireHitRange[jwire].second;
1341  for(unsigned short iv = 0; iv < vtx.size(); ++iv) {
1342  if(vtx[iv].CTP != clCTP) continue;
1343  // vertex must be US of the cluster
1344  if(vtx[iv].Wire > jwire) continue;
1345  // but not too far US
1346  if(vtx[iv].Wire < jwire - 10) continue;
1347  recob::Hit const& hit = fHits[ihit];
1348  clpar[0] = hit.PeakTime();
1349  clpar[1] = (vtx[iv].Time - hit.PeakTime()) / (vtx[iv].Wire - iwire);
1350  clpar[2] = hit.WireID().Wire;
1351  float prtime = clpar[0] + clpar[1] * (jwire - iwire);
1352  for(unsigned int jhit = jfirsthit; jhit < jlasthit; ++jhit) {
1353  if(inClus[jhit] != 0) continue;
1354  const float tdiff = std::abs(fHits[jhit].TimeDistanceAsRMS(prtime));
1355  if(tdiff < 2.5) {
1356  useHit = jhit;
1357  doConstrain = true;
1358  return;
1359  }
1360  } // jhit
1361  } // iv
1362  } // VtxConstraint()
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
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< VtxStore > vtx
the endpoints we are reconstructing
std::vector< bool > fFindVertices
run vertexing code after clustering?
Detector simulation of raw signals on wires.
std::vector< std::pair< int, int > > WireHitRange
std::vector< recob::Hit > fHits
our version of the hits
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
void cluster::ClusterCrawlerAlg::VtxMatch ( geo::TPCID const &  tpcid)
private

Definition at line 5830 of file ClusterCrawlerAlg.cxx.

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

5831  {
5832  // Create 3D vertices from 2D vertices. 3D vertices that are matched
5833  // in all three planes have Ptr2D >= 0 for all planes
5834 
5835 
5836  geo::TPCGeo const& TPC = geom->TPC(tpcid);
5837  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
5838 
5839  const unsigned int cstat = tpcid.Cryostat;
5840  const unsigned int tpc = tpcid.TPC;
5841 
5842  // Y,Z limits of the detector
5843  double local[3] = {0.,0.,0.};
5844  double world[3] = {0.,0.,0.};
5845 
5846  const geo::TPCGeo &thetpc = geom->TPC(tpc, cstat);
5847  thetpc.LocalToWorld(local,world);
5848  // reduce the active area of the TPC by 1 cm to prevent wire boundary issues
5849  float YLo = world[1]-geom->DetHalfHeight(tpc,cstat) + 1;
5850  float YHi = world[1]+geom->DetHalfHeight(tpc,cstat) - 1;
5851  float ZLo = world[2]-geom->DetLength(tpc,cstat)/2 + 1;
5852  float ZHi = world[2]+geom->DetLength(tpc,cstat)/2 - 1;
5853 
5854  vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5855 
5856  if(vtxprt) {
5857  mf::LogVerbatim("CC")<<"Inside VtxMatch";
5858  PrintVertices();
5859  }
5860 
5861  // wire spacing in cm
5862  float wirePitch = geom->WirePitch(0, tpcid.TPC, tpcid.Cryostat);
5863 
5864  // fill temp vectors of 2D vertex X and X errors
5865  std::vector<float> vX(vtx.size());
5866  std::vector<float> vXsigma(vtx.size());
5867  float vXp;
5868  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5869  if(vtx[ivx].NClusters == 0) continue;
5870  geo::PlaneID iplID = DecodeCTP(vtx[ivx].CTP);
5871  if(iplID.TPC != tpc || iplID.Cryostat != cstat) continue;
5872  // Convert 2D vertex time error to X error
5873  vX[ivx] = detprop->ConvertTicksToX((double)vtx[ivx].Time, (int)iplID.Plane, (int)tpc, (int)cstat);
5874  vXp = detprop->ConvertTicksToX((double)(vtx[ivx].Time + vtx[ivx].TimeErr), (int)iplID.Plane, (int)tpc, (int)cstat);
5875  vXsigma[ivx] = fabs(vXp - vX[ivx]);
5876  } // ivx
5877 
5878  // create a array/vector of 2D vertex indices in each plane
5879  std::array<std::vector<unsigned short>, 3> vIndex;
5880  unsigned short indx, ipl;
5881  for(unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5882  if(vtx[ivx].NClusters == 0) continue;
5883  geo::PlaneID iplID = DecodeCTP(vtx[ivx].CTP);
5884  if(iplID.TPC != tpc || iplID.Cryostat != cstat) continue;
5885  ipl = iplID.Plane;
5886  if(ipl > 2) continue;
5887  indx = vIndex[ipl].size();
5888  vIndex[ipl].resize(indx + 1);
5889  vIndex[ipl][indx] = ivx;
5890  }
5891 
5892  // vector of 2D vertices -> 3D vertices.
5893  std::vector<short> vPtr;
5894  for(unsigned short ii = 0; ii < vtx.size(); ++ii) vPtr.push_back(-1);
5895 
5896  // temp vector of all 2D vertex matches
5897  std::vector<Vtx3Store> v3temp;
5898 
5899  double y = 0, z = 0;
5900  TVector3 WPos = {0, 0, 0};
5901  // i, j, k indicates 3 different wire planes
5902  unsigned short ii, jpl, jj, kpl, kk, ivx, jvx, kvx;
5903  unsigned int iWire, jWire;
5904  unsigned short v3dBest = 0;
5905  float xbest = 0, ybest = 0, zbest = 0;
5906  float kX, kWire;
5907  // compare vertices in each view
5908  bool gotit = false;
5909  for(ipl = 0; ipl < 2; ++ipl) {
5910  for(ii = 0; ii < vIndex[ipl].size(); ++ii) {
5911  ivx = vIndex[ipl][ii];
5912  if(ivx > vtx.size() - 1) {
5913  mf::LogError("CC")<<"VtxMatch: bad ivx "<<ivx;
5914  return;
5915  }
5916  // vertex has been matched already
5917  if(vPtr[ivx] >= 0) continue;
5918  iWire = vtx[ivx].Wire;
5919  float best = fVertex3DCut;
5920  // temp array of 2D vertex indices in each plane
5921  // BUG the double brace syntax is required to work around clang bug 21629
5922  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
5923  std::array<short, 3> t2dIndex = {{-1, -1, -1}};
5924  std::array<short, 3> tmpIndex = {{-1, -1, -1}};
5925  for(jpl = ipl + 1; jpl < 3; ++jpl) {
5926  for(jj = 0; jj < vIndex[jpl].size(); ++jj) {
5927  jvx = vIndex[jpl][jj];
5928  if(jvx > vtx.size() - 1) {
5929  mf::LogError("CC")<<"VtxMatch: bad jvx "<<jvx;
5930  return;
5931  }
5932  // vertex has been matched already
5933  if(vPtr[jvx] >= 0) continue;
5934  jWire = vtx[jvx].Wire;
5935  // new stuff
5936  float dX = fabs(vX[ivx] - vX[jvx]);
5937  float dXSigma = sqrt(vXsigma[ivx] * vXsigma[ivx] + vXsigma[jvx] * vXsigma[jvx]);
5938  float dXChi = dX / dXSigma;
5939 
5940  if(vtxprt) mf::LogVerbatim("CC")<<"VtxMatch: ipl "<<ipl<<" ivx "<<ivx<<" ivX "<<vX[ivx]
5941  <<" jpl "<<jpl<<" jvx "<<jvx<<" jvX "<<vX[jvx]<<" W:T "<<(int)vtx[jvx].Wire<<":"<<(int)vtx[jvx].Time<<" dXChi "<<dXChi<<" fVertex3DCut "<<fVertex3DCut;
5942 
5943  if(dXChi > fVertex3DCut) continue;
5944  geom->IntersectionPoint(iWire, jWire, ipl, jpl, cstat, tpc, y, z);
5945  if(y < YLo || y > YHi || z < ZLo || z > ZHi) continue;
5946  WPos[1] = y;
5947  WPos[2] = z;
5948  kpl = 3 - ipl - jpl;
5949  kX = 0.5 * (vX[ivx] + vX[jvx]);
5950  kWire = -1;
5951  if(TPC.Nplanes() > 2){
5952  try{
5953  kWire = geom->NearestWire(WPos, kpl, tpc, cstat);
5954  }
5955  catch(geo::InvalidWireError const& e) {
5956  kWire = e.suggestedWireID().Wire; // pick the closest valid wire
5957  }
5958  }
5959  kpl = 3 - ipl - jpl;
5960  // save this incomplete 3D vertex
5961  Vtx3Store v3d;
5962  v3d.ProcCode = 1;
5963  tmpIndex[ipl] = ivx;
5964  tmpIndex[jpl] = jvx;
5965  tmpIndex[kpl] = -1;
5966  v3d.Ptr2D = tmpIndex;
5967  v3d.X = kX;
5968  v3d.XErr = dXSigma;
5969  v3d.Y = y;
5970  float yzSigma = wirePitch * sqrt(vtx[ivx].WireErr * vtx[ivx].WireErr + vtx[jvx].WireErr * vtx[jvx].WireErr);
5971  v3d.YErr = yzSigma;
5972  v3d.Z = z;
5973  v3d.ZErr = yzSigma;
5974  v3d.Wire = kWire;
5975  v3d.CStat = cstat;
5976  v3d.TPC = tpc;
5977  v3temp.push_back(v3d);
5978 
5979  if(vtxprt) mf::LogVerbatim("CC")
5980  <<"VtxMatch: 2 Plane match ivx "<<ivx<<" P:W:T "<<ipl<<":"<<(int)vtx[ivx].Wire<<":"<<(int)vtx[ivx].Time
5981  <<" jvx "<<jvx<<" P:W:T "<<jpl<<":"<<(int)vtx[jvx].Wire<<":"<<(int)vtx[jvx].Time<<" dXChi "<<dXChi<<" yzSigma "<<yzSigma;
5982 
5983  if(TPC.Nplanes() == 2) continue;
5984  // look for a 3 plane match
5985  best = fVertex3DCut;
5986  for(kk = 0; kk < vIndex[kpl].size(); ++kk) {
5987  kvx = vIndex[kpl][kk];
5988  if(vPtr[kvx] >= 0) continue;
5989 // float kvxX = detprop->ConvertTicksToX((double)vtx[kvx].Time, (int)kpl, (int)tpc, (int)cstat);
5990  // Wire difference error
5991  float dW = wirePitch * (vtx[kvx].Wire - kWire) / yzSigma;
5992  // X difference error
5993  float dX = (vX[kvx] - kX) / dXSigma;
5994  float kChi = 0.5 * sqrt(dW * dW + dX * dX);
5995  if(kChi < best) {
5996  best = kChi;
5997  xbest = (vX[kvx] + 2 * kX) / 3;
5998  ybest = y;
5999  zbest = z;
6000  t2dIndex[ipl] = ivx;
6001  t2dIndex[jpl] = jvx;
6002  t2dIndex[kpl] = kvx;
6003  v3dBest = v3temp.size() - 1;
6004  }
6005 
6006  if(vtxprt) mf::LogVerbatim("CC")<<" kvx "<<kvx<<" kpl "<<kpl
6007  <<" wire "<<(int)vtx[kvx].Wire<<" kTime "<<(int)vtx[kvx].Time<<" kChi "<<kChi<<" best "<<best<<" dW "<<vtx[kvx].Wire - kWire;
6008 
6009  } // kk
6010  if(vtxprt) mf::LogVerbatim("CC")<<" done best = "<<best<<" fVertex3DCut "<<fVertex3DCut;
6011  if(TPC.Nplanes() > 2 && best < fVertex3DCut) {
6012  // create a real 3D vertex using the previously entered incomplete 3D vertex as a template
6013  if(v3dBest > v3temp.size() - 1) {
6014  mf::LogError("CC")<<"VtxMatch: bad v3dBest "<<v3dBest;
6015  return;
6016  }
6017  Vtx3Store v3d = v3temp[v3dBest];
6018  v3d.Ptr2D = t2dIndex;
6019  v3d.Wire = -1;
6020  // TODO need to average ybest and zbest here with error weighting
6021  v3d.X = xbest;
6022  v3d.Y = ybest;
6023  v3d.Z = zbest;
6024  vtx3.push_back(v3d);
6025  gotit = true;
6026  // mark the 2D vertices as used
6027  for(unsigned short jj = 0; jj < 3; ++jj) if(t2dIndex[jj] >= 0) vPtr[t2dIndex[jj]] = vtx3.size() - 1;
6028 
6029  if(vtxprt) mf::LogVerbatim("CC")<<"New 3D vtx "<<vtx3.size()<<" X "<<v3d.X<<" Y "<<v3d.Y<<" Z "<<v3d.Z
6030  <<" t2dIndex "<<t2dIndex[0]<<" "<<t2dIndex[1]<<" "<<t2dIndex[2]<<" best Chi "<<best;
6031 
6032  } // best < dRCut
6033  if(gotit) break;
6034  } // jj
6035  if(gotit) break;
6036  } // jpl
6037  if(gotit) break;
6038  } // ii
6039  } // ipl
6040 
6041  // Store incomplete 3D vertices but ignore those that are part of a complete 3D vertex
6042  unsigned short vsize = vtx3.size();
6043  for(unsigned short it = 0; it < v3temp.size(); ++it) {
6044  bool keepit = true;
6045  for(unsigned short i3d = 0; i3d < vsize; ++i3d) {
6046  for(unsigned short plane = 0; plane < 3; ++plane) {
6047  if(v3temp[it].Ptr2D[plane] == vtx3[i3d].Ptr2D[plane]) {
6048  keepit = false;
6049  break;
6050  }
6051  } // plane
6052  if(!keepit) break;
6053  } // i3d
6054 
6055  if(keepit) vtx3.push_back(v3temp[it]);
6056  } // it
6057 
6058  // Modify Ptr2D for 2-plane detector
6059  if(TPC.Nplanes() == 2) {
6060  for(unsigned short iv3 = 0; iv3 < vtx3.size(); ++iv3) {
6061  vtx3[iv3].Ptr2D[2] = 666;
6062  } //iv3
6063  } // 2 planes
6064 
6065  if(vtxprt) {
6066  for(unsigned short it = 0; it < vtx3.size(); ++it) {
6067  mf::LogVerbatim("CC")<<"vtx3 "<<it<<" Ptr2D "<<vtx3[it].Ptr2D[0]<<" "<<vtx3[it].Ptr2D[1]<<" "<<vtx3[it].Ptr2D[2]
6068  <<" wire "<<vtx3[it].Wire;
6069  }
6070  }
6071 
6072  } // VtxMatch
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< Vtx3Store > vtx3
the 3D vertices we are reconstructing
static unsigned int kWire
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
Planes which measure X direction.
Definition: geo_types.h:81
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
Geometry information for a single TPC.
Definition: TPCGeo.h:37
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
for(int i=0;i< 401;i++)
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
art::ServiceHandle< geo::Geometry > geom
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
static geo::PlaneID DecodeCTP(CTP_t CTP)
int fDebugHit
out detailed information while crawling
if(nlines<=0)
geo::Length_t DetHalfHeight(geo::TPCID const &tpcid) const
Returns the half height of the active volume of the specified TPC.
std::vector< VtxStore > vtx
the endpoints we are reconstructing
geo::WireID::WireID_t NearestWire(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the index of wire closest to position in the specified TPC.
float fVertex3DCut
2D vtx -> 3D vtx matching cut (chisq/dof)
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
Float_t e
Definition: plot.C:34
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
Definition: TPCGeo.h:490
std::vector<recob::Hit>&& cluster::ClusterCrawlerAlg::YieldHits ( )
inline

Returns (and loses) the collection of reconstructed hits.

Definition at line 119 of file ClusterCrawlerAlg.h.

References fHits.

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

119 { 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 287 of file ClusterCrawlerAlg.h.

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

fit chisq for monitoring kinks, etc

Definition at line 283 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginAng
private

Definition at line 227 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginChg
private

begin average charge

Definition at line 231 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginChgNear
private

nearby charge

Definition at line 232 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginSlp
private

begin slope (= DS end = high wire number)

Definition at line 226 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginSlpErr
private

Definition at line 228 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clBeginTim
private

begin time

Definition at line 230 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::clBeginWir
private

begin wire

Definition at line 229 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clChisq
private

chisq of the current fit

Definition at line 205 of file ClusterCrawlerAlg.h.

CTP_t cluster::ClusterCrawlerAlg::clCTP
private

Cryostat/TPC/Plane code.

Definition at line 262 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndAng
private

Definition at line 234 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndChg
private

end average charge

Definition at line 238 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndChgNear
private

nearby charge

Definition at line 239 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndSlp
private

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

Definition at line 233 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndSlpErr
private

Definition at line 235 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::clEndTim
private

begin time

Definition at line 237 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::clEndWir
private

begin wire

Definition at line 236 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::clLA
private

using Large Angle crawling code

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

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

cluster parameter errors

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

short cluster::ClusterCrawlerAlg::clStopCode
private

8 = SPECIAL CODE FOR STEP CRAWLING

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

Definition at line 240 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::cstat
private

Definition at line 268 of file ClusterCrawlerAlg.h.

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

Definition at line 42 of file ClusterCrawlerAlg.h.

Referenced by DecodeCTP().

unsigned short cluster::ClusterCrawlerAlg::fAllowNoHitWire
private

Definition at line 189 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveChg
private

average charge at leading edge of cluster

Definition at line 206 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fAveHitWidth
private

average width (EndTick - StartTick) of hits

Definition at line 209 of file ClusterCrawlerAlg.h.

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

charge difference cut for adding a hit to a cluster

Definition at line 156 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgNearCut
private

to define a shower-like cluster

cut on ratio of nearby/cluster charge to

Definition at line 289 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgNearWindow
private

window (ticks) for finding nearby charge

Definition at line 288 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fChgSlp
private

slope of the charge vs wire

Definition at line 208 of file ClusterCrawlerAlg.h.

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

stop adding hits to clusters if chisq too high

Definition at line 152 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fChkClusterDS
private

Definition at line 172 of file ClusterCrawlerAlg.h.

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

vector of hits used in the cluster

Definition at line 282 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fClProjErrFac
private

cluster projection error factor

Definition at line 180 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugHit
private

out detailed information while crawling

Definition at line 196 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugPlane
private

Definition at line 194 of file ClusterCrawlerAlg.h.

int cluster::ClusterCrawlerAlg::fDebugWire
private

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

Definition at line 195 of file ClusterCrawlerAlg.h.

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

try to merge clusters?

Definition at line 160 of file ClusterCrawlerAlg.h.

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

Definition at line 199 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindHammerClusters
private

look for hammer type clusters

Definition at line 165 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fFindStarVertices
private

Definition at line 174 of file ClusterCrawlerAlg.h.

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

run vertexing code after clustering?

Definition at line 163 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fFirstHit
private

first hit used

Definition at line 266 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fFirstWire
private

the first wire with a hit

Definition at line 265 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitErrFac
private

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

Definition at line 178 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitMergeChiCut
private

is < cut. Set < 0 for no merging

Merge cluster hit-multiplets if the separation chisq

Definition at line 186 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fHitMinAmp
private

< ignore hits with Amp < this value

Definition at line 179 of file ClusterCrawlerAlg.h.

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

our version of the hits

Definition at line 217 of file ClusterCrawlerAlg.h.

Referenced by GetHits(), and YieldHits().

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

Definition at line 292 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fKillGarbageClusters
private

Definition at line 171 of file ClusterCrawlerAlg.h.

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

kink angle cut made after fKinkChiRat

Definition at line 155 of file ClusterCrawlerAlg.h.

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

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

Definition at line 153 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusAngleCut
private

call Large Angle Clustering code if > 0

Definition at line 182 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fLAClusMaxHitsFit
private

max hits fitted on a Large Angle cluster

Definition at line 183 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fLAClusSlopeCut
private

Definition at line 184 of file ClusterCrawlerAlg.h.

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

Crawl Large Angle clusters on pass?

Definition at line 164 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fLastWire
private

the last wire with a hit

Definition at line 267 of file ClusterCrawlerAlg.h.

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

Definition at line 224 of file ClusterCrawlerAlg.h.

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

Max number of hits fitted.

Definition at line 148 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fMaxTime
private

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

bool cluster::ClusterCrawlerAlg::fMergeAllHits
private

Definition at line 185 of file ClusterCrawlerAlg.h.

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

max charge ratio for matching

Definition at line 162 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMergeOverlapAngCut
private

angle cut for merging overlapping clusters

Definition at line 188 of file ClusterCrawlerAlg.h.

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

expected minimum signal in each wire plane

Definition at line 169 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fMinHitFrac
private

Definition at line 181 of file ClusterCrawlerAlg.h.

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

Min number of hits to make a cluster.

Definition at line 149 of file ClusterCrawlerAlg.h.

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

after skipping

minimum number of hits on consecutive wires

Definition at line 158 of file ClusterCrawlerAlg.h.

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

set to > 2 to do a charge fit using fNHitsAve hits

number of US hits used to compute fAveChg

Definition at line 150 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::fNumPass
private

number of passes over the hit collection

Definition at line 147 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::fNumWires
private

Definition at line 271 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fRefineVertexClusters
private

Definition at line 167 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fScaleF
private

scale factor from Tick/Wire to dx/du

Definition at line 273 of file ClusterCrawlerAlg.h.

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

max time difference for matching

Definition at line 161 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DCut
private

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

Definition at line 190 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex2DWireErrCut
private

Definition at line 191 of file ClusterCrawlerAlg.h.

float cluster::ClusterCrawlerAlg::fVertex3DCut
private

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

Definition at line 192 of file ClusterCrawlerAlg.h.

bool cluster::ClusterCrawlerAlg::fVtxClusterSplit
private

Definition at line 173 of file ClusterCrawlerAlg.h.

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

Definition at line 215 of file ClusterCrawlerAlg.h.

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

Number of nearby hits that were merged have hitnear < 0

Definition at line 284 of file ClusterCrawlerAlg.h.

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

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

Definition at line 218 of file ClusterCrawlerAlg.h.

Referenced by GetinClus().

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

set true if hit is with HitMergeChiCut of a neighbor hit

Definition at line 219 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::NClusters
private

Definition at line 213 of file ClusterCrawlerAlg.h.

unsigned short cluster::ClusterCrawlerAlg::pass
private

Definition at line 275 of file ClusterCrawlerAlg.h.

unsigned int cluster::ClusterCrawlerAlg::plane
private

Definition at line 270 of file ClusterCrawlerAlg.h.

Referenced by EncodeCTP().

bool cluster::ClusterCrawlerAlg::prt
private

Definition at line 211 of file ClusterCrawlerAlg.h.

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

the clusters we are creating

Definition at line 220 of file ClusterCrawlerAlg.h.

Referenced by GetClusters().

unsigned int cluster::ClusterCrawlerAlg::tpc
private

Definition at line 269 of file ClusterCrawlerAlg.h.

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

the endpoints we are reconstructing

Definition at line 221 of file ClusterCrawlerAlg.h.

Referenced by GetEndPoints().

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

the 3D vertices we are reconstructing

Definition at line 222 of file ClusterCrawlerAlg.h.

Referenced by GetVertices().

bool cluster::ClusterCrawlerAlg::vtxprt
private

Definition at line 212 of file ClusterCrawlerAlg.h.

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

Definition at line 280 of file ClusterCrawlerAlg.h.


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