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