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