LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
LArPandoraOutput.cxx
Go to the documentation of this file.
1 
8 
10 #include "cetlib_except/exception.h"
12 
18 
24 
25 #include "Objects/CaloHit.h"
26 #include "Objects/Cluster.h"
27 #include "Objects/ParticleFlowObject.h"
28 #include "Objects/Vertex.h"
29 
33 
34 #include <algorithm>
35 #include <iostream>
36 #include <iterator>
37 #include <limits>
38 #include <numeric> // std::iota()
39 
40 namespace lar_pandora {
41 
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(
71  PFParticleToSpacePointCollection outputParticlesToSpacePoints(
73  PFParticleToClusterCollection outputParticlesToClusters(
75  PFParticleToVertexCollection outputParticlesToVertices(
78  SpacePointToHitCollection outputSpacePointsToHits(
81 
82  // Set up optional output associations
83  PFParticleToVertexCollection outputParticlesToTestBeamInteractionVertices(
86  nullptr);
87  PFParticleToT0Collection outputParticlesToT0s(
89  PFParticleToSliceCollection outputParticlesToSlices(
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 LArPandoraOutput::GetPandoraInstance(const pandora::Pandora* const pPrimaryPandora,
215  const std::string& name,
216  const pandora::Pandora*& pPandoraInstance)
217  {
218  if (!pPrimaryPandora)
219  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- input "
220  "primary pandora instance address is invalid ";
221 
222  if (pPandoraInstance)
223  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- the input "
224  "pandora instance address is non-null ";
225 
226  for (const pandora::Pandora* const pPandora :
228  if (pPandora->GetName() != name) continue;
229 
230  if (pPandoraInstance)
231  throw cet::exception("LArPandora")
232  << " LArPandoraOutput::GetPandoraInstance--- found multiple pandora instances with name: "
233  << name;
234 
235  pPandoraInstance = pPandora;
236  }
237 
238  return static_cast<bool>(pPandoraInstance);
239  }
240 
241  //------------------------------------------------------------------------------------------------------------------------------------------
242 
243  void LArPandoraOutput::GetPandoraSlices(const pandora::Pandora* const pPrimaryPandora,
244  pandora::PfoVector& slicePfos)
245  {
246  if (!slicePfos.empty())
247  throw cet::exception("LArPandora")
248  << " LArPandoraOutput::GetPandoraSlices--- Input slicePfo vector is not empty ";
249 
250  // Get the pandora slicing worker - if it exists
251  const pandora::Pandora* pSlicingWorker(nullptr);
252  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SlicingWorker", pSlicingWorker))
253  return;
254 
255  // Get the slice PFOs - one PFO per slice
256  const pandora::PfoList* pSlicePfoList(nullptr);
257  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
258  !=,
259  PandoraApi::GetCurrentPfoList(*pSlicingWorker, pSlicePfoList));
260 
261  slicePfos.insert(slicePfos.end(), pSlicePfoList->begin(), pSlicePfoList->end());
262  }
263 
264  //------------------------------------------------------------------------------------------------------------------------------------------
265 
267  const pandora::Pandora* const pPrimaryPandora)
268  {
269  pandora::PfoList collectedPfos;
270 
271  // Get the list of slice pfos - one per slice
272  pandora::PfoVector slicePfos;
273  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
274 
275  // Identify the pandora worker instances by their name
276  const pandora::Pandora* pSliceNuWorker(nullptr);
277  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceNuWorker", pSliceNuWorker))
278  throw cet::exception("LArPandora")
279  << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice nu worker instance. ";
280 
281  const pandora::Pandora* pSliceCRWorker(nullptr);
282  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceCRWorker", pSliceCRWorker))
283  throw cet::exception("LArPandora")
284  << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice CR worker instance. ";
285 
286  // Collect slices under both reconstruction hypotheses
287  for (unsigned int sliceIndex = 0; sliceIndex < slicePfos.size(); ++sliceIndex) {
288  const pandora::PfoList* pNuPfoList(nullptr);
289  if (pandora::STATUS_CODE_SUCCESS ==
290  PandoraApi::GetPfoList(
291  *pSliceNuWorker, "NeutrinoParticles3D" + std::to_string(sliceIndex), pNuPfoList))
292  collectedPfos.insert(collectedPfos.end(), pNuPfoList->begin(), pNuPfoList->end());
293 
294  const pandora::PfoList* pCRPfoList(nullptr);
295  if (pandora::STATUS_CODE_SUCCESS ==
296  PandoraApi::GetPfoList(
297  *pSliceCRWorker, "MuonParticles3D" + std::to_string(sliceIndex), pCRPfoList))
298  collectedPfos.insert(collectedPfos.end(), pCRPfoList->begin(), pCRPfoList->end());
299  }
300 
301  // Get the list of the parent pfos from the primary pandora instance
302  const pandora::PfoList* pParentPfoList(nullptr);
303  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
304  !=,
305  PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
306 
307  // Collect clear cosmic-rays
308  for (const pandora::ParticleFlowObject* const pPfo : *pParentPfoList) {
309  if (LArPandoraOutput::IsClearCosmic(pPfo)) collectedPfos.push_back(pPfo);
310  }
311 
312  // Collect all pfos that are downstream of the parents we have collected
313  pandora::PfoVector pfoVector;
314  LArPandoraOutput::CollectPfos(collectedPfos, pfoVector);
315 
316  return pfoVector;
317  }
318 
319  //------------------------------------------------------------------------------------------------------------------------------------------
320 
321  bool LArPandoraOutput::IsClearCosmic(const pandora::ParticleFlowObject* const pPfo)
322  {
323  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
324 
325  const auto& properties(pParent->GetPropertiesMap());
326  const auto it(properties.find("IsClearCosmic"));
327 
328  if (it == properties.end()) return false;
329 
330  return static_cast<bool>(std::round(it->second));
331  }
332 
333  //------------------------------------------------------------------------------------------------------------------------------------------
334 
335  bool LArPandoraOutput::IsFromSlice(const pandora::ParticleFlowObject* const pPfo)
336  {
337  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
338 
339  const auto& properties(pParent->GetPropertiesMap());
340  return (properties.find("SliceIndex") != properties.end());
341  }
342 
343  //------------------------------------------------------------------------------------------------------------------------------------------
344 
345  unsigned int LArPandoraOutput::GetSliceIndex(const pandora::ParticleFlowObject* const pPfo)
346  {
347  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
348 
349  const auto& properties(pParent->GetPropertiesMap());
350  const auto it(properties.find("SliceIndex"));
351 
352  if (it == properties.end())
353  throw cet::exception("LArPandora")
354  << " LArPandoraOutput::GetSliceIndex--- Input PFO was not from a slice ";
355 
356  return static_cast<unsigned int>(std::round(it->second));
357  }
358 
359  //------------------------------------------------------------------------------------------------------------------------------------------
360 
361  pandora::PfoVector LArPandoraOutput::CollectPfos(const pandora::Pandora* const pPrimaryPandora)
362  {
363  const pandora::PfoList* pParentPfoList(nullptr);
364  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
365  !=,
366  PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
367 
368  pandora::PfoVector pfoVector;
369  LArPandoraOutput::CollectPfos(*pParentPfoList, pfoVector);
370 
371  return pfoVector;
372  }
373 
374  //------------------------------------------------------------------------------------------------------------------------------------------
375 
376  void LArPandoraOutput::CollectPfos(const pandora::PfoList& parentPfoList,
377  pandora::PfoVector& pfoVector)
378  {
379  if (!pfoVector.empty())
380  throw cet::exception("LArPandora")
381  << " LArPandoraOutput::CollectPfos--- trying to collect pfos into a non-empty list ";
382 
383  pandora::PfoList pfoList;
384  lar_content::LArPfoHelper::GetAllConnectedPfos(parentPfoList, pfoList);
385 
386  pfoVector.insert(pfoVector.end(), pfoList.begin(), pfoList.end());
387  std::sort(pfoVector.begin(), pfoVector.end(), lar_content::LArPfoHelper::SortByNHits);
388  }
389 
390  //------------------------------------------------------------------------------------------------------------------------------------------
391 
393  const pandora::PfoVector& pfoVector,
394  IdToIdVectorMap& pfoToVerticesMap,
395  std::function<const pandora::Vertex* const(const pandora::ParticleFlowObject* const)> fCriteria)
396  {
397  pandora::VertexVector vertexVector;
398 
399  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
400  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
401 
402  if (pPfo->GetVertexList().empty()) continue;
403 
404  try {
405  const pandora::Vertex* const pVertex(fCriteria(pPfo));
406 
407  // Get the vertex ID and add it to the vertex list if required
408  const auto it(std::find(vertexVector.begin(), vertexVector.end(), pVertex));
409  const bool isInList(it != vertexVector.end());
410  const size_t vertexId(isInList ? std::distance(vertexVector.begin(), it) :
411  vertexVector.size());
412 
413  if (!isInList) vertexVector.push_back(pVertex);
414 
415  if (!pfoToVerticesMap.insert(IdToIdVectorMap::value_type(pfoId, {vertexId})).second)
416  throw cet::exception("LArPandora")
417  << " LArPandoraOutput::CollectVertices --- repeated pfos in input list ";
418  }
419  catch (const pandora::StatusCodeException&) {
420  continue;
421  }
422  }
423 
424  return vertexVector;
425  }
426 
427  //------------------------------------------------------------------------------------------------------------------------------------------
428 
429  pandora::ClusterList LArPandoraOutput::CollectClusters(const pandora::PfoVector& pfoVector,
430  IdToIdVectorMap& pfoToClustersMap)
431  {
432  pandora::ClusterList clusterList;
433 
434  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
435  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
436 
437  // Get the sorted list of clusters from the pfo
438  pandora::ClusterList clusters;
441 
442  // Get incrementing id's for each cluster
443  IdVector clusterIds(clusters.size());
444  std::iota(clusterIds.begin(), clusterIds.end(), clusterList.size());
445 
446  clusterList.insert(clusterList.end(), clusters.begin(), clusters.end());
447 
448  if (!pfoToClustersMap.insert(IdToIdVectorMap::value_type(pfoId, clusterIds)).second)
449  throw cet::exception("LArPandora")
450  << " LArPandoraOutput::CollectClusters --- repeated pfos in input list ";
451  }
452 
453  return clusterList;
454  }
455 
456  //------------------------------------------------------------------------------------------------------------------------------------------
457 
458  pandora::CaloHitList LArPandoraOutput::Collect3DHits(const pandora::PfoVector& pfoVector,
459  IdToIdVectorMap& pfoToThreeDHitsMap)
460  {
461  pandora::CaloHitList caloHitList;
462 
463  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
464  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
465 
466  if (!pfoToThreeDHitsMap.insert(IdToIdVectorMap::value_type(pfoId, {})).second)
467  throw cet::exception("LArPandora")
468  << " LArPandoraOutput::Collect3DHits --- repeated pfos in input list ";
469 
470  pandora::CaloHitVector sorted3DHits;
471  LArPandoraOutput::Collect3DHits(pPfo, sorted3DHits);
472 
473  for (const pandora::CaloHit* const pCaloHit3D : sorted3DHits) {
474  if (pandora::TPC_3D !=
475  pCaloHit3D
476  ->GetHitType()) // TODO decide if this is required, or should I just insert them?
477  throw cet::exception("LArPandora")
478  << " LArPandoraOutput::Collect3DHits --- found a 2D hit in a 3D cluster";
479 
480  pfoToThreeDHitsMap.at(pfoId).push_back(caloHitList.size());
481  caloHitList.push_back(pCaloHit3D);
482  }
483  }
484 
485  return caloHitList;
486  }
487 
488  //------------------------------------------------------------------------------------------------------------------------------------------
489 
490  void LArPandoraOutput::Collect3DHits(const pandora::ParticleFlowObject* const pPfo,
491  pandora::CaloHitVector& caloHits)
492  {
493  // Get the sorted list of 3D hits associated with the pfo
494  pandora::CaloHitList threeDHits;
495  lar_content::LArPfoHelper::GetCaloHits(pPfo, pandora::TPC_3D, threeDHits);
496 
497  caloHits.insert(caloHits.end(), threeDHits.begin(), threeDHits.end());
498  std::sort(caloHits.begin(), caloHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
499  }
500 
501  //------------------------------------------------------------------------------------------------------------------------------------------
502 
503  void LArPandoraOutput::GetPandoraToArtHitMap(const pandora::ClusterList& clusterList,
504  const pandora::CaloHitList& threeDHitList,
505  const IdToHitMap& idToHitMap,
506  CaloHitToArtHitMap& pandoraHitToArtHitMap)
507  {
508  // Collect 2D hits from clusters
509  for (const pandora::Cluster* const pCluster : clusterList) {
510  if (pandora::TPC_3D == lar_content::LArClusterHelper::GetClusterHitType(pCluster))
511  throw cet::exception("LArPandora")
512  << " LArPandoraOutput::GetPandoraToArtHitMap --- found a 3D input cluster ";
513 
514  pandora::CaloHitVector sortedHits;
515  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
516 
517  for (const pandora::CaloHit* const pCaloHit : sortedHits) {
518  if (!pandoraHitToArtHitMap
519  .insert(CaloHitToArtHitMap::value_type(
520  pCaloHit, LArPandoraOutput::GetHit(idToHitMap, pCaloHit)))
521  .second)
522  throw cet::exception("LArPandora")
523  << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
524  }
525  }
526 
527  for (const pandora::CaloHit* const pCaloHit : threeDHitList) {
528  if (pCaloHit->GetHitType() != pandora::TPC_3D)
529  throw cet::exception("LArPandora")
530  << " LArPandoraOutput::GetPandoraToArtHitMap --- found a non-3D hit in the input list ";
531 
532  // ATTN get the 2D calo hit from the 3D calo hit then find the art hit!
533  if (!pandoraHitToArtHitMap
534  .insert(CaloHitToArtHitMap::value_type(
535  pCaloHit,
537  idToHitMap, static_cast<const pandora::CaloHit*>(pCaloHit->GetParentAddress()))))
538  .second)
539  throw cet::exception("LArPandora")
540  << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
541  }
542  }
543 
544  //------------------------------------------------------------------------------------------------------------------------------------------
545 
547  const pandora::CaloHit* const pCaloHit)
548  {
549  // TODO make this less evil
550 
551  // ATTN The CaloHit can come from the primary pandora instance (depth = 0) or one of its daughers (depth = 1).
552  // Here we keep trying to access the ART hit increasing the depth step-by-step
553  for (unsigned int depth = 0, maxDepth = 2; depth < maxDepth; ++depth) {
554  // Navigate to the hit address in the pandora master instance (assuming the depth is correct)
555  const pandora::CaloHit* pParentCaloHit = pCaloHit;
556  for (unsigned int i = 0; i < depth; ++i)
557  pParentCaloHit = static_cast<const pandora::CaloHit*>(pCaloHit->GetParentAddress());
558 
559  // Attempt to find the mapping from the "parent" calo hit to the ART hit
560  const void* const pHitAddress(pParentCaloHit->GetParentAddress());
561  const intptr_t hitID_temp((intptr_t)(pHitAddress));
562  const int hitID((int)(hitID_temp));
563 
564  IdToHitMap::const_iterator artIter = idToHitMap.find(hitID);
565 
566  // If there is no such mapping from "parent" calo hit to the ART hit, then increase the depth and try again!
567  if (idToHitMap.end() == artIter) continue;
568 
569  return artIter->second;
570  }
571 
572  throw cet::exception("LArPandora")
573  << " LArPandoraOutput::GetHit --- found a Pandora hit without a parent ART hit ";
574  }
575 
576  //------------------------------------------------------------------------------------------------------------------------------------------
577 
579  VertexCollection& outputVertices)
580  {
581  for (size_t vertexId = 0; vertexId < vertexVector.size(); ++vertexId)
582  outputVertices->push_back(LArPandoraOutput::BuildVertex(vertexVector.at(vertexId), vertexId));
583  }
584 
585  //------------------------------------------------------------------------------------------------------------------------------------------
586 
588  const std::string& instanceLabel,
589  const pandora::CaloHitList& threeDHitList,
590  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
591  SpacePointCollection& outputSpacePoints,
592  SpacePointToHitCollection& outputSpacePointsToHits)
593  {
594  pandora::CaloHitVector threeDHitVector;
595  threeDHitVector.insert(threeDHitVector.end(), threeDHitList.begin(), threeDHitList.end());
596 
597  for (unsigned int hitId = 0; hitId < threeDHitVector.size(); hitId++) {
598  const pandora::CaloHit* const pCaloHit(threeDHitVector.at(hitId));
599 
600  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit));
601  if (it == pandoraHitToArtHitMap.end())
602  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSpacePoints --- found a "
603  "pandora hit without a corresponding art hit ";
604 
606  event, instanceLabel, hitId, {it->second}, outputSpacePointsToHits);
607  outputSpacePoints->push_back(LArPandoraOutput::BuildSpacePoint(pCaloHit, hitId));
608  }
609  }
610 
611  //------------------------------------------------------------------------------------------------------------------------------------------
612 
614  const std::string& instanceLabel,
615  const pandora::ClusterList& clusterList,
616  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
617  const IdToIdVectorMap& pfoToClustersMap,
618  ClusterCollection& outputClusters,
619  ClusterToHitCollection& outputClustersToHits,
620  IdToIdVectorMap& pfoToArtClustersMap)
621  {
622  cluster::StandardClusterParamsAlg clusterParamAlgo;
623 
625  auto const& wireReadoutGeom = art::ServiceHandle<geo::WireReadout const>()->Get();
626  auto const clock_data =
628  auto const det_prop =
630  util::GeometryUtilities const gser{*geom, wireReadoutGeom, clock_data, det_prop};
631 
632  // Produce the art clusters
633  size_t nextClusterId(0);
634  IdToIdVectorMap pandoraClusterToArtClustersMap;
635  for (const pandora::Cluster* const pCluster : clusterList) {
636  std::vector<HitVector> hitVectors;
637  const std::vector<recob::Cluster> clusters(
639  pCluster,
640  clusterList,
641  pandoraHitToArtHitMap,
642  pandoraClusterToArtClustersMap,
643  hitVectors,
644  nextClusterId,
645  clusterParamAlgo));
646 
647  if (hitVectors.size() != clusters.size())
648  throw cet::exception("LArPandora")
649  << " LArPandoraOutput::BuildClusters --- invalid hit vectors for clusters produced ";
650 
651  for (unsigned int i = 0; i < clusters.size(); ++i) {
653  event, instanceLabel, nextClusterId - 1, hitVectors.at(i), outputClustersToHits);
654  outputClusters->push_back(clusters.at(i));
655  }
656  }
657 
658  // Get mapping from pfo id to art cluster id
659  for (IdToIdVectorMap::const_iterator it = pfoToClustersMap.begin();
660  it != pfoToClustersMap.end();
661  ++it) {
662  if (!pfoToArtClustersMap.insert(IdToIdVectorMap::value_type(it->first, {})).second)
663  throw cet::exception("LArPandora")
664  << " LArPandoraOutput::BuildClusters --- repeated pfo ids ";
665 
666  for (const size_t pandoraClusterId : it->second) {
667  IdToIdVectorMap::const_iterator it2(pandoraClusterToArtClustersMap.find(pandoraClusterId));
668 
669  if (it2 == pandoraClusterToArtClustersMap.end())
670  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- found a "
671  "pandora cluster with no associated recob cluster ";
672 
673  for (const size_t recobClusterId : it2->second)
674  pfoToArtClustersMap.at(it->first).push_back(recobClusterId);
675  }
676  }
677  }
678 
679  //------------------------------------------------------------------------------------------------------------------------------------------
680 
682  const art::Event& event,
683  const std::string& instanceLabel,
684  const pandora::PfoVector& pfoVector,
685  const IdToIdVectorMap& pfoToVerticesMap,
686  const IdToIdVectorMap& pfoToThreeDHitsMap,
687  const IdToIdVectorMap& pfoToArtClustersMap,
688  PFParticleCollection& outputParticles,
689  PFParticleToVertexCollection& outputParticlesToVertices,
690  PFParticleToSpacePointCollection& outputParticlesToSpacePoints,
691  PFParticleToClusterCollection& outputParticlesToClusters)
692  {
693  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
694  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
695 
696  outputParticles->push_back(LArPandoraOutput::BuildPFParticle(pPfo, pfoId, pfoVector));
697 
698  // Associations from PFParticle
699  if (pfoToVerticesMap.find(pfoId) != pfoToVerticesMap.end())
701  event, instanceLabel, pfoId, pfoToVerticesMap, outputParticlesToVertices);
702 
703  if (pfoToThreeDHitsMap.find(pfoId) != pfoToThreeDHitsMap.end())
705  event, instanceLabel, pfoId, pfoToThreeDHitsMap, outputParticlesToSpacePoints);
706 
707  if (pfoToArtClustersMap.find(pfoId) != pfoToArtClustersMap.end())
709  event, instanceLabel, pfoId, pfoToArtClustersMap, outputParticlesToClusters);
710  }
711  }
712 
713  //------------------------------------------------------------------------------------------------------------------------------------------
714 
716  const art::Event& event,
717  const std::string& instanceLabel,
718  const pandora::PfoVector& pfoVector,
719  const IdToIdVectorMap& pfoToVerticesMap,
720  PFParticleToVertexCollection& outputParticlesToVertices)
721  {
722  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
723  if (pfoToVerticesMap.find(pfoId) != pfoToVerticesMap.end())
725  event, instanceLabel, pfoId, pfoToVerticesMap, outputParticlesToVertices);
726  }
727  }
728 
729  //------------------------------------------------------------------------------------------------------------------------------------------
730 
732  const art::Event& event,
733  const std::string& instanceLabel,
734  const pandora::PfoVector& pfoVector,
735  PFParticleMetadataCollection& outputParticleMetadata,
736  PFParticleToMetadataCollection& outputParticlesToMetadata)
737  {
738  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
739  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
740 
742  event, instanceLabel, pfoId, outputParticleMetadata->size(), outputParticlesToMetadata);
743  larpandoraobj::PFParticleMetadata pPFParticleMetadata(
745  outputParticleMetadata->push_back(pPFParticleMetadata);
746  }
747  }
748 
749  //------------------------------------------------------------------------------------------------------------------------------------------
750 
752  const pandora::Pandora* const pPrimaryPandora,
753  const art::Event& event,
754  const std::string& instanceLabel,
755  const pandora::PfoVector& pfoVector,
756  const IdToHitMap& idToHitMap,
757  SliceCollection& outputSlices,
758  PFParticleToSliceCollection& outputParticlesToSlices,
759  SliceToHitCollection& outputSlicesToHits)
760  {
761  // Check for the special case in which there are no slices, and only the neutrino reconstruction was used on all hits
762  if (settings.m_isNeutrinoRecoOnlyNoSlicing) {
764  event,
765  instanceLabel,
766  pfoVector,
767  idToHitMap,
768  outputSlices,
769  outputParticlesToSlices,
770  outputSlicesToHits);
771  return;
772  }
773 
774  // Collect the slice pfos - one per slice (if there is no slicing instance, this vector will be empty)
775  pandora::PfoVector slicePfos;
776  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
777 
778  // Make one slice per Pandora Slice pfo
779  for (const pandora::ParticleFlowObject* const pSlicePfo : slicePfos)
781  pSlicePfo, event, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits);
782 
783  // Make a slice for every remaining pfo hierarchy that wasn't already in a slice
784  std::unordered_map<const pandora::ParticleFlowObject*, unsigned int> parentPfoToSliceIndexMap;
785  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
786  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
787 
788  // If this PFO is the parent of a hierarchy we have yet to use, then add a new slice
789  if (LArPandoraOutput::IsFromSlice(pPfo)) continue;
790 
791  if (lar_content::LArPfoHelper::GetParentPfo(pPfo) != pPfo) continue;
792 
793  if (!parentPfoToSliceIndexMap
794  .emplace(pPfo,
796  pPfo, event, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits))
797  .second)
798  throw cet::exception("LArPandora")
799  << " LArPandoraOutput::BuildSlices --- found repeated primary particles ";
800  }
801 
802  // Add the associations from PFOs to slices
803  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
804  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
805 
806  // For PFOs that are from a Pandora slice, add the association and move on to the next PFO
807  if (LArPandoraOutput::IsFromSlice(pPfo)) {
809  instanceLabel,
810  pfoId,
812  outputParticlesToSlices);
813  continue;
814  }
815 
816  // Get the parent of the particle
817  const pandora::ParticleFlowObject* const pParent(
819  if (parentPfoToSliceIndexMap.find(pParent) == parentPfoToSliceIndexMap.end())
820  throw cet::exception("LArPandora")
821  << " LArPandoraOutput::BuildSlices --- found pfo without a parent in the input list ";
822 
823  // Add the association from the PFO to the slice
825  event, instanceLabel, pfoId, parentPfoToSliceIndexMap.at(pParent), outputParticlesToSlices);
826  }
827  }
828 
829  //------------------------------------------------------------------------------------------------------------------------------------------
830 
832  {
833  // Make a slice with dummy properties
834  const float bogusFloat(std::numeric_limits<float>::max());
835  const recob::tracking::Point_t bogusPoint(bogusFloat, bogusFloat, bogusFloat);
836  const recob::tracking::Vector_t bogusVector(bogusFloat, bogusFloat, bogusFloat);
837 
838  const unsigned int sliceIndex(outputSlices->size());
839  outputSlices->emplace_back(
840  sliceIndex, bogusPoint, bogusVector, bogusPoint, bogusPoint, bogusFloat, bogusFloat);
841 
842  return sliceIndex;
843  }
844 
845  //------------------------------------------------------------------------------------------------------------------------------------------
846 
848  const Settings& settings,
849  const art::Event& event,
850  const std::string& instanceLabel,
851  const pandora::PfoVector& pfoVector,
852  const IdToHitMap& idToHitMap,
853  SliceCollection& outputSlices,
854  PFParticleToSliceCollection& outputParticlesToSlices,
855  SliceToHitCollection& outputSlicesToHits)
856  {
857  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
858 
859  // Add all of the hits in the events to the slice
860  HitVector hits;
862  LArPandoraOutput::AddAssociation(event, instanceLabel, sliceIndex, hits, outputSlicesToHits);
863 
864  mf::LogDebug("LArPandora") << "Finding hits with label: " << settings.m_hitfinderModuleLabel
865  << std::endl;
866  mf::LogDebug("LArPandora") << " - Found " << hits.size() << std::endl;
867  mf::LogDebug("LArPandora") << " - Making associations " << outputSlicesToHits->size()
868  << std::endl;
869 
870  // Add all of the PFOs to the slice
871  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
873  event, instanceLabel, pfoId, sliceIndex, outputParticlesToSlices);
874  }
875 
876  //------------------------------------------------------------------------------------------------------------------------------------------
877 
878  unsigned int LArPandoraOutput::BuildSlice(const pandora::ParticleFlowObject* const pParentPfo,
879  const art::Event& event,
880  const std::string& instanceLabel,
881  const IdToHitMap& idToHitMap,
882  SliceCollection& outputSlices,
883  SliceToHitCollection& outputSlicesToHits)
884  {
885  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
886 
887  // Collect the pfos connected to the input primary pfos
888  pandora::PfoList pfosInSlice;
889  lar_content::LArPfoHelper::GetAllConnectedPfos(pParentPfo, pfosInSlice);
890  pfosInSlice.sort(lar_content::LArPfoHelper::SortByNHits);
891 
892  // Collect the hits from the pfos in all views
893  pandora::CaloHitList hits;
894  for (const pandora::ParticleFlowObject* const pPfo : pfosInSlice) {
895  for (const pandora::HitType& hitType :
896  {pandora::TPC_VIEW_U, pandora::TPC_VIEW_V, pandora::TPC_VIEW_W}) {
897  lar_content::LArPfoHelper::GetCaloHits(pPfo, hitType, hits);
899  }
900  }
901 
902  // Add the associations to the hits
903  for (const pandora::CaloHit* const pCaloHit : hits)
905  instanceLabel,
906  sliceIndex,
907  {LArPandoraOutput::GetHit(idToHitMap, pCaloHit)},
908  outputSlicesToHits);
909 
910  return sliceIndex;
911  }
912 
913  //------------------------------------------------------------------------------------------------------------------------------------------
914 
916  const std::string& instanceLabel,
917  const pandora::PfoVector& pfoVector,
918  T0Collection& outputT0s,
919  PFParticleToT0Collection& outputParticlesToT0s)
920  {
921  size_t nextT0Id(0);
922  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId) {
923  const pandora::ParticleFlowObject* const pPfo(pfoVector.at(pfoId));
924 
925  anab::T0 t0;
926  if (!LArPandoraOutput::BuildT0(event, pPfo, pfoVector, nextT0Id, t0)) continue;
927 
929  event, instanceLabel, pfoId, nextT0Id - 1, outputParticlesToT0s);
930  outputT0s->push_back(t0);
931  }
932  }
933 
934  //------------------------------------------------------------------------------------------------------------------------------------------
935 
936  recob::PFParticle LArPandoraOutput::BuildPFParticle(const pandora::ParticleFlowObject* const pPfo,
937  const size_t pfoId,
938  const pandora::PfoVector& pfoVector)
939  {
940  // Get parent Pfo ID
941  const pandora::PfoList& parentList(pPfo->GetParentPfoList());
942  if (parentList.size() > 1)
943  throw cet::exception("LArPandora")
944  << " LArPandoraOutput::BuildPFParticle --- this pfo has multiple parent particles ";
945 
946  const size_t parentId(parentList.empty() ?
948  LArPandoraOutput::GetId(parentList.front(), pfoVector));
949 
950  // Get daughters Pfo IDs
951  std::vector<size_t> daughterIds;
952  for (const pandora::ParticleFlowObject* const pDaughterPfo : pPfo->GetDaughterPfoList())
953  daughterIds.push_back(LArPandoraOutput::GetId(pDaughterPfo, pfoVector));
954 
955  std::sort(daughterIds.begin(), daughterIds.end());
956 
957  return recob::PFParticle(pPfo->GetParticleId(), pfoId, parentId, daughterIds);
958  }
959 
960  //------------------------------------------------------------------------------------------------------------------------------------------
961 
963  const size_t vertexId)
964  {
965  double pos[3] = {
966  pVertex->GetPosition().GetX(), pVertex->GetPosition().GetY(), pVertex->GetPosition().GetZ()};
967  return recob::Vertex(pos, vertexId);
968  }
969 
970  //------------------------------------------------------------------------------------------------------------------------------------------
971 
972  void LArPandoraOutput::GetHitsInCluster(const pandora::Cluster* const pCluster,
973  pandora::CaloHitVector& sortedHits)
974  {
975  if (!sortedHits.empty())
976  throw cet::exception("LArPandora")
977  << " LArPandoraOutput::GetHitsInCluster --- vector to hold hits is not empty ";
978 
979  pandora::CaloHitList hitList;
980  pCluster->GetOrderedCaloHitList().FillCaloHitList(hitList);
981  hitList.insert(hitList.end(),
982  pCluster->GetIsolatedCaloHitList().begin(),
983  pCluster->GetIsolatedCaloHitList().end());
984 
985  sortedHits.insert(sortedHits.end(), hitList.begin(), hitList.end());
986  std::sort(
987  sortedHits.begin(), sortedHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
988  }
989 
990  //------------------------------------------------------------------------------------------------------------------------------------------
991 
992  std::vector<recob::Cluster> LArPandoraOutput::BuildClusters(
993  util::GeometryUtilities const& gser,
994  const pandora::Cluster* const pCluster,
995  const pandora::ClusterList& clusterList,
996  const CaloHitToArtHitMap& pandoraHitToArtHitMap,
997  IdToIdVectorMap& pandoraClusterToArtClustersMap,
998  std::vector<HitVector>& hitVectors,
999  size_t& nextId,
1001  {
1002  std::vector<recob::Cluster> clusters;
1003 
1004  // Get the cluster ID and set up the map entry
1005  const size_t clusterId(LArPandoraOutput::GetId(pCluster, clusterList));
1006  if (!pandoraClusterToArtClustersMap.insert(IdToIdVectorMap::value_type(clusterId, {})).second)
1007  throw cet::exception("LArPandora")
1008  << " LArPandoraOutput::BuildClusters --- repeated clusters in input list ";
1009 
1010  pandora::CaloHitVector sortedHits;
1011  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
1012 
1013  HitArray hitArray; // hits organised by drift volume
1014  HitList isolatedHits;
1015 
1016  for (const pandora::CaloHit* const pCaloHit2D : sortedHits) {
1017  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit2D));
1018  if (it == pandoraHitToArtHitMap.end())
1019  throw cet::exception("LArPandora")
1020  << " LArPandoraOutput::BuildClusters --- couldn't find art hit for input pandora hit ";
1021 
1022  const art::Ptr<recob::Hit> hit(it->second);
1023 
1024  const geo::WireID wireID(hit->WireID());
1025  const unsigned int volID(100000 * wireID.Cryostat + wireID.TPC);
1026  hitArray[volID].push_back(hit);
1027 
1028  if (pCaloHit2D->IsIsolated()) isolatedHits.insert(hit);
1029  }
1030 
1031  if (hitArray.empty())
1032  throw cet::exception("LArPandora")
1033  << " LArPandoraOutput::BuildClusters --- found a cluster with no hits ";
1034 
1035  for (const HitArray::value_type& hitArrayEntry : hitArray) {
1036  const HitVector& clusterHits(hitArrayEntry.second);
1037 
1038  clusters.push_back(
1039  LArPandoraOutput::BuildCluster(gser, nextId, clusterHits, isolatedHits, algo));
1040  hitVectors.push_back(clusterHits);
1041  pandoraClusterToArtClustersMap.at(clusterId).push_back(nextId);
1042 
1043  nextId++;
1044  }
1045 
1046  return clusters;
1047  }
1048 
1049  //------------------------------------------------------------------------------------------------------------------------------------------
1050 
1052  const size_t id,
1053  const HitVector& hitVector,
1054  const HitList& isolatedHits,
1056  {
1057  if (hitVector.empty())
1058  throw cet::exception("LArPandora")
1059  << " LArPandoraOutput::BuildCluster --- No input hits were provided ";
1060 
1061  // Fill list of cluster properties
1062  geo::View_t view(geo::kUnknown);
1063  geo::PlaneID planeID;
1064 
1065  double startWire(+std::numeric_limits<float>::max()), sigmaStartWire(0.0);
1066  double startTime(+std::numeric_limits<float>::max()), sigmaStartTime(0.0);
1067  double endWire(-std::numeric_limits<float>::max()), sigmaEndWire(0.0);
1068  double endTime(-std::numeric_limits<float>::max()), sigmaEndTime(0.0);
1069 
1070  std::vector<recob::Hit const*> hits_for_params;
1071  hits_for_params.reserve(hitVector.size());
1072 
1073  for (const art::Ptr<recob::Hit>& hit : hitVector) {
1074  const double thisWire(hit->WireID().Wire);
1075  const double thisWireSigma(0.5);
1076  const double thisTime(hit->PeakTime());
1077  const double thisTimeSigma(double(2. * hit->RMS()));
1078  const geo::View_t thisView(hit->View());
1079  const geo::PlaneID thisPlaneID(hit->WireID().planeID());
1080 
1081  if (geo::kUnknown == view) {
1082  view = thisView;
1083  planeID = thisPlaneID;
1084  }
1085 
1086  if (!(thisView == view && thisPlaneID == planeID)) {
1087  throw cet::exception("LArPandora")
1088  << " LArPandoraOutput::BuildCluster --- Input hits have inconsistent plane IDs ";
1089  }
1090 
1091  hits_for_params.push_back(&*hit);
1092 
1093  if (isolatedHits.count(hit)) continue;
1094 
1095  if (thisWire < startWire || (thisWire == startWire && thisTime < startTime)) {
1096  startWire = thisWire;
1097  sigmaStartWire = thisWireSigma;
1098  startTime = thisTime;
1099  sigmaStartTime = thisTimeSigma;
1100  }
1101 
1102  if (thisWire > endWire || (thisWire == endWire && thisTime > endTime)) {
1103  endWire = thisWire;
1104  sigmaEndWire = thisWireSigma;
1105  endTime = thisTime;
1106  sigmaEndTime = thisTimeSigma;
1107  }
1108  }
1109 
1110  // feed the algorithm with all the cluster hits
1111  algo.SetHitsFromPointers(gser, hits_for_params);
1112 
1113  // create the recob::Cluster directly in the vector
1114  return cluster::ClusterCreator(gser,
1115  algo, // algo
1116  startWire, // start_wire
1117  sigmaStartWire, // sigma_start_wire
1118  startTime, // start_tick
1119  sigmaStartTime, // sigma_start_tick
1120  endWire, // end_wire
1121  sigmaEndWire, // sigma_end_wire
1122  endTime, // end_tick
1123  sigmaEndTime, // sigma_end_tick
1124  id, // ID
1125  view, // view
1126  planeID, // plane
1127  recob::Cluster::Sentry // sentry
1128  )
1129  .move();
1130  }
1131 
1132  //------------------------------------------------------------------------------------------------------------------------------------------
1133 
1134  recob::SpacePoint LArPandoraOutput::BuildSpacePoint(const pandora::CaloHit* const pCaloHit,
1135  const size_t spacePointId)
1136  {
1137  if (pandora::TPC_3D != pCaloHit->GetHitType())
1138  throw cet::exception("LArPandora")
1139  << " LArPandoraOutput::BuildSpacePoint --- trying to build a space point from a 2D hit";
1140 
1141  const pandora::CartesianVector point(pCaloHit->GetPositionVector());
1142  double xyz[3] = {point.GetX(), point.GetY(), point.GetZ()};
1143 
1144  // ATTN using dummy information
1145  double dxdydz[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // TODO: Fill in the error matrix
1146  double chi2(0.0);
1147 
1148  return recob::SpacePoint(xyz, dxdydz, chi2, spacePointId);
1149  }
1150 
1151  //------------------------------------------------------------------------------------------------------------------------------------------
1152 
1154  const pandora::ParticleFlowObject* const pPfo,
1155  const pandora::PfoVector& pfoVector,
1156  size_t& nextId,
1157  anab::T0& t0)
1158  {
1159  const pandora::ParticleFlowObject* const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
1160  const float x0(pParent->GetPropertiesMap().count("X0") ? pParent->GetPropertiesMap().at("X0") :
1161  0.f);
1162 
1163  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e);
1164  auto const det_prop =
1166  const double cm_per_tick(det_prop.GetXTicksCoefficient());
1167  const double ns_per_tick(sampling_rate(clock_data));
1168 
1169  // ATTN: T0 values are currently calculated in nanoseconds relative to the trigger offset. Only non-zero values are outputted.
1170  const double T0(x0 * ns_per_tick / cm_per_tick);
1171 
1172  if (std::fabs(T0) <= std::numeric_limits<double>::epsilon()) return false;
1173 
1174  // Output T0 objects [arguments are: time (nanoseconds); trigger type (3 for TPC stitching!); pfparticle SelfID code; T0 ID code]
1175  t0 = anab::T0(T0, 3, LArPandoraOutput::GetId(pPfo, pfoVector), nextId++);
1176 
1177  return true;
1178  }
1179 
1180  //------------------------------------------------------------------------------------------------------------------------------------------
1181  //------------------------------------------------------------------------------------------------------------------------------------------
1182 
1184  : m_pPrimaryPandora(nullptr)
1185  , m_shouldRunStitching(false)
1186  , m_shouldProduceAllOutcomes(false)
1187  , m_shouldProduceTestBeamInteractionVertices(false)
1188  , m_isNeutrinoRecoOnlyNoSlicing(false)
1189  {}
1190 
1191  //------------------------------------------------------------------------------------------------------------------------------------------
1192 
1194  {
1195  if (!m_pPrimaryPandora)
1196  throw cet::exception("LArPandora")
1197  << " LArPandoraOutput::Settings::Validate --- primary Pandora instance does not exist ";
1198 
1199  if (!m_shouldProduceAllOutcomes) return;
1200 
1201  if (m_allOutcomesInstanceLabel.empty())
1202  throw cet::exception("LArPandora")
1203  << " LArPandoraOutput::Settings::Validate --- all outcomes instance label not set ";
1204  }
1205 
1206 } // namespace lar_pandora
code to link reconstructed objects back to the MC truth information
std::map< int, art::Ptr< recob::Hit > > IdToHitMap
Definition: ILArPandora.h:24
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...
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:57
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::map< int, HitVector > HitArray
Unknown view.
Definition: geo_types.h:138
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.
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:364
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
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Definition: AddMC.C:8
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:69
std::unique_ptr< art::Assns< recob::PFParticle, larpandoraobj::PFParticleMetadata > > PFParticleToMetadataCollection
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.
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:290
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.
virtual void SetHitsFromPointers(util::GeometryUtilities const &gser, std::vector< recob::Hit const * > const &hits)=0
Sets the list of input hits.
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.
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:174
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
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
std::vector< size_t > IdVector
void hits()
Definition: readHits.C:15
Metadata associated to PFParticles.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
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.
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.
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:31
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.
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.
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
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
Utility object to perform functions of association.
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...
HitType
Definition: HitType.h:12
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:8
Float_t e
Definition: plot.C:35
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:82
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:27
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...
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
art framework interface to geometry description
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.
Event finding and building.