LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Cluster3D_module.cc
Go to the documentation of this file.
1 
46 // Framework Includes
53 #include "art_root_io/TFileService.h"
54 #include "cetlib/cpu_timer.h"
55 
56 // LArSoft includes
70 
85 
86 // ROOT includes
87 #include "TTree.h"
88 #include "TVector3.h"
89 
90 // std includes
91 #include <iostream>
92 #include <memory>
93 #include <string>
94 
95 //------------------------------------------------------------------------------------------------------------------------------------------
96 
97 namespace lar_cluster3d {
98  using Hit3DToSPPtrMap =
99  std::unordered_map<const reco::ClusterHit3D*, art::Ptr<recob::SpacePoint>>;
102 
103  //------------------------------------------------------------------------------------------------------------------------------------------
104  // Definition of the producer module here
105 
109  class Cluster3D : public art::EDProducer {
110  public:
111  explicit Cluster3D(fhicl::ParameterSet const& pset);
112 
113  private:
114  void beginJob() override;
115  void produce(art::Event& evt) override;
116 
118  public:
120  std::string& pathName,
121  std::string& vertexName,
122  std::string& extremeName)
123  : artPCAxisVector(new std::vector<recob::PCAxis>)
124  , artPFParticleVector(new std::vector<recob::PFParticle>)
125  , artClusterVector(new std::vector<recob::Cluster>)
126  , artSpacePointVector(new std::vector<recob::SpacePoint>)
127  , artPathPointVector(new std::vector<recob::SpacePoint>)
128  , artVertexPointVector(new std::vector<recob::SpacePoint>)
129  , artExtremePointVector(new std::vector<recob::SpacePoint>)
130  , artSeedVector(new std::vector<recob::Seed>)
131  , artEdgeVector(new std::vector<recob::Edge>)
134  , artClusterAssociations(new art::Assns<recob::Cluster, recob::Hit>)
135  , artPFPartAxisAssociations(new art::Assns<recob::PFParticle, recob::PCAxis>)
136  , artPFPartClusAssociations(new art::Assns<recob::PFParticle, recob::Cluster>)
137  , artPFPartSPAssociations(new art::Assns<recob::SpacePoint, recob::PFParticle>)
138  , artPFPartPPAssociations(new art::Assns<recob::SpacePoint, recob::PFParticle>)
139  , artPFPartSeedAssociations(new art::Assns<recob::PFParticle, recob::Seed>)
140  , artPFPartEdgeAssociations(new art::Assns<recob::Edge, recob::PFParticle>)
141  , artPFPartPathEdgeAssociations(new art::Assns<recob::Edge, recob::PFParticle>)
142  , artSeedHitAssociations(new art::Assns<recob::Seed, recob::Hit>)
143  , artSPHitAssociations(new art::Assns<recob::Hit, recob::SpacePoint>)
144  , artPPHitAssociations(new art::Assns<recob::Hit, recob::SpacePoint>)
145  , artEdgeSPAssociations(new art::Assns<recob::SpacePoint, recob::Edge>)
146  , artEdgePPAssociations(new art::Assns<recob::SpacePoint, recob::Edge>)
147  , fEvt(evt)
148  , fSPPtrMaker(evt)
149  , fSPPtrMakerPath(evt, pathName)
150  , fEdgePtrMaker(evt)
151  , fEdgePtrMakerPath(evt, pathName)
152  , fPathName(pathName)
153  , fVertexName(vertexName)
154  , fExtremeName(extremeName)
155  {}
156 
158  {
160  }
161 
162  void makeSpacePointHitAssns(std::vector<recob::SpacePoint>& spacePointVector,
163  RecobHitVector& recobHits,
165  const std::string& path = "")
166  {
167  for (auto& hit : recobHits)
168  util::CreateAssn(fEvt, spacePointVector, hit, spHitAssns, path);
169  }
170 
172  {
177  artPCAxisVector->size() - 2,
178  artPCAxisVector->size());
179  }
180 
181  void makePFPartSeedAssns(size_t numSeedsStart)
182  {
185  *artSeedVector,
187  numSeedsStart,
188  artSeedVector->size());
189  }
190 
191  void makePFPartClusterAssns(size_t clusterStart)
192  {
197  clusterStart,
198  artClusterVector->size());
199  }
200 
202  std::vector<recob::SpacePoint>& spacePointVector,
204  size_t spacePointStart,
205  const std::string& instance = "")
206  {
207  for (size_t idx = spacePointStart; idx < spacePointVector.size(); idx++) {
209  util::CreateAssn(fEvt, *artPFParticleVector, spacePoint, pfPartSPAssociations);
210  }
211  }
212 
213  void makePFPartEdgeAssns(std::vector<recob::Edge>& edgeVector,
214  art::Assns<recob::Edge, recob::PFParticle>& pfPartEdgeAssociations,
215  size_t edgeStart,
216  const std::string& instance = "")
217  {
218  for (size_t idx = edgeStart; idx < edgeVector.size(); idx++) {
220 
221  util::CreateAssn(fEvt, *artPFParticleVector, edge, pfPartEdgeAssociations);
222  }
223  }
224 
225  void makeEdgeSpacePointAssns(std::vector<recob::Edge>& edgeVector,
226  RecobSpacePointVector& spacePointVector,
227  art::Assns<recob::SpacePoint, recob::Edge>& edgeSPAssociations,
228  const std::string& path = "")
229  {
230  for (auto& spacePoint : spacePointVector)
231  util::CreateAssn(fEvt, edgeVector, spacePoint, edgeSPAssociations, path);
232  }
233 
235  {
236  fEvt.put(std::move(artPCAxisVector));
237  fEvt.put(std::move(artPFParticleVector));
238  fEvt.put(std::move(artClusterVector));
239  fEvt.put(std::move(artSpacePointVector));
240  fEvt.put(std::move(artSeedVector));
241  fEvt.put(std::move(artEdgeVector));
242  fEvt.put(std::move(artPFPartAxisAssociations));
243  fEvt.put(std::move(artPFPartClusAssociations));
244  fEvt.put(std::move(artClusterAssociations));
245  fEvt.put(std::move(artPFPartSPAssociations));
246  fEvt.put(std::move(artPFPartSeedAssociations));
247  fEvt.put(std::move(artPFPartEdgeAssociations));
248  fEvt.put(std::move(artSeedHitAssociations));
249  fEvt.put(std::move(artSPHitAssociations));
250  fEvt.put(std::move(artEdgeSPAssociations));
251  fEvt.put(std::move(artPathEdgeVector), fPathName);
252  fEvt.put(std::move(artPathPointVector), fPathName);
256  fEvt.put(std::move(artPPHitAssociations), fPathName);
260  }
261 
262  art::Ptr<recob::SpacePoint> makeSpacePointPtr(size_t index, const std::string& instance = "")
263  {
264  if (empty(instance)) { return fSPPtrMaker(index); }
265  return fSPPtrMakerPath(index);
266  };
267 
268  art::Ptr<recob::Edge> makeEdgePtr(size_t index, const std::string& instance = "")
269  {
270  if (empty(instance)) { return fEdgePtrMaker(index); }
271  return fEdgePtrMakerPath(index);
272  };
273 
274  std::unique_ptr<std::vector<recob::PCAxis>> artPCAxisVector;
275  std::unique_ptr<std::vector<recob::PFParticle>> artPFParticleVector;
276  std::unique_ptr<std::vector<recob::Cluster>> artClusterVector;
277  std::unique_ptr<std::vector<recob::SpacePoint>> artSpacePointVector;
278  std::unique_ptr<std::vector<recob::SpacePoint>> artPathPointVector;
279  std::unique_ptr<std::vector<recob::SpacePoint>> artVertexPointVector;
280  std::unique_ptr<std::vector<recob::SpacePoint>> artExtremePointVector;
281  std::unique_ptr<std::vector<recob::Seed>> artSeedVector;
282  std::unique_ptr<std::vector<recob::Edge>> artEdgeVector;
283  std::unique_ptr<std::vector<recob::Edge>> artPathEdgeVector;
284  std::unique_ptr<std::vector<recob::Edge>> artVertexEdgeVector;
285 
286  std::unique_ptr<art::Assns<recob::Cluster, recob::Hit>> artClusterAssociations;
287  std::unique_ptr<art::Assns<recob::PFParticle, recob::PCAxis>> artPFPartAxisAssociations;
288  std::unique_ptr<art::Assns<recob::PFParticle, recob::Cluster>> artPFPartClusAssociations;
289  std::unique_ptr<art::Assns<recob::SpacePoint, recob::PFParticle>> artPFPartSPAssociations;
290  std::unique_ptr<art::Assns<recob::SpacePoint, recob::PFParticle>> artPFPartPPAssociations;
291  std::unique_ptr<art::Assns<recob::PFParticle, recob::Seed>> artPFPartSeedAssociations;
292  std::unique_ptr<art::Assns<recob::Edge, recob::PFParticle>> artPFPartEdgeAssociations;
293  std::unique_ptr<art::Assns<recob::Edge, recob::PFParticle>> artPFPartPathEdgeAssociations;
294  std::unique_ptr<art::Assns<recob::Seed, recob::Hit>> artSeedHitAssociations;
295  std::unique_ptr<art::Assns<recob::Hit, recob::SpacePoint>> artSPHitAssociations;
296  std::unique_ptr<art::Assns<recob::Hit, recob::SpacePoint>> artPPHitAssociations;
297  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Edge>> artEdgeSPAssociations;
298  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Edge>> artEdgePPAssociations;
299 
300  private:
306  std::string& fPathName;
307  std::string& fVertexName;
308  std::string& fExtremeName;
309  };
310 
316  void PrepareEvent(const art::Event& evt);
317 
321  void InitializeMonitoring();
322 
332  void findTrackSeeds(art::Event& evt,
334  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
335  std::vector<recob::Seed>& seedVec,
336  art::Assns<recob::Seed, recob::Hit>& seedHitAssns) const;
337 
344  void splitClustersWithHough(reco::ClusterParameters& clusterParameters,
345  reco::ClusterParametersList& clusterParametersList) const;
346 
356  std::vector<recob::SpacePoint>& spacePointVec,
358  reco::HitPairListPtr& clusHitPairVector,
359  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
360  Hit3DToSPPtrMap& hit3DToSPPtrMap,
361  const std::string& path = "") const;
362 
370  reco::ConvexHullKinkTupleList& clusHitPairVector) const;
371 
381  dcel2d::HalfEdgeList&) const;
382 
389  using IdxToPCAMap = std::map<size_t, const reco::PrincipalComponents*>;
390 
393  IdxToPCAMap&) const;
394 
405  ArtOutputHandler& output,
406  reco::ClusterParameters& clusterParameters,
407  size_t pfParticleParent,
408  IdxToPCAMap& idxToPCAMap,
409  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
410  Hit3DToSPPtrMap& hit3DToSPPtrMap,
411  Hit3DToSPPtrMap& best3DToSPPtrMap) const;
412 
421  ArtOutputHandler& output,
422  reco::HitPairList& hitPairList,
423  reco::ClusterParametersList& clusterParametersList,
424  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap) const;
425 
434  size_t ConvertToArtOutput(util::GeometryUtilities const& gser,
435  ArtOutputHandler& output,
436  reco::ClusterParameters& clusterParameters,
437  size_t pfParticleParent,
438  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
439  Hit3DToSPPtrMap& hit3DToSPPtrMap,
440  Hit3DToSPPtrMap& best3DToSPPtrMap) const;
441 
449  {
450  return fabs(pca.getEigenVectors().row(2)(0)) > m_parallelHitsCosAng &&
451  3. * sqrt(pca.getEigenValues()(1)) > m_parallelHitsTransWid;
452  }
453 
459  size_t countUltimateDaughters(reco::ClusterParameters& clusterParameters) const;
460 
468 
472  TTree* m_pRecoTree;
473  int m_run;
474  int m_event;
475  int m_hits;
476  int m_hits3D;
477  float m_totalTime;
481  float m_dbscanTime;
484  float m_finishTime;
485  std::string m_pathInstance;
486  std::string m_vertexInstance;
487  std::string m_extremeInstance;
488 
489  // Algorithms
490  std::unique_ptr<lar_cluster3d::IHit3DBuilder>
492  std::unique_ptr<lar_cluster3d::IClusterAlg>
494  std::unique_ptr<lar_cluster3d::IClusterModAlg>
496  std::unique_ptr<lar_cluster3d::IClusterModAlg>
498  std::unique_ptr<lar_cluster3d::IClusterParametersBuilder>
505  };
506 
508 
509 } // namespace lar_cluster3d
510 
511 //------------------------------------------------------------------------------------------------------------------------------------------
512 // implementation follows
513 
514 namespace lar_cluster3d {
515 
517  : EDProducer{pset}
518  , m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
519  , m_skeletonAlg(pset.get<fhicl::ParameterSet>("SkeletonAlg"))
520  , m_seedFinderAlg(pset.get<fhicl::ParameterSet>("SeedFinderAlg"))
521  , m_pcaSeedFinderAlg(pset.get<fhicl::ParameterSet>("PCASeedFinderAlg"))
522  , m_parallelHitsAlg(pset.get<fhicl::ParameterSet>("ParallelHitsAlg"))
523  {
524  m_onlyMakSpacePoints = pset.get<bool>("MakeSpacePointsOnly", false);
525  m_enableMonitoring = pset.get<bool>("EnableMonitoring", false);
526  m_parallelHitsCosAng = pset.get<float>("ParallelHitsCosAng", 0.999);
527  m_parallelHitsTransWid = pset.get<float>("ParallelHitsTransWid", 25.0);
528  m_pathInstance = pset.get<std::string>("PathPointsName", "Path");
529  m_vertexInstance = pset.get<std::string>("VertexPointsName", "Vertex");
530  m_extremeInstance = pset.get<std::string>("ExtremePointsName", "Extreme");
531 
532  m_hit3DBuilderAlg = art::make_tool<lar_cluster3d::IHit3DBuilder>(
533  pset.get<fhicl::ParameterSet>("Hit3DBuilderAlg"));
534  m_clusterAlg =
535  art::make_tool<lar_cluster3d::IClusterAlg>(pset.get<fhicl::ParameterSet>("ClusterAlg"));
536  m_clusterMergeAlg = art::make_tool<lar_cluster3d::IClusterModAlg>(
537  pset.get<fhicl::ParameterSet>("ClusterMergeAlg"));
538  m_clusterPathAlg = art::make_tool<lar_cluster3d::IClusterModAlg>(
539  pset.get<fhicl::ParameterSet>("ClusterPathAlg"));
540  m_clusterBuilder = art::make_tool<lar_cluster3d::IClusterParametersBuilder>(
541  pset.get<fhicl::ParameterSet>("ClusterParamsBuilder"));
542 
543  // Handle special case of Space Point building outputting a new hit collection
544  m_hit3DBuilderAlg->produces(producesCollector());
545 
546  produces<std::vector<recob::PCAxis>>();
547  produces<std::vector<recob::PFParticle>>();
548  produces<std::vector<recob::Cluster>>();
549  produces<std::vector<recob::Seed>>();
550  produces<std::vector<recob::Edge>>();
551 
552  produces<art::Assns<recob::PFParticle, recob::PCAxis>>();
553  produces<art::Assns<recob::PFParticle, recob::Cluster>>();
554  produces<art::Assns<recob::PFParticle, recob::Seed>>();
555  produces<art::Assns<recob::Edge, recob::PFParticle>>();
556  produces<art::Assns<recob::Seed, recob::Hit>>();
557  produces<art::Assns<recob::Cluster, recob::Hit>>();
558 
559  produces<std::vector<recob::SpacePoint>>();
560  produces<art::Assns<recob::SpacePoint, recob::PFParticle>>();
561  produces<art::Assns<recob::Hit, recob::SpacePoint>>();
562  produces<art::Assns<recob::SpacePoint, recob::Edge>>();
563 
564  produces<std::vector<recob::SpacePoint>>(m_pathInstance);
565  produces<std::vector<recob::Edge>>(m_pathInstance);
566  produces<art::Assns<recob::SpacePoint, recob::PFParticle>>(m_pathInstance);
567  produces<art::Assns<recob::Edge, recob::PFParticle>>(m_pathInstance);
568  produces<art::Assns<recob::Hit, recob::SpacePoint>>(m_pathInstance);
569  produces<art::Assns<recob::SpacePoint, recob::Edge>>(m_pathInstance);
570 
571  produces<std::vector<recob::Edge>>(m_vertexInstance);
572  produces<std::vector<recob::SpacePoint>>(m_vertexInstance);
573 
574  produces<std::vector<recob::SpacePoint>>(m_extremeInstance);
575  }
576 
577  //------------------------------------------------------------------------------------------------------------------------------------------
578 
580  {
586  }
587 
588  //------------------------------------------------------------------------------------------------------------------------------------------
589 
591  {
592  mf::LogInfo("Cluster3D") << " *** Cluster3D::produce(...) [Run=" << evt.run()
593  << ", Event=" << evt.id().event() << "] Starting Now! *** "
594  << std::endl;
595 
596  // Set up for monitoring the timing... at some point this should be removed in favor of
597  // external profilers
598  cet::cpu_timer theClockTotal;
599  cet::cpu_timer theClockFinish;
600 
601  if (m_enableMonitoring) theClockTotal.start();
602 
603  // This really only does anything if we are monitoring since it clears our tree variables
604  this->PrepareEvent(evt);
605 
606  // Get instances of the primary data structures needed
607  reco::ClusterParametersList clusterParametersList;
608  IHit3DBuilder::RecobHitToPtrMap clusterHitToArtPtrMap;
609  std::unique_ptr<reco::HitPairList> hitPairList(
610  new reco::HitPairList); // Potentially lots of hits, use heap instead of stack
611 
612  // Call the algorithm that builds 3D hits and stores the hit collection
613  m_hit3DBuilderAlg->Hit3DBuilder(evt, *hitPairList, clusterHitToArtPtrMap);
614 
615  // Only do the rest if we are not in the mode of only building space points (requested by ML folks)
616  if (!m_onlyMakSpacePoints) {
617  // Call the main workhorse algorithm for building the local version of candidate 3D clusters
618  m_clusterAlg->Cluster3DHits(*hitPairList, clusterParametersList);
619 
620  // Try merging clusters
621  m_clusterMergeAlg->ModifyClusters(clusterParametersList);
622 
623  // Run the path finding
624  m_clusterPathAlg->ModifyClusters(clusterParametersList);
625  }
626 
627  if (m_enableMonitoring) theClockFinish.start();
628 
629  // Get the art ouput object
631 
632  // Call the module that does the end processing (of which there is quite a bit of work!)
633  // This goes here to insure that something is always written to the data store
634  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
635  auto const detProp =
637  util::GeometryUtilities const gser{*lar::providerFrom<geo::Geometry>(), clockData, detProp};
638  ProduceArtClusters(gser, output, *hitPairList, clusterParametersList, clusterHitToArtPtrMap);
639 
640  // Output to art
641  output.outputObjects();
642 
643  // If monitoring then deal with the fallout
644  if (m_enableMonitoring) {
645  theClockFinish.stop();
646  theClockTotal.stop();
647 
648  m_run = evt.run();
649  m_event = evt.id().event();
650  m_totalTime = theClockTotal.accumulated_real_time();
654  m_dbscanTime = m_clusterAlg->getTimeToExecute(IClusterAlg::RUNDBSCAN) +
655  m_clusterAlg->getTimeToExecute(IClusterAlg::BUILDCLUSTERINFO);
656  m_clusterMergeTime = m_clusterMergeAlg->getTimeToExecute();
657  m_pathFindingTime = m_clusterPathAlg->getTimeToExecute();
658  m_finishTime = theClockFinish.accumulated_real_time();
659  m_hits = static_cast<int>(clusterHitToArtPtrMap.size());
660  m_hits3D = static_cast<int>(hitPairList->size());
661  m_pRecoTree->Fill();
662 
663  mf::LogDebug("Cluster3D") << "*** Cluster3D total time: " << m_totalTime
664  << ", art: " << m_artHitsTime << ", make: " << m_makeHitsTime
665  << ", build: " << m_buildNeighborhoodTime
666  << ", clustering: " << m_dbscanTime
667  << ", merge: " << m_clusterMergeTime
668  << ", path: " << m_pathFindingTime << ", finish: " << m_finishTime
669  << std::endl;
670  }
671 
672  // Will we ever get here? ;-)
673  return;
674  }
675 
676  //------------------------------------------------------------------------------------------------------------------------------------------
677 
679  {
681  m_pRecoTree = tfs->make<TTree>("monitoring", "LAr Reco");
682  m_pRecoTree->Branch("run", &m_run, "run/I");
683  m_pRecoTree->Branch("event", &m_event, "event/I");
684  m_pRecoTree->Branch("hits", &m_hits, "hits/I");
685  m_pRecoTree->Branch("hits3D", &m_hits3D, "hits3D/I");
686  m_pRecoTree->Branch("totalTime", &m_totalTime, "time/F");
687  m_pRecoTree->Branch("artHitsTime", &m_artHitsTime, "time/F");
688  m_pRecoTree->Branch("makeHitsTime", &m_makeHitsTime, "time/F");
689  m_pRecoTree->Branch("buildneigborhoodTime", &m_buildNeighborhoodTime, "time/F");
690  m_pRecoTree->Branch("dbscanTime", &m_dbscanTime, "time/F");
691  m_pRecoTree->Branch("clusterMergeTime", &m_clusterMergeTime, "time/F");
692  m_pRecoTree->Branch("pathfindingtime", &m_pathFindingTime, "time/F");
693  m_pRecoTree->Branch("finishTime", &m_finishTime, "time/F");
694 
695  m_clusterPathAlg->initializeHistograms(*tfs.get());
696  }
697 
698  //------------------------------------------------------------------------------------------------------------------------------------------
699 
701  {
702  m_run = evt.run();
703  m_event = evt.id().event();
704  m_hits = 0;
705  m_hits3D = 0;
706  m_totalTime = 0.f;
707  m_artHitsTime = 0.f;
708  m_makeHitsTime = 0.f;
710  m_dbscanTime = 0.f;
711  m_pathFindingTime = 0.f;
712  m_finishTime = 0.f;
713  }
714 
715  //------------------------------------------------------------------------------------------------------------------------------------------
716 
719  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
720  std::vector<recob::Seed>& seedVec,
721  art::Assns<recob::Seed, recob::Hit>& seedHitAssns) const
722  {
728  // Make sure we are using the right pca
729  reco::PrincipalComponents& fullPCA = cluster.getFullPCA();
730  reco::PrincipalComponents& skeletonPCA = cluster.getSkeletonPCA();
731  reco::HitPairListPtr& hitPairListPtr = cluster.getHitPairListPtr();
732  reco::HitPairListPtr skeletonListPtr;
733 
734  // We want to work with the "skeleton" hits so first step is to call the algorithm to
735  // recover only these hits from the entire input collection
736  m_skeletonAlg.GetSkeletonHits(hitPairListPtr, skeletonListPtr);
737 
738  // Skeleton hits are nice but we can do better if we then make a pass through to "average"
739  // the skeleton hits position in the Y-Z plane
740  m_skeletonAlg.AverageSkeletonPositions(skeletonListPtr);
741 
742  SeedHitPairListPairVec seedHitPairVec;
743 
744  // Some combination of the elements below will be used to determine which seed finding algorithm
745  // to pursue below
746  float eigenVal0 = 3. * sqrt(skeletonPCA.getEigenValues()[0]);
747  float eigenVal1 = 3. * sqrt(skeletonPCA.getEigenValues()[1]);
748  float eigenVal2 = 3. * sqrt(skeletonPCA.getEigenValues()[2]);
749  float transRMS = std::hypot(eigenVal0, eigenVal1);
750 
751  bool foundGoodSeed(false);
752 
753  // Choose a method for finding the seeds based on the PCA that was run...
754  // Currently we have an ad hoc if-else block which I hope will be improved soon!
755  if (aParallelHitsCluster(fullPCA)) {
756  // In this case we have a track moving relatively parallel to the wire plane with lots of
757  // ambiguous 3D hits. Your best bet here is to use the "parallel hits" algorithm to get the
758  // best axis and seeds
759  // This algorithm does not fail (foundGoodSeed will always return true)
760  foundGoodSeed = m_parallelHitsAlg.findTrackSeeds(hitPairListPtr, skeletonPCA, seedHitPairVec);
761  }
762  else if (eigenVal2 > 40. && transRMS < 5.) {
763  // If the input cluster is relatively "straight" then chances are it is a single straight track,
764  // probably a CR muon, and we can simply use the PCA to determine the seed
765  // This algorithm will check both "ends" of the input hits and if the angles become inconsistent
766  // then it will "fail"
767  foundGoodSeed =
768  m_pcaSeedFinderAlg.findTrackSeeds(skeletonListPtr, skeletonPCA, seedHitPairVec);
769  }
770 
771  // In the event the above two methods failed then we hit it with the real seed finder
772  if (!foundGoodSeed) {
773  // If here then we have a complicated 3D cluster and we'll use the hough transform algorithm to
774  // return a list of candidate seeds and seed hits
775  m_seedFinderAlg.findTrackSeeds(skeletonListPtr, skeletonPCA, seedHitPairVec);
776  }
777 
778  // Go through the returned lists and build out the art friendly seeds and hits
779  for (const auto& seedHitPair : seedHitPairVec) {
780  seedVec.push_back(seedHitPair.first);
781 
782  // We use a set here because our 3D hits can share 2D hits
783  // The set will make sure we get unique combinations of 2D hits
784  std::set<art::Ptr<recob::Hit>> seedHitSet;
785  for (const auto& hit3D : seedHitPair.second) {
786  for (const auto& hit2D : hit3D->getHits()) {
787  if (!hit2D) continue;
788 
789  const recob::Hit* recobHit = hit2D->getHit();
790  seedHitSet.insert(hitToPtrMap[recobHit]);
791  }
792  }
793 
794  RecobHitVector seedHitVec;
795  for (const auto& hit2D : seedHitSet)
796  seedHitVec.push_back(hit2D);
797 
798  util::CreateAssn(evt, seedVec, seedHitVec, seedHitAssns);
799  }
800  }
801 
803  bool operator()(const std::pair<float, const reco::ClusterHit3D*>& left,
804  const std::pair<float, const reco::ClusterHit3D*>& right)
805  {
806  return left.first < right.first;
807  }
808  };
809 
811  public:
812  CopyIfInRange(float maxRange) : m_maxRange(maxRange) {}
813 
814  bool operator()(const reco::ClusterHit3D* hit3D) const
815  {
816  return hit3D->getDocaToAxis() < m_maxRange;
817  }
818 
819  private:
820  float m_maxRange;
821  };
822 
824  reco::ClusterParametersList& clusterParametersList) const
825  {
826  // @brief A method for splitted "crossed tracks" clusters into separate clusters
827  //
828  // If this routine is called then we believe we have a cluster which needs splitting.
829  // The specific topology we are looking for is two long straight tracks which cross at some
830  // point in close proximity so their hits were joined into a single 3D cluster. The method
831  // to split this topology is to let the hough transform algorithm find the two leading candidates
832  // and then to see if we use those to build two clusters instead of one.
833 
834  // Recover the hits we'll work on.
835  // Note that we use on the skeleton hits so will need to recover them
836  reco::HitPairListPtr& hitPairListPtr = clusterParameters.getHitPairListPtr();
837  reco::HitPairListPtr skeletonListPtr;
838 
839  // We want to work with the "skeleton" hits so first step is to call the algorithm to
840  // recover only these hits from the entire input collection
841  m_skeletonAlg.GetSkeletonHits(hitPairListPtr, skeletonListPtr);
842 
843  // Skeleton hits are nice but we can do better if we then make a pass through to "average"
844  // the skeleton hits position in the Y-Z plane
845  m_skeletonAlg.AverageSkeletonPositions(skeletonListPtr);
846 
847  // Define the container for our lists of hits
848  reco::HitPairListPtrList hitPairListPtrList;
849 
850  // Now feed this to the Hough Transform to find candidate straight lines
852  skeletonListPtr, clusterParameters.getSkeletonPCA(), hitPairListPtrList);
853 
854  // We need at least two lists or else there is nothing to do
855  if (hitPairListPtrList.size() < 2) return;
856 
857  // The game plan will be the following:
858  // 1) Take the first list of hits and run the PCA on this to get an axis
859  // - Then calculate the 3d doca for ALL hits in the cluster to this axis
860  // - Move all hits within "3 sigam" of the axis to a new list
861  // 2) run the PCA on the second list of hits to get that axis
862  // - Then calculate the 3d doca for all hits in our first list
863  // - Copy hits in the first list which are within 3 sigma of the new axis
864  // back into our original cluster - these are shared hits
865  reco::HitPairListPtrList::iterator hitPairListIter = hitPairListPtrList.begin();
866  reco::HitPairListPtr& firstHitList = *hitPairListIter++;
867  reco::PrincipalComponents firstHitListPCA;
868 
869  m_pcaAlg.PCAAnalysis_3D(firstHitList, firstHitListPCA);
870 
871  // Make sure we have a successful calculation.
872  if (firstHitListPCA.getSvdOK()) {
873  // The fill routines below will expect to see unused 2D hits so we need to clear the
874  // status bits... and I am not sure of a better way...
875  for (const auto& hit3D : hitPairListPtr) {
876  for (const auto& hit2D : hit3D->getHits())
877  if (hit2D) hit2D->clearStatusBits(0x1);
878  }
879 
880  // Calculate the 3D doca's for the hits which were used to make this PCA
881  m_pcaAlg.PCAAnalysis_calc3DDocas(firstHitList, firstHitListPCA);
882 
883  // Divine from the ether some maximum allowed range for transfering hits
884  float allowedHitRange = 6. * firstHitListPCA.getAveHitDoca();
885 
886  // Now go through and calculate the 3D doca's for ALL the hits in the original cluster
887  m_pcaAlg.PCAAnalysis_calc3DDocas(hitPairListPtr, firstHitListPCA);
888 
889  // Let's make a new cluster to hold the hits
890  clusterParametersList.push_back(reco::ClusterParameters());
891 
892  // Can we get a reference to what we just created?
893  reco::ClusterParameters& newClusterParams = clusterParametersList.back();
894 
895  reco::HitPairListPtr& newClusterHitList = newClusterParams.getHitPairListPtr();
896 
897  newClusterHitList.resize(hitPairListPtr.size());
898 
899  // Do the actual copy of the hits we want
900  reco::HitPairListPtr::iterator newListEnd = std::copy_if(hitPairListPtr.begin(),
901  hitPairListPtr.end(),
902  newClusterHitList.begin(),
903  CopyIfInRange(allowedHitRange));
904 
905  // Shrink to fit
906  newClusterHitList.resize(std::distance(newClusterHitList.begin(), newListEnd));
907 
908  // And now remove these hits from the original cluster
909  hitPairListPtr.remove_if(CopyIfInRange(allowedHitRange));
910 
911  // Get an empty hit to cluster map...
912  reco::Hit2DToClusterMap hit2DToClusterMap;
913 
914  // Now "fill" the cluster parameters but turn off the hit rejection
915  m_clusterBuilder->FillClusterParams(newClusterParams, hit2DToClusterMap, 0., 1.);
916 
917  // Set the skeleton pca to the value calculated above on input
918  clusterParameters.getSkeletonPCA() = firstHitListPCA;
919 
920  // We are done with splitting out one track. Because the two tracks cross in
921  // close proximity, this is the one case where we might consider sharing 3D hits
922  // So let's make a little detour here to try to copy some of those hits back into
923  // the main hit list
924  reco::HitPairListPtr& secondHitList = *hitPairListIter;
925  reco::PrincipalComponents secondHitListPCA;
926 
927  m_pcaAlg.PCAAnalysis_3D(secondHitList, secondHitListPCA);
928 
929  // Make sure we have a successful calculation.
930  if (secondHitListPCA.getSvdOK()) {
931  // Calculate the 3D doca's for the hits which were used to make this PCA
932  m_pcaAlg.PCAAnalysis_calc3DDocas(secondHitList, secondHitListPCA);
933 
934  // Since this is the "other" cluster, we'll be a bit more generous in adding back hits
935  float newAllowedHitRange = 6. * secondHitListPCA.getAveHitDoca();
936 
937  // Go through and calculate the 3D doca's for the hits in our new candidate cluster
938  m_pcaAlg.PCAAnalysis_calc3DDocas(newClusterHitList, secondHitListPCA);
939 
940  // Create a temporary list to fill with the hits we might want to save
941  reco::HitPairListPtr tempHitList(newClusterHitList.size());
942 
943  // Do the actual copy of the hits we want...
944  reco::HitPairListPtr::iterator tempListEnd =
945  std::copy_if(newClusterHitList.begin(),
946  newClusterHitList.end(),
947  tempHitList.begin(),
948  CopyIfInRange(newAllowedHitRange));
949 
950  hitPairListPtr.insert(hitPairListPtr.end(), tempHitList.begin(), tempListEnd);
951  }
952 
953  // Of course, now we need to modify the original cluster parameters
954  reco::ClusterParameters originalParams(hitPairListPtr);
955 
956  // Now "fill" the cluster parameters but turn off the hit rejection
957  m_clusterBuilder->FillClusterParams(originalParams, hit2DToClusterMap, 0., 1.);
958 
959  // Overwrite original cluster parameters with our new values
960  clusterParameters.getClusterParams() = originalParams.getClusterParams();
961  clusterParameters.getFullPCA() = originalParams.getFullPCA();
962  clusterParameters.getSkeletonPCA() = secondHitListPCA;
963  }
964  }
965 
967  ArtOutputHandler& output,
968  reco::HitPairList& hitPairVector,
969  reco::ClusterParametersList& clusterParametersList,
970  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap) const
971  {
976  mf::LogDebug("Cluster3D") << " *** Cluster3D::ProduceArtClusters() *** " << std::endl;
977 
978  // Make sure there is something to do here!
979  if (!clusterParametersList.empty()) {
980  // This is the loop over candidate 3D clusters
981  // Note that it might be that the list of candidate clusters is modified by splitting
982  // So we use the following construct to make sure we get all of them
983  for (auto& clusterParameters : clusterParametersList) {
984  // It should be straightforward at this point to transfer information from our vector of clusters
985  // to the larsoft objects... of course we still have some work to do first, in particular to
986  // find the candidate seeds and their seed hits
987 
988  // The chances of getting here and this condition not being true are probably zero... but check anyway
989  if (!clusterParameters.getFullPCA().getSvdOK()) {
990  mf::LogDebug("Cluster3D")
991  << "--> no feature extraction done on this cluster!!" << std::endl;
992  continue;
993  }
994 
995  // Keep track of hit 3D to SP for when we do edges
996  Hit3DToSPPtrMap hit3DToSPPtrMap;
997  Hit3DToSPPtrMap best3DToSPPtrMap;
998 
999  // Do a special output of voronoi vertices here...
1000  dcel2d::VertexList& vertexList = clusterParameters.getVertexList();
1001  dcel2d::HalfEdgeList& halfEdgeList = clusterParameters.getHalfEdgeList();
1002 
1003  MakeAndSaveVertexPoints(output, vertexList, halfEdgeList);
1004 
1005  // Special case handling... if no daughters then call standard conversion routine to make sure space points
1006  // created, etc.
1007  if (clusterParameters.daughterList().empty()) {
1008  ConvertToArtOutput(gser,
1009  output,
1010  clusterParameters,
1012  hitToPtrMap,
1013  hit3DToSPPtrMap,
1014  best3DToSPPtrMap);
1015 
1016  // Get the extreme points
1017  MakeAndSaveKinkPoints(output,
1018  clusterParameters.getConvexHull().getConvexHullKinkPoints());
1019  }
1020  // Otherwise, the cluster has daughters so we handle specially
1021  else {
1022  // Set up to keep track of parent/daughters
1023  IdxToPCAMap idxToPCAMap;
1024  size_t numTotalDaughters = countUltimateDaughters(clusterParameters);
1025  size_t pfParticleIdx(output.artPFParticleVector->size() + numTotalDaughters);
1026 
1027  FindAndStoreDaughters(gser,
1028  output,
1029  clusterParameters,
1030  pfParticleIdx,
1031  idxToPCAMap,
1032  hitToPtrMap,
1033  hit3DToSPPtrMap,
1034  best3DToSPPtrMap);
1035 
1036  // Need to make a daughter vec from our map
1037  std::vector<size_t> daughterVec;
1038 
1039  for (auto& idxToPCA : idxToPCAMap)
1040  daughterVec.emplace_back(idxToPCA.first);
1041 
1042  // Now create/handle the parent PFParticle
1043  recob::PFParticle pfParticle(
1044  13, pfParticleIdx, recob::PFParticle::kPFParticlePrimary, daughterVec);
1045  output.artPFParticleVector->push_back(pfParticle);
1046 
1047  recob::PCAxis::EigenVectors eigenVecs;
1048  double eigenVals[] = {0., 0., 0.};
1049  double avePosition[] = {0., 0., 0.};
1050 
1051  eigenVecs.resize(3);
1052 
1053  reco::PrincipalComponents& skeletonPCA = clusterParameters.getSkeletonPCA();
1054 
1055  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1056  avePosition[outerIdx] = skeletonPCA.getAvePosition()[outerIdx];
1057  eigenVals[outerIdx] = skeletonPCA.getEigenValues()[outerIdx];
1058 
1059  eigenVecs[outerIdx].resize(3);
1060 
1061  // Be careful here... eigen stores in column major order buy default
1062  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1063  eigenVecs[outerIdx][innerIdx] = skeletonPCA.getEigenVectors().row(outerIdx)[innerIdx];
1064  }
1065 
1066  recob::PCAxis skelPcAxis(skeletonPCA.getSvdOK(),
1067  skeletonPCA.getNumHitsUsed(),
1068  eigenVals,
1069  eigenVecs,
1070  avePosition,
1071  skeletonPCA.getAveHitDoca(),
1072  output.artPCAxisVector->size());
1073 
1074  output.artPCAxisVector->push_back(skelPcAxis);
1075 
1076  reco::PrincipalComponents& fullPCA = clusterParameters.getFullPCA();
1077 
1078  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1079  avePosition[outerIdx] = fullPCA.getAvePosition()[outerIdx];
1080  eigenVals[outerIdx] = fullPCA.getEigenValues()[outerIdx];
1081 
1082  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1083  eigenVecs[outerIdx][innerIdx] = fullPCA.getEigenVectors().row(outerIdx)(innerIdx);
1084  }
1085 
1086  recob::PCAxis fullPcAxis(fullPCA.getSvdOK(),
1087  fullPCA.getNumHitsUsed(),
1088  eigenVals,
1089  eigenVecs,
1090  avePosition,
1091  fullPCA.getAveHitDoca(),
1092  output.artPCAxisVector->size());
1093 
1094  output.artPCAxisVector->push_back(fullPcAxis);
1095 
1096  // Create associations to the PFParticle
1097  output.makePFPartPCAAssns();
1098 
1099  // Make associations to all space points for this cluster
1100  MakeAndSaveSpacePoints(output,
1101  *output.artSpacePointVector.get(),
1102  *output.artSPHitAssociations.get(),
1103  clusterParameters.getHitPairListPtr(),
1104  hitToPtrMap,
1105  hit3DToSPPtrMap);
1106 
1107  // Get the extreme points
1108  MakeAndSaveKinkPoints(output,
1109  clusterParameters.getConvexHull().getConvexHullKinkPoints());
1110 
1111  // Build the edges now
1112  size_t edgeStart(output.artEdgeVector->size());
1113 
1114  for (const auto& edge : clusterParameters.getConvexHull().getConvexHullEdgeList()) {
1115  RecobSpacePointVector spacePointVec;
1116 
1117  try {
1118  spacePointVec.push_back(hit3DToSPPtrMap.at(std::get<0>(edge)));
1119  spacePointVec.push_back(hit3DToSPPtrMap.at(std::get<1>(edge)));
1120  }
1121  catch (...) {
1122  std::cout << "Caught exception in looking up space point ptr... " << std::get<0>(edge)
1123  << ", " << std::get<1>(edge) << std::endl;
1124  continue;
1125  }
1126 
1127  output.artEdgeVector->emplace_back(std::get<2>(edge),
1128  spacePointVec[0].key(),
1129  spacePointVec[1].key(),
1130  output.artEdgeVector->size());
1131 
1132  output.makeEdgeSpacePointAssns(
1133  *output.artEdgeVector.get(), spacePointVec, *output.artEdgeSPAssociations.get());
1134  }
1135 
1136  output.makePFPartEdgeAssns(
1137  *output.artEdgeVector.get(), *output.artPFPartEdgeAssociations.get(), edgeStart);
1138  }
1139  }
1140  }
1141 
1142  // Right now error matrix is uniform...
1143  int nFreePoints(0);
1144 
1145  // Run through the HitPairVector and add any unused hit pairs to the list
1146  for (auto& hitPair : hitPairVector) {
1147  if (hitPair.bitsAreSet(reco::ClusterHit3D::MADESPACEPOINT)) continue;
1148 
1149  double spacePointPos[] = {
1150  hitPair.getPosition()[0], hitPair.getPosition()[1], hitPair.getPosition()[2]};
1151  double spacePointErr[] = {1., 0., 0., 1., 0., 1.};
1152  double chisq = hitPair.getHitChiSquare();
1153 
1154  RecobHitVector recobHits;
1155 
1156  for (const auto hit : hitPair.getHits()) {
1157  if (!hit) {
1158  chisq = -1000.;
1159  continue;
1160  }
1161 
1162  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit->getHit()];
1163  recobHits.push_back(hitPtr);
1164  }
1165 
1166  nFreePoints++;
1167 
1168  spacePointErr[1] = hitPair.getTotalCharge();
1169  spacePointErr[3] = hitPair.getChargeAsymmetry();
1170 
1171  output.artSpacePointVector->push_back(
1172  recob::SpacePoint(spacePointPos, spacePointErr, chisq, output.artSpacePointVector->size()));
1173 
1174  if (!recobHits.empty())
1175  output.makeSpacePointHitAssns(
1176  *output.artSpacePointVector.get(), recobHits, *output.artSPHitAssociations.get());
1177  }
1178 
1179  std::cout << "++++>>>> total num hits: " << hitPairVector.size()
1180  << ", num free: " << nFreePoints << std::endl;
1181  }
1182 
1184  {
1185  size_t localCount(0);
1186 
1187  if (!clusterParameters.daughterList().empty()) {
1188  for (auto& clusterParams : clusterParameters.daughterList())
1189  localCount += countUltimateDaughters(clusterParams);
1190  }
1191  else
1192  localCount++;
1193 
1194  return localCount;
1195  }
1196 
1198  ArtOutputHandler& output,
1199  reco::ClusterParameters& clusterParameters,
1200  size_t pfParticleParent,
1201  IdxToPCAMap& idxToPCAMap,
1202  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1203  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1204  Hit3DToSPPtrMap& best3DToSPPtrMap) const
1205  {
1206  // This is a recursive routine, we keep calling ourself as long as the daughter list is non empty
1207  if (!clusterParameters.daughterList().empty()) {
1208  for (auto& clusterParams : clusterParameters.daughterList())
1209  FindAndStoreDaughters(gser,
1210  output,
1211  clusterParams,
1212  pfParticleParent,
1213  idxToPCAMap,
1214  hitToPtrMap,
1215  hit3DToSPPtrMap,
1216  best3DToSPPtrMap);
1217  }
1218  // Otherwise we want to store the information
1219  else {
1220  size_t daughterIdx = ConvertToArtOutput(gser,
1221  output,
1222  clusterParameters,
1223  pfParticleParent,
1224  hitToPtrMap,
1225  hit3DToSPPtrMap,
1226  best3DToSPPtrMap);
1227 
1228  idxToPCAMap[daughterIdx] = &clusterParameters.getFullPCA();
1229  }
1230 
1231  return idxToPCAMap.size();
1232  }
1233 
1235  ArtOutputHandler& output,
1236  reco::ClusterParameters& clusterParameters,
1237  size_t pfParticleParent,
1238  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1239  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1240  Hit3DToSPPtrMap& best3DToSPPtrMap) const
1241  {
1242  // prepare the algorithm to compute the cluster characteristics;
1243  // we use the "standard" one here, except that we override selected items
1244  // (so, thanks to metaprogramming, we finally have wrappers of wrappers);
1245  // configuration would happen here, but we are using the default
1246  // configuration for that algorithm
1247  using OverriddenClusterParamsAlg_t =
1249 
1251 
1252  // It should be straightforward at this point to transfer information from our vector of clusters
1253  // to the larsoft objects... of course we still have some work to do first, in particular to
1254  // find the candidate seeds and their seed hits
1255 
1256  // We keep track of 2 PCA axes, the first is the "full" PCA run over all the 3D hits in the
1257  // candidate cluster. The second will be that derived from just using the "skeleton" hits.
1258  // Make a copy of the full PCA to keep that, then get a reference for the skeleton PCA
1259  reco::PrincipalComponents& fullPCA = clusterParameters.getFullPCA();
1260  reco::PrincipalComponents& skeletonPCA = clusterParameters.getSkeletonPCA();
1261 
1262  size_t clusterStart = output.artClusterVector->size();
1263 
1264  // Start loop over views to build out the hit lists and the 2D cluster objects
1265  for (const auto& clusParametersPair : clusterParameters.getClusterParams()) {
1266  const reco::RecobClusterParameters& clusParams = clusParametersPair.second;
1267 
1268  // Protect against a missing view
1269  if (clusParams.m_view == geo::kUnknown) continue;
1270 
1271  // Get a vector of hit pointers to seed the cluster algorithm
1272  std::vector<const recob::Hit*> recobHitVec(clusParams.m_hitVector.size());
1273 
1274  std::transform(clusParams.m_hitVector.begin(),
1275  clusParams.m_hitVector.end(),
1276  recobHitVec.begin(),
1277  [](const auto& hit2D) { return hit2D->getHit(); });
1278 
1279  // Get the tdc/wire slope... from the unit vector...
1280  double startWire(clusParams.m_startWire);
1281  double endWire(clusParams.m_endWire);
1282  double startTime(clusParams.m_startTime);
1283  double endTime(clusParams.m_endTime);
1284 
1285  // feed the algorithm with all the cluster hits
1286  ClusterParamAlgo.ImportHits(gser, recobHitVec);
1287 
1288  // create the recob::Cluster directly in the vector
1289  cluster::ClusterCreator artCluster(gser,
1290  ClusterParamAlgo, // algo
1291  startWire, // start_wire
1292  0., // sigma_start_wire
1293  startTime, // start_tick
1294  clusParams.m_sigmaStartTime, // sigma_start_tick
1295  endWire, // end_wire
1296  0., // sigma_end_wire,
1297  endTime, // end_tick
1298  clusParams.m_sigmaEndTime, // sigma_end_tick
1299  output.artClusterVector->size(), // ID
1300  clusParams.m_view, // view
1301  clusParams.m_plane, // plane
1302  recob::Cluster::Sentry // sentry
1303  );
1304 
1305  output.artClusterVector->emplace_back(artCluster.move());
1306 
1307  // We love looping. In this case, our list of hits is comprised of "ClusterHits" and we need to get a RecobHitVector instead...
1308  RecobHitVector recobHits;
1309 
1310  for (const auto& hit2D : clusParams.m_hitVector) {
1311  if (hit2D == nullptr || hit2D->getHit() == nullptr) continue;
1312 
1313  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit2D->getHit()];
1314  recobHits.push_back(hitPtr);
1315  }
1316 
1317  output.makeClusterHitAssns(recobHits);
1318  }
1319 
1320  // Last, let's try to get seeds for tracking..
1321  // Keep track of how many we have so far
1322  size_t numSeedsStart = output.artSeedVector->size();
1323 
1324  // Empty daughter vector for now
1325  std::vector<size_t> nullVector;
1326  size_t pfParticleIdx(output.artPFParticleVector->size());
1327 
1328  recob::PFParticle pfParticle(13, pfParticleIdx, pfParticleParent, nullVector);
1329  output.artPFParticleVector->push_back(pfParticle);
1330 
1331  // Assume that if we are a daughter particle then there is a set of "best" 3D points and the convex hull will have been calculated from them
1332  // If there is no best list then assume the convex hull is from all of the points...
1333  std::string instance("");
1334  reco::HitPairListPtr* hit3DListPtr = &clusterParameters.getHitPairListPtr();
1335  Hit3DToSPPtrMap* hit3DToPtrMap = &hit3DToSPPtrMap;
1336 
1337  auto spVector = output.artSpacePointVector.get();
1338  auto edgeVector = output.artEdgeVector.get();
1339  auto pfPartEdgeAssns = output.artPFPartEdgeAssociations.get();
1340  auto spEdgeAssns = output.artEdgeSPAssociations.get();
1341  auto spHitAssns = output.artSPHitAssociations.get();
1342  auto pfPartSPAssns = output.artPFPartSPAssociations.get();
1343 
1344  // Make associations to all space points for this cluster
1345  int spacePointStart = spVector->size();
1346 
1348  output, *spVector, *spHitAssns, *hit3DListPtr, hitToPtrMap, *hit3DToPtrMap);
1349 
1350  // And make sure to have associations to the PFParticle
1351  output.makePFPartSpacePointAssns(*spVector, *pfPartSPAssns, spacePointStart);
1352 
1353  // If they exist, make space points for the Path points
1354  if (!clusterParameters.getBestHitPairListPtr().empty()) {
1355  instance = m_pathInstance;
1356  hit3DListPtr = &clusterParameters.getBestHitPairListPtr();
1357  hit3DToPtrMap = &best3DToSPPtrMap;
1358 
1359  spVector = output.artPathPointVector.get();
1360  edgeVector = output.artPathEdgeVector.get();
1361  pfPartEdgeAssns = output.artPFPartPathEdgeAssociations.get();
1362  spEdgeAssns = output.artEdgePPAssociations.get();
1363  spHitAssns = output.artPPHitAssociations.get();
1364  pfPartSPAssns = output.artPFPartPPAssociations.get();
1365 
1366  spacePointStart = spVector->size();
1367 
1369  output, *spVector, *spHitAssns, *hit3DListPtr, hitToPtrMap, *hit3DToPtrMap, instance);
1370 
1371  // And make sure to have associations to the PFParticle
1372  output.makePFPartSpacePointAssns(*spVector, *pfPartSPAssns, spacePointStart, instance);
1373  }
1374 
1375  // Now handle the edges according to whether associated with regular or "best" space points
1376  if (!clusterParameters.getBestEdgeList().empty()) {
1377  size_t edgeStart = edgeVector->size();
1378 
1379  for (const auto& edge : clusterParameters.getBestEdgeList()) {
1380  RecobSpacePointVector spacePointVec;
1381 
1382  try {
1383  spacePointVec.push_back(hit3DToPtrMap->at(std::get<0>(edge)));
1384  spacePointVec.push_back(hit3DToPtrMap->at(std::get<1>(edge)));
1385  }
1386  catch (...) {
1387  std::cout << "Caught exception in looking up space point ptr... " << std::get<0>(edge)
1388  << ", " << std::get<1>(edge) << std::endl;
1389  continue;
1390  }
1391 
1392  edgeVector->emplace_back(
1393  std::get<2>(edge), spacePointVec[0].key(), spacePointVec[1].key(), edgeVector->size());
1394 
1395  output.makeEdgeSpacePointAssns(*edgeVector, spacePointVec, *spEdgeAssns, instance);
1396  }
1397 
1398  output.makePFPartEdgeAssns(*edgeVector, *pfPartEdgeAssns, edgeStart, instance);
1399  }
1400 
1401  // Look at making the PCAxis and associations - for both the skeleton (the first) and the full
1402  // First need some float to double conversion containers
1403  recob::PCAxis::EigenVectors eigenVecs;
1404  double eigenVals[] = {0., 0., 0.};
1405  double avePosition[] = {0., 0., 0.};
1406 
1407  eigenVecs.resize(3);
1408 
1409  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1410  avePosition[outerIdx] = skeletonPCA.getAvePosition()[outerIdx];
1411  eigenVals[outerIdx] = skeletonPCA.getEigenValues()[outerIdx];
1412 
1413  eigenVecs[outerIdx].resize(3);
1414 
1415  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1416  eigenVecs[outerIdx][innerIdx] = skeletonPCA.getEigenVectors().row(outerIdx)(innerIdx);
1417  }
1418 
1419  recob::PCAxis skelPcAxis(skeletonPCA.getSvdOK(),
1420  skeletonPCA.getNumHitsUsed(),
1421  eigenVals,
1422  eigenVecs,
1423  avePosition,
1424  skeletonPCA.getAveHitDoca(),
1425  output.artPCAxisVector->size());
1426 
1427  output.artPCAxisVector->push_back(skelPcAxis);
1428 
1429  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1430  avePosition[outerIdx] = fullPCA.getAvePosition()[outerIdx];
1431  eigenVals[outerIdx] = fullPCA.getEigenValues()[outerIdx];
1432 
1433  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1434  eigenVecs[outerIdx][innerIdx] = fullPCA.getEigenVectors().row(outerIdx)(innerIdx);
1435  }
1436 
1437  recob::PCAxis fullPcAxis(fullPCA.getSvdOK(),
1438  fullPCA.getNumHitsUsed(),
1439  eigenVals, //fullPCA.getEigenValues(),
1440  eigenVecs, //fullPCA.getEigenVectors(),
1441  avePosition, //fullPCA.getAvePosition(),
1442  fullPCA.getAveHitDoca(),
1443  output.artPCAxisVector->size());
1444 
1445  output.artPCAxisVector->push_back(fullPcAxis);
1446 
1447  // Create associations to the PFParticle
1448  output.makePFPartPCAAssns();
1449  output.makePFPartSeedAssns(numSeedsStart);
1450  output.makePFPartClusterAssns(clusterStart);
1451 
1452  return pfParticleIdx;
1453  }
1454 
1456  std::vector<recob::SpacePoint>& spacePointVec,
1458  reco::HitPairListPtr& clusHitPairVector,
1459  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1460  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1461  const std::string& instance) const
1462  {
1463  // Reserve space...
1464  spacePointVec.reserve(spacePointVec.size() + clusHitPairVector.size());
1465 
1466  // Right now error matrix is uniform...
1467  double spError[] = {1., 0., 1., 0., 0., 1.};
1468 
1469  // Copy these hits to the vector to be stored with the event
1470  for (auto& hitPair : clusHitPairVector) {
1471  // Skip those space points that have already been created
1472  if (hit3DToSPPtrMap.find(hitPair) != hit3DToSPPtrMap.end()) continue;
1473 
1474  // Don't make space point if this hit was "rejected"
1475  if (hitPair->bitsAreSet(reco::ClusterHit3D::REJECTEDHIT)) continue;
1476 
1477  double chisq = hitPair->getHitChiSquare(); // secret handshake...
1478 
1479  // Mark this hit pair as in use
1480  hitPair->setStatusBit(reco::ClusterHit3D::MADESPACEPOINT);
1481 
1482  // Create and store the space point
1483  size_t spacePointID = spacePointVec.size();
1484  double spacePointPos[] = {
1485  hitPair->getPosition()[0], hitPair->getPosition()[1], hitPair->getPosition()[2]};
1486 
1487  spError[1] = hitPair->getTotalCharge();
1488  spError[3] = hitPair->getChargeAsymmetry();
1489 
1490  spacePointVec.emplace_back(spacePointPos, spError, chisq, spacePointID);
1491 
1492  // Update mapping
1493  hit3DToSPPtrMap[hitPair] = output.makeSpacePointPtr(spacePointID, instance);
1494 
1495  // space point hits associations
1496  RecobHitVector recobHits;
1497 
1498  for (const auto& hit : hitPair->getHits()) {
1499  if (!hit) continue;
1500 
1501  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit->getHit()];
1502  recobHits.push_back(hitPtr);
1503  }
1504 
1505  if (!recobHits.empty())
1506  output.makeSpacePointHitAssns(spacePointVec, recobHits, spHitAssns, instance);
1507  }
1508 
1509  return;
1510  }
1511 
1513  reco::ConvexHullKinkTupleList& kinkTupleVec) const
1514  {
1515  // Right now error matrix is uniform...
1516  double spError[] = {1., 0., 1., 0., 0., 1.};
1517 
1518  // Copy these hits to the vector to be stored with the event
1519  for (auto& kinkTuple : kinkTupleVec) {
1520  const reco::ClusterHit3D* hit = std::get<2>(std::get<0>(kinkTuple));
1521 
1522  double chisq = hit->getHitChiSquare(); // secret handshake...
1523 
1524  // Create and store the space point
1525  double spacePointPos[] = {
1526  hit->getPosition()[0], hit->getPosition()[1], hit->getPosition()[2]};
1527 
1528  spError[1] = hit->getTotalCharge();
1529  spError[3] = hit->getChargeAsymmetry();
1530 
1531  output.artExtremePointVector->push_back(
1532  recob::SpacePoint(spacePointPos, spError, chisq, output.artExtremePointVector->size()));
1533  }
1534 
1535  return;
1536  }
1537 
1539  dcel2d::VertexList& vertexList,
1540  dcel2d::HalfEdgeList& halfEdgeList) const
1541  {
1542  // We actually do two things here:
1543  // 1) Create space points to represent the vertex locations of the voronoi diagram
1544  // 2) Create the edges that link the space points together
1545 
1546  // Set up the space point creation
1547  // Right now error matrix is uniform...
1548  double spError[] = {1., 0., 1., 0., 0., 1.};
1549  double chisq = 1.;
1550 
1551  // Keep track of the vertex to space point association
1552  std::map<const dcel2d::Vertex*, size_t> vertexToSpacePointMap;
1553 
1554  // Copy these hits to the vector to be stored with the event
1555  for (auto& vertex : vertexList) {
1556  const dcel2d::Coords& coords = vertex.getCoords();
1557 
1558  // Create and store the space point
1559  double spacePointPos[] = {coords[0], coords[1], coords[2]};
1560 
1561  vertexToSpacePointMap[&vertex] = output.artVertexPointVector->size();
1562 
1563  output.artVertexPointVector->emplace_back(
1564  spacePointPos, spError, chisq, output.artVertexPointVector->size());
1565  }
1566 
1567  // Try to avoid double counting
1568  std::set<const dcel2d::HalfEdge*> halfEdgeSet;
1569 
1570  // Build the edges now
1571  for (const auto& halfEdge : halfEdgeList) {
1572  // Recover twin
1573  const dcel2d::HalfEdge* twin = halfEdge.getTwinHalfEdge();
1574 
1575  // It can happen that we have no twin... and also check that we've not been here before
1576  if (twin && halfEdgeSet.find(twin) == halfEdgeSet.end()) {
1577  // Recover the vertices
1578  const dcel2d::Vertex* fromVertex = twin->getTargetVertex();
1579  const dcel2d::Vertex* toVertex = halfEdge.getTargetVertex();
1580 
1581  // It can happen for the open edges that there is no target vertex
1582  if (!toVertex || !fromVertex) continue;
1583 
1584  if (vertexToSpacePointMap.find(fromVertex) == vertexToSpacePointMap.end() ||
1585  vertexToSpacePointMap.find(toVertex) == vertexToSpacePointMap.end())
1586  continue;
1587 
1588  // Need the distance between vertices
1589  Eigen::Vector3f distVec = toVertex->getCoords() - fromVertex->getCoords();
1590 
1591  output.artVertexEdgeVector->emplace_back(distVec.norm(),
1592  vertexToSpacePointMap[fromVertex],
1593  vertexToSpacePointMap[toVertex],
1594  output.artEdgeVector->size());
1595 
1596  halfEdgeSet.insert(&halfEdge);
1597  }
1598  }
1599 
1600  return;
1601  }
1602 
1604  const reco::PrincipalComponents& fullPCA,
1605  IdxToPCAMap& idxToPCAMap) const
1606  {
1607  // We actually do two things here:
1608  // 1) Create space points from the centroids of the PCA for each cluster
1609  // 2) Create the edges that link the space points together
1610 
1611  // The first task is to put the list of PCA's into some semblance of order... they may be
1612  // preordered by likely they are piecewise ordered so fix that here
1613 
1614  // We'll need the current PCA axis to determine doca and arclen
1615  Eigen::Vector3f avePosition(
1616  fullPCA.getAvePosition()[0], fullPCA.getAvePosition()[1], fullPCA.getAvePosition()[2]);
1617  Eigen::Vector3f axisDirVec(fullPCA.getEigenVectors().row(2));
1618 
1619  using DocaToPCAPair = std::pair<float, const reco::PrincipalComponents*>;
1620  using DocaToPCAVec = std::vector<DocaToPCAPair>;
1621 
1622  DocaToPCAVec docaToPCAVec;
1623 
1624  // Outer loop over views
1625  for (const auto& idxToPCA : idxToPCAMap) {
1626  const reco::PrincipalComponents* pca = idxToPCA.second;
1627 
1628  // Now we need to calculate the doca and poca...
1629  // Start by getting this hits position
1630  Eigen::Vector3f pcaPos(
1631  pca->getAvePosition()[0], pca->getAvePosition()[1], pca->getAvePosition()[2]);
1632 
1633  // Form a TVector from this to the cluster average position
1634  Eigen::Vector3f pcaToAveVec = pcaPos - avePosition;
1635 
1636  // With this we can get the arclength to the doca point
1637  float arclenToPoca = pcaToAveVec.dot(axisDirVec);
1638 
1639  docaToPCAVec.emplace_back(arclenToPoca, pca);
1640  }
1641 
1642  std::sort(docaToPCAVec.begin(), docaToPCAVec.end(), [](const auto& left, const auto& right) {
1643  return left.first < right.first;
1644  });
1645 
1646  // Set up the space point creation
1647  // Right now error matrix is uniform...
1648  double spError[] = {1., 0., 1., 0., 0., 1.};
1649  double chisq = 1.;
1650 
1651  const reco::PrincipalComponents* lastPCA(nullptr);
1652 
1653  // Set up to loop through the clusters
1654  for (const auto& docaToPCAPair : docaToPCAVec) {
1655  // Recover the PCA for this cluster
1656  const reco::PrincipalComponents* curPCA = docaToPCAPair.second;
1657 
1658  if (lastPCA) {
1659  double lastPointPos[] = {
1660  lastPCA->getAvePosition()[0], lastPCA->getAvePosition()[1], lastPCA->getAvePosition()[2]};
1661  size_t lastPointBin = output.artVertexPointVector->size();
1662  double curPointPos[] = {
1663  curPCA->getAvePosition()[0], curPCA->getAvePosition()[1], curPCA->getAvePosition()[2]};
1664  size_t curPointBin = lastPointBin + 1;
1665 
1666  output.artVertexPointVector->emplace_back(lastPointPos, spError, chisq, lastPointBin);
1667  output.artVertexPointVector->emplace_back(curPointPos, spError, chisq, curPointBin);
1668 
1669  Eigen::Vector3f distVec(curPointPos[0] - lastPointPos[0],
1670  curPointPos[1] - lastPointPos[1],
1671  curPointPos[2] - lastPointPos[2]);
1672 
1673  output.artVertexEdgeVector->emplace_back(
1674  distVec.norm(), lastPointBin, curPointBin, output.artEdgeVector->size());
1675  }
1676 
1677  lastPCA = curPCA;
1678  }
1679  }
1680 
1681 } // namespace lar_cluster3d
reco::HitPairListPtr & getBestHitPairListPtr()
Definition: Cluster3D.h:467
intermediate_table::iterator iterator
std::unique_ptr< std::vector< recob::Edge > > artPathEdgeVector
float m_buildNeighborhoodTime
Keeps track of time to build epsilon neighborhood.
std::unique_ptr< art::Assns< recob::SpacePoint, recob::PFParticle > > artPFPartSPAssociations
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
std::list< reco::ClusterHit3D > HitPairList
Definition: Cluster3D.h:330
std::unique_ptr< std::vector< recob::SpacePoint > > artVertexPointVector
std::unique_ptr< lar_cluster3d::IClusterModAlg > m_clusterPathAlg
Algorithm to do cluster path finding.
bool getSvdOK() const
Definition: Cluster3D.h:240
void makeEdgeSpacePointAssns(std::vector< recob::Edge > &edgeVector, RecobSpacePointVector &spacePointVector, art::Assns< recob::SpacePoint, recob::Edge > &edgeSPAssociations, const std::string &path="")
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
Utilities related to art service access.
An object to define a "edge" which is used to connect space points in a triangulation algorithm...
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
Class managing the creation of a new recob::Cluster object.
std::unique_ptr< std::vector< recob::Seed > > artSeedVector
Reconstruction base classes.
T * get() const
Definition: ServiceHandle.h:69
std::string m_vertexInstance
Special instance name for vertex points.
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:57
std::list< HalfEdge > HalfEdgeList
Definition: DCEL.h:171
void makePFPartSpacePointAssns(std::vector< recob::SpacePoint > &spacePointVector, art::Assns< recob::SpacePoint, recob::PFParticle > &pfPartSPAssociations, size_t spacePointStart, const std::string &instance="")
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:155
std::unique_ptr< art::Assns< recob::Seed, recob::Hit > > artSeedHitAssociations
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
float m_parallelHitsTransWid
Cut on transverse width of cluster (PCA 2nd eigenvalue)
HalfEdge * getTwinHalfEdge() const
Definition: DCEL.h:150
Unknown view.
Definition: geo_types.h:142
Float_t x1[n_points_granero]
Definition: compare.C:5
Cluster3D class.
Definition: SkeletonAlg.h:28
float m_parallelHitsCosAng
Cut for PCA 3rd axis angle to X axis.
bool aParallelHitsCluster(const reco::PrincipalComponents &pca) const
There are several places we will want to know if a candidate cluster is a "parallel hits" type of clu...
Declaration of signal hit object.
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:465
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
void findTrackSeeds(art::Event &evt, reco::ClusterParameters &cluster, IHit3DBuilder::RecobHitToPtrMap &hitToPtrMap, std::vector< recob::Seed > &seedVec, art::Assns< recob::Seed, recob::Hit > &seedHitAssns) const
An interface to the seed finding algorithm.
bool findTrackSeeds(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitPairVec) const override
Given the list of hits this will search for candidate Seed objects and return them.
void makeClusterHitAssns(RecobHitVector &recobHits)
SkeletonAlg m_skeletonAlg
Skeleton point finder.
void makePFPartEdgeAssns(std::vector< recob::Edge > &edgeVector, art::Assns< recob::Edge, recob::PFParticle > &pfPartEdgeAssociations, size_t edgeStart, const std::string &instance="")
std::unique_ptr< std::vector< recob::Edge > > artVertexEdgeVector
const std::string instance
int m_hits3D
Keeps track of the number of 3D hits made.
STL namespace.
float getTotalCharge() const
Definition: Cluster3D.h:159
Hit has been rejected for any reason.
Definition: Cluster3D.h:96
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:468
int getNumHitsUsed() const
Definition: Cluster3D.h:241
HoughSeedFinderAlg class.
boost::graph_traits< ModuleGraph >::edge_descriptor Edge
Definition: ModuleGraph.h:24
std::list< HitPairListPtr > HitPairListPtrList
Definition: Cluster3D.h:328
A utility class used in construction of 3D clusters.
Definition: Cluster3D.h:292
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:463
void ProduceArtClusters(util::GeometryUtilities const &gser, ArtOutputHandler &output, reco::HitPairList &hitPairList, reco::ClusterParametersList &clusterParametersList, IHit3DBuilder::RecobHitToPtrMap &hitToPtrMap) const
Top level output routine, allows checking cluster status.
bool m_onlyMakSpacePoints
If true we don&#39;t do the full cluster 3D processing.
void makePFPartSeedAssns(size_t numSeedsStart)
Cluster finding and building.
reco::PlaneToClusterParamsMap & getClusterParams()
Definition: Cluster3D.h:461
HoughSeedFinderAlg m_seedFinderAlg
Seed finder.
std::unique_ptr< lar_cluster3d::IClusterAlg > m_clusterAlg
Algorithm to do 3D space point clustering.
std::unique_ptr< art::Assns< recob::PFParticle, recob::Seed > > artPFPartSeedAssociations
float m_makeHitsTime
Keeps track of time to build 3D hits.
std::unique_ptr< std::vector< recob::PFParticle > > artPFParticleVector
void makeSpacePointHitAssns(std::vector< recob::SpacePoint > &spacePointVector, RecobHitVector &recobHits, art::Assns< recob::Hit, recob::SpacePoint > &spHitAssns, const std::string &path="")
void GetSkeletonHits(const reco::HitPairListPtr &inputHitList, reco::HitPairListPtr &skeletonHitList) const
Return the skeleton hits from the input list.
art::Ptr< recob::Edge > makeEdgePtr(size_t index, const std::string &instance="")
This is an algorithm for finding recob::Seed objects in 3D clusters.
float getDocaToAxis() const
Definition: Cluster3D.h:166
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:174
float m_dbscanTime
Keeps track of time to run DBScan.
void ImportHits(util::GeometryUtilities const &gser, Iter begin, Iter end)
Calls SetHits() with the hits in the sequence.
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
ClusterParametersList & daughterList()
Definition: Cluster3D.h:438
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
std::unique_ptr< art::Assns< recob::Hit, recob::SpacePoint > > artPPHitAssociations
float getAveHitDoca() const
Definition: Cluster3D.h:245
Overrides another ClusterParamsAlgBase class with selected constants.
This is an algorithm for finding recob::Seed objects in 3D clusters.
bool findTrackSeeds(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitMap) const override
Given the list of hits this will search for candidate Seed objects and return them.
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:242
art::PtrMaker< recob::Edge > fEdgePtrMaker
std::string m_extremeInstance
Instance name for the extreme points.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:464
size_t countUltimateDaughters(reco::ClusterParameters &clusterParameters) const
Count number of end of line daughters.
float getChargeAsymmetry() const
Definition: Cluster3D.h:165
art::PtrMaker< recob::SpacePoint > fSPPtrMakerPath
This is an algorithm for finding recob::Seed objects in 3D clusters.
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
std::unique_ptr< std::vector< recob::SpacePoint > > artPathPointVector
void InitializeMonitoring()
Initialize the internal monitoring.
std::unordered_map< const reco::ClusterHit2D *, ClusterToHitPairSetMap > Hit2DToClusterMap
Definition: Cluster3D.h:499
float m_finishTime
Keeps track of time to run output module.
Helper functions to create a cluster.
Wrapper for ClusterParamsAlgBase objects to accept diverse input.
std::unique_ptr< std::vector< recob::SpacePoint > > artSpacePointVector
float m_clusterMergeTime
Keeps track of the time to merge clusters.
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:244
std::unique_ptr< art::Assns< recob::PFParticle, recob::PCAxis > > artPFPartAxisAssociations
std::unique_ptr< art::Assns< recob::Cluster, recob::Hit > > artClusterAssociations
PCASeedFinderAlg m_pcaSeedFinderAlg
Use PCA axis to find seeds.
ArtOutputHandler(art::Event &evt, std::string &pathName, std::string &vertexName, std::string &extremeName)
std::list< ConvexHullKinkTuple > ConvexHullKinkTupleList
Definition: Cluster3D.h:349
void AverageSkeletonPositions(reco::HitPairListPtr &skeletonHitList) const
Modifies the position of input skeleton hits by averaging along the "best" wire direction.
Wrapper for ClusterParamsAlgBase objects to accept arbitrary input.
bool findTrackSeeds(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitMap) const override
Given the list of hits this will search for candidate Seed objects and return them.
ParallelHitsSeedFinderAlg m_parallelHitsAlg
Deal with parallel hits clusters.
std::unique_ptr< std::vector< recob::Edge > > artEdgeVector
void MakeAndSavePCAPoints(ArtOutputHandler &, const reco::PrincipalComponents &, IdxToPCAMap &) const
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:326
std::unique_ptr< art::Assns< recob::Hit, recob::SpacePoint > > artSPHitAssociations
This provides an art tool interface definition for 3D Cluster algorithms.
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Edge > > artEdgePPAssociations
int m_hits
Keeps track of the number of hits seen.
void produce(art::Event &evt) override
Declaration of cluster object.
size_t FindAndStoreDaughters(util::GeometryUtilities const &gser, ArtOutputHandler &output, reco::ClusterParameters &clusterParameters, size_t pfParticleParent, IdxToPCAMap &idxToPCAMap, IHit3DBuilder::RecobHitToPtrMap &hitToPtrMap, Hit3DToSPPtrMap &hit3DToSPPtrMap, Hit3DToSPPtrMap &best3DToSPPtrMap) const
This will produce art output for daughters noting that it needs to be done recursively.
bool empty() const
Definition: PtrVector.h:330
size_type size() const
Definition: PtrVector.h:302
Detector simulation of raw signals on wires.
bool operator()(const std::pair< float, const reco::ClusterHit3D * > &left, const std::pair< float, const reco::ClusterHit3D * > &right)
void MakeAndSaveSpacePoints(ArtOutputHandler &output, std::vector< recob::SpacePoint > &spacePointVec, art::Assns< recob::Hit, recob::SpacePoint > &spHitAssns, reco::HitPairListPtr &clusHitPairVector, IHit3DBuilder::RecobHitToPtrMap &hitToPtrMap, Hit3DToSPPtrMap &hit3DToSPPtrMap, const std::string &path="") const
Special routine to handle creating and saving space points.
This provides an art tool interface definition for tools which construct 3D hits used in 3D clusterin...
This header file defines the interface to a principal components analysis designed to be used within ...
std::unique_ptr< art::Assns< recob::SpacePoint, recob::PFParticle > > artPFPartPPAssociations
std::unique_ptr< art::Assns< recob::PFParticle, recob::Cluster > > artPFPartClusAssociations
ProducesCollector & producesCollector() noexcept
float m_pathFindingTime
Keeps track of the path finding time.
bool findTrackHits(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, reco::HitPairListPtrList &hitPairListPtrList) const
Given the list of hits this will return the sets of hits which belong on the same line...
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
bool operator()(const reco::ClusterHit3D *hit3D) const
art::Ptr< recob::SpacePoint > makeSpacePointPtr(size_t index, const std::string &instance="")
std::unique_ptr< lar_cluster3d::IClusterParametersBuilder > m_clusterBuilder
Common cluster builder tool.
Cluster3D(fhicl::ParameterSet const &pset)
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
art::PtrMaker< recob::SpacePoint > fSPPtrMaker
std::unique_ptr< std::vector< recob::SpacePoint > > artExtremePointVector
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
Utility object to perform functions of association.
void makePFPartClusterAssns(size_t clusterStart)
Header file to define the interface to the SkeletonAlg.
Hit has been made into Space Point.
Definition: Cluster3D.h:100
std::vector< SeedHitPairListPair > SeedHitPairListPairVec
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
This provides an art tool interface definition for 3D Cluster algorithms.
void MakeAndSaveVertexPoints(ArtOutputHandler &, dcel2d::VertexList &, dcel2d::HalfEdgeList &) const
Special routine to handle creating and saving space points & edges associated to voronoi diagrams...
std::unique_ptr< std::vector< recob::Cluster > > artClusterVector
std::unique_ptr< lar_cluster3d::IClusterModAlg > m_clusterMergeAlg
Algorithm to do cluster merging.
size_t ConvertToArtOutput(util::GeometryUtilities const &gser, ArtOutputHandler &output, reco::ClusterParameters &clusterParameters, size_t pfParticleParent, IHit3DBuilder::RecobHitToPtrMap &hitToPtrMap, Hit3DToSPPtrMap &hit3DToSPPtrMap, Hit3DToSPPtrMap &best3DToSPPtrMap) const
Produces the art output from all the work done in this producer module.
std::unique_ptr< lar_cluster3d::IHit3DBuilder > m_hit3DBuilderAlg
Builds the 3D hits to operate on.
PrincipalComponentsAlg m_pcaAlg
Principal Components algorithm.
Definition: MVAAlg.h:12
EventNumber_t event() const
Definition: EventID.h:116
art::PtrMaker< recob::Edge > fEdgePtrMakerPath
ClusterHit2DVec m_hitVector
Definition: Cluster3D.h:319
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
Algorithm collection class computing cluster parameters.
float getHitChiSquare() const
Definition: Cluster3D.h:163
Definition of the Cluster3D class.
float m_artHitsTime
Keeps track of time to recover hits.
Interface to class computing cluster parameters.
std::unique_ptr< std::vector< recob::PCAxis > > artPCAxisVector
TCEvent evt
Definition: DataStructs.cxx:8
Vertex * getTargetVertex() const
Definition: DCEL.h:148
Eigen::Vector3f Coords
Definition: DCEL.h:44
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Edge > > artEdgeSPAssociations
std::unordered_map< const reco::ClusterHit3D *, art::Ptr< recob::SpacePoint >> Hit3DToSPPtrMap
RunNumber_t run() const
Definition: Event.cc:29
void MakeAndSaveKinkPoints(ArtOutputHandler &output, reco::ConvexHullKinkTupleList &clusHitPairVector) const
Special routine to handle creating and saving space points.
PCASeedFinderAlg class.
std::vector< std::vector< double > > EigenVectors
Definition: PCAxis.h:26
std::unordered_map< const recob::Hit *, art::Ptr< recob::Hit >> RecobHitToPtrMap
Defines a structure mapping art representation to internal.
Definition: IHit3DBuilder.h:60
void PrepareEvent(const art::Event &evt)
Event Preparation.
const Coords & getCoords() const
Definition: DCEL.h:62
std::list< Vertex > VertexList
Definition: DCEL.h:169
void splitClustersWithHough(reco::ClusterParameters &clusterParameters, reco::ClusterParametersList &clusterParametersList) const
Attempt to split clusters using the output of the Hough Filter.
EventID id() const
Definition: Event.cc:23
std::string m_pathInstance
Special instance for path points.
art framework interface to geometry description
float m_totalTime
Keeps track of total execution time.
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:393
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:243
std::unique_ptr< art::Assns< recob::Edge, recob::PFParticle > > artPFPartEdgeAssociations
std::unique_ptr< art::Assns< recob::Edge, recob::PFParticle > > artPFPartPathEdgeAssociations
std::map< size_t, const reco::PrincipalComponents * > IdxToPCAMap
Special routine to handle creating and saving space points & edges PCA points.
vertex reconstruction
bool m_enableMonitoring
Turn on monitoring of this algorithm.