All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LArPandoraOutput.cxx
Go to the documentation of this file.
1 /**
2  * @file larpandora/LArPandoraInterface/LArPandoraOutput.cxx
3  *
4  * @brief Helper functions for processing outputs from pandora
5  *
6  */
8 
9 #include "art/Framework/Principal/Event.h"
10 #include "cetlib_except/exception.h"
11 #include "messagefacility/MessageLogger/MessageLogger.h"
12 
18 
23 
24 #include "Objects/CaloHit.h"
25 #include "Objects/Cluster.h"
26 #include "Objects/ParticleFlowObject.h"
27 #include "Objects/Vertex.h"
28 
32 
33 #include <algorithm>
34 #include <iostream>
35 #include <iterator>
36 #include <limits>
37 #include <numeric> // std::iota()
38 
39 namespace lar_pandora {
40 
41  void
43  const IdToHitMap& idToHitMap,
44  art::Event& evt)
45  {
46  settings.Validate();
47  const std::string instanceLabel(
49  const std::string testBeamInteractionVertexInstanceLabel(
50  instanceLabel + settings.m_testBeamInteractionVerticesInstanceLabel);
51 
52  // Set up mandatory output collections
53  PFParticleCollection outputParticles(new std::vector<recob::PFParticle>);
54  VertexCollection outputVertices(new std::vector<recob::Vertex>);
55  ClusterCollection outputClusters(new std::vector<recob::Cluster>);
56  SpacePointCollection outputSpacePoints(new std::vector<recob::SpacePoint>);
57  PFParticleMetadataCollection outputParticleMetadata(
58  new std::vector<larpandoraobj::PFParticleMetadata>);
59 
60  // Set up optional output collections
61  VertexCollection outputTestBeamInteractionVertices(
62  settings.m_shouldProduceTestBeamInteractionVertices ? new std::vector<recob::Vertex> :
63  nullptr);
64  T0Collection outputT0s(settings.m_shouldRunStitching ? new std::vector<anab::T0> : nullptr);
65  SliceCollection outputSlices(settings.m_shouldProduceSlices ? new std::vector<recob::Slice> :
66  nullptr);
67 
68  // Set up mandatory output associations
69  PFParticleToMetadataCollection outputParticlesToMetadata(
70  new art::Assns<recob::PFParticle, larpandoraobj::PFParticleMetadata>);
71  PFParticleToSpacePointCollection outputParticlesToSpacePoints(
72  new art::Assns<recob::PFParticle, recob::SpacePoint>);
73  PFParticleToClusterCollection outputParticlesToClusters(
74  new art::Assns<recob::PFParticle, recob::Cluster>);
75  PFParticleToVertexCollection outputParticlesToVertices(
76  new art::Assns<recob::PFParticle, recob::Vertex>);
77  ClusterToHitCollection outputClustersToHits(new art::Assns<recob::Cluster, recob::Hit>);
78  SpacePointToHitCollection outputSpacePointsToHits(
79  new art::Assns<recob::SpacePoint, recob::Hit>);
80  SliceToHitCollection outputSlicesToHits(new art::Assns<recob::Slice, recob::Hit>);
81 
82  // Set up optional output associations
83  PFParticleToVertexCollection outputParticlesToTestBeamInteractionVertices(
85  new art::Assns<recob::PFParticle, recob::Vertex> :
86  nullptr);
87  PFParticleToT0Collection outputParticlesToT0s(
88  settings.m_shouldRunStitching ? new art::Assns<recob::PFParticle, anab::T0> : nullptr);
89  PFParticleToSliceCollection outputParticlesToSlices(
90  settings.m_shouldProduceSlices ? new art::Assns<recob::PFParticle, recob::Slice> : nullptr);
91 
92  // Collect immutable lists of pandora collections that we should convert to ART format
93  const pandora::PfoVector pfoVector(
97 
98  IdToIdVectorMap pfoToVerticesMap, pfoToTestBeamInteractionVerticesMap;
100  pfoVector, pfoToVerticesMap, lar_content::LArPfoHelper::GetVertex));
101  const pandora::VertexVector testBeamInteractionVertexVector(
104  pfoToTestBeamInteractionVerticesMap,
107 
108  IdToIdVectorMap pfoToClustersMap;
109  const pandora::ClusterList clusterList(
110  LArPandoraOutput::CollectClusters(pfoVector, pfoToClustersMap));
111 
112  IdToIdVectorMap pfoToThreeDHitsMap;
113  const pandora::CaloHitList threeDHitList(
114  LArPandoraOutput::Collect3DHits(pfoVector, pfoToThreeDHitsMap));
115 
116  // Get mapping from pandora hits to art hits
117  CaloHitToArtHitMap pandoraHitToArtHitMap;
119  clusterList, threeDHitList, idToHitMap, pandoraHitToArtHitMap);
120 
121  // Build the ART outputs from the pandora objects
122  LArPandoraOutput::BuildVertices(vertexVector, outputVertices);
123 
125  LArPandoraOutput::BuildVertices(testBeamInteractionVertexVector,
126  outputTestBeamInteractionVertices);
127 
129  instanceLabel,
130  threeDHitList,
131  pandoraHitToArtHitMap,
132  outputSpacePoints,
133  outputSpacePointsToHits);
134 
135  IdToIdVectorMap pfoToArtClustersMap;
137  instanceLabel,
138  clusterList,
139  pandoraHitToArtHitMap,
140  pfoToClustersMap,
141  outputClusters,
142  outputClustersToHits,
143  pfoToArtClustersMap);
144 
146  instanceLabel,
147  pfoVector,
148  pfoToVerticesMap,
149  pfoToThreeDHitsMap,
150  pfoToArtClustersMap,
151  outputParticles,
152  outputParticlesToVertices,
153  outputParticlesToSpacePoints,
154  outputParticlesToClusters);
155 
157  evt, instanceLabel, pfoVector, outputParticleMetadata, outputParticlesToMetadata);
158 
159  if (settings.m_shouldProduceSlices)
161  settings.m_pPrimaryPandora,
162  evt,
163  instanceLabel,
164  pfoVector,
165  idToHitMap,
166  outputSlices,
167  outputParticlesToSlices,
168  outputSlicesToHits);
169 
170  if (settings.m_shouldRunStitching)
171  LArPandoraOutput::BuildT0s(evt, instanceLabel, pfoVector, outputT0s, outputParticlesToT0s);
172 
175  instanceLabel,
176  pfoVector,
177  pfoToTestBeamInteractionVerticesMap,
178  outputParticlesToTestBeamInteractionVertices);
179 
180  // Add the outputs to the event
181  evt.put(std::move(outputParticles), instanceLabel);
182  evt.put(std::move(outputSpacePoints), instanceLabel);
183  evt.put(std::move(outputClusters), instanceLabel);
184  evt.put(std::move(outputVertices), instanceLabel);
185  evt.put(std::move(outputParticleMetadata), instanceLabel);
186 
187  evt.put(std::move(outputParticlesToMetadata), instanceLabel);
188  evt.put(std::move(outputParticlesToSpacePoints), instanceLabel);
189  evt.put(std::move(outputParticlesToClusters), instanceLabel);
190  evt.put(std::move(outputParticlesToVertices), instanceLabel);
191  evt.put(std::move(outputParticlesToSlices), instanceLabel);
192  evt.put(std::move(outputSpacePointsToHits), instanceLabel);
193  evt.put(std::move(outputClustersToHits), instanceLabel);
194 
196  evt.put(std::move(outputTestBeamInteractionVertices), testBeamInteractionVertexInstanceLabel);
197  evt.put(std::move(outputParticlesToTestBeamInteractionVertices),
198  testBeamInteractionVertexInstanceLabel);
199  }
200 
201  if (settings.m_shouldRunStitching) {
202  evt.put(std::move(outputT0s), instanceLabel);
203  evt.put(std::move(outputParticlesToT0s), instanceLabel);
204  }
205 
206  if (settings.m_shouldProduceSlices) {
207  evt.put(std::move(outputSlices), instanceLabel);
208  evt.put(std::move(outputSlicesToHits), instanceLabel);
209  }
210  }
211 
212  //------------------------------------------------------------------------------------------------------------------------------------------
213 
214  bool
215  LArPandoraOutput::GetPandoraInstance(const pandora::Pandora* const pPrimaryPandora,
216  const std::string& name,
217  const pandora::Pandora*& pPandoraInstance)
218  {
219  if (!pPrimaryPandora)
220  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- input "
221  "primary pandora instance address is invalid ";
222 
223  if (pPandoraInstance)
224  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- the input "
225  "pandora instance address is non-null ";
226 
227  for (const pandora::Pandora* const pPandora :
229  if (pPandora->GetName() != name) continue;
230 
231  if (pPandoraInstance)
232  throw cet::exception("LArPandora")
233  << " LArPandoraOutput::GetPandoraInstance--- found multiple pandora instances with name: "
234  << name;
235 
236  pPandoraInstance = pPandora;
237  }
238 
239  return static_cast<bool>(pPandoraInstance);
240  }
241 
242  //------------------------------------------------------------------------------------------------------------------------------------------
243 
244  void
245  LArPandoraOutput::GetPandoraSlices(const pandora::Pandora* const pPrimaryPandora,
246  pandora::PfoVector& slicePfos)
247  {
248  if (!slicePfos.empty())
249  throw cet::exception("LArPandora")
250  << " LArPandoraOutput::GetPandoraSlices--- Input slicePfo vector is not empty ";
251 
252  // Get the pandora slicing worker - if it exists
253  const pandora::Pandora* pSlicingWorker(nullptr);
254  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SlicingWorker", pSlicingWorker))
255  return;
256 
257  // Get the slice PFOs - one PFO per slice
258  const pandora::PfoList* pSlicePfoList(nullptr);
259  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
260  !=,
261  PandoraApi::GetCurrentPfoList(*pSlicingWorker, pSlicePfoList));
262 
263  slicePfos.insert(slicePfos.end(), pSlicePfoList->begin(), pSlicePfoList->end());
264  }
265 
266  //------------------------------------------------------------------------------------------------------------------------------------------
267 
268  pandora::PfoVector
269  LArPandoraOutput::CollectAllPfoOutcomes(const pandora::Pandora* const pPrimaryPandora)
270  {
271  pandora::PfoList collectedPfos;
272 
273  // Get the list of slice pfos - one per slice
274  pandora::PfoVector slicePfos;
275  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
276 
277  // Identify the pandora worker instances by their name
278  const pandora::Pandora* pSliceNuWorker(nullptr);
279  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceNuWorker", pSliceNuWorker))
280  throw cet::exception("LArPandora")
281  << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice nu worker instance. ";
282 
283  const pandora::Pandora* pSliceCRWorker(nullptr);
284  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceCRWorker", pSliceCRWorker))
285  throw cet::exception("LArPandora")
286  << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice CR worker instance. ";
287 
288  // Collect slices under both reconstruction hypotheses
289  for (unsigned int sliceIndex = 0; sliceIndex < slicePfos.size(); ++sliceIndex) {
290  const pandora::PfoList* pNuPfoList(nullptr);
291  if (pandora::STATUS_CODE_SUCCESS ==
292  PandoraApi::GetPfoList(
293  *pSliceNuWorker, "NeutrinoParticles3D" + std::to_string(sliceIndex), pNuPfoList))
294  collectedPfos.insert(collectedPfos.end(), pNuPfoList->begin(), pNuPfoList->end());
295 
296  const pandora::PfoList* pCRPfoList(nullptr);
297  if (pandora::STATUS_CODE_SUCCESS ==
298  PandoraApi::GetPfoList(
299  *pSliceCRWorker, "MuonParticles3D" + std::to_string(sliceIndex), pCRPfoList))
300  collectedPfos.insert(collectedPfos.end(), pCRPfoList->begin(), pCRPfoList->end());
301  }
302 
303  // Get the list of the parent pfos from the primary pandora instance
304  const pandora::PfoList* pParentPfoList(nullptr);
305  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
306  !=,
307  PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
308 
309  // Collect clear cosmic-rays
310  for (const pandora::ParticleFlowObject* const pPfo : *pParentPfoList) {
311  if (LArPandoraOutput::IsClearCosmic(pPfo)) collectedPfos.push_back(pPfo);
312  }
313 
314  // Collect all pfos that are downstream of the parents we have collected
315  pandora::PfoVector pfoVector;
316  LArPandoraOutput::CollectPfos(collectedPfos, pfoVector);
317 
318  return pfoVector;
319  }
320 
321  //------------------------------------------------------------------------------------------------------------------------------------------
322 
323  bool
324  LArPandoraOutput::IsClearCosmic(const pandora::ParticleFlowObject* const pPfo)
325  {
326  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
327 
328  const auto& properties(pParent->GetPropertiesMap());
329  const auto it(properties.find("IsClearCosmic"));
330 
331  if (it == properties.end()) return false;
332 
333  return static_cast<bool>(std::round(it->second));
334  }
335 
336  //------------------------------------------------------------------------------------------------------------------------------------------
337 
338  bool
339  LArPandoraOutput::IsFromSlice(const pandora::ParticleFlowObject* const pPfo)
340  {
341  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
342 
343  const auto& properties(pParent->GetPropertiesMap());
344  return (properties.find("SliceIndex") != properties.end());
345  }
346 
347  //------------------------------------------------------------------------------------------------------------------------------------------
348 
349  unsigned int
350  LArPandoraOutput::GetSliceIndex(const pandora::ParticleFlowObject* const pPfo)
351  {
352  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
353 
354  const auto& properties(pParent->GetPropertiesMap());
355  const auto it(properties.find("SliceIndex"));
356 
357  if (it == properties.end())
358  throw cet::exception("LArPandora")
359  << " LArPandoraOutput::GetSliceIndex--- Input PFO was not from a slice ";
360 
361  return static_cast<unsigned int>(std::round(it->second));
362  }
363 
364  //------------------------------------------------------------------------------------------------------------------------------------------
365 
366  pandora::PfoVector
367  LArPandoraOutput::CollectPfos(const pandora::Pandora* const pPrimaryPandora)
368  {
369  const pandora::PfoList* pParentPfoList(nullptr);
370  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
371  !=,
372  PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
373 
374  pandora::PfoVector pfoVector;
375  LArPandoraOutput::CollectPfos(*pParentPfoList, pfoVector);
376 
377  return pfoVector;
378  }
379 
380  //------------------------------------------------------------------------------------------------------------------------------------------
381 
382  void
383  LArPandoraOutput::CollectPfos(const pandora::PfoList& parentPfoList,
384  pandora::PfoVector& pfoVector)
385  {
386  if (!pfoVector.empty())
387  throw cet::exception("LArPandora")
388  << " LArPandoraOutput::CollectPfos--- trying to collect pfos into a non-empty list ";
389 
390  pandora::PfoList pfoList;
391  lar_content::LArPfoHelper::GetAllConnectedPfos(parentPfoList, pfoList);
392 
393  pfoVector.insert(pfoVector.end(), pfoList.begin(), pfoList.end());
394  std::sort(pfoVector.begin(), pfoVector.end(), lar_content::LArPfoHelper::SortByNHits);
395  }
396 
397  //------------------------------------------------------------------------------------------------------------------------------------------
398 
401  const pandora::PfoVector& pfoVector,
402  IdToIdVectorMap& pfoToVerticesMap,
403  std::function<const pandora::Vertex* const(const pandora::ParticleFlowObject* const)> fCriteria)
404  {
405  pandora::VertexVector vertexVector;
406 
407  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
408  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
409 
410  if (pPfo->GetVertexList().empty()) continue;
411 
412  try {
413  const pandora::Vertex* const pVertex(fCriteria(pPfo));
414 
415  // Get the vertex ID and add it to the vertex list if required
416  const auto it(std::find(vertexVector.begin(), vertexVector.end(), pVertex));
417  const bool isInList(it != vertexVector.end());
418  const size_t vertexId(isInList ? std::distance(vertexVector.begin(), it) :
419  vertexVector.size());
420 
421  if (!isInList) vertexVector.push_back(pVertex);
422 
423  if (!pfoToVerticesMap.insert(IdToIdVectorMap::value_type(pfoId, {vertexId})).second)
424  throw cet::exception("LArPandora")
425  << " LArPandoraOutput::CollectVertices --- repeated pfos in input list ";
426  }
427  catch (const pandora::StatusCodeException&) {
428  continue;
429  }
430  }
431 
432  return vertexVector;
433  }
434 
435  //------------------------------------------------------------------------------------------------------------------------------------------
436 
437  pandora::ClusterList
438  LArPandoraOutput::CollectClusters(const pandora::PfoVector& pfoVector,
439  IdToIdVectorMap& pfoToClustersMap)
440  {
441  pandora::ClusterList clusterList;
442 
443  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
444  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
445 
446  // Get the sorted list of clusters from the pfo
447  pandora::ClusterList clusters;
450 
451  // Get incrementing id's for each cluster
452  IdVector clusterIds(clusters.size());
453  std::iota(clusterIds.begin(), clusterIds.end(), clusterList.size());
454 
455  clusterList.insert(clusterList.end(), clusters.begin(), clusters.end());
456 
457  if (!pfoToClustersMap.insert(IdToIdVectorMap::value_type(pfoId, clusterIds)).second)
458  throw cet::exception("LArPandora")
459  << " LArPandoraOutput::CollectClusters --- repeated pfos in input list ";
460  }
461 
462  return clusterList;
463  }
464 
465  //------------------------------------------------------------------------------------------------------------------------------------------
466 
467  pandora::CaloHitList
468  LArPandoraOutput::Collect3DHits(const pandora::PfoVector& pfoVector,
469  IdToIdVectorMap& pfoToThreeDHitsMap)
470  {
471  pandora::CaloHitList caloHitList;
472 
473  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
474  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
475 
476  if (!pfoToThreeDHitsMap.insert(IdToIdVectorMap::value_type(pfoId, {})).second)
477  throw cet::exception("LArPandora")
478  << " LArPandoraOutput::Collect3DHits --- repeated pfos in input list ";
479 
480  pandora::CaloHitVector sorted3DHits;
481  LArPandoraOutput::Collect3DHits(pPfo, sorted3DHits);
482 
483  for (const pandora::CaloHit* const pCaloHit3D : sorted3DHits) {
484  if (pandora::TPC_3D !=
485  pCaloHit3D
486  ->GetHitType()) // TODO decide if this is required, or should I just insert them?
487  throw cet::exception("LArPandora")
488  << " LArPandoraOutput::Collect3DHits --- found a 2D hit in a 3D cluster";
489 
490  pfoToThreeDHitsMap.at(pfoId).push_back(caloHitList.size());
491  caloHitList.push_back(pCaloHit3D);
492  }
493  }
494 
495  return caloHitList;
496  }
497 
498  //------------------------------------------------------------------------------------------------------------------------------------------
499 
500  void
501  LArPandoraOutput::Collect3DHits(const pandora::ParticleFlowObject* const pPfo,
502  pandora::CaloHitVector& caloHits)
503  {
504  // Get the sorted list of 3D hits associated with the pfo
505  pandora::CaloHitList threeDHits;
506  lar_content::LArPfoHelper::GetCaloHits(pPfo, pandora::TPC_3D, threeDHits);
507 
508  caloHits.insert(caloHits.end(), threeDHits.begin(), threeDHits.end());
509  std::sort(caloHits.begin(), caloHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
510  }
511 
512  //------------------------------------------------------------------------------------------------------------------------------------------
513 
514  void
515  LArPandoraOutput::GetPandoraToArtHitMap(const pandora::ClusterList& clusterList,
516  const pandora::CaloHitList& threeDHitList,
517  const IdToHitMap& idToHitMap,
518  CaloHitToArtHitMap& pandoraHitToArtHitMap)
519  {
520  // Collect 2D hits from clusters
521  for (const pandora::Cluster* const pCluster : clusterList) {
522  if (pandora::TPC_3D == lar_content::LArClusterHelper::GetClusterHitType(pCluster))
523  throw cet::exception("LArPandora")
524  << " LArPandoraOutput::GetPandoraToArtHitMap --- found a 3D input cluster ";
525 
526  pandora::CaloHitVector sortedHits;
527  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
528 
529  for (const pandora::CaloHit* const pCaloHit : sortedHits) {
530  if (!pandoraHitToArtHitMap
531  .insert(CaloHitToArtHitMap::value_type(
532  pCaloHit, LArPandoraOutput::GetHit(idToHitMap, pCaloHit)))
533  .second)
534  throw cet::exception("LArPandora")
535  << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
536  }
537  }
538 
539  for (const pandora::CaloHit* const pCaloHit : threeDHitList) {
540  if (pCaloHit->GetHitType() != pandora::TPC_3D)
541  throw cet::exception("LArPandora")
542  << " LArPandoraOutput::GetPandoraToArtHitMap --- found a non-3D hit in the input list ";
543 
544  // ATTN get the 2D calo hit from the 3D calo hit then find the art hit!
545  if (!pandoraHitToArtHitMap
546  .insert(CaloHitToArtHitMap::value_type(
547  pCaloHit,
548  LArPandoraOutput::GetHit(
549  idToHitMap, static_cast<const pandora::CaloHit*>(pCaloHit->GetParentAddress()))))
550  .second)
551  throw cet::exception("LArPandora")
552  << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
553  }
554  }
555 
556  //------------------------------------------------------------------------------------------------------------------------------------------
557 
558  art::Ptr<recob::Hit>
559  LArPandoraOutput::GetHit(const IdToHitMap& idToHitMap, const pandora::CaloHit* const pCaloHit)
560  {
561  // TODO make this less evil
562 
563  // ATTN The CaloHit can come from the primary pandora instance (depth = 0) or one of its daughers (depth = 1).
564  // Here we keep trying to access the ART hit increasing the depth step-by-step
565  for (unsigned int depth = 0, maxDepth = 2; depth < maxDepth; ++depth) {
566  // Navigate to the hit address in the pandora master instance (assuming the depth is correct)
567  const pandora::CaloHit* pParentCaloHit = pCaloHit;
568  for (unsigned int i = 0; i < depth; ++i)
569  pParentCaloHit = static_cast<const pandora::CaloHit*>(pCaloHit->GetParentAddress());
570 
571  // Attempt to find the mapping from the "parent" calo hit to the ART hit
572  const void* const pHitAddress(pParentCaloHit->GetParentAddress());
573  const intptr_t hitID_temp((intptr_t)(pHitAddress));
574  const int hitID((int)(hitID_temp));
575 
576  IdToHitMap::const_iterator artIter = idToHitMap.find(hitID);
577 
578  // If there is no such mapping from "parent" calo hit to the ART hit, then increase the depth and try again!
579  if (idToHitMap.end() == artIter) continue;
580 
581  return artIter->second;
582  }
583 
584  throw cet::exception("LArPandora")
585  << " LArPandoraOutput::GetHit --- found a Pandora hit without a parent ART hit ";
586  }
587 
588  //------------------------------------------------------------------------------------------------------------------------------------------
589 
590  void
591  LArPandoraOutput::BuildVertices(const pandora::VertexVector& vertexVector,
592  VertexCollection& outputVertices)
593  {
594  for (size_t vertexId = 0; vertexId < vertexVector.size(); ++vertexId)
595  outputVertices->push_back(LArPandoraOutput::BuildVertex(vertexVector.at(vertexId), vertexId));
596  }
597 
598  //------------------------------------------------------------------------------------------------------------------------------------------
599 
600  void
601  LArPandoraOutput::BuildSpacePoints(const art::Event& event,
602  const std::string& instanceLabel,
603  const pandora::CaloHitList& threeDHitList,
604  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
605  SpacePointCollection& outputSpacePoints,
606  SpacePointToHitCollection& outputSpacePointsToHits)
607  {
608  pandora::CaloHitVector threeDHitVector;
609  threeDHitVector.insert(threeDHitVector.end(), threeDHitList.begin(), threeDHitList.end());
610 
611  for (unsigned int hitId = 0; hitId < threeDHitVector.size(); hitId++) {
612  const pandora::CaloHit* const pCaloHit(threeDHitVector.at(hitId));
613 
614  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit));
615  if (it == pandoraHitToArtHitMap.end())
616  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSpacePoints --- found a "
617  "pandora hit without a corresponding art hit ";
618 
619  LArPandoraOutput::AddAssociation(
620  event, instanceLabel, hitId, {it->second}, outputSpacePointsToHits);
621  outputSpacePoints->push_back(LArPandoraOutput::BuildSpacePoint(pCaloHit, hitId));
622  }
623  }
624 
625  //------------------------------------------------------------------------------------------------------------------------------------------
626 
627  void
628  LArPandoraOutput::BuildClusters(const art::Event& event,
629  const std::string& instanceLabel,
630  const pandora::ClusterList& clusterList,
631  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
632  const IdToIdVectorMap& pfoToClustersMap,
633  ClusterCollection& outputClusters,
634  ClusterToHitCollection& outputClustersToHits,
635  IdToIdVectorMap& pfoToArtClustersMap)
636  {
637  cluster::StandardClusterParamsAlg clusterParamAlgo;
638 
639  art::ServiceHandle<geo::Geometry const> geom{};
640  auto const clock_data =
641  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event);
642  auto const det_prop =
643  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(event, clock_data);
644  util::GeometryUtilities const gser{*geom, clock_data, det_prop};
645 
646  // Produce the art clusters
647  size_t nextClusterId(0);
648  IdToIdVectorMap pandoraClusterToArtClustersMap;
649  for (const pandora::Cluster* const pCluster : clusterList) {
650  std::vector<HitVector> hitVectors;
651  const std::vector<recob::Cluster> clusters(
652  LArPandoraOutput::BuildClusters(gser,
653  pCluster,
654  clusterList,
655  pandoraHitToArtHitMap,
656  pandoraClusterToArtClustersMap,
657  hitVectors,
658  nextClusterId,
659  clusterParamAlgo));
660 
661  if (hitVectors.size() != clusters.size())
662  throw cet::exception("LArPandora")
663  << " LArPandoraOutput::BuildClusters --- invalid hit vectors for clusters produced ";
664 
665  for (unsigned int i = 0; i < clusters.size(); ++i) {
666  LArPandoraOutput::AddAssociation(
667  event, instanceLabel, nextClusterId - 1, hitVectors.at(i), outputClustersToHits);
668  outputClusters->push_back(clusters.at(i));
669  }
670  }
671 
672  // Get mapping from pfo id to art cluster id
673  for (IdToIdVectorMap::const_iterator it = pfoToClustersMap.begin();
674  it != pfoToClustersMap.end();
675  ++it) {
676  if (!pfoToArtClustersMap.insert(IdToIdVectorMap::value_type(it->first, {})).second)
677  throw cet::exception("LArPandora")
678  << " LArPandoraOutput::BuildClusters --- repeated pfo ids ";
679 
680  for (const size_t pandoraClusterId : it->second) {
681  IdToIdVectorMap::const_iterator it2(pandoraClusterToArtClustersMap.find(pandoraClusterId));
682 
683  if (it2 == pandoraClusterToArtClustersMap.end())
684  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- found a "
685  "pandora cluster with no associated recob cluster ";
686 
687  for (const size_t recobClusterId : it2->second)
688  pfoToArtClustersMap.at(it->first).push_back(recobClusterId);
689  }
690  }
691  }
692 
693  //------------------------------------------------------------------------------------------------------------------------------------------
694 
695  void
696  LArPandoraOutput::BuildPFParticles(const art::Event& event,
697  const std::string& instanceLabel,
698  const pandora::PfoVector& pfoVector,
699  const IdToIdVectorMap& pfoToVerticesMap,
700  const IdToIdVectorMap& pfoToThreeDHitsMap,
701  const IdToIdVectorMap& pfoToArtClustersMap,
702  PFParticleCollection& outputParticles,
703  PFParticleToVertexCollection& outputParticlesToVertices,
704  PFParticleToSpacePointCollection& outputParticlesToSpacePoints,
705  PFParticleToClusterCollection& outputParticlesToClusters)
706  {
707  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
708  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
709 
710  outputParticles->push_back(LArPandoraOutput::BuildPFParticle(pPfo, pfoId, pfoVector));
711 
712  // Associations from PFParticle
713  if (pfoToVerticesMap.find(pfoId) != pfoToVerticesMap.end())
714  LArPandoraOutput::AddAssociation(
715  event, instanceLabel, pfoId, pfoToVerticesMap, outputParticlesToVertices);
716 
717  if (pfoToThreeDHitsMap.find(pfoId) != pfoToThreeDHitsMap.end())
718  LArPandoraOutput::AddAssociation(
719  event, instanceLabel, pfoId, pfoToThreeDHitsMap, outputParticlesToSpacePoints);
720 
721  if (pfoToArtClustersMap.find(pfoId) != pfoToArtClustersMap.end())
722  LArPandoraOutput::AddAssociation(
723  event, instanceLabel, pfoId, pfoToArtClustersMap, outputParticlesToClusters);
724  }
725  }
726 
727  //------------------------------------------------------------------------------------------------------------------------------------------
728 
729  void
730  LArPandoraOutput::AssociateAdditionalVertices(
731  const art::Event& event,
732  const std::string& instanceLabel,
733  const pandora::PfoVector& pfoVector,
734  const IdToIdVectorMap& pfoToVerticesMap,
735  PFParticleToVertexCollection& outputParticlesToVertices)
736  {
737  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
738  if (pfoToVerticesMap.find(pfoId) != pfoToVerticesMap.end())
739  LArPandoraOutput::AddAssociation(
740  event, instanceLabel, pfoId, pfoToVerticesMap, outputParticlesToVertices);
741  }
742  }
743 
744  //------------------------------------------------------------------------------------------------------------------------------------------
745 
746  void
747  LArPandoraOutput::BuildParticleMetadata(const art::Event& event,
748  const std::string& instanceLabel,
749  const pandora::PfoVector& pfoVector,
750  PFParticleMetadataCollection& outputParticleMetadata,
751  PFParticleToMetadataCollection& outputParticlesToMetadata)
752  {
753  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
754  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
755 
756  LArPandoraOutput::AddAssociation(event,
757  instanceLabel,
758  pfoId,
759  outputParticleMetadata->size(),
760  outputParticlesToMetadata);
761  larpandoraobj::PFParticleMetadata pPFParticleMetadata(
762  LArPandoraHelper::GetPFParticleMetadata(pPfo));
763  outputParticleMetadata->push_back(pPFParticleMetadata);
764  }
765  }
766 
767  //------------------------------------------------------------------------------------------------------------------------------------------
768 
769  void
770  LArPandoraOutput::BuildSlices(const Settings& settings,
771  const pandora::Pandora* const pPrimaryPandora,
772  const art::Event& event,
773  const std::string& instanceLabel,
774  const pandora::PfoVector& pfoVector,
775  const IdToHitMap& idToHitMap,
776  SliceCollection& outputSlices,
777  PFParticleToSliceCollection& outputParticlesToSlices,
778  SliceToHitCollection& outputSlicesToHits)
779  {
780  // Check for the special case in which there are no slices, and only the neutrino reconstruction was used on all hits
781  if (settings.m_isNeutrinoRecoOnlyNoSlicing) {
782  LArPandoraOutput::CopyAllHitsToSingleSlice(settings,
783  event,
784  instanceLabel,
785  pfoVector,
786  idToHitMap,
787  outputSlices,
788  outputParticlesToSlices,
789  outputSlicesToHits);
790  return;
791  }
792 
793  // Collect the slice pfos - one per slice (if there is no slicing instance, this vector will be empty)
794  pandora::PfoVector slicePfos;
795  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
796 
797  // Make one slice per Pandora Slice pfo
798  for (const pandora::ParticleFlowObject* const pSlicePfo : slicePfos)
799  LArPandoraOutput::BuildSlice(
800  pSlicePfo, event, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits);
801 
802  // Make a slice for every remaining pfo hierarchy that wasn't already in a slice
803  std::unordered_map<const pandora::ParticleFlowObject*, unsigned int> parentPfoToSliceIndexMap;
804  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
805  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
806 
807  // If this PFO is the parent of a hierarchy we have yet to use, then add a new slice
808  if (LArPandoraOutput::IsFromSlice(pPfo)) continue;
809 
810  if (lar_content::LArPfoHelper::GetParentPfo(pPfo) != pPfo) continue;
811 
812  if (!parentPfoToSliceIndexMap
813  .emplace(pPfo,
814  LArPandoraOutput::BuildSlice(
815  pPfo, event, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits))
816  .second)
817  throw cet::exception("LArPandora")
818  << " LArPandoraOutput::BuildSlices --- found repeated primary particles ";
819  }
820 
821  // Add the associations from PFOs to slices
822  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
823  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
824 
825  // For PFOs that are from a Pandora slice, add the association and move on to the next PFO
826  if (LArPandoraOutput::IsFromSlice(pPfo)) {
827  LArPandoraOutput::AddAssociation(event,
828  instanceLabel,
829  pfoId,
831  outputParticlesToSlices);
832  continue;
833  }
834 
835  // Get the parent of the particle
836  const pandora::ParticleFlowObject* const pParent(
838  if (parentPfoToSliceIndexMap.find(pParent) == parentPfoToSliceIndexMap.end())
839  throw cet::exception("LArPandora")
840  << " LArPandoraOutput::BuildSlices --- found pfo without a parent in the input list ";
841 
842  // Add the association from the PFO to the slice
843  LArPandoraOutput::AddAssociation(
844  event, instanceLabel, pfoId, parentPfoToSliceIndexMap.at(pParent), outputParticlesToSlices);
845  }
846  }
847 
848  //------------------------------------------------------------------------------------------------------------------------------------------
849 
850  unsigned int
851  LArPandoraOutput::BuildDummySlice(SliceCollection& outputSlices)
852  {
853  // Make a slice with dummy properties
854  const float bogusFloat(std::numeric_limits<float>::max());
855  const recob::tracking::Point_t bogusPoint(bogusFloat, bogusFloat, bogusFloat);
856  const recob::tracking::Vector_t bogusVector(bogusFloat, bogusFloat, bogusFloat);
857 
858  const unsigned int sliceIndex(outputSlices->size());
859  outputSlices->emplace_back(
860  sliceIndex, bogusPoint, bogusVector, bogusPoint, bogusPoint, bogusFloat, bogusFloat);
861 
862  return sliceIndex;
863  }
864 
865  //------------------------------------------------------------------------------------------------------------------------------------------
866 
867  void
868  LArPandoraOutput::CopyAllHitsToSingleSlice(const Settings& settings,
869  const art::Event& event,
870  const std::string& instanceLabel,
871  const pandora::PfoVector& pfoVector,
872  const IdToHitMap& idToHitMap,
873  SliceCollection& outputSlices,
874  PFParticleToSliceCollection& outputParticlesToSlices,
875  SliceToHitCollection& outputSlicesToHits)
876  {
877  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
878 
879  // Add all of the hits in the events to the slice
880  HitVector hits;
882  LArPandoraOutput::AddAssociation(event, instanceLabel, sliceIndex, hits, outputSlicesToHits);
883 
884  mf::LogDebug("LArPandora") << "Finding hits with label: " << settings.m_hitfinderModuleLabel
885  << std::endl;
886  mf::LogDebug("LArPandora") << " - Found " << hits.size() << std::endl;
887  mf::LogDebug("LArPandora") << " - Making associations " << outputSlicesToHits->size()
888  << std::endl;
889 
890  // Add all of the PFOs to the slice
891  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
892  LArPandoraOutput::AddAssociation(
893  event, instanceLabel, pfoId, sliceIndex, outputParticlesToSlices);
894  }
895 
896  //------------------------------------------------------------------------------------------------------------------------------------------
897 
898  unsigned int
899  LArPandoraOutput::BuildSlice(const pandora::ParticleFlowObject* const pParentPfo,
900  const art::Event& event,
901  const std::string& instanceLabel,
902  const IdToHitMap& idToHitMap,
903  SliceCollection& outputSlices,
904  SliceToHitCollection& outputSlicesToHits)
905  {
906  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
907 
908  // Collect the pfos connected to the input primary pfos
909  pandora::PfoList pfosInSlice;
910  lar_content::LArPfoHelper::GetAllConnectedPfos(pParentPfo, pfosInSlice);
911  pfosInSlice.sort(lar_content::LArPfoHelper::SortByNHits);
912 
913  // Collect the hits from the pfos in all views
914  pandora::CaloHitList hits;
915  for (const pandora::ParticleFlowObject* const pPfo : pfosInSlice) {
916  for (const pandora::HitType& hitType :
917  {pandora::TPC_VIEW_U, pandora::TPC_VIEW_V, pandora::TPC_VIEW_W}) {
918  lar_content::LArPfoHelper::GetCaloHits(pPfo, hitType, hits);
920  }
921  }
922 
923  // Add the associations to the hits
924  for (const pandora::CaloHit* const pCaloHit : hits)
925  LArPandoraOutput::AddAssociation(event,
926  instanceLabel,
927  sliceIndex,
928  {LArPandoraOutput::GetHit(idToHitMap, pCaloHit)},
929  outputSlicesToHits);
930 
931  return sliceIndex;
932  }
933 
934  //------------------------------------------------------------------------------------------------------------------------------------------
935 
936  void
937  LArPandoraOutput::BuildT0s(const art::Event& event,
938  const std::string& instanceLabel,
939  const pandora::PfoVector& pfoVector,
940  T0Collection& outputT0s,
941  PFParticleToT0Collection& outputParticlesToT0s)
942  {
943  size_t nextT0Id(0);
944  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
945  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
946 
947  anab::T0 t0;
948  if (!LArPandoraOutput::BuildT0(event, pPfo, pfoVector, nextT0Id, t0)) continue;
949 
950  LArPandoraOutput::AddAssociation(
951  event, instanceLabel, pfoId, nextT0Id - 1, outputParticlesToT0s);
952  outputT0s->push_back(t0);
953  }
954  }
955 
956  //------------------------------------------------------------------------------------------------------------------------------------------
957 
959  LArPandoraOutput::BuildPFParticle(const pandora::ParticleFlowObject* const pPfo,
960  const size_t pfoId,
961  const pandora::PfoVector& pfoVector)
962  {
963  // Get parent Pfo ID
964  const pandora::PfoList& parentList(pPfo->GetParentPfoList());
965  if (parentList.size() > 1)
966  throw cet::exception("LArPandora")
967  << " LArPandoraOutput::BuildPFParticle --- this pfo has multiple parent particles ";
968 
969  const size_t parentId(parentList.empty() ?
971  LArPandoraOutput::GetId(parentList.front(), pfoVector));
972 
973  // Get daughters Pfo IDs
974  std::vector<size_t> daughterIds;
975  for (const pandora::ParticleFlowObject* const pDaughterPfo : pPfo->GetDaughterPfoList())
976  daughterIds.push_back(LArPandoraOutput::GetId(pDaughterPfo, pfoVector));
977 
978  std::sort(daughterIds.begin(), daughterIds.end());
979 
980  return recob::PFParticle(pPfo->GetParticleId(), pfoId, parentId, daughterIds);
981  }
982 
983  //------------------------------------------------------------------------------------------------------------------------------------------
984 
986  LArPandoraOutput::BuildVertex(const pandora::Vertex* const pVertex, const size_t vertexId)
987  {
988  double pos[3] = {
989  pVertex->GetPosition().GetX(), pVertex->GetPosition().GetY(), pVertex->GetPosition().GetZ()};
990  return recob::Vertex(pos, vertexId);
991  }
992 
993  //------------------------------------------------------------------------------------------------------------------------------------------
994 
995  void
996  LArPandoraOutput::GetHitsInCluster(const pandora::Cluster* const pCluster,
997  pandora::CaloHitVector& sortedHits)
998  {
999  if (!sortedHits.empty())
1000  throw cet::exception("LArPandora")
1001  << " LArPandoraOutput::GetHitsInCluster --- vector to hold hits is not empty ";
1002 
1003  pandora::CaloHitList hitList;
1004  pCluster->GetOrderedCaloHitList().FillCaloHitList(hitList);
1005  hitList.insert(hitList.end(),
1006  pCluster->GetIsolatedCaloHitList().begin(),
1007  pCluster->GetIsolatedCaloHitList().end());
1008 
1009  sortedHits.insert(sortedHits.end(), hitList.begin(), hitList.end());
1010  std::sort(
1011  sortedHits.begin(), sortedHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
1012  }
1013 
1014  //------------------------------------------------------------------------------------------------------------------------------------------
1015 
1016  std::vector<recob::Cluster>
1017  LArPandoraOutput::BuildClusters(util::GeometryUtilities const& gser,
1018  const pandora::Cluster* const pCluster,
1019  const pandora::ClusterList& clusterList,
1020  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
1021  IdToIdVectorMap& pandoraClusterToArtClustersMap,
1022  std::vector<HitVector>& hitVectors,
1023  size_t& nextId,
1025  {
1026  std::vector<recob::Cluster> clusters;
1027 
1028  // Get the cluster ID and set up the map entry
1029  const size_t clusterId(LArPandoraOutput::GetId(pCluster, clusterList));
1030  if (!pandoraClusterToArtClustersMap.insert(IdToIdVectorMap::value_type(clusterId, {})).second)
1031  throw cet::exception("LArPandora")
1032  << " LArPandoraOutput::BuildClusters --- repeated clusters in input list ";
1033 
1034  pandora::CaloHitVector sortedHits;
1035  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
1036 
1037  HitArray hitArray; // hits organised by drift volume
1038  HitList isolatedHits;
1039 
1040  for (const pandora::CaloHit* const pCaloHit2D : sortedHits) {
1041  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit2D));
1042  if (it == pandoraHitToArtHitMap.end())
1043  throw cet::exception("LArPandora")
1044  << " LArPandoraOutput::BuildClusters --- couldn't find art hit for input pandora hit ";
1045 
1046  const art::Ptr<recob::Hit> hit(it->second);
1047 
1048  const geo::WireID wireID(hit->WireID());
1049  const unsigned int volID(100000 * wireID.Cryostat + wireID.TPC);
1050  hitArray[volID].push_back(hit);
1051 
1052  if (pCaloHit2D->IsIsolated()) isolatedHits.insert(hit);
1053  }
1054 
1055  if (hitArray.empty())
1056  throw cet::exception("LArPandora")
1057  << " LArPandoraOutput::BuildClusters --- found a cluster with no hits ";
1058 
1059  for (const HitArray::value_type& hitArrayEntry : hitArray) {
1060  const HitVector& clusterHits(hitArrayEntry.second);
1061 
1062  clusters.push_back(
1063  LArPandoraOutput::BuildCluster(gser, nextId, clusterHits, isolatedHits, algo));
1064  hitVectors.push_back(clusterHits);
1065  pandoraClusterToArtClustersMap.at(clusterId).push_back(nextId);
1066 
1067  nextId++;
1068  }
1069 
1070  return clusters;
1071  }
1072 
1073  //------------------------------------------------------------------------------------------------------------------------------------------
1074 
1076  LArPandoraOutput::BuildCluster(util::GeometryUtilities const& gser,
1077  const size_t id,
1078  const HitVector& hitVector,
1079  const HitList& isolatedHits,
1081  {
1082  if (hitVector.empty())
1083  throw cet::exception("LArPandora")
1084  << " LArPandoraOutput::BuildCluster --- No input hits were provided ";
1085 
1086  // Fill list of cluster properties
1087  geo::View_t view(geo::kUnknown);
1088  geo::PlaneID planeID;
1089 
1090  double startWire(+std::numeric_limits<float>::max()), sigmaStartWire(0.0);
1091  double startTime(+std::numeric_limits<float>::max()), sigmaStartTime(0.0);
1092  double endWire(-std::numeric_limits<float>::max()), sigmaEndWire(0.0);
1093  double endTime(-std::numeric_limits<float>::max()), sigmaEndTime(0.0);
1094 
1095  std::vector<recob::Hit const*> hits_for_params;
1096  hits_for_params.reserve(hitVector.size());
1097 
1098  for (const art::Ptr<recob::Hit>& hit : hitVector) {
1099  const double thisWire(hit->WireID().Wire);
1100  const double thisWireSigma(0.5);
1101  const double thisTime(hit->PeakTime());
1102  const double thisTimeSigma(double(2. * hit->RMS()));
1103  const geo::View_t thisView(hit->View());
1104  const geo::PlaneID thisPlaneID(hit->WireID().planeID());
1105 
1106  if (geo::kUnknown == view) {
1107  view = thisView;
1108  planeID = thisPlaneID;
1109  }
1110 
1111  if (!(thisView == view && thisPlaneID == planeID)) {
1112  throw cet::exception("LArPandora")
1113  << " LArPandoraOutput::BuildCluster --- Input hits have inconsistent plane IDs ";
1114  }
1115 
1116  hits_for_params.push_back(&*hit);
1117 
1118  if (isolatedHits.count(hit)) continue;
1119 
1120  if (thisWire < startWire || (thisWire == startWire && thisTime < startTime)) {
1121  startWire = thisWire;
1122  sigmaStartWire = thisWireSigma;
1123  startTime = thisTime;
1124  sigmaStartTime = thisTimeSigma;
1125  }
1126 
1127  if (thisWire > endWire || (thisWire == endWire && thisTime > endTime)) {
1128  endWire = thisWire;
1129  sigmaEndWire = thisWireSigma;
1130  endTime = thisTime;
1131  sigmaEndTime = thisTimeSigma;
1132  }
1133  }
1134 
1135  // feed the algorithm with all the cluster hits
1136  algo.SetHits(gser, hits_for_params);
1137 
1138  // create the recob::Cluster directly in the vector
1139  return cluster::ClusterCreator(gser,
1140  algo, // algo
1141  startWire, // start_wire
1142  sigmaStartWire, // sigma_start_wire
1143  startTime, // start_tick
1144  sigmaStartTime, // sigma_start_tick
1145  endWire, // end_wire
1146  sigmaEndWire, // sigma_end_wire
1147  endTime, // end_tick
1148  sigmaEndTime, // sigma_end_tick
1149  id, // ID
1150  view, // view
1151  planeID, // plane
1152  recob::Cluster::Sentry // sentry
1153  )
1154  .move();
1155  }
1156 
1157  //------------------------------------------------------------------------------------------------------------------------------------------
1158 
1160  LArPandoraOutput::BuildSpacePoint(const pandora::CaloHit* const pCaloHit,
1161  const size_t spacePointId)
1162  {
1163  if (pandora::TPC_3D != pCaloHit->GetHitType())
1164  throw cet::exception("LArPandora")
1165  << " LArPandoraOutput::BuildSpacePoint --- trying to build a space point from a 2D hit";
1166 
1167  const pandora::CartesianVector point(pCaloHit->GetPositionVector());
1168  double xyz[3] = {point.GetX(), point.GetY(), point.GetZ()};
1169 
1170  // ATTN using dummy information
1171  double dxdydz[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // TODO: Fill in the error matrix
1172  double chi2(0.0);
1173 
1174  return recob::SpacePoint(xyz, dxdydz, chi2, spacePointId);
1175  }
1176 
1177  //------------------------------------------------------------------------------------------------------------------------------------------
1178 
1179  bool
1180  LArPandoraOutput::BuildT0(const art::Event& e,
1181  const pandora::ParticleFlowObject* const pPfo,
1182  const pandora::PfoVector& pfoVector,
1183  size_t& nextId,
1184  anab::T0& t0)
1185  {
1186  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
1187  const float x0(pParent->GetPropertiesMap().count("X0") ? pParent->GetPropertiesMap().at("X0") :
1188  0.f);
1189 
1190  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e);
1191  auto const det_prop =
1192  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(e, clock_data);
1193  const double cm_per_tick(det_prop.GetXTicksCoefficient());
1194  const double ns_per_tick(sampling_rate(clock_data));
1195 
1196  // ATTN: T0 values are currently calculated in nanoseconds relative to the trigger offset. Only non-zero values are outputted.
1197  const double T0(x0 * ns_per_tick / cm_per_tick);
1198 
1199  if (std::fabs(T0) <= std::numeric_limits<double>::epsilon()) return false;
1200 
1201  // Output T0 objects [arguments are: time (nanoseconds); trigger type (3 for TPC stitching!); pfparticle SelfID code; T0 ID code]
1202  t0 = anab::T0(T0, 3, LArPandoraOutput::GetId(pPfo, pfoVector), nextId++);
1203 
1204  return true;
1205  }
1206 
1207  //------------------------------------------------------------------------------------------------------------------------------------------
1208  //------------------------------------------------------------------------------------------------------------------------------------------
1209 
1210  LArPandoraOutput::Settings::Settings()
1211  : m_pPrimaryPandora(nullptr)
1212  , m_shouldRunStitching(false)
1213  , m_shouldProduceAllOutcomes(false)
1214  , m_shouldProduceTestBeamInteractionVertices(false)
1215  , m_isNeutrinoRecoOnlyNoSlicing(false)
1216  {}
1217 
1218  //------------------------------------------------------------------------------------------------------------------------------------------
1219 
1220  void
1222  {
1223  if (!m_pPrimaryPandora)
1224  throw cet::exception("LArPandora")
1225  << " LArPandoraOutput::Settings::Validate --- primary Pandora instance does not exist ";
1226 
1227  if (!m_shouldProduceAllOutcomes) return;
1228 
1229  if (m_allOutcomesInstanceLabel.empty())
1230  throw cet::exception("LArPandora")
1231  << " LArPandoraOutput::Settings::Validate --- all outcomes instance label not set ";
1232  }
1233 
1234 } // namespace lar_pandora
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
static pandora::VertexVector CollectVertices(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToVerticesMap, std::function< const pandora::Vertex *const (const pandora::ParticleFlowObject *const)> fCriteria)
Collect all vertices contained in the input pfo list Order is guaranteed provided pfoVector is ordere...
void Validate() const
Check the parameters and throw an exception if they are not valid.
static void GetPandoraSlices(const pandora::Pandora *const pPrimaryPandora, pandora::PfoVector &slicePfos)
Get the slice pfos - one pfo per slice.
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
Header file for the pfo helper class.
Class managing the creation of a new recob::Cluster object.
const pandora::Pandora * m_pPrimaryPandora
static bool GetPandoraInstance(const pandora::Pandora *const pPrimaryPandora, const std::string &name, const pandora::Pandora *&pPandoraInstance)
Get the address of a pandora instance with a given name.
std::unique_ptr< std::vector< larpandoraobj::PFParticleMetadata > > PFParticleMetadataCollection
static void GetPandoraToArtHitMap(const pandora::ClusterList &clusterList, const pandora::CaloHitList &threeDHitList, const IdToHitMap &idToHitMap, CaloHitToArtHitMap &pandoraHitToArtHitMap)
Collect all 2D and 3D hits that were used / produced in the reconstruction and map them to their corr...
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:61
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::map< int, HitVector > HitArray
Unknown view.
Definition: geo_types.h:136
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
std::unique_ptr< art::Assns< recob::PFParticle, recob::Slice > > PFParticleToSliceCollection
static void BuildClusters(const art::Event &event, const std::string &instanceLabel, const pandora::ClusterList &clusterList, const CaloHitToArtHitMap &pandoraHitToArtHitMap, const IdToIdVectorMap &pfoToClustersMap, ClusterCollection &outputClusters, ClusterToHitCollection &outputClustersToHits, IdToIdVectorMap &pfoToArtClustersMap)
Convert pandora 2D clusters to ART clusters and add them to the output vector Create the associations...
static void BuildSpacePoints(const art::Event &event, const std::string &instanceLabel, const pandora::CaloHitList &threeDHitList, const CaloHitToArtHitMap &pandoraHitToArtHitMap, SpacePointCollection &outputSpacePoints, SpacePointToHitCollection &outputSpacePointsToHits)
Convert pandora 3D hits to ART spacepoints and add them to the output vector Create the associations ...
Declaration of signal hit object.
std::unique_ptr< std::vector< recob::Slice > > SliceCollection
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
std::unique_ptr< std::vector< recob::PFParticle > > PFParticleCollection
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::string m_testBeamInteractionVerticesInstanceLabel
The label for the test beam interaction vertices.
std::unique_ptr< std::vector< recob::Vertex > > VertexCollection
static const pandora::Vertex * GetTestBeamInteractionVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo test beam interaction vertex.
std::string m_allOutcomesInstanceLabel
The label for the instance producing all outcomes.
std::map< size_t, IdVector > IdToIdVectorMap
Algorithm collection class computing cluster parameters.
Set of hits with a 2D structure.
Definition: Cluster.h:71
std::unique_ptr< art::Assns< recob::PFParticle, larpandoraobj::PFParticleMetadata > > PFParticleToMetadataCollection
std::map< int, art::Ptr< recob::Hit > > IdToHitMap
Definition: ILArPandora.h:21
bool m_isNeutrinoRecoOnlyNoSlicing
If we are running the neutrino reconstruction only with no slicing.
Helper functions for processing outputs from pandora.
Definition: T0.h:16
process_name hit
Definition: cheaterreco.fcl:51
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static bool IsFromSlice(const pandora::ParticleFlowObject *const pPfo)
Check if the input pfo is from a slice.
Definition of vertex object for LArSoft.
Definition: Vertex.h:35
std::array< float, 2 > HitVector(const recob::Hit &hit, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:182
std::unique_ptr< art::Assns< recob::PFParticle, recob::Cluster > > PFParticleToClusterCollection
static void AssociateAdditionalVertices(const art::Event &event, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, const IdToIdVectorMap &pfoToVerticesMap, PFParticleToVertexCollection &outputParticlesToVertices)
Convert Create the associations between pre-existing PFParticle and additional vertices.
std::string m_hitfinderModuleLabel
The hit finder module label.
Algorithm collection class computing cluster parameters.
std::unique_ptr< art::Assns< recob::Slice, recob::Hit > > SliceToHitCollection
std::vector< size_t > IdVector
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. See recob::tracking::Coord_t for more details on the ...
Definition: TrackingTypes.h:29
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Metadata associated to PFParticles.
static bool SortHitsByPosition(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their position (use Z, followed by X, followed by Y)
static const pandora::ParticleFlowObject * GetParentPfo(const pandora::ParticleFlowObject *const pPfo)
Get the primary parent pfo.
Header file for the cluster helper class.
static unsigned int GetSliceIndex(const pandora::ParticleFlowObject *const pPfo)
Get the index of the slice from which this pfo was produced.
std::unique_ptr< art::Assns< recob::PFParticle, anab::T0 > > PFParticleToT0Collection
Helper functions to create a cluster.
static void BuildVertices(const pandora::VertexVector &vertexVector, VertexCollection &outputVertices)
Convert pandora vertices to ART vertices and add them to the output vector.
std::vector< art::Ptr< recob::Hit > > CollectHits(const std::vector< art::Ptr< recob::Hit >> &hits, const sbn::VertexHit &vhit, const recob::Hit &vhit_hit, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
Definition: StubBuilder.cxx:56
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Hit > > SpacePointToHitCollection
static pandora::PfoVector CollectPfos(const pandora::Pandora *const pPrimaryPandora)
Collect the current pfos (including all downstream pfos) from the master pandora instance.
static bool IsClearCosmic(const pandora::ParticleFlowObject *const pPfo)
Check if the input pfo is an unambiguous cosmic ray.
Wrapper for ClusterParamsAlgBase objects to accept arbitrary input.
static void ProduceArtOutput(const Settings &settings, const IdToHitMap &idToHitMap, art::Event &evt)
Convert the Pandora PFOs into ART clusters and write into ART event.
std::unique_ptr< std::vector< recob::Cluster > > ClusterCollection
std::map< const pandora::CaloHit *, art::Ptr< recob::Hit > > CaloHitToArtHitMap
std::unique_ptr< art::Assns< recob::PFParticle, recob::Vertex > > PFParticleToVertexCollection
Header file for the MultiPandoraApi class.
virtual void SetHits(util::GeometryUtilities const &gser, std::vector< recob::Hit const * > const &hits)=0
Sets the list of input hits.
static const PandoraInstanceList & GetDaughterPandoraInstanceList(const pandora::Pandora *const pPrimaryPandora)
Get the list of daughter pandora instances associated with a given primary pandora instance...
static pandora::ClusterList CollectClusters(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToClustersMap)
Collect a sorted list of all 2D clusters contained in the input pfo list Order is guaranteed provided...
static void Collect3DHits(const pandora::ParticleFlowObject *const pPfo, pandora::CaloHitVector &caloHits)
Collect a sorted vector of all 3D hits in the input pfo.
static void BuildT0s(const art::Event &event, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, T0Collection &outputT0s, PFParticleToT0Collection &outputParticlesToT0s)
Calculate the T0 of each pfos and add them to the output vector Create the associations between PFPar...
bool m_shouldProduceTestBeamInteractionVertices
Whether to write the test beam interaction vertices in a separate collection.
std::unique_ptr< art::Assns< recob::PFParticle, recob::SpacePoint > > PFParticleToSpacePointCollection
std::vector< art::Ptr< recob::Hit > > HitVector
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
std::unique_ptr< std::vector< anab::T0 > > T0Collection
bool m_shouldProduceAllOutcomes
If all outcomes should be produced in separate collections (choose false if you only require the cons...
std::string to_string(WindowPattern const &pattern)
bool m_shouldProduceSlices
Whether to produce output slices e.g. may not want to do this if only (re)processing single slices...
static void GetIsolatedCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of isolated calo hits of a particular hit type from a list of pfos.
std::pair< unsigned short, unsigned short > GetSliceIndex(std::string typeName, int uID)
Definition: Utils.cxx:5088
do i e
static void BuildSlices(const Settings &settings, const pandora::Pandora *const pPrimaryPandora, const art::Event &event, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, const IdToHitMap &idToHitMap, SliceCollection &outputSlices, PFParticleToSliceCollection &outputParticlesToSlices, SliceToHitCollection &outputSlicesToHits)
Build slices - collections of hits which each describe a single particle hierarchy.
then echo fcl name
static void BuildPFParticles(const art::Event &event, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, const IdToIdVectorMap &pfoToVerticesMap, const IdToIdVectorMap &pfoToThreeDHitsMap, const IdToIdVectorMap &pfoToArtClustersMap, PFParticleCollection &outputParticles, PFParticleToVertexCollection &outputParticlesToVertices, PFParticleToSpacePointCollection &outputParticlesToSpacePoints, PFParticleToClusterCollection &outputParticlesToClusters)
Convert between pfos and PFParticles and add them to the output vector Create the associations betwee...
static void BuildParticleMetadata(const art::Event &event, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, PFParticleMetadataCollection &outputParticleMetadata, PFParticleToMetadataCollection &outputParticlesToMetadata)
Build metadata objects from a list of input pfos.
std::unique_ptr< std::vector< recob::SpacePoint > > SpacePointCollection
Interface to class computing cluster parameters.
TCEvent evt
Definition: DataStructs.cxx:8
static void GetAllConnectedPfos(const pandora::PfoList &inputPfoList, pandora::PfoList &outputPfoList)
Get a flat list of all pfos, recursively including all daughters and parents associated with those pf...
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:26
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
std::set< art::Ptr< recob::Hit > > HitList
recob::Cluster && move()
Prepares the constructed hit to be moved away.
static pandora::PfoVector CollectAllPfoOutcomes(const pandora::Pandora *const pPrimaryPandora)
Collect the pfos (including all downstream pfos) from the master and daughter pandora instances...
std::array< float, 2 > VertexVector(const recob::Vertex &vert, const geo::PlaneID &plane, const geo::GeometryCore *geo, const detinfo::DetectorPropertiesData &dprop)
std::unique_ptr< art::Assns< recob::Cluster, recob::Hit > > ClusterToHitCollection
art framework interface to geometry description
process_name opdaq physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator physics producers generator T0
Definition: gen_protons.fcl:45