LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
StandardHit3DBuilder_tool.cc
Go to the documentation of this file.
1 
8 // Framework Includes
10 #include "cetlib/search_path.h"
11 #include "cetlib/cpu_timer.h"
13 
15 
16 // LArSoft includes
21 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
22 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
23 
24 // Eigen
25 #include <Eigen/Dense>
26 
27 // std includes
28 #include <string>
29 #include <functional>
30 #include <iostream>
31 #include <memory>
32 
33 //------------------------------------------------------------------------------------------------------------------------------------------
34 // implementation follows
35 
36 namespace lar_cluster3d {
37 
43 // forward declaration to define an ordering function for our hit set
45 {
46  bool operator() (const reco::ClusterHit2D*, const reco::ClusterHit2D*) const;
47 };
48 
49 using HitVector = std::vector<reco::ClusterHit2D*>;
50 using PlaneToHitVectorMap = std::map<geo::PlaneID, HitVector>;
51 using TPCToPlaneToHitVectorMap = std::map<geo::TPCID, PlaneToHitVectorMap>;
52 using Hit2DVector = std::vector<reco::ClusterHit2D>;
53 using Hit2DSet = std::set<const reco::ClusterHit2D*, Hit2DSetCompare>;
54 using WireToHitSetMap = std::map<unsigned int, Hit2DSet>;
55 using PlaneToWireToHitSetMap = std::map<geo::PlaneID, WireToHitSetMap>;
56 using TPCToPlaneToWireToHitSetMap = std::map<geo::TPCID, PlaneToWireToHitSetMap>;
57 using HitVectorMap = std::map<size_t, HitVector>;
58 
59 using HitPairVector = std::vector<std::unique_ptr<reco::ClusterHit3D>>;
60 
64 class StandardHit3DBuilder : virtual public IHit3DBuilder
65 {
66 public:
72  explicit StandardHit3DBuilder(fhicl::ParameterSet const &pset);
73 
78 
79  void configure(const fhicl::ParameterSet&) override;
80 
87  void Hit3DBuilder(const art::Event &evt, reco::HitPairList& hitPairList, RecobHitToPtrMap&) const override;
88 
92  float getTimeToExecute(IHit3DBuilder::TimeValues index) const override {return m_timeVector.at(index);}
93 
94 private:
95 
105  void CollectArtHits(const art::Event& evt,
106  RecobHitToPtrMap& hitToPtrMap) const;
107 
111  void BuildHit3D(reco::HitPairList& hitPairList) const;
112 
116  size_t BuildHitPairMap(PlaneToHitVectorMap& planeToHitVectorMap, reco::HitPairList& hitPairList) const;
117 
121  using PlaneHitVectorItrPairVec = std::vector<std::pair<HitVector::iterator,HitVector::iterator>>;
122 
123  size_t BuildHitPairMapByTPC(PlaneHitVectorItrPairVec& planeHitVectorItrPairVec, reco::HitPairList& hitPairList) const;
124 
128  using HitMatchPair = std::pair<const reco::ClusterHit2D*,reco::ClusterHit3D>;
129  using HitMatchPairVec = std::vector<HitMatchPair>;
130  using HitMatchPairVecMap = std::map<geo::WireID,HitMatchPairVec>;
131 
132  int findGoodHitPairs(const reco::ClusterHit2D*, HitVector::iterator&, HitVector::iterator&, HitMatchPairVecMap&) const;
133 
137  void findGoodTriplets(HitMatchPairVecMap&, HitMatchPairVecMap&, reco::HitPairList&, bool = false) const;
138 
142  bool makeHitPair(reco::ClusterHit3D& pairOut,
143  const reco::ClusterHit2D* hit1,
144  const reco::ClusterHit2D* hit2,
145  float hitWidthSclFctr = 1.,
146  size_t hitPairCntr = 0) const;
147 
151  bool makeHitTriplet(reco::ClusterHit3D& pairOut,
152  const reco::ClusterHit3D& pairIn,
153  const reco::ClusterHit2D* hit2) const;
154 
158  bool makeDeadChannelPair(reco::ClusterHit3D& pairOut, const reco::ClusterHit3D& pair, size_t maxStatus = 4, size_t minStatus = 0, float minOverlap=0.2) const;
159 
163  const reco::ClusterHit2D* FindBestMatchingHit(const Hit2DSet& hit2DSet, const reco::ClusterHit3D& pair, float pairDeltaTimeLimits) const;
164 
168  int FindNumberInRange(const Hit2DSet& hit2DSet, const reco::ClusterHit3D& pair, float range) const;
169 
173  geo::WireID NearestWireID(const float* position, const geo::WireID& wireID) const;
174 
178  void BuildChannelStatusVec(PlaneToWireToHitSetMap& planeToWiretoHitSetMap) const;
179 
183  using ChannelStatusVec = std::vector<size_t>;
184  using ChannelStatusByPlaneVec = std::vector<ChannelStatusVec>;
185 
193 
195  float m_wirePitch[3];
196  mutable std::vector<float> m_timeVector;
197 
199 
200  // Get instances of the primary data structures needed
204 
205 
207  mutable size_t m_numBadChannels;
208 
209  geo::Geometry* m_geometry; //< pointer to the Geometry service
210  const detinfo::DetectorProperties* m_detector; //< Pointer to the detector properties
211  const lariov::ChannelStatusProvider* m_channelFilter;
212 };
213 
215  m_channelFilter(&art::ServiceHandle<lariov::ChannelStatusService>()->GetProvider())
216 
217 {
218  this->configure(pset);
219 }
220 
221 //------------------------------------------------------------------------------------------------------------------------------------------
222 
224 {
225 }
226 
227 //------------------------------------------------------------------------------------------------------------------------------------------
228 
230 {
231  m_hitFinderTag = pset.get<art::InputTag>("HitFinderTag");
232  m_enableMonitoring = pset.get<bool> ("EnableMonitoring", true);
233  m_numSigmaPeakTime = pset.get<float> ("NumSigmaPeakTime", 3. );
234  m_hitWidthSclFctr = pset.get<float> ("HitWidthScaleFactor", 6. );
235  m_deltaPeakTimeSig = pset.get<float> ("DeltaPeakTimeSig", 1.7 );
236  m_zPosOffset = pset.get<float> ("ZPosOffset", 0.0 );
237 
239 
240  m_geometry = &*geometry;
241  m_detector = lar::providerFrom<detinfo::DetectorPropertiesService>();
242 
244  m_wirePitch[1] = m_geometry->WirePitch(1);
245  m_wirePitch[2] = m_geometry->WirePitch(2);
246 }
247 
249 {
250  // This is called each event, clear out the previous version and start over
251  if (!m_channelStatus.empty()) m_channelStatus.clear();
252 
253  m_numBadChannels = 0;
255 
256  // Loop through views/planes to set the wire length vectors
257  for(size_t idx = 0; idx < m_channelStatus.size(); idx++)
258  {
260  }
261 
262  // Loop through the channels and mark those that are "bad"
263  for(size_t channel = 0; channel < m_geometry->Nchannels(); channel++)
264  {
265  if( !m_channelFilter->IsGood(channel))
266  {
267  std::vector<geo::WireID> wireIDVec = m_geometry->ChannelToWire(channel);
268  geo::WireID wireID = wireIDVec[0];
269  lariov::ChannelStatusProvider::Status_t chanStat = m_channelFilter->Status(channel);
270 
271  m_channelStatus[wireID.Plane][wireID.Wire] = chanStat;
273  }
274  }
275 
276  // add quiet wires in U plane for microboone (this will done "correctly" in near term)
277  // PlaneToWireToHitSetMap::iterator plane0HitItr = planeToWireToHitSetMap.find(geo::PlaneID(0,0,0));
278 
279  // if (plane0HitItr != planeToWireToHitSetMap.end())
280  // {
282 
283  // for(size_t idx = 2016; idx < 2096; idx++) m_channelStatus[0][idx] = 3;
284  // for(size_t idx = 2192; idx < 2304; idx++) m_channelStatus[0][idx] = 3;
285  // for(size_t idx = 2352; idx < 2384; idx++) m_channelStatus[0][idx] = 3;
286  // //for(size_t idx = 2016; idx < 2096; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
287  // //for(size_t idx = 2192; idx < 2304; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
288  // //for(size_t idx = 2352; idx < 2384; idx++) if (wireToHitSetMap.find(idx) == wireToHitSetMap.end()) m_channelStatus[0][idx] = 3;
290  // }
291 
292  return;
293 }
294 
295 
297 {
298  return (*left)->getAvePeakTime() < (*right)->getAvePeakTime();
299 }
300 
301 struct HitPairClusterOrder
302 {
304  {
305  // Watch out for the case where two clusters can have the same number of hits!
306  if (left->second.size() == right->second.size())
307  return left->first < right->first;
308 
309  return left->second.size() > right->second.size();
310  }
311 };
312 
313 void StandardHit3DBuilder::Hit3DBuilder(const art::Event& evt, reco::HitPairList& hitPairList, RecobHitToPtrMap& clusterHitToArtPtrMap) const
314 {
315  // Clear the internal data structures
316  m_clusterHit2DMasterVec.clear();
317  m_planeToHitVectorMap.clear();
318  m_planeToWireToHitSetMap.clear();
319 
320  m_timeVector.resize(NUMTIMEVALUES, 0.);
321 
322  // Recover the 2D hits and then organize them into data structures which will be used in the
323  // DBscan algorithm for building the 3D clusters
324  this->CollectArtHits(evt, clusterHitToArtPtrMap);
325 
326 // if (m_enableMonitoring) theClockArtHits.stop();
327 
328  // If there are no hits in our view/wire data structure then do not proceed with the full analysis
329  if (!m_planeToWireToHitSetMap.empty())
330  {
331  // Call the algorithm that builds 3D hits
332  this->BuildHit3D(hitPairList);
333  }
334 
335  return;
336 }
337 
339 {
344  cet::cpu_timer theClockMakeHits;
345 
346  if (m_enableMonitoring) theClockMakeHits.start();
347 
348  // The first task is to take the lists of input 2D hits (a map of view to sorted lists of 2D hits)
349  // and then to build a list of 3D hits to be used in downstream processing
351 
352  size_t numHitPairs = BuildHitPairMap(m_planeToHitVectorMap, hitPairList);
353 
354  if (m_enableMonitoring)
355  {
356  theClockMakeHits.stop();
357 
358  m_timeVector[BUILDTHREEDHITS] = theClockMakeHits.accumulated_real_time();
359  }
360 
361  mf::LogDebug("Cluster3D") << ">>>>> 3D hit building done, found " << numHitPairs << " 3D Hits" << std::endl;
362 
363  return;
364 }
365 
366 //------------------------------------------------------------------------------------------------------------------------------------------
367 namespace {
368 //bool SetHitStartTimeOrder(const reco::ClusterHit2D* left, const reco::ClusterHit2D* right)
369 //{
370 // // Sort by "modified start time" of pulse
371 // return left->getHit().PeakTime() - left->getHit().RMS() < right->getHit().PeakTime() - right->getHit().RMS();
372 //}
373 
374 class SetHitEarliestTimeOrder
375 {
376 public:
377  SetHitEarliestTimeOrder() : m_numRMS(1.) {}
378  SetHitEarliestTimeOrder(float numRMS) : m_numRMS(numRMS) {}
379 
380  bool operator()(const reco::ClusterHit2D* left, const reco::ClusterHit2D* right) const
381  {
382  return left->getTimeTicks() - m_numRMS * left->getHit().RMS() < right->getTimeTicks() - m_numRMS * right->getHit().RMS();
383  }
384 
385 public:
386  float m_numRMS;
387 };
388 
389 using HitVectorItrPair = std::pair<HitVector::iterator,HitVector::iterator>;
390 
391 class SetStartTimeOrder
392 {
393 public:
394  SetStartTimeOrder() : m_numRMS(1.) {}
395  SetStartTimeOrder(float numRMS) : m_numRMS(numRMS) {}
396 
397  bool operator()(const HitVectorItrPair& left, const HitVectorItrPair& right) const
398  {
399  // Protect against possible issue?
400  if (left.first != left.second && right.first != right.second)
401  {
402  // Sort by "modified start time" of pulse
403  return (*left.first)->getTimeTicks() - m_numRMS*(*left.first)->getHit().RMS() < (*right.first)->getTimeTicks() - m_numRMS*(*right.first)->getHit().RMS();
404  }
405 
406  return left.first != left.second;
407  }
408 
409 private:
410  float m_numRMS;
411 };
412 
413 bool SetPairStartTimeOrder(const std::unique_ptr<reco::ClusterHit3D>& left, const std::unique_ptr<reco::ClusterHit3D>& right)
414 {
415  // Sort by "modified start time" of pulse
416  return left->getAvePeakTime() - left->getSigmaPeakTime() < right->getAvePeakTime() - right->getSigmaPeakTime();
417 }
418 }
419 
420 //------------------------------------------------------------------------------------------------------------------------------------------
421 
422 size_t StandardHit3DBuilder::BuildHitPairMap(PlaneToHitVectorMap& planeToHitVectorMap, reco::HitPairList& hitPairList) const
423 {
433  size_t totalNumHits(0);
434  size_t hitPairCntr(0);
435 
436  size_t nTriplets(0);
437  size_t nDeadChanHits(0);
438 
439  // Set up to loop over cryostats and tpcs...
440  for(size_t cryoIdx = 0; cryoIdx < m_geometry->Ncryostats(); cryoIdx++)
441  {
442  for(size_t tpcIdx = 0; tpcIdx < m_geometry->NTPC(); tpcIdx++)
443  {
444  PlaneToHitVectorMap::iterator mapItr0 = planeToHitVectorMap.find(geo::PlaneID(cryoIdx,tpcIdx,0));
445  PlaneToHitVectorMap::iterator mapItr1 = planeToHitVectorMap.find(geo::PlaneID(cryoIdx,tpcIdx,1));
446  PlaneToHitVectorMap::iterator mapItr2 = planeToHitVectorMap.find(geo::PlaneID(cryoIdx,tpcIdx,2));
447 
448  size_t nPlanesWithHits = (mapItr0 != planeToHitVectorMap.end() && !mapItr0->second.empty() ? 1 : 0)
449  + (mapItr1 != planeToHitVectorMap.end() && !mapItr1->second.empty() ? 1 : 0)
450  + (mapItr2 != planeToHitVectorMap.end() && !mapItr2->second.empty() ? 1 : 0);
451 
452  if (nPlanesWithHits < 2) continue;
453 
454  HitVector& hitVector0 = mapItr0->second;
455  HitVector& hitVector1 = mapItr1->second;
456  HitVector& hitVector2 = mapItr2->second;
457 
458  // We are going to resort the hits into "start time" order...
459  std::sort(hitVector0.begin(), hitVector0.end(), SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
460  std::sort(hitVector1.begin(), hitVector1.end(), SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
461  std::sort(hitVector2.begin(), hitVector2.end(), SetHitEarliestTimeOrder(m_numSigmaPeakTime)); //SetHitStartTimeOrder);
462 
463  PlaneHitVectorItrPairVec hitItrVec = {HitVectorItrPair(hitVector0.begin(),hitVector0.end()),
464  HitVectorItrPair(hitVector1.begin(),hitVector1.end()),
465  HitVectorItrPair(hitVector2.begin(),hitVector2.end())};
466 
467  totalNumHits += BuildHitPairMapByTPC(hitItrVec, hitPairList);
468  }
469  }
470 
471  // Return the hit pair list but sorted by z and y positions (faster traversal in next steps)
472  hitPairList.sort(SetPairStartTimeOrder);
473 
474  // Where are we?
475  mf::LogDebug("Cluster3D") << "Total number hits: " << totalNumHits << std::endl;
476  mf::LogDebug("Cluster3D") << "Created a total of " << hitPairList.size() << " hit pairs, counted: " << hitPairCntr << std::endl;
477  mf::LogDebug("Cluster3D") << "-- Triplets: " << nTriplets << ", dead channel pairs: " << nDeadChanHits << std::endl;
478 
479  return hitPairList.size();
480 }
481 
483 {
494  // Define functions to set start/end iterators in the loop below
495  auto SetStartIterator = [](HitVector::iterator startItr, HitVector::iterator endItr, float rms, float startTime)
496  {
497  while(startItr != endItr)
498  {
499  float numRMS(rms);
500  if ((*startItr)->getTimeTicks() + numRMS * (*startItr)->getHit().RMS() < startTime) startItr++;
501  else break;
502  }
503  return startItr;
504  };
505 
506  auto SetEndIterator = [](HitVector::iterator firstItr, HitVector::iterator endItr, float rms, float endTime)
507  {
508  while(firstItr != endItr)
509  {
510  float numRMS(rms);
511  if ((*firstItr)->getTimeTicks() - numRMS * (*firstItr)->getHit().RMS() < endTime) firstItr++;
512  else break;
513  }
514  return firstItr;
515  };
516 
517  size_t nTriplets(0);
518  size_t nDeadChanHits(0);
519 
520  //*********************************************************************************
521  // Basically, we try to loop until done...
522  while(1)
523  {
524  // Sort so that the earliest hit time will be the first element, etc.
525  std::sort(hitItrVec.begin(),hitItrVec.end(),SetStartTimeOrder(m_numSigmaPeakTime));
526 
527  // This loop iteration's golden hit
528  const reco::ClusterHit2D* goldenHit = *hitItrVec[0].first;
529 
530  // The range of history... (for this hit)
531  float goldenTimeStart = goldenHit->getTimeTicks() - m_numSigmaPeakTime * goldenHit->getHit().RMS() - std::numeric_limits<float>::epsilon();
532  float goldenTimeEnd = goldenHit->getTimeTicks() + m_numSigmaPeakTime * goldenHit->getHit().RMS() + std::numeric_limits<float>::epsilon();
533 
534  // Set iterators to insure we'll be in the overlap ranges
535  HitVector::iterator hitItr1Start = SetStartIterator(hitItrVec[1].first, hitItrVec[1].second, m_numSigmaPeakTime, goldenTimeStart);
536  HitVector::iterator hitItr1End = SetEndIterator( hitItr1Start, hitItrVec[1].second, m_numSigmaPeakTime, goldenTimeEnd);
537  HitVector::iterator hitItr2Start = SetStartIterator(hitItrVec[2].first, hitItrVec[2].second, m_numSigmaPeakTime, goldenTimeStart);
538  HitVector::iterator hitItr2End = SetEndIterator( hitItr2Start, hitItrVec[2].second, m_numSigmaPeakTime, goldenTimeEnd);
539 
540  // Since we'll use these many times in the internal loops, pre make the pairs for the second set of hits
541  size_t curHitListSize(hitPairList.size());
542  HitMatchPairVecMap pair12Map;
543  HitMatchPairVecMap pair13Map;
544 
545  size_t n12Pairs = findGoodHitPairs(goldenHit, hitItr1Start, hitItr1End, pair12Map);
546  size_t n13Pairs = findGoodHitPairs(goldenHit, hitItr2Start, hitItr2End, pair13Map);
547 
548  nDeadChanHits += hitPairList.size() - curHitListSize;
549  curHitListSize = hitPairList.size();
550 
551  if (n12Pairs > n13Pairs) findGoodTriplets(pair12Map, pair13Map, hitPairList);
552  else findGoodTriplets(pair13Map, pair12Map, hitPairList);
553 
554  nTriplets += hitPairList.size() - curHitListSize;
555 
556  hitItrVec[0].first++;
557 
558  int nPlanesWithHits(0);
559 
560  for(auto& pair : hitItrVec)
561  if (pair.first != pair.second) nPlanesWithHits++;
562 
563  if (nPlanesWithHits < 2) break;
564  }
565 
566  return hitPairList.size();
567 }
568 
570  HitVector::iterator& startItr,
571  HitVector::iterator& endItr,
572  HitMatchPairVecMap& hitMatchMap) const
573 {
574  int numPairs(0);
575 
576  // Loop through the input secon hits and make pairs
577  while(startItr != endItr)
578  {
579  reco::ClusterHit2D* hit = *startItr++;
580  reco::ClusterHit3D pair;
581 
582  // pair returned with a negative ave time is signal of failure
583  if (!makeHitPair(pair, goldenHit, hit, m_hitWidthSclFctr)) continue;
584 
585  geo::WireID wireID = hit->getHit().WireID();
586 
587  hitMatchMap[wireID].emplace_back(hit,pair);
588 
589  numPairs++;
590  }
591 
592  return numPairs;
593 }
594 
595 void StandardHit3DBuilder::findGoodTriplets(HitMatchPairVecMap& pair12Map, HitMatchPairVecMap& pair13Map, reco::HitPairList& hitPairList, bool tagged) const
596 {
597  // Build triplets from the two lists of hit pairs
598  if (!pair12Map.empty())
599  {
600  // temporary container for dead channel hits
601  std::vector<reco::ClusterHit3D> tempDeadChanVec;
602  reco::ClusterHit3D deadChanPair;
603 
604  // Keep track of which third plane hits have been used
605  std::map<const reco::ClusterHit3D*,bool> usedPairMap;
606 
607  // Initial population of this map with the pair13Map hits
608  for(const auto& pair13 : pair13Map)
609  {
610  for(const auto& hit2Dhit3DPair : pair13.second) usedPairMap[&hit2Dhit3DPair.second] = false;
611  }
612 
613  // The outer loop is over all hit pairs made from the first two plane combinations
614  for(const auto& pair12 : pair12Map)
615  {
616  if (pair12.second.empty()) continue;
617 
618  // Use the planeID for the first hit
619  geo::WireID missingPlaneID = pair12.first;
620 
621  // "Discover" the missing view (and we can't rely on assuming there are hits in the pair13Map at this point)
622  size_t missPlane = 0;
623 
624  if (!pair12.second.front().second.getHits()[1]) missPlane = 1;
625  else if (!pair12.second.front().second.getHits()[2]) missPlane = 2;
626 
627  missingPlaneID.Plane = missPlane;
628 
629  // This loop is over hit pairs that share the same first two plane wires but may have different
630  // hit times on those wires
631  for(const auto& hit2Dhit3DPair : pair12.second)
632  {
633  const reco::ClusterHit3D& pair1 = hit2Dhit3DPair.second;
634 
635  // Get the wire ID for the nearest wire to the position of this hit
636  geo::WireID wireID = NearestWireID(pair1.getPosition(), missingPlaneID);
637 
638  // populate the map with initial value
639  usedPairMap[&pair1] = false;
640 
641  // For TPC's with 60 degree wire pitch the position returned for the the pair will
642  // lie between two wires in the missing plane. The call to nearestWireID should return
643  // the lower of the pair.
644  // So we really want to do a loop here so we can consider both wire combinations
645  for(int loopIdx = 0; loopIdx < 2; loopIdx++)
646  {
647  // Now look up the hit pairs on the wire which matches the current hit pair
648  HitMatchPairVecMap::iterator thirdPlaneHitMapItr = pair13Map.find(wireID);
649 
650  // Loop over third plane hits and try to form a triplet
651  if (thirdPlaneHitMapItr != pair13Map.end())
652  {
653  for(const auto& thirdPlaneHitItr : thirdPlaneHitMapItr->second)
654  {
655  const reco::ClusterHit2D* hit2 = thirdPlaneHitItr.first;
656  const reco::ClusterHit3D& pair2 = thirdPlaneHitItr.second;
657 
658  // If success try for the triplet
659  reco::ClusterHit3D triplet;
660 
661  if (makeHitTriplet(triplet, pair1, hit2))
662  {
663  triplet.setID(hitPairList.size());
664  hitPairList.emplace_back(new reco::ClusterHit3D(triplet));
665  usedPairMap[&pair1] = true;
666  usedPairMap[&pair2] = true;
667  }
668  }
669  }
670 
671  // Now bump the wire id to the next wire and do this again
672  wireID.Wire += 1;
673  }
674  }
675  }
676 
677  // One more loop through the other pairs to check for sick channels
678  if (m_numBadChannels > 0)
679  {
680  for(const auto& pairMapPair : usedPairMap)
681  {
682  if (pairMapPair.second) continue;
683 
684  const reco::ClusterHit3D* pair = pairMapPair.first;
685 
686  // Here we look to see if we failed to make a triplet because the partner wire was dead/noisy/sick
687  if (makeDeadChannelPair(deadChanPair, *pair, 4, 0, 0.)) tempDeadChanVec.emplace_back(deadChanPair);
688  }
689 
690  // Handle the dead wire triplets
691  if(!tempDeadChanVec.empty())
692  {
693  // If we have many then see if we can trim down a bit by keeping those with time significance
694  if (tempDeadChanVec.size() > 1)
695  {
696  // Sort by "significance" of agreement
697  std::sort(tempDeadChanVec.begin(),tempDeadChanVec.end(),[](const auto& left, const auto& right){return left.getDeltaPeakTime()/left.getSigmaPeakTime() < right.getDeltaPeakTime()/right.getSigmaPeakTime();});
698 
699  // What is the range of "significance" from first to last?
700  float firstSig = tempDeadChanVec.front().getDeltaPeakTime() / tempDeadChanVec.front().getSigmaPeakTime();
701  float lastSig = tempDeadChanVec.back().getDeltaPeakTime() / tempDeadChanVec.back().getSigmaPeakTime();
702  float sigRange = lastSig - firstSig;
703 
704  if (lastSig > 0.5 * m_deltaPeakTimeSig && sigRange > 0.5)
705  {
706  // Declare a maximum of 1.5 * the average of the first and last pairs...
707  float maxSignificance = std::max(0.75 * (firstSig + lastSig),1.0);
708 
709  std::vector<reco::ClusterHit3D>::iterator firstBadElem = std::find_if(tempDeadChanVec.begin(),tempDeadChanVec.end(),[&maxSignificance](const auto& pair){return pair.getDeltaPeakTime()/pair.getSigmaPeakTime() > maxSignificance;});
710 
711  // But only keep the best 10?
712  if (std::distance(tempDeadChanVec.begin(),firstBadElem) > 20) firstBadElem = tempDeadChanVec.begin() + 20;
713  // Keep at least one hit...
714  else if (firstBadElem == tempDeadChanVec.begin()) firstBadElem++;
715 
716  tempDeadChanVec.resize(std::distance(tempDeadChanVec.begin(),firstBadElem));
717  }
718  }
719 
720  for(auto& pair : tempDeadChanVec)
721  {
722  pair.setID(hitPairList.size());
723  hitPairList.emplace_back(new reco::ClusterHit3D(pair));
724  }
725  }
726  }
727  }
728 
729  return;
730 }
731 
733  const reco::ClusterHit2D* hit1,
734  const reco::ClusterHit2D* hit2,
735  float hitWidthSclFctr,
736  size_t hitPairCntr) const
737 {
738  // Assume failure
739  bool result(false);
740 
741  // We assume in this routine that we are looking at hits in different views
742  // The first mission is to check that the wires intersect
743  const geo::WireID& hit1WireID = hit1->getHit().WireID();
744  const geo::WireID& hit2WireID = hit2->getHit().WireID();
745 
746  geo::WireIDIntersection widIntersect;
747 
748  if (m_geometry->WireIDsIntersect(hit1WireID, hit2WireID, widIntersect))
749  {
750  // Wires intersect so now we can check the timing
751  float hit1Peak = hit1->getTimeTicks();
752  float hit1Sigma = hit1->getHit().RMS();
753 
754  float hit2Peak = hit2->getTimeTicks();
755  float hit2Sigma = hit2->getHit().RMS();
756 
757  // ad hoc correction for most bad fits...
758  if (hit1Sigma > 2. * hit1->getHit().PeakAmplitude()) hit1Sigma = 2. * hit1->getHit().PeakAmplitude();
759  if (hit2Sigma > 2. * hit2->getHit().PeakAmplitude()) hit2Sigma = 2. * hit2->getHit().PeakAmplitude();
760 
761  float hit1Width = hitWidthSclFctr * hit1Sigma;
762  float hit2Width = hitWidthSclFctr * hit2Sigma;
763 
764  // Coarse check hit times are "in range"
765  if (fabs(hit1Peak - hit2Peak) <= (hit1Width + hit2Width))
766  {
767  // Check to see that hit peak times are consistent with each other
768  float hit1SigSq = hit1Sigma * hit1Sigma;
769  float hit2SigSq = hit2Sigma * hit2Sigma;
770  float avePeakTime = (hit1Peak / hit1SigSq + hit2Peak / hit2SigSq) * hit1SigSq * hit2SigSq / (hit1SigSq + hit2SigSq);
771  float deltaPeakTime = std::fabs(hit1Peak - hit2Peak);
772  float sigmaPeakTime = std::sqrt(hit1SigSq + hit2SigSq);
773 
774  // delta peak time consistency check here
775  if (deltaPeakTime < m_deltaPeakTimeSig * sigmaPeakTime) // 2 sigma consistency? (do this way to avoid divide)
776  {
777  float totalCharge = hit1->getHit().Integral() + hit2->getHit().Integral();
778  float hitChiSquare = std::pow((hit1Peak - avePeakTime),2) / hit1SigSq
779  + std::pow((hit2Peak - avePeakTime),2) / hit2SigSq;
780 
781  float xPositionHit1(hit1->getXPosition());
782  float xPositionHit2(hit2->getXPosition());
783  float xPosition = (xPositionHit1 / hit1SigSq + xPositionHit2 / hit2SigSq) * hit1SigSq * hit2SigSq / (hit1SigSq + hit2SigSq);
784 
785  float position[] = {xPosition, float(widIntersect.y), float(widIntersect.z)-m_zPosOffset};
786 
787  // If to here then we need to sort out the hit pair code telling what views are used
788  unsigned statusBits = 1 << hit1->getHit().WireID().Plane | 1 << hit2->getHit().WireID().Plane;
789 
790  // handle status bits for the 2D hits
793 
796 
797  reco::ClusterHit2DVec hitVector;
798 
799  hitVector.resize(3, NULL);
800 
801  hitVector.at(hit1->getHit().WireID().Plane) = hit1;
802  hitVector.at(hit2->getHit().WireID().Plane) = hit2;
803 
804  unsigned int cryostatIdx = hit1->getHit().WireID().Cryostat;
805  unsigned int tpcIdx = hit1->getHit().WireID().TPC;
806 
807  // Initialize the wireIdVec
808  std::vector<geo::WireID> wireIDVec = {geo::WireID(cryostatIdx,tpcIdx,0,0),
809  geo::WireID(cryostatIdx,tpcIdx,1,0),
810  geo::WireID(cryostatIdx,tpcIdx,2,0)};
811 
812  wireIDVec[hit1->getHit().WireID().Plane] = hit1->getHit().WireID();
813  wireIDVec[hit2->getHit().WireID().Plane] = hit2->getHit().WireID();
814 
815  // For compiling at the moment
816  std::vector<float> hitDelTSigVec = {0.,0.,0.};
817 
818  hitDelTSigVec.at(hit1->getHit().WireID().Plane) = deltaPeakTime / sigmaPeakTime;
819  hitDelTSigVec.at(hit2->getHit().WireID().Plane) = deltaPeakTime / sigmaPeakTime;
820 
821  // Create the 3D cluster hit
822  hitPair.initialize(hitPairCntr,
823  statusBits,
824  position,
825  totalCharge,
826  avePeakTime,
827  deltaPeakTime,
828  sigmaPeakTime,
829  hitChiSquare,
830  0.,
831  0.,
832  hitVector,
833  hitDelTSigVec,
834  wireIDVec);
835 
836  result = true;
837  }
838  }
839  }
840 
841  // Send it back
842  return result;
843 }
844 
845 
847  const reco::ClusterHit3D& pair,
848  const reco::ClusterHit2D* hit) const
849 {
850  // Assume failure
851  bool result(false);
852 
853  static const float rmsToSig(1.0); //0.75); //0.57735027);
854 
855  // We are going to force the wire pitch here, some time in the future we need to fix
856  static const double wirePitch(0.3);
857 
858  // Recover hit info
859  float hitTimeTicks = hit->getTimeTicks();
860  float hitSigma = hit->getHit().RMS();
861 
862  // Special case check
863  if (hitSigma > 2. * hit->getHit().PeakAmplitude()) hitSigma = 2. * hit->getHit().PeakAmplitude();
864 
865  // Let's do a quick consistency check on the input hits to make sure we are in range...
866  // Require the W hit to be "in range" with the UV Pair
867  if (fabs(hitTimeTicks - pair.getAvePeakTime()) < m_hitWidthSclFctr * (pair.getSigmaPeakTime() + hitSigma))
868  {
869  // Timing in range, now check that the input hit wire "intersects" with the input pair's wires
870  geo::WireID wireID = NearestWireID(pair.getPosition(), hit->getHit().WireID());
871 
872  // There is an interesting round off issue that we need to watch for...
873  if (wireID.Wire == hit->getHit().WireID().Wire || wireID.Wire + 1 == hit->getHit().WireID().Wire)
874  {
875  // Use the existing code to see the U and W hits are willing to pair with the V hit
876  reco::ClusterHit3D pair0h;
877  reco::ClusterHit3D pair1h;
878 
879  // Recover all the hits involved
880  const reco::ClusterHit2DVec& pairHitVec = pair.getHits();
881  const reco::ClusterHit2D* hit0 = pairHitVec.at(0);
882  const reco::ClusterHit2D* hit1 = pairHitVec.at(1);
883 
884  if (!hit0) hit0 = pairHitVec.at(2);
885  else if (!hit1) hit1 = pairHitVec.at(2);
886 
887  // If good pairs made here then we can try to make a triplet
888  if (makeHitPair(pair0h, hit0, hit, m_hitWidthSclFctr) && makeHitPair(pair1h, hit1, hit, m_hitWidthSclFctr))
889  {
890  // We want to make sure the 3 sets of pair are really consistent
891  // For TPC's with a 60 degree pitch the wire "intersection" will be an equilateral triangle
892  // with equal sides of length wire pitch / sin(60 degrees) / 2
893  // So we make sure all three achieve this
894  Eigen::Vector2f pair0hYZVec(pair0h.getPosition()[1],pair0h.getPosition()[2]);
895  Eigen::Vector2f pair1hYZVec(pair1h.getPosition()[1],pair1h.getPosition()[2]);
896  Eigen::Vector2f pairYZVec(pair.getPosition()[1],pair.getPosition()[2]);
897 
898  std::vector<float> sideVec = {(pair0hYZVec - pair1hYZVec).norm(),(pair1hYZVec - pairYZVec).norm(),(pairYZVec - pair0hYZVec).norm()};
899 
900  // The three sides will not be identically equal because of numeric issues. It is really sufficient to simply
901  // check that the longest side is less than the wire pitch
902  if (*std::max_element(sideVec.begin(),sideVec.end()) < wirePitch)
903  {
904  // Get a copy of the input hit vector (note the order is by plane - by definition)
905  reco::ClusterHit2DVec hitVector = pair.getHits();
906 
907  // include the new hit
908  hitVector.at(hit->getHit().WireID().Plane) = hit;
909 
910  // Set up to get average peak time, hitChiSquare, etc.
911  unsigned int statusBits(0x7);
912  float totalCharge(0.);
913  float avePeakTime(0.);
914  float weightSum(0.);
915  float xPosition(0.);
916 
917  // And get the wire IDs
918  std::vector<geo::WireID> wireIDVec = {geo::WireID(0,0,geo::kU,0), geo::WireID(0,0,geo::kV,0), geo::WireID(0,0,geo::kW,0)};
919 
920  // First loop through the hits to get WireIDs and calculate the averages
921  for(size_t planeIdx = 0; planeIdx < 3; planeIdx++)
922  {
923  const reco::ClusterHit2D* hit2D = hitVector.at(planeIdx);
924 
925  wireIDVec.at(planeIdx) = hit2D->getHit().WireID();
926 
928 
930 
931  float hitRMS = rmsToSig * hit2D->getHit().RMS();
932  float weight = 1. / (hitRMS * hitRMS);
933  float peakTime = hit2D->getTimeTicks();
934 
935  avePeakTime += peakTime * weight;
936  xPosition += hit2D->getXPosition() * weight;
937  weightSum += weight;
938  totalCharge += hit2D->getHit().Integral();
939  }
940 
941  avePeakTime /= weightSum;
942  xPosition /= weightSum;
943 
944  float position[] = { xPosition,
945  float((pairYZVec[0] + pair0hYZVec[0] + pair1hYZVec[0]) / 3.),
946  float((pairYZVec[1] + pair0hYZVec[1] + pair1hYZVec[1]) / 3.)};
947 
948  // Armed with the average peak time, now get hitChiSquare and the sig vec
949  float hitChiSquare(0.);
950  float sigmaPeakTime(std::sqrt(1./weightSum));
951  std::vector<float> hitDelTSigVec;
952 
953  for(const auto& hit2D : hitVector)
954  {
955  float hitRMS = rmsToSig * hit2D->getHit().RMS();
956  float combRMS = std::sqrt(hitRMS*hitRMS - sigmaPeakTime*sigmaPeakTime);
957  float peakTime = hit2D->getTimeTicks();
958  float deltaTime = peakTime - avePeakTime;
959  float hitSig = deltaTime / combRMS; //hitRMS;
960 
961  hitChiSquare += hitSig * hitSig;
962 
963  hitDelTSigVec.emplace_back(std::fabs(hitSig));
964  }
965 
966  // Usurping "deltaPeakTime" to be the maximum pull
967  float deltaPeakTime = *std::max_element(hitDelTSigVec.begin(),hitDelTSigVec.end());
968 
969  // Create the 3D cluster hit
970  hitTriplet.initialize(0,
971  statusBits,
972  position,
973  totalCharge,
974  avePeakTime,
975  deltaPeakTime,
976  sigmaPeakTime,
977  hitChiSquare,
978  0.,
979  0.,
980  hitVector,
981  hitDelTSigVec,
982  wireIDVec);
983 
984  result = true;
985  }
986  }
987  }
988  }
989 
990  // return success/fail
991  return result;
992 }
993 
995  const reco::ClusterHit3D& pair,
996  size_t maxChanStatus,
997  size_t minChanStatus,
998  float minOverlap) const
999 {
1000  // Assume failure (most common result)
1001  bool result(false);
1002 
1003  const reco::ClusterHit2D* hit0 = pair.getHits().at(0);
1004  const reco::ClusterHit2D* hit1 = pair.getHits().at(1);
1005 
1006  size_t missPlane(2);
1007 
1008  // u plane hit is missing
1009  if (!hit0)
1010  {
1011  hit0 = pair.getHits().at(2);
1012  missPlane = 0;
1013  }
1014  // v plane hit is missing
1015  else if (!hit1)
1016  {
1017  hit1 = pair.getHits().at(2);
1018  missPlane = 1;
1019  }
1020 
1021  // Which plane is missing?
1022  geo::WireID wireID0 = hit0->getHit().WireID();
1023  geo::WireID wireID1 = hit1->getHit().WireID();
1024 
1025  // Ok, recover the wireID expected in the third plane...
1026  geo::WireID wireIn(wireID0.Cryostat,wireID0.TPC,missPlane,0);
1027  geo::WireID wireID = NearestWireID(pair.getPosition(), wireIn);
1028 
1029  // There can be a round off issue so check the next wire as well
1030  bool wireStatus = m_channelStatus[wireID.Plane][wireID.Wire] < maxChanStatus && m_channelStatus[wireID.Plane][wireID.Wire] >= minChanStatus;
1031  bool wireOneStatus = m_channelStatus[wireID.Plane][wireID.Wire+1] < maxChanStatus && m_channelStatus[wireID.Plane][wireID.Wire+1] >= minChanStatus;
1032 
1033  // Make sure they are of at least the minimum status
1034  if(wireStatus || wireOneStatus)
1035  {
1036  // Sort out which is the wire we're dealing with
1037  if (!wireStatus) wireID.Wire += 1;
1038 
1039  // Want to refine position since we "know" the missing wire
1040  geo::WireIDIntersection widIntersect0;
1041 
1042  if (m_geometry->WireIDsIntersect(wireID0, wireID, widIntersect0))
1043  {
1044  geo::WireIDIntersection widIntersect1;
1045 
1046  if (m_geometry->WireIDsIntersect(wireID1, wireID, widIntersect1))
1047  {
1048  float newPosition[] = {pair.getPosition()[0],pair.getPosition()[1],pair.getPosition()[2]};
1049 
1050  newPosition[1] = (newPosition[1] + widIntersect0.y + widIntersect1.y) / 3.;
1051  newPosition[2] = (newPosition[2] + widIntersect0.z + widIntersect1.z - 2. * m_zPosOffset) / 3.;
1052 
1053  pairOut = pair;
1054  pairOut.setWireID(wireID);
1055  pairOut.setPosition(newPosition);
1056 
1059 
1062 
1063  result = true;
1064  }
1065  }
1066  }
1067 
1068  return result;
1069 }
1070 
1071 const reco::ClusterHit2D* StandardHit3DBuilder::FindBestMatchingHit(const Hit2DSet& hit2DSet, const reco::ClusterHit3D& pair, float pairDeltaTimeLimits) const
1072 {
1073  static const float minCharge(0.);
1074 
1075  const reco::ClusterHit2D* bestVHit(0);
1076 
1077  float pairAvePeakTime(pair.getAvePeakTime());
1078 
1079  // Idea is to loop through the input set of hits and look for the best combination
1080  for (const auto& hit2D : hit2DSet)
1081  {
1082  if (hit2D->getHit().Integral() < minCharge) continue;
1083 
1084  float hitVPeakTime(hit2D->getTimeTicks());
1085  float deltaPeakTime(pairAvePeakTime-hitVPeakTime);
1086 
1087  if (deltaPeakTime > pairDeltaTimeLimits) continue;
1088 
1089  if (deltaPeakTime < -pairDeltaTimeLimits) break;
1090 
1091  pairDeltaTimeLimits = fabs(deltaPeakTime);
1092  bestVHit = hit2D;
1093  }
1094 
1095  return bestVHit;
1096 }
1097 
1098 int StandardHit3DBuilder::FindNumberInRange(const Hit2DSet& hit2DSet, const reco::ClusterHit3D& pair, float range) const
1099 {
1100  static const float minCharge(0.);
1101 
1102  int numberInRange(0);
1103  float pairAvePeakTime(pair.getAvePeakTime());
1104 
1105  // Idea is to loop through the input set of hits and look for the best combination
1106  for (const auto& hit2D : hit2DSet)
1107  {
1108  if (hit2D->getHit().Integral() < minCharge) continue;
1109 
1110  float hitVPeakTime(hit2D->getTimeTicks());
1111  float deltaPeakTime(pairAvePeakTime-hitVPeakTime);
1112 
1113  if (deltaPeakTime > range) continue;
1114 
1115  if (deltaPeakTime < -range) break;
1116 
1117  numberInRange++;
1118  }
1119 
1120  return numberInRange;
1121 }
1122 
1123 geo::WireID StandardHit3DBuilder::NearestWireID(const float* position, const geo::WireID& wireIDIn) const
1124 {
1125  geo::WireID wireID = wireIDIn;
1126 
1127  // Embed the call to the geometry's services nearest wire id method in a try-catch block
1128  try
1129  {
1130  // Switch from NearestWireID to this method to avoid the roundoff error issues...
1131  double distanceToWire = m_geometry->Plane(wireIDIn).WireCoordinate(position);
1132 
1133  wireID.Wire = int(distanceToWire);
1134  }
1135  catch(std::exception& exc)
1136  {
1137  // This can happen, almost always because the coordinates are **just** out of range
1138  mf::LogWarning("Cluster3D") << "Exception caught finding nearest wire, position - " << exc.what() << std::endl;
1139 
1140  // Assume extremum for wire number depending on z coordinate
1141  if (position[2] < 0.5 * m_geometry->DetLength()) wireID.Wire = 0;
1142  else wireID.Wire = m_geometry->Nwires(wireIDIn.Plane) - 1;
1143  }
1144 
1145  return wireID;
1146 }
1147 
1148 //------------------------------------------------------------------------------------------------------------------------------------------
1150 {
1151  // Sort by "modified start time" of pulse
1152  return left->getHit().PeakTime() < right->getHit().PeakTime();
1153 }
1154 
1156 {
1157  return left->getHit().PeakTime() < right->getHit().PeakTime();
1158 }
1159 
1160 //------------------------------------------------------------------------------------------------------------------------------------------
1162  RecobHitToPtrMap& hitToPtrMap) const
1163 {
1167  art::Handle< std::vector<recob::Hit> > recobHitHandle;
1168  evt.getByLabel(m_hitFinderTag, recobHitHandle);
1169 
1170  if (!recobHitHandle.isValid()) return;
1171 
1172  cet::cpu_timer theClockMakeHits;
1173 
1174  if (m_enableMonitoring) theClockMakeHits.start();
1175 
1176  // We'll want to correct the hit times for the plane offsets
1177  // (note this is already taken care of when converting to position)
1178  std::map<geo::PlaneID, double> planeOffsetMap;
1179 
1180  // Reserve memory for the hit vector
1181  m_clusterHit2DMasterVec.reserve(recobHitHandle->size());
1182 
1183  // Initialize the plane to hit vector map
1184  for(size_t cryoIdx = 0; cryoIdx < m_geometry->Ncryostats(); cryoIdx++)
1185  {
1186  for(size_t tpcIdx = 0; tpcIdx < m_geometry->NTPC(); tpcIdx++)
1187  {
1188  m_planeToHitVectorMap[geo::PlaneID(cryoIdx,tpcIdx,0)] = HitVector();
1189  m_planeToHitVectorMap[geo::PlaneID(cryoIdx,tpcIdx,1)] = HitVector();
1190  m_planeToHitVectorMap[geo::PlaneID(cryoIdx,tpcIdx,2)] = HitVector();
1191 
1192  // What we want here are the relative offsets between the planes
1193  // Note that plane 0 is assumed the "first" plane and is the reference
1194  planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,0)] = 0.;
1195  planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,1)] = m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,1))
1196  - m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,0));
1197  planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,2)] = m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,2))
1198  - m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,0));
1199 
1200  std::cout << "***> plane 0 offset: " << planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,0)] << ", plane 1: " << planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,1)] << ", plane 2: " << planeOffsetMap[geo::PlaneID(cryoIdx,tpcIdx,2)] << std::endl;
1201  std::cout << " Det prop plane 0: " << m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,0)) << ", plane 1: " << m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,1)) << ", plane 2: " << m_detector->GetXTicksOffset(geo::PlaneID(cryoIdx,tpcIdx,2)) << ", Trig: " << m_detector->TriggerOffset() << std::endl;
1202  }
1203  }
1204 
1205  // Cycle through the recob hits to build ClusterHit2D objects and insert
1206  // them into the map
1207  for (size_t cIdx = 0; cIdx < recobHitHandle->size(); cIdx++)
1208  {
1209  art::Ptr<recob::Hit> recobHit(recobHitHandle, cIdx);
1210 
1211  // Skip junk hits
1212 // if (recobHit->DegreesOfFreedom() > 1 && recobHit->Multiplicity() > 1 && (recobHit->RMS() < 3.8 || recobHit->PeakAmplitude() < 10)) continue;
1213 
1214  const geo::WireID& hitWireID(recobHit->WireID());
1215 
1216  double hitPeakTime(recobHit->PeakTime() - planeOffsetMap[recobHit->WireID().planeID()]);
1217  double xPosition(m_detector->ConvertTicksToX(recobHit->PeakTime(), hitWireID.Plane, hitWireID.TPC, hitWireID.Cryostat));
1218 
1219  m_clusterHit2DMasterVec.emplace_back(0, 0., 0., xPosition, hitPeakTime, *recobHit);
1220 
1221  m_planeToHitVectorMap[recobHit->WireID().planeID()].push_back(&m_clusterHit2DMasterVec.back());
1222  m_planeToWireToHitSetMap[recobHit->WireID().planeID()][recobHit->WireID().Wire].insert(&m_clusterHit2DMasterVec.back());
1223 
1224  const recob::Hit* recobHitPtr = recobHit.get();
1225  hitToPtrMap[recobHitPtr] = recobHit;
1226  }
1227 
1228  // Make a loop through to sort the recover hits in time order
1229  for(auto& hitVectorMap : m_planeToHitVectorMap)
1230  std::sort(hitVectorMap.second.begin(), hitVectorMap.second.end(), SetHitTimeOrder);
1231 
1232  if (m_enableMonitoring)
1233  {
1234  theClockMakeHits.stop();
1235 
1236  m_timeVector[COLLECTARTHITS] = theClockMakeHits.accumulated_real_time();
1237  }
1238 
1239  mf::LogDebug("Cluster3D") << ">>>>> Number of ART hits: " << m_clusterHit2DMasterVec.size() << std::endl;
1240 }
1241 
1242 //------------------------------------------------------------------------------------------------------------------------------------------
1243 
1245 } // namespace lar_cluster3d
bool makeHitTriplet(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pairIn, const reco::ClusterHit2D *hit2) const
Make a 3D HitPair object by checking two hits.
PlaneID const & planeID() const
Definition: geo_types.h:355
void setWireID(const geo::WireID &wid) const
Definition: Cluster3D.cxx:155
double z
z position of intersection
Definition: geo_types.h:494
std::map< size_t, HitVector > HitVectorMap
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:45
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
float getTimeTicks() const
Definition: Cluster3D.h:72
virtual int TriggerOffset() const =0
const detinfo::DetectorProperties * m_detector
intermediate_table::iterator iterator
std::vector< size_t > ChannelStatusVec
define data structure for keeping track of channel status
geo::WireID NearestWireID(const float *position, const geo::WireID &wireID) const
Jacket the calls to finding the nearest wire in order to intercept the exceptions if out of range...
bool SetHitTimeOrder(const reco::ClusterHit2D *left, const reco::ClusterHit2D *right)
Planes which measure V.
Definition: geo_types.h:77
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
What follows are several highly useful typedefs which we want to expose to the outside world...
Declaration of signal hit object.
size_t BuildHitPairMapByTPC(PlaneHitVectorItrPairVec &planeHitVectorItrPairVec, reco::HitPairList &hitPairList) const
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
art::InputTag m_hitFinderTag
Data members to follow.
int findGoodHitPairs(const reco::ClusterHit2D *, HitVector::iterator &, HitVector::iterator &, HitMatchPairVecMap &) const
bool operator()(const reco::ClusterHit2D *, const reco::ClusterHit2D *) const
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
void BuildHit3D(reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
bool makeHitPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit2D *hit1, const reco::ClusterHit2D *hit2, float hitWidthSclFctr=1., size_t hitPairCntr=0) const
Make a HitPair object by checking two hits.
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
float getSigmaPeakTime() const
Definition: Cluster3D.h:154
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
std::map< geo::PlaneID, WireToHitSetMap > PlaneToWireToHitSetMap
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
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.
bool SetPeakHitPairIteratorOrder(const reco::HitPairList::iterator &left, const reco::HitPairList::iterator &right)
const reco::ClusterHit2D * FindBestMatchingHit(const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float pairDeltaTimeLimits) const
A utility routine for finding a 2D hit closest in time to the given pair.
void Hit3DBuilder(const art::Event &evt, reco::HitPairList &hitPairList, RecobHitToPtrMap &) const override
Given a set of recob hits, run DBscan to form 3D clusters.
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
Definition: Hit.h:222
std::list< std::unique_ptr< reco::ClusterHit3D >> HitPairList
Definition: Cluster3D.h:321
std::vector< reco::ClusterHit2D * > HitVector
bool isValid() const
Definition: Handle.h:190
float getAvePeakTime() const
Definition: Cluster3D.h:152
std::vector< std::unique_ptr< reco::ClusterHit3D >> HitPairVector
Planes which measure U.
Definition: geo_types.h:76
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
Int_t max
Definition: plot.C:27
std::map< geo::TPCID, PlaneToWireToHitSetMap > TPCToPlaneToWireToHitSetMap
std::map< geo::PlaneID, HitVector > PlaneToHitVectorMap
T get(std::string const &key) const
Definition: ParameterSet.h:231
StandardHit3DBuilder class definiton.
int FindNumberInRange(const Hit2DSet &hit2DSet, const reco::ClusterHit3D &pair, float range) const
A utility routine for returning the number of 2D hits from the list in a given range.
const recob::Hit & getHit() const
Definition: Cluster3D.h:73
geo::Length_t DetLength(geo::TPCID const &tpcid) const
Returns the length of the active volume of the specified TPC.
float getXPosition() const
Definition: Cluster3D.h:71
TimeValues
enumerate the possible values for time checking if monitoring timing
Definition: IHit3DBuilder.h:57
The geometry of one entire detector, as served by art.
Definition: Geometry.h:110
std::map< const recob::Hit *, art::Ptr< recob::Hit >> RecobHitToPtrMap
Defines a structure mapping art representation to internal.
Definition: IHit3DBuilder.h:44
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
IHit3DBuilder interface class definiton.
Definition: IHit3DBuilder.h:26
const float * getPosition() const
Definition: Cluster3D.h:147
std::pair< const reco::ClusterHit2D *, reco::ClusterHit3D > HitMatchPair
This builds a list of candidate hit pairs from lists of hits on two planes.
Detector simulation of raw signals on wires.
This provides an art tool interface definition for tools which construct 3D hits used in 3D clusterin...
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
Definition: Cluster3D.h:85
void findGoodTriplets(HitMatchPairVecMap &, HitMatchPairVecMap &, reco::HitPairList &, bool=false) const
This algorithm takes lists of hit pairs and finds good triplets.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::map< unsigned int, Hit2DSet > WireToHitSetMap
const lariov::ChannelStatusProvider * m_channelFilter
void initialize(size_t id, unsigned int statusBits, const float *position, float totalCharge, float avePeakTime, float deltaPeakTime, float sigmaPeakTime, float hitChiSquare, float docaToAxis, float arclenToPoca, const ClusterHit2DVec &hitVec, const std::vector< float > &hitDelTSigVec, const std::vector< geo::WireID > &wireIDVec)
Definition: Cluster3D.cxx:122
void CollectArtHits(const art::Event &evt, RecobHitToPtrMap &hitToPtrMap) const
Extract the ART hits and the ART hit-particle relationships.
Filters for channels, events, etc.
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
double weight
Definition: plottest35.C:25
bool operator()(const reco::HitPairClusterMap::iterator &left, const reco::HitPairClusterMap::iterator &right)
std::map< geo::TPCID, PlaneToHitVectorMap > TPCToPlaneToHitVectorMap
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
Utility object to perform functions of association.
void setID(const size_t &id) const
Definition: Cluster3D.h:164
Float_t norm
T const * get() const
Definition: Ptr.h:321
void setPosition(const float *pos) const
Definition: Cluster3D.h:171
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
std::vector< reco::ClusterHit2D > Hit2DVector
std::vector< ChannelStatusVec > ChannelStatusByPlaneVec
double y
y position of intersection
Definition: geo_types.h:493
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
size_t BuildHitPairMap(PlaneToHitVectorMap &planeToHitVectorMap, reco::HitPairList &hitPairList) const
Given the ClusterHit2D objects, build the HitPairMap.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
std::map< geo::WireID, HitMatchPairVec > HitMatchPairVecMap
std::vector< std::pair< HitVector::iterator, HitVector::iterator >> PlaneHitVectorItrPairVec
Given the ClusterHit2D objects, build the HitPairMap.
HLT enums.
StandardHit3DBuilder(fhicl::ParameterSet const &pset)
Constructor.
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:78
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
bool makeDeadChannelPair(reco::ClusterHit3D &pairOut, const reco::ClusterHit3D &pair, size_t maxStatus=4, size_t minStatus=0, float minOverlap=0.2) const
Make a 3D HitPair object from a valid pair and a dead channel in the missing plane.
double WireCoordinate(Point const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:725
TCEvent evt
Definition: DataStructs.cxx:5
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
float getTimeToExecute(IHit3DBuilder::TimeValues index) const override
If monitoring, recover the time to execute a particular function.
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:158
std::set< const reco::ClusterHit2D *, Hit2DSetCompare > Hit2DSet
void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void BuildChannelStatusVec(PlaneToWireToHitSetMap &planeToWiretoHitSetMap) const
Create the internal channel status vector (assume will eventually be event-by-event) ...
unsigned getStatusBits() const
Definition: Cluster3D.h:68
virtual double GetXTicksOffset(int p, int t, int c) const =0
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:75