All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Cluster3DICARUS_module.cc
Go to the documentation of this file.
1 /**
2  * @file Cluster3DICARUS_module.cc
3  *
4  * Class: Cluster3DICARUS
5  * Module Type: Producer
6  *
7  * @brief Producer module to create 3D clusters from input recob::Hit objects
8  *
9  * This producer module will drive the 3D association of recob::Hit objects
10  * to form 3D clusters. This information will be output as:
11  * 1) a PFParticle to anchor all the other objects (as associations)
12  * 2) three recob::Cluster objects representing 2D hit clusterswith associations
13  * to the 2D hits comprising each of them
14  * 3) One or more recob::PCAxis objects representing the Principal Components
15  * Analysis output of the space points associated to the 3D objects
16  * 4) recob::SpacePoints representing the accepted 3D points for each PFParticle
17  * 5) recob::Seed objects and associated seed hits representing candidate straight
18  * line segments in the space point collection.
19  *
20  * The module has two main sections
21  * 1) Find the 3D clusters of 3D hits
22  * 2) Get the output objects for each of the 3D clusters
23  * See the code below for more detail on these steps
24  *
25  * Note that the general 3D cluster suite of algorithms make extensive use of a set of data objects
26  * which contain volatile data members. At the end of the routine these are used to make the output
27  * LArSoft data products described above. See LarData/RecoObjects/Cluster3D.h
28  *
29  * Configuration parameters:
30  * HitFinderModuleLabel: the producer module responsible for making the recob:Hits to use
31  * EnableMonitoring: if true then basic monitoring of the module performed
32  * ClusterAlg: Parameter block required by the 3D clustering algorithm
33  * PrincipalComponentsAlg: Parameter block required by the Principal Components Analysis Algorithm
34  * SkeletonAlg: Parameter block required by the 3D skeletonization algorithm
35  * SeedFinderAlg: Parameter block required by the Hough Seed Finder algorithm
36  * PCASeedFinderAlg: Parameter block required by the PCA Seed Finder algorithm
37  * ParrallelHitsAlg: Parameter block required by the parallel hits algorithm
38  *
39  * The current producer module does not try to analyze or break apart PFParticles
40  * so, for example, all tracks emanating from a common vertex will be associated
41  * to a single PFParticle
42  *
43  * @author usher@slac.stanford.edu
44  */
45 
46 // Framework Includes
47 #include "art/Framework/Core/EDProducer.h"
48 #include "art/Framework/Principal/Event.h"
49 #include "art/Framework/Core/ModuleMacros.h"
50 #include "art/Persistency/Common/PtrMaker.h"
51 #include "art/Utilities/make_tool.h"
52 #include "art_root_io/TFileService.h"
53 #include "cetlib/cpu_timer.h"
54 
55 // LArSoft includes
69 
84 
85 // ROOT includes
86 #include "TTree.h"
87 #include "TVector3.h"
88 
89 // std includes
90 #include <iostream>
91 #include <memory>
92 #include <string>
93 
94 //------------------------------------------------------------------------------------------------------------------------------------------
95 
96 namespace lar_cluster3d {
97  using Hit3DToSPPtrMap =
98  std::unordered_map<const reco::ClusterHit3D*, art::Ptr<recob::SpacePoint>>;
99  using RecobHitVector = art::PtrVector<recob::Hit>;
100  using RecobSpacePointVector = art::PtrVector<recob::SpacePoint>;
101 
102  //------------------------------------------------------------------------------------------------------------------------------------------
103  // Definition of the producer module here
104 
105  /**
106  * @brief Definition of the Cluster3D class
107  */
108  class Cluster3DICARUS : public art::EDProducer {
109  public:
110  explicit Cluster3DICARUS(fhicl::ParameterSet const& pset);
111 
112  private:
113  void beginJob() override;
114  void produce(art::Event& evt) override;
115 
117  public:
118  ArtOutputHandler(art::Event& evt,
119  std::string& pathName,
120  std::string& vertexName,
121  std::string& extremeName)
122  : artPCAxisVector(new std::vector<recob::PCAxis>)
123  , artPFParticleVector(new std::vector<recob::PFParticle>)
124  , artClusterVector(new std::vector<recob::Cluster>)
125  , artSpacePointVector(new std::vector<recob::SpacePoint>)
126  , artPathPointVector(new std::vector<recob::SpacePoint>)
127  , artVertexPointVector(new std::vector<recob::SpacePoint>)
128  , artExtremePointVector(new std::vector<recob::SpacePoint>)
129  , artSeedVector(new std::vector<recob::Seed>)
130  , artEdgeVector(new std::vector<recob::Edge>)
131  , artPathEdgeVector(new std::vector<recob::Edge>)
132  , artVertexEdgeVector(new std::vector<recob::Edge>)
133  , artClusterAssociations(new art::Assns<recob::Cluster, recob::Hit>)
134  , artPFPartAxisAssociations(new art::Assns<recob::PFParticle, recob::PCAxis>)
135  , artPFPartClusAssociations(new art::Assns<recob::PFParticle, recob::Cluster>)
136  , artPFPartSPAssociations(new art::Assns<recob::SpacePoint, recob::PFParticle>)
137  , artPFPartPPAssociations(new art::Assns<recob::SpacePoint, recob::PFParticle>)
138  , artPFPartSeedAssociations(new art::Assns<recob::PFParticle, recob::Seed>)
139  , artPFPartEdgeAssociations(new art::Assns<recob::Edge, recob::PFParticle>)
140  , artPFPartPathEdgeAssociations(new art::Assns<recob::Edge, recob::PFParticle>)
141  , artSeedHitAssociations(new art::Assns<recob::Seed, recob::Hit>)
142  , artSPHitAssociations(new art::Assns<recob::Hit, recob::SpacePoint>)
143  , artPPHitAssociations(new art::Assns<recob::Hit, recob::SpacePoint>)
144  , artEdgeSPAssociations(new art::Assns<recob::SpacePoint, recob::Edge>)
145  , artEdgePPAssociations(new art::Assns<recob::SpacePoint, recob::Edge>)
146  , fEvt(evt)
147  , fSPPtrMaker(evt)
148  , fSPPtrMakerPath(evt, pathName)
149  , fEdgePtrMaker(evt)
150  , fEdgePtrMakerPath(evt, pathName)
151  , fPathName(pathName)
152  , fVertexName(vertexName)
153  , fExtremeName(extremeName)
154  {}
155 
156  void
158  {
160  }
161 
162  void
163  makeSpacePointHitAssns(std::vector<recob::SpacePoint>& spacePointVector,
164  RecobHitVector& recobHits,
165  art::Assns<recob::Hit, recob::SpacePoint>& spHitAssns,
166  const std::string& path = "")
167  {
168  for (auto& hit : recobHits)
169  util::CreateAssn(fEvt, spacePointVector, hit, spHitAssns, path);
170  }
171 
172  void
174  {
179  artPCAxisVector->size() - 2,
180  artPCAxisVector->size());
181  }
182 
183  void
184  makePFPartSeedAssns(size_t numSeedsStart)
185  {
188  *artSeedVector,
190  numSeedsStart,
191  artSeedVector->size());
192  }
193 
194  void
195  makePFPartClusterAssns(size_t clusterStart)
196  {
201  clusterStart,
202  artClusterVector->size());
203  }
204 
205  void
207  std::vector<recob::SpacePoint>& spacePointVector,
208  art::Assns<recob::SpacePoint, recob::PFParticle>& pfPartSPAssociations,
209  size_t spacePointStart,
210  const std::string& instance = "")
211  {
212  for (size_t idx = spacePointStart; idx < spacePointVector.size(); idx++) {
213  art::Ptr<recob::SpacePoint> spacePoint = makeSpacePointPtr(idx, instance);
214  util::CreateAssn(fEvt, *artPFParticleVector, spacePoint, pfPartSPAssociations);
215  }
216  }
217 
218  void
219  makePFPartEdgeAssns(std::vector<recob::Edge>& edgeVector,
220  art::Assns<recob::Edge, recob::PFParticle>& pfPartEdgeAssociations,
221  size_t edgeStart,
222  const std::string& instance = "")
223  {
224  for (size_t idx = edgeStart; idx < edgeVector.size(); idx++) {
225  art::Ptr<recob::Edge> edge = makeEdgePtr(idx, instance);
226 
227  util::CreateAssn(fEvt, *artPFParticleVector, edge, pfPartEdgeAssociations);
228  }
229  }
230 
231  void
232  makeEdgeSpacePointAssns(std::vector<recob::Edge>& edgeVector,
233  RecobSpacePointVector& spacePointVector,
234  art::Assns<recob::SpacePoint, recob::Edge>& edgeSPAssociations,
235  const std::string& path = "")
236  {
237  for (auto& spacePoint : spacePointVector)
238  util::CreateAssn(fEvt, edgeVector, spacePoint, edgeSPAssociations, path);
239  }
240 
241  void
243  {
244  fEvt.put(std::move(artPCAxisVector));
245  fEvt.put(std::move(artPFParticleVector));
246  fEvt.put(std::move(artClusterVector));
247  fEvt.put(std::move(artSpacePointVector));
248  fEvt.put(std::move(artSeedVector));
249  fEvt.put(std::move(artEdgeVector));
250  fEvt.put(std::move(artPFPartAxisAssociations));
251  fEvt.put(std::move(artPFPartClusAssociations));
252  fEvt.put(std::move(artClusterAssociations));
253  fEvt.put(std::move(artPFPartSPAssociations));
254  fEvt.put(std::move(artPFPartSeedAssociations));
255  fEvt.put(std::move(artPFPartEdgeAssociations));
256  fEvt.put(std::move(artSeedHitAssociations));
257  fEvt.put(std::move(artSPHitAssociations));
258  fEvt.put(std::move(artEdgeSPAssociations));
259  fEvt.put(std::move(artPathEdgeVector), fPathName);
260  fEvt.put(std::move(artPathPointVector), fPathName);
261  fEvt.put(std::move(artEdgePPAssociations), fPathName);
262  fEvt.put(std::move(artPFPartPPAssociations), fPathName);
264  fEvt.put(std::move(artPPHitAssociations), fPathName);
265  fEvt.put(std::move(artVertexEdgeVector), fVertexName);
266  fEvt.put(std::move(artVertexPointVector), fVertexName);
267  fEvt.put(std::move(artExtremePointVector), fExtremeName);
268  }
269 
270  art::Ptr<recob::SpacePoint>
271  makeSpacePointPtr(size_t index, const std::string& instance = "")
272  {
273  if (empty(instance)) { return fSPPtrMaker(index); }
274  return fSPPtrMakerPath(index);
275  };
276 
277  art::Ptr<recob::Edge>
278  makeEdgePtr(size_t index, const std::string& instance = "")
279  {
280  if (empty(instance)) { return fEdgePtrMaker(index); }
281  return fEdgePtrMakerPath(index);
282  };
283 
284  std::unique_ptr<std::vector<recob::PCAxis>> artPCAxisVector;
285  std::unique_ptr<std::vector<recob::PFParticle>> artPFParticleVector;
286  std::unique_ptr<std::vector<recob::Cluster>> artClusterVector;
287  std::unique_ptr<std::vector<recob::SpacePoint>> artSpacePointVector;
288  std::unique_ptr<std::vector<recob::SpacePoint>> artPathPointVector;
289  std::unique_ptr<std::vector<recob::SpacePoint>> artVertexPointVector;
290  std::unique_ptr<std::vector<recob::SpacePoint>> artExtremePointVector;
291  std::unique_ptr<std::vector<recob::Seed>> artSeedVector;
292  std::unique_ptr<std::vector<recob::Edge>> artEdgeVector;
293  std::unique_ptr<std::vector<recob::Edge>> artPathEdgeVector;
294  std::unique_ptr<std::vector<recob::Edge>> artVertexEdgeVector;
295 
296  std::unique_ptr<art::Assns<recob::Cluster, recob::Hit>> artClusterAssociations;
297  std::unique_ptr<art::Assns<recob::PFParticle, recob::PCAxis>> artPFPartAxisAssociations;
298  std::unique_ptr<art::Assns<recob::PFParticle, recob::Cluster>> artPFPartClusAssociations;
299  std::unique_ptr<art::Assns<recob::SpacePoint, recob::PFParticle>> artPFPartSPAssociations;
300  std::unique_ptr<art::Assns<recob::SpacePoint, recob::PFParticle>> artPFPartPPAssociations;
301  std::unique_ptr<art::Assns<recob::PFParticle, recob::Seed>> artPFPartSeedAssociations;
302  std::unique_ptr<art::Assns<recob::Edge, recob::PFParticle>> artPFPartEdgeAssociations;
303  std::unique_ptr<art::Assns<recob::Edge, recob::PFParticle>> artPFPartPathEdgeAssociations;
304  std::unique_ptr<art::Assns<recob::Seed, recob::Hit>> artSeedHitAssociations;
305  std::unique_ptr<art::Assns<recob::Hit, recob::SpacePoint>> artSPHitAssociations;
306  std::unique_ptr<art::Assns<recob::Hit, recob::SpacePoint>> artPPHitAssociations;
307  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Edge>> artEdgeSPAssociations;
308  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Edge>> artEdgePPAssociations;
309 
310  private:
311  art::Event& fEvt;
312  art::PtrMaker<recob::SpacePoint> fSPPtrMaker;
313  art::PtrMaker<recob::SpacePoint> fSPPtrMakerPath;
314  art::PtrMaker<recob::Edge> fEdgePtrMaker;
315  art::PtrMaker<recob::Edge> fEdgePtrMakerPath;
316  std::string& fPathName;
317  std::string& fVertexName;
318  std::string& fExtremeName;
319  };
320 
321  /**
322  * @brief Event Preparation
323  *
324  * @param evt the ART event
325  */
326  void PrepareEvent(const art::Event& evt);
327 
328  /**
329  * @brief Initialize the internal monitoring
330  */
331  void InitializeMonitoring();
332 
333  /**
334  * @brief An interface to the seed finding algorithm
335  *
336  * @param evt the ART event
337  * @param cluster structure of information representing a single cluster
338  * @param hitToPtrMap This maps our Cluster2D hits back to art Ptr's to reco Hits
339  * @param seedVec the output vector of candidate seeds
340  * @param seedHitAssns the associations between the seeds and the 2D hits making them
341  */
342  void findTrackSeeds(art::Event& evt,
344  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
345  std::vector<recob::Seed>& seedVec,
346  art::Assns<recob::Seed, recob::Hit>& seedHitAssns) const;
347 
348  /**
349  * @brief Attempt to split clusters by using a minimum spanning tree
350  *
351  * @param clusterParameters The given cluster parameters object to try to split
352  * @param clusterParametersList The list of clusters
353  */
354  void splitClustersWithMST(reco::ClusterParameters& clusterParameters,
355  reco::ClusterParametersList& clusterParametersList) const;
356 
357  /**
358  * @brief Attempt to split clusters using the output of the Hough Filter
359  *
360  * @param clusterParameters The given cluster parameters object to try to split
361  * @param clusterParametersList The list of clusters
362  */
363  void splitClustersWithHough(reco::ClusterParameters& clusterParameters,
364  reco::ClusterParametersList& clusterParametersList) const;
365 
366  /**
367  * @brief Special routine to handle creating and saving space points
368  *
369  * @param output the object containting the art output
370  * @param clusterParameters Cluster info to output (in internal format)
371  * @param pfParticleParent The parent ID reference for the output PFParticle
372  * @param hitToPtrMap This maps our Cluster2D hits back to art Ptr's to reco Hits
373  */
375  std::vector<recob::SpacePoint>& spacePointVec,
376  art::Assns<recob::Hit, recob::SpacePoint>& spHitAssns,
377  reco::HitPairListPtr& clusHitPairVector,
378  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
379  Hit3DToSPPtrMap& hit3DToSPPtrMap,
380  const std::string& path = "") const;
381 
382  /**
383  * @brief Special routine to handle creating and saving space points
384  *
385  * @param output the object containting the art output
386  * @param clusHitPairVector List of 3D hits to output as "extreme" space points
387  */
389  reco::ConvexHullKinkTupleList& clusHitPairVector) const;
390 
391  /**
392  * @brief Special routine to handle creating and saving space points & edges associated to voronoi diagrams
393  *
394  * @param output the object containting the art output
395  * @param vertexList list of vertices in the diagram
396  * @param HalfEdgeList list of half edges in the diagram
397  */
400  dcel2d::HalfEdgeList&) const;
401 
402  /**
403  * @brief Special routine to handle creating and saving space points & edges PCA points
404  *
405  * @param output the object containting the art output
406  * @param clusterParamsList List of clusters to get PCA's from
407  */
408  using IdxToPCAMap = std::map<size_t, const reco::PrincipalComponents*>;
409 
412  IdxToPCAMap&) const;
413 
414  /**
415  * @brief This will produce art output for daughters noting that it needs to be done recursively
416  *
417  * @param output the object containting the art output
418  * @param clusterParameters Cluster info to output (in internal format)
419  * @param pfParticleParent The parent ID reference for the output PFParticle
420  * @param daughterList List of PFParticle indices for stored daughters
421  * @param hitToPtrMap This maps our Cluster2D hits back to art Ptr's to reco Hits
422  */
425  reco::ClusterParameters& clusterParameters,
426  size_t pfParticleParent,
427  IdxToPCAMap& idxToPCAMap,
428  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
429  Hit3DToSPPtrMap& hit3DToSPPtrMap,
430  Hit3DToSPPtrMap& best3DToSPPtrMap) const;
431 
432  /**
433  * @brief Top level output routine, allows checking cluster status
434  *
435  * @param hitPairList List of all 3D Hits in internal Cluster3D format
436  * @param clusterParametersList Data structure containing the cluster information to output
437  * @param hitToPtrMap This maps our Cluster2D hits back to art Ptr's to reco Hits
438  */
441  reco::HitPairList& hitPairList,
442  reco::ClusterParametersList& clusterParametersList,
443  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap) const;
444 
445  /**
446  * @brief Produces the art output from all the work done in this producer module
447  *
448  * @param output the object containting the art output
449  * @param clusterParameters Cluster info to output (in internal format)
450  * @param pfParticleParent The parent ID reference for the output PFParticle
451  * @param hitToPtrMap This maps our Cluster2D hits back to art Ptr's to reco Hits
452  */
453  size_t ConvertToArtOutput(util::GeometryUtilities const& gser,
455  reco::ClusterParameters& clusterParameters,
456  size_t pfParticleParent,
457  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
458  Hit3DToSPPtrMap& hit3DToSPPtrMap,
459  Hit3DToSPPtrMap& best3DToSPPtrMap) const;
460 
461  /**
462  * @brief There are several places we will want to know if a candidate cluster is a
463  * "parallel hits" type of cluster so encapsulate that here.
464  *
465  * @param pca The Principal Components Analysis parameters for the cluster
466  */
467  bool
469  {
470  return fabs(pca.getEigenVectors().row(2)(0)) > m_parallelHitsCosAng &&
471  3. * sqrt(pca.getEigenValues()(1)) > m_parallelHitsTransWid;
472  }
473 
474  /**
475  * @brief Count number of end of line daughters
476  *
477  * @param clusterParams input cluster parameters to look at
478  */
479  size_t countUltimateDaughters(reco::ClusterParameters& clusterParameters) const;
480 
481  /**
482  * Algorithm parameters
483  */
484  bool m_onlyMakSpacePoints; ///< If true we don't do the full cluster 3D processing
485  bool m_enableMonitoring; ///< Turn on monitoring of this algorithm
486  float m_parallelHitsCosAng; ///< Cut for PCA 3rd axis angle to X axis
487  float m_parallelHitsTransWid; ///< Cut on transverse width of cluster (PCA 2nd eigenvalue)
488 
489  /**
490  * Tree variables for output
491  */
492  TTree* m_pRecoTree; ///<
493  int m_run; ///<
494  int m_event; ///<
495  int m_hits; ///< Keeps track of the number of hits seen
496  int m_hits3D; ///< Keeps track of the number of 3D hits made
497  float m_totalTime; ///< Keeps track of total execution time
498  float m_artHitsTime; ///< Keeps track of time to recover hits
499  float m_makeHitsTime; ///< Keeps track of time to build 3D hits
500  float m_buildNeighborhoodTime; ///< Keeps track of time to build epsilon neighborhood
501  float m_dbscanTime; ///< Keeps track of time to run DBScan
502  float m_clusterMergeTime; ///< Keeps track of the time to merge clusters
503  float m_pathFindingTime; ///< Keeps track of the path finding time
504  float m_finishTime; ///< Keeps track of time to run output module
505  std::string m_pathInstance; ///< Special instance for path points
506  std::string m_vertexInstance; ///< Special instance name for vertex points
507  std::string m_extremeInstance; ///< Instance name for the extreme points
508 
509  // Algorithms
510  std::unique_ptr<lar_cluster3d::IHit3DBuilder>
511  m_hit3DBuilderAlg; ///< Builds the 3D hits to operate on
512  std::unique_ptr<lar_cluster3d::IClusterAlg>
513  m_clusterAlg; ///< Algorithm to do 3D space point clustering
514  std::unique_ptr<lar_cluster3d::IClusterModAlg>
515  m_clusterMergeAlg; ///< Algorithm to do cluster merging
516  std::unique_ptr<lar_cluster3d::IClusterModAlg>
517  m_clusterPathAlg; ///< Algorithm to do cluster path finding
518  std::unique_ptr<lar_cluster3d::IClusterParametersBuilder>
519  m_clusterBuilder; ///< Common cluster builder tool
520  PrincipalComponentsAlg m_pcaAlg; ///< Principal Components algorithm
521  SkeletonAlg m_skeletonAlg; ///< Skeleton point finder
523  PCASeedFinderAlg m_pcaSeedFinderAlg; ///< Use PCA axis to find seeds
524  ParallelHitsSeedFinderAlg m_parallelHitsAlg; ///< Deal with parallel hits clusters
525  };
526 
527  DEFINE_ART_MODULE(Cluster3DICARUS)
528 
529 } // namespace lar_cluster3d
530 
531 //------------------------------------------------------------------------------------------------------------------------------------------
532 // implementation follows
533 
534 namespace lar_cluster3d {
535 
536  Cluster3DICARUS::Cluster3DICARUS(fhicl::ParameterSet const& pset)
537  : EDProducer{pset}
538  , m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
539  , m_skeletonAlg(pset.get<fhicl::ParameterSet>("SkeletonAlg"))
540  , m_seedFinderAlg(pset.get<fhicl::ParameterSet>("SeedFinderAlg"))
541  , m_pcaSeedFinderAlg(pset.get<fhicl::ParameterSet>("PCASeedFinderAlg"))
542  , m_parallelHitsAlg(pset.get<fhicl::ParameterSet>("ParallelHitsAlg"))
543  {
544  m_onlyMakSpacePoints = pset.get<bool>("MakeSpacePointsOnly", false);
545  m_enableMonitoring = pset.get<bool>("EnableMonitoring", false);
546  m_parallelHitsCosAng = pset.get<float>("ParallelHitsCosAng", 0.999);
547  m_parallelHitsTransWid = pset.get<float>("ParallelHitsTransWid", 25.0);
548  m_pathInstance = pset.get<std::string>("PathPointsName", "Path");
549  m_vertexInstance = pset.get<std::string>("VertexPointsName", "Vertex");
550  m_extremeInstance = pset.get<std::string>("ExtremePointsName", "Extreme");
551 
552  m_hit3DBuilderAlg = art::make_tool<lar_cluster3d::IHit3DBuilder>(
553  pset.get<fhicl::ParameterSet>("Hit3DBuilderAlg"));
554  m_clusterAlg =
555  art::make_tool<lar_cluster3d::IClusterAlg>(pset.get<fhicl::ParameterSet>("ClusterAlg"));
556  m_clusterMergeAlg = art::make_tool<lar_cluster3d::IClusterModAlg>(
557  pset.get<fhicl::ParameterSet>("ClusterMergeAlg"));
558  m_clusterPathAlg = art::make_tool<lar_cluster3d::IClusterModAlg>(
559  pset.get<fhicl::ParameterSet>("ClusterPathAlg"));
560  m_clusterBuilder = art::make_tool<lar_cluster3d::IClusterParametersBuilder>(
561  pset.get<fhicl::ParameterSet>("ClusterParamsBuilder"));
562 
563  // Handle special case of Space Point building outputting a new hit collection
564  m_hit3DBuilderAlg->produces(producesCollector());
565 
566  produces<std::vector<recob::PCAxis>>();
567  produces<std::vector<recob::PFParticle>>();
568  produces<std::vector<recob::Cluster>>();
569  produces<std::vector<recob::Seed>>();
570  produces<std::vector<recob::Edge>>();
571 
572  produces<art::Assns<recob::PFParticle, recob::PCAxis>>();
573  produces<art::Assns<recob::PFParticle, recob::Cluster>>();
574  produces<art::Assns<recob::PFParticle, recob::Seed>>();
575  produces<art::Assns<recob::Edge, recob::PFParticle>>();
576  produces<art::Assns<recob::Seed, recob::Hit>>();
577  produces<art::Assns<recob::Cluster, recob::Hit>>();
578 
579  produces<std::vector<recob::SpacePoint>>();
580  produces<art::Assns<recob::SpacePoint, recob::PFParticle>>();
581  produces<art::Assns<recob::Hit, recob::SpacePoint>>();
582  produces<art::Assns<recob::SpacePoint, recob::Edge>>();
583 
584  produces<std::vector<recob::SpacePoint>>(m_pathInstance);
585  produces<std::vector<recob::Edge>>(m_pathInstance);
586  produces<art::Assns<recob::SpacePoint, recob::PFParticle>>(m_pathInstance);
587  produces<art::Assns<recob::Edge, recob::PFParticle>>(m_pathInstance);
588  produces<art::Assns<recob::Hit, recob::SpacePoint>>(m_pathInstance);
589  produces<art::Assns<recob::SpacePoint, recob::Edge>>(m_pathInstance);
590 
591  produces<std::vector<recob::Edge>>(m_vertexInstance);
592  produces<std::vector<recob::SpacePoint>>(m_vertexInstance);
593 
594  produces<std::vector<recob::SpacePoint>>(m_extremeInstance);
595  }
596 
597  //------------------------------------------------------------------------------------------------------------------------------------------
598 
599  void
601  {
602  /**
603  * @brief beginJob will be tasked with initializing monitoring, in necessary, but also to init the
604  * geometry and detector services (and this probably needs to go in a "beginEvent" method?)
605  */
607  }
608 
609  //------------------------------------------------------------------------------------------------------------------------------------------
610 
611  void
613  {
614  mf::LogInfo("Cluster3DICARUS") << " *** Cluster3D::produce(...) [Run=" << evt.run()
615  << ", Event=" << evt.id().event() << "] Starting Now! *** "
616  << std::endl;
617 
618  // Set up for monitoring the timing... at some point this should be removed in favor of
619  // external profilers
620  cet::cpu_timer theClockTotal;
621  cet::cpu_timer theClockFinish;
622 
623  if (m_enableMonitoring) theClockTotal.start();
624 
625  // This really only does anything if we are monitoring since it clears our tree variables
626  this->PrepareEvent(evt);
627 
628  // Get instances of the primary data structures needed
629  reco::ClusterParametersList clusterParametersList;
630  IHit3DBuilder::RecobHitToPtrMap clusterHitToArtPtrMap;
631  std::unique_ptr<reco::HitPairList> hitPairList(
632  new reco::HitPairList); // Potentially lots of hits, use heap instead of stack
633 
634  // Call the algorithm that builds 3D hits and stores the hit collection
635  m_hit3DBuilderAlg->Hit3DBuilder(evt, *hitPairList, clusterHitToArtPtrMap);
636 
637  // Only do the rest if we are not in the mode of only building space points (requested by ML folks)
638  if (!m_onlyMakSpacePoints) {
639  // Call the main workhorse algorithm for building the local version of candidate 3D clusters
640  m_clusterAlg->Cluster3DHits(*hitPairList, clusterParametersList);
641 
642  // Try merging clusters
643  m_clusterMergeAlg->ModifyClusters(clusterParametersList);
644 
645  // Run the path finding
646  m_clusterPathAlg->ModifyClusters(clusterParametersList);
647  }
648 
649  if (m_enableMonitoring) theClockFinish.start();
650 
651  // Get the art ouput object
653 
654  // Call the module that does the end processing (of which there is quite a bit of work!)
655  // This goes here to insure that something is always written to the data store
656  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
657  auto const detProp =
658  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clockData);
659  util::GeometryUtilities const gser{*lar::providerFrom<geo::Geometry>(), clockData, detProp};
660  ProduceArtClusters(gser, output, *hitPairList, clusterParametersList, clusterHitToArtPtrMap);
661 
662  // Output to art
663  output.outputObjects();
664 
665  // If monitoring then deal with the fallout
666  if (m_enableMonitoring) {
667  theClockFinish.stop();
668  theClockTotal.stop();
669 
670  m_run = evt.run();
671  m_event = evt.id().event();
672  m_totalTime = theClockTotal.accumulated_real_time();
676  m_dbscanTime = m_clusterAlg->getTimeToExecute(IClusterAlg::RUNDBSCAN) +
677  m_clusterAlg->getTimeToExecute(IClusterAlg::BUILDCLUSTERINFO);
678  m_clusterMergeTime = m_clusterMergeAlg->getTimeToExecute();
679  m_pathFindingTime = m_clusterPathAlg->getTimeToExecute();
680  m_finishTime = theClockFinish.accumulated_real_time();
681  m_hits = static_cast<int>(clusterHitToArtPtrMap.size());
682  m_hits3D = static_cast<int>(hitPairList->size());
683  m_pRecoTree->Fill();
684 
685  mf::LogDebug("Cluster3DICARUS") << "*** Cluster3DICARUS total time: " << m_totalTime
686  << ", art: " << m_artHitsTime << ", make: " << m_makeHitsTime
687  << ", build: " << m_buildNeighborhoodTime
688  << ", clustering: " << m_dbscanTime
689  << ", merge: " << m_clusterMergeTime
690  << ", path: " << m_pathFindingTime << ", finish: " << m_finishTime
691  << std::endl;
692  }
693 
694  // Will we ever get here? ;-)
695  return;
696  }
697 
698  //------------------------------------------------------------------------------------------------------------------------------------------
699 
700  void
702  {
703  art::ServiceHandle<art::TFileService> tfs;
704  m_pRecoTree = tfs->make<TTree>("monitoring", "LAr Reco");
705  m_pRecoTree->Branch("run", &m_run, "run/I");
706  m_pRecoTree->Branch("event", &m_event, "event/I");
707  m_pRecoTree->Branch("hits", &m_hits, "hits/I");
708  m_pRecoTree->Branch("hits3D", &m_hits3D, "hits3D/I");
709  m_pRecoTree->Branch("totalTime", &m_totalTime, "time/F");
710  m_pRecoTree->Branch("artHitsTime", &m_artHitsTime, "time/F");
711  m_pRecoTree->Branch("makeHitsTime", &m_makeHitsTime, "time/F");
712  m_pRecoTree->Branch("buildneigborhoodTime", &m_buildNeighborhoodTime, "time/F");
713  m_pRecoTree->Branch("dbscanTime", &m_dbscanTime, "time/F");
714  m_pRecoTree->Branch("clusterMergeTime", &m_clusterMergeTime, "time/F");
715  m_pRecoTree->Branch("pathfindingtime", &m_pathFindingTime, "time/F");
716  m_pRecoTree->Branch("finishTime", &m_finishTime, "time/F");
717 
718  m_clusterPathAlg->initializeHistograms(*tfs.get());
719  }
720 
721  //------------------------------------------------------------------------------------------------------------------------------------------
722 
723  void
724  Cluster3DICARUS::PrepareEvent(const art::Event& evt)
725  {
726  m_run = evt.run();
727  m_event = evt.id().event();
728  m_hits = 0;
729  m_hits3D = 0;
730  m_totalTime = 0.f;
731  m_artHitsTime = 0.f;
732  m_makeHitsTime = 0.f;
734  m_dbscanTime = 0.f;
735  m_pathFindingTime = 0.f;
736  m_finishTime = 0.f;
737  }
738 
739  //------------------------------------------------------------------------------------------------------------------------------------------
740 
741  void
744  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
745  std::vector<recob::Seed>& seedVec,
746  art::Assns<recob::Seed, recob::Hit>& seedHitAssns) const
747  {
748  /**
749  * @brief This method provides an interface to various algorithms for finding candiate
750  * recob::Seed objects and, as well, their candidate related seed hits
751  */
752 
753  // Make sure we are using the right pca
754  reco::PrincipalComponents& fullPCA = cluster.getFullPCA();
755  reco::PrincipalComponents& skeletonPCA = cluster.getSkeletonPCA();
756  reco::HitPairListPtr& hitPairListPtr = cluster.getHitPairListPtr();
757  reco::HitPairListPtr skeletonListPtr;
758 
759  // We want to work with the "skeleton" hits so first step is to call the algorithm to
760  // recover only these hits from the entire input collection
761  m_skeletonAlg.GetSkeletonHits(hitPairListPtr, skeletonListPtr);
762 
763  // Skeleton hits are nice but we can do better if we then make a pass through to "average"
764  // the skeleton hits position in the Y-Z plane
765  m_skeletonAlg.AverageSkeletonPositions(skeletonListPtr);
766 
767  SeedHitPairListPairVec seedHitPairVec;
768 
769  // Some combination of the elements below will be used to determine which seed finding algorithm
770  // to pursue below
771  float eigenVal0 = 3. * sqrt(skeletonPCA.getEigenValues()[0]);
772  float eigenVal1 = 3. * sqrt(skeletonPCA.getEigenValues()[1]);
773  float eigenVal2 = 3. * sqrt(skeletonPCA.getEigenValues()[2]);
774  float transRMS = std::hypot(eigenVal0, eigenVal1);
775 
776  bool foundGoodSeed(false);
777 
778  // Choose a method for finding the seeds based on the PCA that was run...
779  // Currently we have an ad hoc if-else block which I hope will be improved soon!
780  if (aParallelHitsCluster(fullPCA)) {
781  // In this case we have a track moving relatively parallel to the wire plane with lots of
782  // ambiguous 3D hits. Your best bet here is to use the "parallel hits" algorithm to get the
783  // best axis and seeds
784  // This algorithm does not fail (foundGoodSeed will always return true)
785  foundGoodSeed = m_parallelHitsAlg.findTrackSeeds(hitPairListPtr, skeletonPCA, seedHitPairVec);
786  }
787  else if (eigenVal2 > 40. && transRMS < 5.) {
788  // If the input cluster is relatively "straight" then chances are it is a single straight track,
789  // probably a CR muon, and we can simply use the PCA to determine the seed
790  // This algorithm will check both "ends" of the input hits and if the angles become inconsistent
791  // then it will "fail"
792  foundGoodSeed =
793  m_pcaSeedFinderAlg.findTrackSeeds(skeletonListPtr, skeletonPCA, seedHitPairVec);
794  }
795 
796  // In the event the above two methods failed then we hit it with the real seed finder
797  if (!foundGoodSeed) {
798  // If here then we have a complicated 3D cluster and we'll use the hough transform algorithm to
799  // return a list of candidate seeds and seed hits
800  m_seedFinderAlg.findTrackSeeds(skeletonListPtr, skeletonPCA, seedHitPairVec);
801  }
802 
803  // Go through the returned lists and build out the art friendly seeds and hits
804  for (const auto& seedHitPair : seedHitPairVec) {
805  seedVec.push_back(seedHitPair.first);
806 
807  // We use a set here because our 3D hits can share 2D hits
808  // The set will make sure we get unique combinations of 2D hits
809  std::set<art::Ptr<recob::Hit>> seedHitSet;
810  for (const auto& hit3D : seedHitPair.second) {
811  for (const auto& hit2D : hit3D->getHits()) {
812  if (!hit2D) continue;
813 
814  const recob::Hit* recobHit = hit2D->getHit();
815  seedHitSet.insert(hitToPtrMap[recobHit]);
816  }
817  }
818 
819  RecobHitVector seedHitVec;
820  for (const auto& hit2D : seedHitSet)
821  seedHitVec.push_back(hit2D);
822 
823  util::CreateAssn(evt, seedVec, seedHitVec, seedHitAssns);
824  }
825  }
826 
828  bool
829  operator()(const std::pair<float, const reco::ClusterHit3D*>& left,
830  const std::pair<float, const reco::ClusterHit3D*>& right)
831  {
832  return left.first < right.first;
833  }
834  };
835 
836  void
838  reco::ClusterParametersList& clusterParametersList) const
839  {
840  // This is being left in place for future development. Essentially, it was an attempt to implement
841  // a Minimum Spanning Tree as a way to split a particular cluster topology, one where two straight
842  // tracks cross closely enought to appear as one cluster. As of Feb 2, 2015 I think the idea is still
843  // worth merit so am leaving this module in place for now.
844  //
845  // If this routine is called then we believe we have a cluster which needs splitting.
846  // The way we will do this is to use a Minimum Spanning Tree algorithm to associate all
847  // hits together by their distance apart. In theory, we should be able to split the cluster
848  // by finding the largest distance and splitting at that point.
849  //
850  // Typedef some data structures that we will use.
851  // Start with the adjacency map
852  typedef std::pair<float, const reco::ClusterHit3D*> DistanceHit3DPair;
853  typedef std::list<DistanceHit3DPair> DistanceHit3DPairList;
854  typedef std::map<const reco::ClusterHit3D*, DistanceHit3DPairList> Hit3DToDistanceMap;
855 
856  // Now typedef the lists we'll keep
857  typedef std::list<const reco::ClusterHit3D*> Hit3DList;
858  typedef std::pair<Hit3DList::iterator, Hit3DList::iterator> Hit3DEdgePair;
859  typedef std::pair<float, Hit3DEdgePair> DistanceEdgePair;
860  typedef std::list<DistanceEdgePair> DistanceEdgePairList;
861 
862  struct DistanceEdgePairOrder {
863  bool
864  operator()(const DistanceEdgePair& left, const DistanceEdgePair& right) const
865  {
866  return left.first > right.first;
867  }
868  };
869 
870  // Recover the hits we'll work on.
871  // Note that we use on the skeleton hits so will need to recover them
872  reco::HitPairListPtr& hitPairListPtr = clusterParameters.getHitPairListPtr();
873  reco::HitPairListPtr skeletonListPtr;
874 
875  // We want to work with the "skeleton" hits so first step is to call the algorithm to
876  // recover only these hits from the entire input collection
877  m_skeletonAlg.GetSkeletonHits(hitPairListPtr, skeletonListPtr);
878 
879  // Skeleton hits are nice but we can do better if we then make a pass through to "average"
880  // the skeleton hits position in the Y-Z plane
881  m_skeletonAlg.AverageSkeletonPositions(skeletonListPtr);
882 
883  // First task is to define and build the adjacency map
884  Hit3DToDistanceMap hit3DToDistanceMap;
885 
886  for (reco::HitPairListPtr::const_iterator hit3DOuterItr = skeletonListPtr.begin();
887  hit3DOuterItr != skeletonListPtr.end();) {
888  const reco::ClusterHit3D* hit3DOuter = *hit3DOuterItr++;
889  DistanceHit3DPairList& outerHitList = hit3DToDistanceMap[hit3DOuter];
890  TVector3 outerPos(
891  hit3DOuter->getPosition()[0], hit3DOuter->getPosition()[1], hit3DOuter->getPosition()[2]);
892 
893  for (reco::HitPairListPtr::const_iterator hit3DInnerItr = hit3DOuterItr;
894  hit3DInnerItr != skeletonListPtr.end();
895  hit3DInnerItr++) {
896  const reco::ClusterHit3D* hit3DInner = *hit3DInnerItr;
897  TVector3 innerPos(
898  hit3DInner->getPosition()[0], hit3DInner->getPosition()[1], hit3DInner->getPosition()[2]);
899  TVector3 deltaPos = innerPos - outerPos;
900  float hitDistance(float(deltaPos.Mag()));
901 
902  if (hitDistance > 20.) continue;
903 
904  hit3DToDistanceMap[hit3DInner].emplace_back(hitDistance, hit3DOuter);
905  outerHitList.emplace_back(hitDistance, hit3DInner);
906  }
907 
908  // Make sure our membership bit is clear
910  }
911 
912  // Make pass through again to order each of the lists
913  for (auto& mapPair : hit3DToDistanceMap) {
914  mapPair.second.sort(Hit3DDistanceOrder());
915  }
916 
917  // Get the containers for the MST to operate on/with
918  Hit3DList hit3DList;
919  DistanceEdgePairList distanceEdgePairList;
920 
921  // Initialize with first element
922  hit3DList.emplace_back(skeletonListPtr.front());
923  distanceEdgePairList.emplace_back(
924  DistanceEdgePair(0., Hit3DEdgePair(hit3DList.begin(), hit3DList.begin())));
925 
926  skeletonListPtr.front()->setStatusBit(reco::ClusterHit3D::SELECTEDBYMST);
927 
928  float largestDistance(0.);
929  float averageDistance(0.);
930 
931  // Now run the MST
932  // Basically, we loop until the MST list is the same size as the input list
933  while (hit3DList.size() < skeletonListPtr.size()) {
934  Hit3DList::iterator bestHit3DIter = hit3DList.begin();
935  float bestDist = 10000000.;
936 
937  // Loop through all hits currently in the list and look for closest hit not in the list
938  for (Hit3DList::iterator hit3DIter = hit3DList.begin(); hit3DIter != hit3DList.end();
939  hit3DIter++) {
940  const reco::ClusterHit3D* hit3D = *hit3DIter;
941 
942  // For the given 3D hit, find the closest to it that is not already in the list
943  DistanceHit3DPairList& nearestList = hit3DToDistanceMap[hit3D];
944 
945  while (!nearestList.empty()) {
946  const reco::ClusterHit3D* hit3DToCheck = nearestList.front().second;
947 
948  if (!hit3DToCheck->bitsAreSet(reco::ClusterHit3D::SELECTEDBYMST)) {
949  if (nearestList.front().first < bestDist) {
950  bestHit3DIter = hit3DIter;
951  bestDist = nearestList.front().first;
952  }
953  break;
954  }
955 
956  nearestList.pop_front();
957  }
958  }
959 
960  if (bestDist > largestDistance) largestDistance = bestDist;
961 
962  averageDistance += bestDist;
963 
964  // Now we add the best hit not in the list to our list, keep track of the distance
965  // to the object it was closest to
966  const reco::ClusterHit3D* bestHit3D = *bestHit3DIter; // "best" hit already in the list
967  const reco::ClusterHit3D* nextHit3D =
968  hit3DToDistanceMap[bestHit3D].front().second; // "next" hit we are adding to the list
969 
970  Hit3DList::iterator nextHit3DIter = hit3DList.insert(hit3DList.end(), nextHit3D);
971 
972  distanceEdgePairList.emplace_back(bestDist, Hit3DEdgePair(bestHit3DIter, nextHit3DIter));
973 
975  }
976 
977  averageDistance /= float(hit3DList.size());
978 
979  float thirdDist = 2. * sqrt(clusterParameters.getSkeletonPCA().getEigenValues()[2]);
980 
981  // Ok, find the largest distance in the iterator map
982  distanceEdgePairList.sort(DistanceEdgePairOrder());
983 
984  DistanceEdgePairList::iterator largestDistIter = distanceEdgePairList.begin();
985 
986  for (DistanceEdgePairList::iterator edgeIter = distanceEdgePairList.begin();
987  edgeIter != distanceEdgePairList.end();
988  edgeIter++) {
989  if (edgeIter->first < thirdDist) break;
990 
991  largestDistIter = edgeIter;
992  }
993 
994  reco::HitPairListPtr::iterator breakIter = largestDistIter->second.second;
995  reco::HitPairListPtr bestList;
996 
997  bestList.resize(std::distance(hit3DList.begin(), breakIter));
998 
999  std::copy(hit3DList.begin(), breakIter, bestList.begin());
1000 
1001  // Remove from the grand hit list and see what happens...
1002  // The pieces below are incomplete and were really for testing only.
1003  hitPairListPtr.sort();
1004  bestList.sort();
1005 
1006  reco::HitPairListPtr::iterator newListEnd = std::set_difference(hitPairListPtr.begin(),
1007  hitPairListPtr.end(),
1008  bestList.begin(),
1009  bestList.end(),
1010  hitPairListPtr.begin());
1011 
1012  hitPairListPtr.erase(newListEnd, hitPairListPtr.end());
1013  }
1014 
1016  public:
1017  CopyIfInRange(float maxRange) : m_maxRange(maxRange) {}
1018 
1019  bool
1020  operator()(const reco::ClusterHit3D* hit3D) const
1021  {
1022  return hit3D->getDocaToAxis() < m_maxRange;
1023  }
1024 
1025  private:
1026  float m_maxRange;
1027  };
1028 
1029  void
1031  reco::ClusterParametersList& clusterParametersList) const
1032  {
1033  // @brief A method for splitted "crossed tracks" clusters into separate clusters
1034  //
1035  // If this routine is called then we believe we have a cluster which needs splitting.
1036  // The specific topology we are looking for is two long straight tracks which cross at some
1037  // point in close proximity so their hits were joined into a single 3D cluster. The method
1038  // to split this topology is to let the hough transform algorithm find the two leading candidates
1039  // and then to see if we use those to build two clusters instead of one.
1040 
1041  // Recover the hits we'll work on.
1042  // Note that we use on the skeleton hits so will need to recover them
1043  reco::HitPairListPtr& hitPairListPtr = clusterParameters.getHitPairListPtr();
1044  reco::HitPairListPtr skeletonListPtr;
1045 
1046  // We want to work with the "skeleton" hits so first step is to call the algorithm to
1047  // recover only these hits from the entire input collection
1048  m_skeletonAlg.GetSkeletonHits(hitPairListPtr, skeletonListPtr);
1049 
1050  // Skeleton hits are nice but we can do better if we then make a pass through to "average"
1051  // the skeleton hits position in the Y-Z plane
1052  m_skeletonAlg.AverageSkeletonPositions(skeletonListPtr);
1053 
1054  // Define the container for our lists of hits
1055  reco::HitPairListPtrList hitPairListPtrList;
1056 
1057  // Now feed this to the Hough Transform to find candidate straight lines
1059  skeletonListPtr, clusterParameters.getSkeletonPCA(), hitPairListPtrList);
1060 
1061  // We need at least two lists or else there is nothing to do
1062  if (hitPairListPtrList.size() < 2) return;
1063 
1064  // The game plan will be the following:
1065  // 1) Take the first list of hits and run the PCA on this to get an axis
1066  // - Then calculate the 3d doca for ALL hits in the cluster to this axis
1067  // - Move all hits within "3 sigam" of the axis to a new list
1068  // 2) run the PCA on the second list of hits to get that axis
1069  // - Then calculate the 3d doca for all hits in our first list
1070  // - Copy hits in the first list which are within 3 sigma of the new axis
1071  // back into our original cluster - these are shared hits
1072  reco::HitPairListPtrList::iterator hitPairListIter = hitPairListPtrList.begin();
1073  reco::HitPairListPtr& firstHitList = *hitPairListIter++;
1074  reco::PrincipalComponents firstHitListPCA;
1075 
1076  m_pcaAlg.PCAAnalysis_3D(firstHitList, firstHitListPCA);
1077 
1078  // Make sure we have a successful calculation.
1079  if (firstHitListPCA.getSvdOK()) {
1080  // The fill routines below will expect to see unused 2D hits so we need to clear the
1081  // status bits... and I am not sure of a better way...
1082  for (const auto& hit3D : hitPairListPtr) {
1083  for (const auto& hit2D : hit3D->getHits())
1084  if (hit2D) hit2D->clearStatusBits(0x1);
1085  }
1086 
1087  // Calculate the 3D doca's for the hits which were used to make this PCA
1088  m_pcaAlg.PCAAnalysis_calc3DDocas(firstHitList, firstHitListPCA);
1089 
1090  // Divine from the ether some maximum allowed range for transfering hits
1091  float allowedHitRange = 6. * firstHitListPCA.getAveHitDoca();
1092 
1093  // Now go through and calculate the 3D doca's for ALL the hits in the original cluster
1094  m_pcaAlg.PCAAnalysis_calc3DDocas(hitPairListPtr, firstHitListPCA);
1095 
1096  // Let's make a new cluster to hold the hits
1097  clusterParametersList.push_back(reco::ClusterParameters());
1098 
1099  // Can we get a reference to what we just created?
1100  reco::ClusterParameters& newClusterParams = clusterParametersList.back();
1101 
1102  reco::HitPairListPtr& newClusterHitList = newClusterParams.getHitPairListPtr();
1103 
1104  newClusterHitList.resize(hitPairListPtr.size());
1105 
1106  // Do the actual copy of the hits we want
1107  reco::HitPairListPtr::iterator newListEnd = std::copy_if(hitPairListPtr.begin(),
1108  hitPairListPtr.end(),
1109  newClusterHitList.begin(),
1110  CopyIfInRange(allowedHitRange));
1111 
1112  // Shrink to fit
1113  newClusterHitList.resize(std::distance(newClusterHitList.begin(), newListEnd));
1114 
1115  // And now remove these hits from the original cluster
1116  hitPairListPtr.remove_if(CopyIfInRange(allowedHitRange));
1117 
1118  // Get an empty hit to cluster map...
1119  reco::Hit2DToClusterMap hit2DToClusterMap;
1120 
1121  // Now "fill" the cluster parameters but turn off the hit rejection
1122  m_clusterBuilder->FillClusterParams(newClusterParams, hit2DToClusterMap, 0., 1.);
1123 
1124  // Set the skeleton pca to the value calculated above on input
1125  clusterParameters.getSkeletonPCA() = firstHitListPCA;
1126 
1127  // We are done with splitting out one track. Because the two tracks cross in
1128  // close proximity, this is the one case where we might consider sharing 3D hits
1129  // So let's make a little detour here to try to copy some of those hits back into
1130  // the main hit list
1131  reco::HitPairListPtr& secondHitList = *hitPairListIter;
1132  reco::PrincipalComponents secondHitListPCA;
1133 
1134  m_pcaAlg.PCAAnalysis_3D(secondHitList, secondHitListPCA);
1135 
1136  // Make sure we have a successful calculation.
1137  if (secondHitListPCA.getSvdOK()) {
1138  // Calculate the 3D doca's for the hits which were used to make this PCA
1139  m_pcaAlg.PCAAnalysis_calc3DDocas(secondHitList, secondHitListPCA);
1140 
1141  // Since this is the "other" cluster, we'll be a bit more generous in adding back hits
1142  float newAllowedHitRange = 6. * secondHitListPCA.getAveHitDoca();
1143 
1144  // Go through and calculate the 3D doca's for the hits in our new candidate cluster
1145  m_pcaAlg.PCAAnalysis_calc3DDocas(newClusterHitList, secondHitListPCA);
1146 
1147  // Create a temporary list to fill with the hits we might want to save
1148  reco::HitPairListPtr tempHitList(newClusterHitList.size());
1149 
1150  // Do the actual copy of the hits we want...
1151  reco::HitPairListPtr::iterator tempListEnd =
1152  std::copy_if(newClusterHitList.begin(),
1153  newClusterHitList.end(),
1154  tempHitList.begin(),
1155  CopyIfInRange(newAllowedHitRange));
1156 
1157  hitPairListPtr.insert(hitPairListPtr.end(), tempHitList.begin(), tempListEnd);
1158  }
1159 
1160  // Of course, now we need to modify the original cluster parameters
1161  reco::ClusterParameters originalParams(hitPairListPtr);
1162 
1163  // Now "fill" the cluster parameters but turn off the hit rejection
1164  m_clusterBuilder->FillClusterParams(originalParams, hit2DToClusterMap, 0., 1.);
1165 
1166  // Overwrite original cluster parameters with our new values
1167  clusterParameters.getClusterParams() = originalParams.getClusterParams();
1168  clusterParameters.getFullPCA() = originalParams.getFullPCA();
1169  clusterParameters.getSkeletonPCA() = secondHitListPCA;
1170  }
1171  }
1172 
1173  void
1175  ArtOutputHandler& output,
1176  reco::HitPairList& hitPairVector,
1177  reco::ClusterParametersList& clusterParametersList,
1178  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap) const
1179  {
1180  /**
1181  * @brief The workhorse to take the candidate 3D clusters and produce all of the necessary art output
1182  */
1183 
1184  mf::LogDebug("Cluster3DICARUS") << " *** Cluster3DICARUS::ProduceArtClusters() *** " << std::endl;
1185 
1186  // Make sure there is something to do here!
1187  if (!clusterParametersList.empty()) {
1188  // This is the loop over candidate 3D clusters
1189  // Note that it might be that the list of candidate clusters is modified by splitting
1190  // So we use the following construct to make sure we get all of them
1191  for (auto& clusterParameters : clusterParametersList) {
1192  // It should be straightforward at this point to transfer information from our vector of clusters
1193  // to the larsoft objects... of course we still have some work to do first, in particular to
1194  // find the candidate seeds and their seed hits
1195 
1196  // The chances of getting here and this condition not being true are probably zero... but check anyway
1197  if (!clusterParameters.getFullPCA().getSvdOK()) {
1198  mf::LogDebug("Cluster3DICARUS")
1199  << "--> no feature extraction done on this cluster!!" << std::endl;
1200  continue;
1201  }
1202 
1203  // Keep track of hit 3D to SP for when we do edges
1204  Hit3DToSPPtrMap hit3DToSPPtrMap;
1205  Hit3DToSPPtrMap best3DToSPPtrMap;
1206 
1207  // Do a special output of voronoi vertices here...
1208  dcel2d::VertexList& vertexList = clusterParameters.getVertexList();
1209  dcel2d::HalfEdgeList& halfEdgeList = clusterParameters.getHalfEdgeList();
1210 
1211  MakeAndSaveVertexPoints(output, vertexList, halfEdgeList);
1212 
1213  // Special case handling... if no daughters then call standard conversion routine to make sure space points
1214  // created, etc.
1215  if (clusterParameters.daughterList().empty()) {
1216  ConvertToArtOutput(gser,
1217  output,
1218  clusterParameters,
1220  hitToPtrMap,
1221  hit3DToSPPtrMap,
1222  best3DToSPPtrMap);
1223 
1224  // Get the extreme points
1225  MakeAndSaveKinkPoints(output,
1226  clusterParameters.getConvexHull().getConvexHullKinkPoints());
1227  }
1228  // Otherwise, the cluster has daughters so we handle specially
1229  else {
1230  // Set up to keep track of parent/daughters
1231  IdxToPCAMap idxToPCAMap;
1232  size_t numTotalDaughters = countUltimateDaughters(clusterParameters);
1233  size_t pfParticleIdx(output.artPFParticleVector->size() + numTotalDaughters);
1234 
1235  FindAndStoreDaughters(gser,
1236  output,
1237  clusterParameters,
1238  pfParticleIdx,
1239  idxToPCAMap,
1240  hitToPtrMap,
1241  hit3DToSPPtrMap,
1242  best3DToSPPtrMap);
1243 
1244  // Need to make a daughter vec from our map
1245  std::vector<size_t> daughterVec;
1246 
1247  for (auto& idxToPCA : idxToPCAMap)
1248  daughterVec.emplace_back(idxToPCA.first);
1249 
1250  // Now create/handle the parent PFParticle
1251  recob::PFParticle pfParticle(
1252  13, pfParticleIdx, recob::PFParticle::kPFParticlePrimary, daughterVec);
1253  output.artPFParticleVector->push_back(pfParticle);
1254 
1255  recob::PCAxis::EigenVectors eigenVecs;
1256  double eigenVals[] = {0., 0., 0.};
1257  double avePosition[] = {0., 0., 0.};
1258 
1259  eigenVecs.resize(3);
1260 
1261  reco::PrincipalComponents& skeletonPCA = clusterParameters.getSkeletonPCA();
1262 
1263  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1264  avePosition[outerIdx] = skeletonPCA.getAvePosition()[outerIdx];
1265  eigenVals[outerIdx] = skeletonPCA.getEigenValues()[outerIdx];
1266 
1267  eigenVecs[outerIdx].resize(3);
1268 
1269  // Be careful here... eigen stores in column major order buy default
1270  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1271  eigenVecs[outerIdx][innerIdx] = skeletonPCA.getEigenVectors().row(outerIdx)[innerIdx];
1272  }
1273 
1274  recob::PCAxis skelPcAxis(skeletonPCA.getSvdOK(),
1275  skeletonPCA.getNumHitsUsed(),
1276  eigenVals,
1277  eigenVecs,
1278  avePosition,
1279  skeletonPCA.getAveHitDoca(),
1280  output.artPCAxisVector->size());
1281 
1282  output.artPCAxisVector->push_back(skelPcAxis);
1283 
1284  reco::PrincipalComponents& fullPCA = clusterParameters.getFullPCA();
1285 
1286  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1287  avePosition[outerIdx] = fullPCA.getAvePosition()[outerIdx];
1288  eigenVals[outerIdx] = fullPCA.getEigenValues()[outerIdx];
1289 
1290  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1291  eigenVecs[outerIdx][innerIdx] = fullPCA.getEigenVectors().row(outerIdx)(innerIdx);
1292  }
1293 
1294  recob::PCAxis fullPcAxis(fullPCA.getSvdOK(),
1295  fullPCA.getNumHitsUsed(),
1296  eigenVals,
1297  eigenVecs,
1298  avePosition,
1299  fullPCA.getAveHitDoca(),
1300  output.artPCAxisVector->size());
1301 
1302  output.artPCAxisVector->push_back(fullPcAxis);
1303 
1304  // Create associations to the PFParticle
1305  output.makePFPartPCAAssns();
1306 
1307  // Make associations to all space points for this cluster
1308  MakeAndSaveSpacePoints(output,
1309  *output.artSpacePointVector.get(),
1310  *output.artSPHitAssociations.get(),
1311  clusterParameters.getHitPairListPtr(),
1312  hitToPtrMap,
1313  hit3DToSPPtrMap);
1314 
1315  // Get the extreme points
1316  MakeAndSaveKinkPoints(output,
1317  clusterParameters.getConvexHull().getConvexHullKinkPoints());
1318 
1319  // Build the edges now
1320  size_t edgeStart(output.artEdgeVector->size());
1321 
1322  for (const auto& edge : clusterParameters.getConvexHull().getConvexHullEdgeList()) {
1323  RecobSpacePointVector spacePointVec;
1324 
1325  try {
1326  spacePointVec.push_back(hit3DToSPPtrMap.at(std::get<0>(edge)));
1327  spacePointVec.push_back(hit3DToSPPtrMap.at(std::get<1>(edge)));
1328  }
1329  catch (...) {
1330  std::cout << "Caught exception in looking up space point ptr... " << std::get<0>(edge)
1331  << ", " << std::get<1>(edge) << std::endl;
1332  continue;
1333  }
1334 
1335  output.artEdgeVector->emplace_back(std::get<2>(edge),
1336  spacePointVec[0].key(),
1337  spacePointVec[1].key(),
1338  output.artEdgeVector->size());
1339 
1340  output.makeEdgeSpacePointAssns(
1341  *output.artEdgeVector.get(), spacePointVec, *output.artEdgeSPAssociations.get());
1342  }
1343 
1344  output.makePFPartEdgeAssns(
1345  *output.artEdgeVector.get(), *output.artPFPartEdgeAssociations.get(), edgeStart);
1346  }
1347  }
1348  }
1349 
1350  // Right now error matrix is uniform...
1351  int nFreePoints(0);
1352 
1353  // Run through the HitPairVector and add any unused hit pairs to the list
1354  for (auto& hitPair : hitPairVector) {
1355  if (hitPair.bitsAreSet(reco::ClusterHit3D::MADESPACEPOINT)) continue;
1356 
1357  double spacePointPos[] = {
1358  hitPair.getPosition()[0], hitPair.getPosition()[1], hitPair.getPosition()[2]};
1359  double spacePointErr[] = {1., 0., 0., 1., 0., 1.};
1360  double chisq = hitPair.getHitChiSquare();
1361 
1362  RecobHitVector recobHits;
1363 
1364  for (const auto hit : hitPair.getHits()) {
1365  if (!hit) continue;
1366 
1367  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit->getHit()];
1368  recobHits.push_back(hitPtr);
1369  }
1370 
1371  nFreePoints++;
1372 
1373  spacePointErr[1] = hitPair.getTotalCharge();
1374  spacePointErr[3] = hitPair.getChargeAsymmetry();
1375 
1376  output.artSpacePointVector->push_back(
1377  recob::SpacePoint(spacePointPos, spacePointErr, chisq, output.artSpacePointVector->size()));
1378 
1379  if (!recobHits.empty())
1380  output.makeSpacePointHitAssns(
1381  *output.artSpacePointVector.get(), recobHits, *output.artSPHitAssociations.get());
1382  }
1383 
1384  std::cout << "++++>>>> total num hits: " << hitPairVector.size()
1385  << ", num free: " << nFreePoints << std::endl;
1386  }
1387 
1388  size_t
1390  {
1391  size_t localCount(0);
1392 
1393  if (!clusterParameters.daughterList().empty()) {
1394  for (auto& clusterParams : clusterParameters.daughterList())
1395  localCount += countUltimateDaughters(clusterParams);
1396  }
1397  else
1398  localCount++;
1399 
1400  return localCount;
1401  }
1402 
1403  size_t
1405  ArtOutputHandler& output,
1406  reco::ClusterParameters& clusterParameters,
1407  size_t pfParticleParent,
1408  IdxToPCAMap& idxToPCAMap,
1409  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1410  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1411  Hit3DToSPPtrMap& best3DToSPPtrMap) const
1412  {
1413  // This is a recursive routine, we keep calling ourself as long as the daughter list is non empty
1414  if (!clusterParameters.daughterList().empty()) {
1415  for (auto& clusterParams : clusterParameters.daughterList())
1416  FindAndStoreDaughters(gser,
1417  output,
1418  clusterParams,
1419  pfParticleParent,
1420  idxToPCAMap,
1421  hitToPtrMap,
1422  hit3DToSPPtrMap,
1423  best3DToSPPtrMap);
1424  }
1425  // Otherwise we want to store the information
1426  else {
1427  size_t daughterIdx = ConvertToArtOutput(gser,
1428  output,
1429  clusterParameters,
1430  pfParticleParent,
1431  hitToPtrMap,
1432  hit3DToSPPtrMap,
1433  best3DToSPPtrMap);
1434 
1435  idxToPCAMap[daughterIdx] = &clusterParameters.getFullPCA();
1436  }
1437 
1438  return idxToPCAMap.size();
1439  }
1440 
1441  size_t
1443  ArtOutputHandler& output,
1444  reco::ClusterParameters& clusterParameters,
1445  size_t pfParticleParent,
1446  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1447  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1448  Hit3DToSPPtrMap& best3DToSPPtrMap) const
1449  {
1450  // prepare the algorithm to compute the cluster characteristics;
1451  // we use the "standard" one here, except that we override selected items
1452  // (so, thanks to metaprogramming, we finally have wrappers of wrappers);
1453  // configuration would happen here, but we are using the default
1454  // configuration for that algorithm
1455  using OverriddenClusterParamsAlg_t =
1457 
1459 
1460  // It should be straightforward at this point to transfer information from our vector of clusters
1461  // to the larsoft objects... of course we still have some work to do first, in particular to
1462  // find the candidate seeds and their seed hits
1463 
1464  // We keep track of 2 PCA axes, the first is the "full" PCA run over all the 3D hits in the
1465  // candidate cluster. The second will be that derived from just using the "skeleton" hits.
1466  // Make a copy of the full PCA to keep that, then get a reference for the skeleton PCA
1467  reco::PrincipalComponents& fullPCA = clusterParameters.getFullPCA();
1468  reco::PrincipalComponents& skeletonPCA = clusterParameters.getSkeletonPCA();
1469 
1470  size_t clusterStart = output.artClusterVector->size();
1471 
1472  // Start loop over views to build out the hit lists and the 2D cluster objects
1473  for (const auto& clusParametersPair : clusterParameters.getClusterParams()) {
1474  const reco::RecobClusterParameters& clusParams = clusParametersPair.second;
1475 
1476  // Protect against a missing view
1477  if (clusParams.m_view == geo::kUnknown) continue;
1478 
1479  // Get a vector of hit pointers to seed the cluster algorithm
1480  std::vector<const recob::Hit*> recobHitVec(clusParams.m_hitVector.size());
1481 
1482  std::transform(clusParams.m_hitVector.begin(),
1483  clusParams.m_hitVector.end(),
1484  recobHitVec.begin(),
1485  [](const auto& hit2D) { return hit2D->getHit(); });
1486 
1487  // Get the tdc/wire slope... from the unit vector...
1488  double startWire(clusParams.m_startWire);
1489  double endWire(clusParams.m_endWire);
1490  double startTime(clusParams.m_startTime);
1491  double endTime(clusParams.m_endTime);
1492 
1493  // feed the algorithm with all the cluster hits
1494  ClusterParamAlgo.ImportHits(gser, recobHitVec);
1495 
1496  // create the recob::Cluster directly in the vector
1497  cluster::ClusterCreator artCluster(gser,
1498  ClusterParamAlgo, // algo
1499  startWire, // start_wire
1500  0., // sigma_start_wire
1501  startTime, // start_tick
1502  clusParams.m_sigmaStartTime, // sigma_start_tick
1503  endWire, // end_wire
1504  0., // sigma_end_wire,
1505  endTime, // end_tick
1506  clusParams.m_sigmaEndTime, // sigma_end_tick
1507  output.artClusterVector->size(), // ID
1508  clusParams.m_view, // view
1509  clusParams.m_plane, // plane
1510  recob::Cluster::Sentry // sentry
1511  );
1512 
1513  output.artClusterVector->emplace_back(artCluster.move());
1514 
1515  // We love looping. In this case, our list of hits is comprised of "ClusterHits" and we need to get a RecobHitVector instead...
1516  RecobHitVector recobHits;
1517 
1518  for (const auto& hit2D : clusParams.m_hitVector) {
1519  if (hit2D == nullptr || hit2D->getHit() == nullptr) continue;
1520 
1521  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit2D->getHit()];
1522  recobHits.push_back(hitPtr);
1523  }
1524 
1525  output.makeClusterHitAssns(recobHits);
1526  }
1527 
1528  // Last, let's try to get seeds for tracking..
1529  // Keep track of how many we have so far
1530  size_t numSeedsStart = output.artSeedVector->size();
1531 
1532  // Empty daughter vector for now
1533  std::vector<size_t> nullVector;
1534  size_t pfParticleIdx(output.artPFParticleVector->size());
1535 
1536  recob::PFParticle pfParticle(13, pfParticleIdx, pfParticleParent, nullVector);
1537  output.artPFParticleVector->push_back(pfParticle);
1538 
1539  // 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
1540  // If there is no best list then assume the convex hull is from all of the points...
1541  std::string instance("");
1542  reco::HitPairListPtr* hit3DListPtr = &clusterParameters.getHitPairListPtr();
1543  Hit3DToSPPtrMap* hit3DToPtrMap = &hit3DToSPPtrMap;
1544 
1545  auto spVector = output.artSpacePointVector.get();
1546  auto edgeVector = output.artEdgeVector.get();
1547  auto pfPartEdgeAssns = output.artPFPartEdgeAssociations.get();
1548  auto spEdgeAssns = output.artEdgeSPAssociations.get();
1549  auto spHitAssns = output.artSPHitAssociations.get();
1550  auto pfPartSPAssns = output.artPFPartSPAssociations.get();
1551 
1552  // Make associations to all space points for this cluster
1553  int spacePointStart = spVector->size();
1554 
1556  output, *spVector, *spHitAssns, *hit3DListPtr, hitToPtrMap, *hit3DToPtrMap);
1557 
1558  // And make sure to have associations to the PFParticle
1559  output.makePFPartSpacePointAssns(*spVector, *pfPartSPAssns, spacePointStart);
1560 
1561  // If they exist, make space points for the Path points
1562  if (!clusterParameters.getBestHitPairListPtr().empty()) {
1563  instance = m_pathInstance;
1564  hit3DListPtr = &clusterParameters.getBestHitPairListPtr();
1565  hit3DToPtrMap = &best3DToSPPtrMap;
1566 
1567  spVector = output.artPathPointVector.get();
1568  edgeVector = output.artPathEdgeVector.get();
1569  pfPartEdgeAssns = output.artPFPartPathEdgeAssociations.get();
1570  spEdgeAssns = output.artEdgePPAssociations.get();
1571  spHitAssns = output.artPPHitAssociations.get();
1572  pfPartSPAssns = output.artPFPartPPAssociations.get();
1573 
1574  spacePointStart = spVector->size();
1575 
1577  output, *spVector, *spHitAssns, *hit3DListPtr, hitToPtrMap, *hit3DToPtrMap, instance);
1578 
1579  // And make sure to have associations to the PFParticle
1580  output.makePFPartSpacePointAssns(*spVector, *pfPartSPAssns, spacePointStart, instance);
1581  }
1582 
1583  // Now handle the edges according to whether associated with regular or "best" space points
1584  if (!clusterParameters.getBestEdgeList().empty()) {
1585  size_t edgeStart = edgeVector->size();
1586 
1587  for (const auto& edge : clusterParameters.getBestEdgeList()) {
1588  RecobSpacePointVector spacePointVec;
1589 
1590  try {
1591  spacePointVec.push_back(hit3DToPtrMap->at(std::get<0>(edge)));
1592  spacePointVec.push_back(hit3DToPtrMap->at(std::get<1>(edge)));
1593  }
1594  catch (...) {
1595  std::cout << "Caught exception in looking up space point ptr... " << std::get<0>(edge)
1596  << ", " << std::get<1>(edge) << std::endl;
1597  continue;
1598  }
1599 
1600  edgeVector->emplace_back(
1601  std::get<2>(edge), spacePointVec[0].key(), spacePointVec[1].key(), edgeVector->size());
1602 
1603  output.makeEdgeSpacePointAssns(*edgeVector, spacePointVec, *spEdgeAssns, instance);
1604  }
1605 
1606  output.makePFPartEdgeAssns(*edgeVector, *pfPartEdgeAssns, edgeStart, instance);
1607  }
1608 
1609  // Look at making the PCAxis and associations - for both the skeleton (the first) and the full
1610  // First need some float to double conversion containers
1611  recob::PCAxis::EigenVectors eigenVecs;
1612  double eigenVals[] = {0., 0., 0.};
1613  double avePosition[] = {0., 0., 0.};
1614 
1615  eigenVecs.resize(3);
1616 
1617  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1618  avePosition[outerIdx] = skeletonPCA.getAvePosition()[outerIdx];
1619  eigenVals[outerIdx] = skeletonPCA.getEigenValues()[outerIdx];
1620 
1621  eigenVecs[outerIdx].resize(3);
1622 
1623  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1624  eigenVecs[outerIdx][innerIdx] = skeletonPCA.getEigenVectors().row(outerIdx)(innerIdx);
1625  }
1626 
1627  recob::PCAxis skelPcAxis(skeletonPCA.getSvdOK(),
1628  skeletonPCA.getNumHitsUsed(),
1629  eigenVals,
1630  eigenVecs,
1631  avePosition,
1632  skeletonPCA.getAveHitDoca(),
1633  output.artPCAxisVector->size());
1634 
1635  output.artPCAxisVector->push_back(skelPcAxis);
1636 
1637  for (size_t outerIdx = 0; outerIdx < 3; outerIdx++) {
1638  avePosition[outerIdx] = fullPCA.getAvePosition()[outerIdx];
1639  eigenVals[outerIdx] = fullPCA.getEigenValues()[outerIdx];
1640 
1641  for (size_t innerIdx = 0; innerIdx < 3; innerIdx++)
1642  eigenVecs[outerIdx][innerIdx] = fullPCA.getEigenVectors().row(outerIdx)(innerIdx);
1643  }
1644 
1645  recob::PCAxis fullPcAxis(fullPCA.getSvdOK(),
1646  fullPCA.getNumHitsUsed(),
1647  eigenVals, //fullPCA.getEigenValues(),
1648  eigenVecs, //fullPCA.getEigenVectors(),
1649  avePosition, //fullPCA.getAvePosition(),
1650  fullPCA.getAveHitDoca(),
1651  output.artPCAxisVector->size());
1652 
1653  output.artPCAxisVector->push_back(fullPcAxis);
1654 
1655  // Create associations to the PFParticle
1656  output.makePFPartPCAAssns();
1657  output.makePFPartSeedAssns(numSeedsStart);
1658  output.makePFPartClusterAssns(clusterStart);
1659 
1660  return pfParticleIdx;
1661  }
1662 
1663  void
1665  std::vector<recob::SpacePoint>& spacePointVec,
1666  art::Assns<recob::Hit, recob::SpacePoint>& spHitAssns,
1667  reco::HitPairListPtr& clusHitPairVector,
1668  IHit3DBuilder::RecobHitToPtrMap& hitToPtrMap,
1669  Hit3DToSPPtrMap& hit3DToSPPtrMap,
1670  const std::string& instance) const
1671  {
1672  // Reserve space...
1673  spacePointVec.reserve(spacePointVec.size() + clusHitPairVector.size());
1674 
1675  // Right now error matrix is uniform...
1676  double spError[] = {1., 0., 1., 0., 0., 1.};
1677 
1678  // Copy these hits to the vector to be stored with the event
1679  for (auto& hitPair : clusHitPairVector) {
1680  // Skip those space points that have already been created
1681  if (hit3DToSPPtrMap.find(hitPair) != hit3DToSPPtrMap.end()) continue;
1682 
1683  // Don't make space point if this hit was "rejected"
1684  if (hitPair->bitsAreSet(reco::ClusterHit3D::REJECTEDHIT)) continue;
1685 
1686  double chisq = hitPair->getHitChiSquare(); // secret handshake...
1687 
1688  // Mark this hit pair as in use
1689  hitPair->setStatusBit(reco::ClusterHit3D::MADESPACEPOINT);
1690 
1691  // Create and store the space point
1692  size_t spacePointID = spacePointVec.size();
1693  double spacePointPos[] = {
1694  hitPair->getPosition()[0], hitPair->getPosition()[1], hitPair->getPosition()[2]};
1695 
1696  spError[1] = hitPair->getTotalCharge();
1697  spError[3] = hitPair->getChargeAsymmetry();
1698 
1699  spacePointVec.emplace_back(spacePointPos, spError, chisq, spacePointID);
1700 
1701  // Update mapping
1702  hit3DToSPPtrMap[hitPair] = output.makeSpacePointPtr(spacePointID, instance);
1703 
1704  // space point hits associations
1705  RecobHitVector recobHits;
1706 
1707  for (const auto& hit : hitPair->getHits()) {
1708  if (!hit) continue;
1709 
1710  art::Ptr<recob::Hit> hitPtr = hitToPtrMap[hit->getHit()];
1711  recobHits.push_back(hitPtr);
1712  }
1713 
1714  if (!recobHits.empty())
1715  output.makeSpacePointHitAssns(spacePointVec, recobHits, spHitAssns, instance);
1716  }
1717 
1718  return;
1719  }
1720 
1721  void
1723  reco::ConvexHullKinkTupleList& kinkTupleVec) const
1724  {
1725  // Right now error matrix is uniform...
1726  double spError[] = {1., 0., 1., 0., 0., 1.};
1727 
1728  // Copy these hits to the vector to be stored with the event
1729  for (auto& kinkTuple : kinkTupleVec) {
1730  const reco::ClusterHit3D* hit = std::get<2>(std::get<0>(kinkTuple));
1731 
1732  double chisq = hit->getHitChiSquare(); // secret handshake...
1733 
1734  // Create and store the space point
1735  double spacePointPos[] = {
1736  hit->getPosition()[0], hit->getPosition()[1], hit->getPosition()[2]};
1737 
1738  spError[1] = hit->getTotalCharge();
1739  spError[3] = hit->getChargeAsymmetry();
1740 
1741  output.artExtremePointVector->push_back(
1742  recob::SpacePoint(spacePointPos, spError, chisq, output.artExtremePointVector->size()));
1743  }
1744 
1745  return;
1746  }
1747 
1748  void
1750  dcel2d::VertexList& vertexList,
1751  dcel2d::HalfEdgeList& halfEdgeList) const
1752  {
1753  // We actually do two things here:
1754  // 1) Create space points to represent the vertex locations of the voronoi diagram
1755  // 2) Create the edges that link the space points together
1756 
1757  // Set up the space point creation
1758  // Right now error matrix is uniform...
1759  double spError[] = {1., 0., 1., 0., 0., 1.};
1760  double chisq = 1.;
1761 
1762  // Keep track of the vertex to space point association
1763  std::map<const dcel2d::Vertex*, size_t> vertexToSpacePointMap;
1764 
1765  // Copy these hits to the vector to be stored with the event
1766  for (auto& vertex : vertexList) {
1767  const dcel2d::Coords& coords = vertex.getCoords();
1768 
1769  // Create and store the space point
1770  double spacePointPos[] = {coords[0], coords[1], coords[2]};
1771 
1772  vertexToSpacePointMap[&vertex] = output.artVertexPointVector->size();
1773 
1774  output.artVertexPointVector->emplace_back(
1775  spacePointPos, spError, chisq, output.artVertexPointVector->size());
1776  }
1777 
1778  // Try to avoid double counting
1779  std::set<const dcel2d::HalfEdge*> halfEdgeSet;
1780 
1781  // Build the edges now
1782  for (const auto& halfEdge : halfEdgeList) {
1783  // Recover twin
1784  const dcel2d::HalfEdge* twin = halfEdge.getTwinHalfEdge();
1785 
1786  // It can happen that we have no twin... and also check that we've not been here before
1787  if (twin && halfEdgeSet.find(twin) == halfEdgeSet.end()) {
1788  // Recover the vertices
1789  const dcel2d::Vertex* fromVertex = twin->getTargetVertex();
1790  const dcel2d::Vertex* toVertex = halfEdge.getTargetVertex();
1791 
1792  // It can happen for the open edges that there is no target vertex
1793  if (!toVertex || !fromVertex) continue;
1794 
1795  if (vertexToSpacePointMap.find(fromVertex) == vertexToSpacePointMap.end() ||
1796  vertexToSpacePointMap.find(toVertex) == vertexToSpacePointMap.end())
1797  continue;
1798 
1799  // Need the distance between vertices
1800  Eigen::Vector3f distVec = toVertex->getCoords() - fromVertex->getCoords();
1801 
1802  output.artVertexEdgeVector->emplace_back(distVec.norm(),
1803  vertexToSpacePointMap[fromVertex],
1804  vertexToSpacePointMap[toVertex],
1805  output.artEdgeVector->size());
1806 
1807  halfEdgeSet.insert(&halfEdge);
1808  }
1809  }
1810 
1811  return;
1812  }
1813 
1814  void
1816  const reco::PrincipalComponents& fullPCA,
1817  IdxToPCAMap& idxToPCAMap) const
1818  {
1819  // We actually do two things here:
1820  // 1) Create space points from the centroids of the PCA for each cluster
1821  // 2) Create the edges that link the space points together
1822 
1823  // The first task is to put the list of PCA's into some semblance of order... they may be
1824  // preordered by likely they are piecewise ordered so fix that here
1825 
1826  // We'll need the current PCA axis to determine doca and arclen
1827  Eigen::Vector3f avePosition(
1828  fullPCA.getAvePosition()[0], fullPCA.getAvePosition()[1], fullPCA.getAvePosition()[2]);
1829  Eigen::Vector3f axisDirVec(fullPCA.getEigenVectors().row(2));
1830 
1831  using DocaToPCAPair = std::pair<float, const reco::PrincipalComponents*>;
1832  using DocaToPCAVec = std::vector<DocaToPCAPair>;
1833 
1834  DocaToPCAVec docaToPCAVec;
1835 
1836  // Outer loop over views
1837  for (const auto& idxToPCA : idxToPCAMap) {
1838  const reco::PrincipalComponents* pca = idxToPCA.second;
1839 
1840  // Now we need to calculate the doca and poca...
1841  // Start by getting this hits position
1842  Eigen::Vector3f pcaPos(
1843  pca->getAvePosition()[0], pca->getAvePosition()[1], pca->getAvePosition()[2]);
1844 
1845  // Form a TVector from this to the cluster average position
1846  Eigen::Vector3f pcaToAveVec = pcaPos - avePosition;
1847 
1848  // With this we can get the arclength to the doca point
1849  float arclenToPoca = pcaToAveVec.dot(axisDirVec);
1850 
1851  docaToPCAVec.emplace_back(arclenToPoca, pca);
1852  }
1853 
1854  std::sort(docaToPCAVec.begin(), docaToPCAVec.end(), [](const auto& left, const auto& right) {
1855  return left.first < right.first;
1856  });
1857 
1858  // Set up the space point creation
1859  // Right now error matrix is uniform...
1860  double spError[] = {1., 0., 1., 0., 0., 1.};
1861  double chisq = 1.;
1862 
1863  const reco::PrincipalComponents* lastPCA(nullptr);
1864 
1865  // Set up to loop through the clusters
1866  for (const auto& docaToPCAPair : docaToPCAVec) {
1867  // Recover the PCA for this cluster
1868  const reco::PrincipalComponents* curPCA = docaToPCAPair.second;
1869 
1870  if (lastPCA) {
1871  double lastPointPos[] = {
1872  lastPCA->getAvePosition()[0], lastPCA->getAvePosition()[1], lastPCA->getAvePosition()[2]};
1873  size_t lastPointBin = output.artVertexPointVector->size();
1874  double curPointPos[] = {
1875  curPCA->getAvePosition()[0], curPCA->getAvePosition()[1], curPCA->getAvePosition()[2]};
1876  size_t curPointBin = lastPointBin + 1;
1877 
1878  output.artVertexPointVector->emplace_back(lastPointPos, spError, chisq, lastPointBin);
1879  output.artVertexPointVector->emplace_back(curPointPos, spError, chisq, curPointBin);
1880 
1881  Eigen::Vector3f distVec(curPointPos[0] - lastPointPos[0],
1882  curPointPos[1] - lastPointPos[1],
1883  curPointPos[2] - lastPointPos[2]);
1884 
1885  output.artVertexEdgeVector->emplace_back(
1886  distVec.norm(), lastPointBin, curPointBin, output.artEdgeVector->size());
1887  }
1888 
1889  lastPCA = curPCA;
1890  }
1891  }
1892 
1893 } // namespace lar_Cluster3DICARUS
process_name vertex
Definition: cheaterreco.fcl:51
Definition of the Cluster3D class.
reco::HitPairListPtr & getBestHitPairListPtr()
Definition: Cluster3D.h:479
float m_artHitsTime
Keeps track of time to recover hits.
HoughSeedFinderAlg m_seedFinderAlg
Seed finder.
std::string m_extremeInstance
Instance name for the extreme points.
std::unique_ptr< art::Assns< recob::Edge, recob::PFParticle > > artPFPartPathEdgeAssociations
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
std::list< reco::ClusterHit3D > HitPairList
Definition: Cluster3D.h:338
bool getSvdOK() const
Definition: Cluster3D.h:243
Utilities related to art service access.
An object to define a &quot;edge&quot; 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< art::Assns< recob::Hit, recob::SpacePoint > > artPPHitAssociations
std::unique_ptr< art::Assns< recob::PFParticle, recob::Seed > > artPFPartSeedAssociations
std::string m_vertexInstance
Special instance name for vertex points.
std::unique_ptr< std::vector< recob::Edge > > artPathEdgeVector
static constexpr Sample_t transform(Sample_t sample)
void makePFPartSpacePointAssns(std::vector< recob::SpacePoint > &spacePointVector, art::Assns< recob::SpacePoint, recob::PFParticle > &pfPartSPAssociations, size_t spacePointStart, const std::string &instance="")
process_name cluster
Definition: cheaterreco.fcl:51
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:61
std::list< HalfEdge > HalfEdgeList
Definition: DCEL.h:184
int m_hits
Keeps track of the number of hits seen.
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:157
void makeEdgeSpacePointAssns(std::vector< recob::Edge > &edgeVector, RecobSpacePointVector &spacePointVector, art::Assns< recob::SpacePoint, recob::Edge > &edgeSPAssociations, const std::string &path="")
HalfEdge * getTwinHalfEdge() const
Definition: DCEL.h:163
Unknown view.
Definition: geo_types.h:136
std::unique_ptr< std::vector< recob::SpacePoint > > artExtremePointVector
std::unique_ptr< std::vector< recob::PFParticle > > artPFParticleVector
Cluster3D class.
Definition: SkeletonAlg.h:27
Declaration of signal hit object.
float m_parallelHitsTransWid
Cut on transverse width of cluster (PCA 2nd eigenvalue)
walls no right
Definition: selectors.fcl:105
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:477
void clearStatusBits(unsigned bits) const
Definition: Cluster3D.h:180
void produce(art::Event &evt) override
bool m_enableMonitoring
Turn on monitoring of this algorithm.
std::unique_ptr< art::Assns< recob::PFParticle, recob::PCAxis > > artPFPartAxisAssociations
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.
const std::string instance
std::unique_ptr< art::Assns< recob::Seed, recob::Hit > > artSeedHitAssociations
float getTotalCharge() const
Definition: Cluster3D.h:161
Hit has been rejected for any reason.
Definition: Cluster3D.h:98
reco::EdgeList & getBestEdgeList()
Definition: Cluster3D.h:480
int getNumHitsUsed() const
Definition: Cluster3D.h:244
HoughSeedFinderAlg class.
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.
std::unique_ptr< lar_cluster3d::IClusterAlg > m_clusterAlg
Algorithm to do 3D space point clustering.
std::list< HitPairListPtr > HitPairListPtrList
Definition: Cluster3D.h:336
A utility class used in construction of 3D clusters.
Definition: Cluster3D.h:299
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:475
float m_pathFindingTime
Keeps track of the path finding time.
process_name hit
Definition: cheaterreco.fcl:51
reco::PlaneToClusterParamsMap & getClusterParams()
Definition: Cluster3D.h:473
void GetSkeletonHits(const reco::HitPairListPtr &inputHitList, reco::HitPairListPtr &skeletonHitList) const
Return the skeleton hits from the input list.
void MakeAndSaveVertexPoints(ArtOutputHandler &, dcel2d::VertexList &, dcel2d::HalfEdgeList &) const
Special routine to handle creating and saving space points &amp; edges associated to voronoi diagrams...
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.
This is an algorithm for finding recob::Seed objects in 3D clusters.
float getDocaToAxis() const
Definition: Cluster3D.h:168
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:182
int m_hits3D
Keeps track of the number of 3D hits made.
Hit has been used in Cluster Splitting MST.
Definition: Cluster3D.h:111
void ImportHits(util::GeometryUtilities const &gser, Iter begin, Iter end)
Calls SetHits() with the hits in the sequence.
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.
art::Ptr< recob::Edge > makeEdgePtr(size_t index, const std::string &instance="")
PCASeedFinderAlg m_pcaSeedFinderAlg
Use PCA axis to find seeds.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
ClusterParametersList & daughterList()
Definition: Cluster3D.h:449
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
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.
size_t countUltimateDaughters(reco::ClusterParameters &clusterParameters) const
Count number of end of line daughters.
Overrides another ClusterParamsAlgBase class with selected constants.
This is an algorithm for finding recob::Seed objects in 3D clusters.
std::unique_ptr< lar_cluster3d::IClusterModAlg > m_clusterPathAlg
Algorithm to do cluster path finding.
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:245
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:476
float getChargeAsymmetry() const
Definition: Cluster3D.h:167
art::PtrVector< recob::Hit > RecobHitVector
SkeletonAlg m_skeletonAlg
Skeleton point finder.
This is an algorithm for finding recob::Seed objects in 3D clusters.
PrincipalComponentsAlg m_pcaAlg
Principal Components algorithm.
void InitializeMonitoring()
Initialize the internal monitoring.
std::string m_pathInstance
Special instance for path points.
std::unique_ptr< art::Assns< recob::PFParticle, recob::Cluster > > artPFPartClusAssociations
std::unique_ptr< lar_cluster3d::IClusterModAlg > m_clusterMergeAlg
Algorithm to do cluster merging.
std::unique_ptr< art::Assns< recob::Cluster, recob::Hit > > artClusterAssociations
void makeSpacePointHitAssns(std::vector< recob::SpacePoint > &spacePointVector, RecobHitVector &recobHits, art::Assns< recob::Hit, recob::SpacePoint > &spHitAssns, const std::string &path="")
Helper functions to create a cluster.
Wrapper for ClusterParamsAlgBase objects to accept diverse input.
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:247
std::unique_ptr< std::vector< recob::SpacePoint > > artPathPointVector
std::list< ConvexHullKinkTuple > ConvexHullKinkTupleList
Definition: Cluster3D.h:354
ParallelHitsSeedFinderAlg m_parallelHitsAlg
Deal with parallel hits clusters.
void AverageSkeletonPositions(reco::HitPairListPtr &skeletonHitList) const
Modifies the position of input skeleton hits by averaging along the &quot;best&quot; wire direction.
Cluster3DICARUS(fhicl::ParameterSet const &pset)
Wrapper for ClusterParamsAlgBase objects to accept arbitrary input.
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::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:334
walls no left
Definition: selectors.fcl:105
This provides an art tool interface definition for 3D Cluster algorithms.
std::unique_ptr< std::vector< recob::Edge > > artEdgeVector
void makePFPartEdgeAssns(std::vector< recob::Edge > &edgeVector, art::Assns< recob::Edge, recob::PFParticle > &pfPartEdgeAssociations, size_t edgeStart, const std::string &instance="")
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Edge > > artEdgeSPAssociations
Declaration of cluster object.
bool operator()(const std::pair< float, const reco::ClusterHit3D * > &left, const std::pair< float, const reco::ClusterHit3D * > &right)
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::Edge, recob::PFParticle > > artPFPartEdgeAssociations
std::unique_ptr< std::vector< recob::SpacePoint > > artVertexPointVector
std::unique_ptr< art::Assns< recob::SpacePoint, recob::PFParticle > > artPFPartSPAssociations
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
ArtOutputHandler(art::Event &evt, std::string &pathName, std::string &vertexName, std::string &extremeName)
std::unique_ptr< art::Assns< recob::Hit, recob::SpacePoint > > artSPHitAssociations
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
bool bitsAreSet(const unsigned int &bitsToCheck) const
Definition: Cluster3D.h:176
void splitClustersWithHough(reco::ClusterParameters &clusterParameters, reco::ClusterParametersList &clusterParametersList) const
Attempt to split clusters using the output of the Hough Filter.
bool aParallelHitsCluster(const reco::PrincipalComponents &pca) const
There are several places we will want to know if a candidate cluster is a &quot;parallel hits&quot; type of clu...
const float getAveHitDoca() const
Definition: Cluster3D.h:248
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.
Header file to define the interface to the SkeletonAlg.
std::unique_ptr< std::vector< recob::SpacePoint > > artSpacePointVector
Hit has been made into Space Point.
Definition: Cluster3D.h:102
std::vector< SeedHitPairListPair > SeedHitPairListPairVec
This provides an art tool interface definition for 3D Cluster algorithms.
BEGIN_PROLOG sequence::SlidingWindowTriggerPatternsOppositeWindows END_PROLOG simSlidingORM6O6 effSlidingORW output
float m_buildNeighborhoodTime
Keeps track of time to build epsilon neighborhood.
void splitClustersWithMST(reco::ClusterParameters &clusterParameters, reco::ClusterParametersList &clusterParametersList) const
Attempt to split clusters by using a minimum spanning tree.
std::unique_ptr< std::vector< recob::Edge > > artVertexEdgeVector
std::unique_ptr< std::vector< recob::Cluster > > artClusterVector
float m_parallelHitsCosAng
Cut for PCA 3rd axis angle to X axis.
float m_totalTime
Keeps track of total execution time.
std::unique_ptr< lar_cluster3d::IClusterParametersBuilder > m_clusterBuilder
Common cluster builder tool.
T copy(T const &v)
float m_clusterMergeTime
Keeps track of the time to merge clusters.
std::unordered_map< const reco::ClusterHit2D *, ClusterToHitPairSetMap > Hit2DToClusterMap
Definition: Cluster3D.h:510
bool m_onlyMakSpacePoints
If true we don&#39;t do the full cluster 3D processing.
std::unique_ptr< lar_cluster3d::IHit3DBuilder > m_hit3DBuilderAlg
Builds the 3D hits to operate on.
ClusterHit2DVec m_hitVector
Definition: Cluster3D.h:326
float m_dbscanTime
Keeps track of time to run DBScan.
float m_finishTime
Keeps track of time to run output module.
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
art::ServiceHandle< art::TFileService > tfs
Algorithm collection class computing cluster parameters.
float getHitChiSquare() const
Definition: Cluster3D.h:165
Interface to class computing cluster parameters.
TCEvent evt
Definition: DataStructs.cxx:8
Vertex * getTargetVertex() const
Definition: DCEL.h:161
Eigen::Vector3f Coords
Definition: DCEL.h:46
std::unordered_map< const reco::ClusterHit3D *, art::Ptr< recob::SpacePoint >> Hit3DToSPPtrMap
PCASeedFinderAlg class.
std::vector< std::vector< double > > EigenVectors
Definition: PCAxis.h:29
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
float m_makeHitsTime
Keeps track of time to build 3D hits.
void MakeAndSavePCAPoints(ArtOutputHandler &, const reco::PrincipalComponents &, IdxToPCAMap &) const
std::unique_ptr< art::Assns< recob::SpacePoint, recob::PFParticle > > artPFPartPPAssociations
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Edge > > artEdgePPAssociations
std::unordered_map< const recob::Hit *, art::Ptr< recob::Hit >> RecobHitToPtrMap
Defines a structure mapping art representation to internal.
Definition: IHit3DBuilder.h:62
const Coords & getCoords() const
Definition: DCEL.h:69
std::list< Vertex > VertexList
Definition: DCEL.h:182
std::map< size_t, const reco::PrincipalComponents * > IdxToPCAMap
Special routine to handle creating and saving space points &amp; edges PCA points.
art::Ptr< recob::SpacePoint > makeSpacePointPtr(size_t index, const std::string &instance="")
art framework interface to geometry description
BEGIN_PROLOG could also be cout
auto const detProp
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:403
void MakeAndSaveKinkPoints(ArtOutputHandler &output, reco::ConvexHullKinkTupleList &clusHitPairVector) const
Special routine to handle creating and saving space points.
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:246
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 PrepareEvent(const art::Event &evt)
Event Preparation.
std::unique_ptr< std::vector< recob::PCAxis > > artPCAxisVector
std::unique_ptr< std::vector< recob::Seed > > artSeedVector
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:179
art::PtrVector< recob::SpacePoint > RecobSpacePointVector