LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LArPandoraOutput.cxx
Go to the documentation of this file.
1 
9 #include "cetlib_except/exception.h"
11 
16 
24 
28 
29 #include "Api/PandoraApi.h"
30 
31 #include "Objects/CaloHit.h"
32 #include "Objects/Cluster.h"
33 #include "Objects/ParticleFlowObject.h"
34 #include "Objects/Vertex.h"
35 
39 
41 
42 #include <algorithm>
43 #include <iterator>
44 #include <iostream>
45 #include <limits>
46 
47 namespace lar_pandora
48 {
49 
50 void LArPandoraOutput::ProduceArtOutput(const Settings &settings, const IdToHitMap &idToHitMap, art::Event &evt)
51 {
52  settings.Validate();
53  const std::string instanceLabel(settings.m_shouldProduceAllOutcomes ? settings.m_allOutcomesInstanceLabel : "");
54 
55  // Set up the output collections
56  PFParticleCollection outputParticles( new std::vector<recob::PFParticle> );
57  VertexCollection outputVertices( new std::vector<recob::Vertex> );
58  ClusterCollection outputClusters( new std::vector<recob::Cluster> );
59  SpacePointCollection outputSpacePoints( new std::vector<recob::SpacePoint> );
60  T0Collection outputT0s( new std::vector<anab::T0> );
61  PFParticleMetadataCollection outputParticleMetadata( new std::vector<larpandoraobj::PFParticleMetadata> );
62  SliceCollection outputSlices( new std::vector<recob::Slice> );
63 
64  // Set up the output associations
74 
75  // Collect immutable lists of pandora collections that we should convert to ART format
76  const pandora::PfoVector pfoVector(settings.m_shouldProduceAllOutcomes ?
79 
80  IdToIdVectorMap pfoToVerticesMap;
81  const pandora::VertexVector vertexVector(LArPandoraOutput::CollectVertices(pfoVector, pfoToVerticesMap));
82 
83  IdToIdVectorMap pfoToClustersMap;
84  const pandora::ClusterList clusterList(LArPandoraOutput::CollectClusters(pfoVector, pfoToClustersMap));
85 
86  IdToIdVectorMap pfoToThreeDHitsMap;
87  const pandora::CaloHitList threeDHitList(LArPandoraOutput::Collect3DHits(pfoVector, pfoToThreeDHitsMap));
88 
89  // Get mapping from pandora hits to art hits
90  CaloHitToArtHitMap pandoraHitToArtHitMap;
91  LArPandoraOutput::GetPandoraToArtHitMap(clusterList, threeDHitList, idToHitMap, pandoraHitToArtHitMap);
92 
93  // Build the ART outputs from the pandora objects
94  LArPandoraOutput::BuildVertices(vertexVector, outputVertices);
95  LArPandoraOutput::BuildSpacePoints(evt, settings.m_pProducer, instanceLabel, threeDHitList, pandoraHitToArtHitMap, outputSpacePoints, outputSpacePointsToHits);
96 
97  IdToIdVectorMap pfoToArtClustersMap;
98  LArPandoraOutput::BuildClusters(evt, settings.m_pProducer, instanceLabel, clusterList, pandoraHitToArtHitMap, pfoToClustersMap, outputClusters, outputClustersToHits, pfoToArtClustersMap);
99 
100  LArPandoraOutput::BuildPFParticles(evt, settings.m_pProducer, instanceLabel, pfoVector, pfoToVerticesMap, pfoToThreeDHitsMap, pfoToArtClustersMap, outputParticles, outputParticlesToVertices, outputParticlesToSpacePoints, outputParticlesToClusters);
101 
102  LArPandoraOutput::BuildParticleMetadata(evt, settings.m_pProducer, instanceLabel, pfoVector, outputParticleMetadata, outputParticlesToMetadata);
103  LArPandoraOutput::BuildSlices(settings, settings.m_pPrimaryPandora, evt, settings.m_pProducer, instanceLabel, pfoVector, idToHitMap, outputSlices, outputParticlesToSlices, outputSlicesToHits);
104 
105  if (settings.m_shouldRunStitching)
106  LArPandoraOutput::BuildT0s(evt, settings.m_pProducer, instanceLabel, pfoVector, outputT0s, pandoraHitToArtHitMap, outputParticlesToT0s);
107 
108  // Add the outputs to the event
109  evt.put(std::move(outputParticles), instanceLabel);
110  evt.put(std::move(outputSpacePoints), instanceLabel);
111  evt.put(std::move(outputClusters), instanceLabel);
112  evt.put(std::move(outputVertices), instanceLabel);
113  evt.put(std::move(outputParticleMetadata), instanceLabel);
114  evt.put(std::move(outputSlices), instanceLabel);
115 
116  evt.put(std::move(outputParticlesToMetadata), instanceLabel);
117  evt.put(std::move(outputParticlesToSpacePoints), instanceLabel);
118  evt.put(std::move(outputParticlesToClusters), instanceLabel);
119  evt.put(std::move(outputParticlesToVertices), instanceLabel);
120  evt.put(std::move(outputParticlesToSlices), instanceLabel);
121  evt.put(std::move(outputSpacePointsToHits), instanceLabel);
122  evt.put(std::move(outputClustersToHits), instanceLabel);
123  evt.put(std::move(outputSlicesToHits), instanceLabel);
124 
125  if (settings.m_shouldRunStitching)
126  {
127  evt.put(std::move(outputT0s), instanceLabel);
128  evt.put(std::move(outputParticlesToT0s), instanceLabel);
129  }
130 }
131 
132 //------------------------------------------------------------------------------------------------------------------------------------------
133 
134 bool LArPandoraOutput::GetPandoraInstance(const pandora::Pandora *const pPrimaryPandora, const std::string &name,
135  const pandora::Pandora *&pPandoraInstance)
136 {
137  if (!pPrimaryPandora)
138  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- input primary pandora instance address is invalid ";
139 
140  if (pPandoraInstance)
141  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- the input pandora instance address is non-null ";
142 
143  for (const pandora::Pandora *const pPandora : MultiPandoraApi::GetDaughterPandoraInstanceList(pPrimaryPandora))
144  {
145  if (pPandora->GetName() != name)
146  continue;
147 
148  if (pPandoraInstance)
149  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraInstance--- found multiple pandora instances with name: " << name;
150 
151  pPandoraInstance = pPandora;
152  }
153 
154  return static_cast<bool>(pPandoraInstance);
155 }
156 
157 //------------------------------------------------------------------------------------------------------------------------------------------
158 
159 void LArPandoraOutput::GetPandoraSlices(const pandora::Pandora *const pPrimaryPandora, pandora::PfoVector &slicePfos)
160 {
161  if (!slicePfos.empty())
162  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraSlices--- Input slicePfo vector is not empty ";
163 
164  // Get the pandora slicing worker - if it exists
165  const pandora::Pandora *pSlicingWorker(nullptr);
166  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SlicingWorker", pSlicingWorker))
167  return;
168 
169  // Get the slice PFOs - one PFO per slice
170  const pandora::PfoList *pSlicePfoList(nullptr);
171  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::GetCurrentPfoList(*pSlicingWorker, pSlicePfoList));
172 
173  slicePfos.insert(slicePfos.end(), pSlicePfoList->begin(), pSlicePfoList->end());
174 }
175 
176 //------------------------------------------------------------------------------------------------------------------------------------------
177 
178 pandora::PfoVector LArPandoraOutput::CollectAllPfoOutcomes(const pandora::Pandora *const pPrimaryPandora)
179 {
180  pandora::PfoList collectedPfos;
181 
182  // Get the list of slice pfos - one per slice
183  pandora::PfoVector slicePfos;
184  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
185 
186  // Identify the pandora worker instances by their name
187  const pandora::Pandora *pSliceNuWorker(nullptr);
188  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceNuWorker", pSliceNuWorker))
189  throw cet::exception("LArPandora") << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice nu worker instance. ";
190 
191  const pandora::Pandora *pSliceCRWorker(nullptr);
192  if (!LArPandoraOutput::GetPandoraInstance(pPrimaryPandora, "SliceCRWorker", pSliceCRWorker))
193  throw cet::exception("LArPandora") << " LArPandoraOutput::CollectAllPfoOutcomes--- Can't find slice CR worker instance. ";
194 
195  // Collect slices under both reconstruction hypotheses
196  for (unsigned int sliceIndex = 0; sliceIndex < slicePfos.size(); ++sliceIndex)
197  {
198  const pandora::PfoList *pNuPfoList(nullptr);
199  if (pandora::STATUS_CODE_SUCCESS == PandoraApi::GetPfoList(*pSliceNuWorker, "NeutrinoParticles3D" + std::to_string(sliceIndex), pNuPfoList))
200  collectedPfos.insert(collectedPfos.end(), pNuPfoList->begin(), pNuPfoList->end());
201 
202  const pandora::PfoList *pCRPfoList(nullptr);
203  if (pandora::STATUS_CODE_SUCCESS == PandoraApi::GetPfoList(*pSliceCRWorker, "MuonParticles3D" + std::to_string(sliceIndex), pCRPfoList))
204  collectedPfos.insert(collectedPfos.end(), pCRPfoList->begin(), pCRPfoList->end());
205  }
206 
207  // Get the list of the parent pfos from the primary pandora instance
208  const pandora::PfoList *pParentPfoList(nullptr);
209  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
210 
211  // Collect clear cosmic-rays
212  for (const pandora::ParticleFlowObject *const pPfo : *pParentPfoList)
213  {
215  collectedPfos.push_back(pPfo);
216  }
217 
218  // Collect all pfos that are downstream of the parents we have collected
219  pandora::PfoVector pfoVector;
220  LArPandoraOutput::CollectPfos(collectedPfos, pfoVector);
221 
222  return pfoVector;
223 }
224 
225 //------------------------------------------------------------------------------------------------------------------------------------------
226 
227 bool LArPandoraOutput::IsClearCosmic(const pandora::ParticleFlowObject *const pPfo)
228 {
229  const pandora::ParticleFlowObject *const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
230 
231  const auto &properties(pParent->GetPropertiesMap());
232  const auto it(properties.find("IsClearCosmic"));
233 
234  if (it == properties.end())
235  return false;
236 
237  return static_cast<bool>(std::round(it->second));
238 }
239 
240 //------------------------------------------------------------------------------------------------------------------------------------------
241 
242 bool LArPandoraOutput::IsFromSlice(const pandora::ParticleFlowObject *const pPfo)
243 {
244  const pandora::ParticleFlowObject *const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
245 
246  const auto &properties(pParent->GetPropertiesMap());
247  return (properties.find("SliceIndex") != properties.end());
248 }
249 
250 //------------------------------------------------------------------------------------------------------------------------------------------
251 
252 unsigned int LArPandoraOutput::GetSliceIndex(const pandora::ParticleFlowObject *const pPfo)
253 {
254  const pandora::ParticleFlowObject *const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
255 
256  const auto &properties(pParent->GetPropertiesMap());
257  const auto it(properties.find("SliceIndex"));
258 
259  if (it == properties.end())
260  throw cet::exception("LArPandora") << " LArPandoraOutput::GetSliceIndex--- Input PFO was not from a slice ";
261 
262  return static_cast<unsigned int>(std::round(it->second));
263 }
264 
265 //------------------------------------------------------------------------------------------------------------------------------------------
266 
267 pandora::PfoVector LArPandoraOutput::CollectPfos(const pandora::Pandora *const pPrimaryPandora)
268 {
269  const pandora::PfoList *pParentPfoList(nullptr);
270  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::GetCurrentPfoList(*pPrimaryPandora, pParentPfoList));
271 
272  pandora::PfoVector pfoVector;
273  LArPandoraOutput::CollectPfos(*pParentPfoList, pfoVector);
274 
275  return pfoVector;
276 }
277 
278 //------------------------------------------------------------------------------------------------------------------------------------------
279 
280 void LArPandoraOutput::CollectPfos(const pandora::PfoList &parentPfoList, pandora::PfoVector &pfoVector)
281 {
282  if (!pfoVector.empty())
283  throw cet::exception("LArPandora") << " LArPandoraOutput::CollectPfos--- trying to collect pfos into a non-empty list ";
284 
285  pandora::PfoList pfoList;
286  lar_content::LArPfoHelper::GetAllConnectedPfos(parentPfoList, pfoList);
287 
288  pfoVector.insert(pfoVector.end(), pfoList.begin(), pfoList.end());
289  std::sort(pfoVector.begin(), pfoVector.end(), lar_content::LArPfoHelper::SortByNHits);
290 }
291 
292 //------------------------------------------------------------------------------------------------------------------------------------------
293 
294 pandora::VertexVector LArPandoraOutput::CollectVertices(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToVerticesMap)
295 {
296  pandora::VertexVector vertexVector;
297 
298  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
299  {
300  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
301 
302  if (pPfo->GetVertexList().empty())
303  continue;
304 
305  const pandora::Vertex *const pVertex(lar_content::LArPfoHelper::GetVertex(pPfo));
306 
307  // Get the vertex ID and add it to the vertex list if required
308  const auto it(std::find(vertexVector.begin(), vertexVector.end(), pVertex));
309  const bool isInList(it != vertexVector.end());
310  const size_t vertexId(isInList ? std::distance(vertexVector.begin(), it) : vertexVector.size());
311 
312  if (!isInList)
313  vertexVector.push_back(pVertex);
314 
315  if (!pfoToVerticesMap.insert(IdToIdVectorMap::value_type(pfoId, {vertexId})).second)
316  throw cet::exception("LArPandora") << " LArPandoraOutput::CollectVertices --- repeated pfos in input list ";
317  }
318 
319  return vertexVector;
320 }
321 
322 //------------------------------------------------------------------------------------------------------------------------------------------
323 
324 pandora::ClusterList LArPandoraOutput::CollectClusters(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToClustersMap)
325 {
326  pandora::ClusterList clusterList;
327 
328  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
329  {
330  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
331 
332  // Get the sorted list of clusters from the pfo
333  pandora::ClusterList clusters;
336 
337  // Get incrementing id's for each cluster
338  IdVector clusterIds(clusters.size());
339  std::iota(clusterIds.begin(), clusterIds.end(), clusterList.size());
340 
341  clusterList.insert(clusterList.end(), clusters.begin(), clusters.end());
342 
343  if (!pfoToClustersMap.insert(IdToIdVectorMap::value_type(pfoId, clusterIds)).second)
344  throw cet::exception("LArPandora") << " LArPandoraOutput::CollectClusters --- repeated pfos in input list ";
345  }
346 
347  return clusterList;
348 }
349 
350 //------------------------------------------------------------------------------------------------------------------------------------------
351 
352 pandora::CaloHitList LArPandoraOutput::Collect3DHits(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToThreeDHitsMap)
353 {
354  pandora::CaloHitList caloHitList;
355 
356  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
357  {
358  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
359 
360  if (!pfoToThreeDHitsMap.insert(IdToIdVectorMap::value_type(pfoId, {})).second)
361  throw cet::exception("LArPandora") << " LArPandoraOutput::Collect3DHits --- repeated pfos in input list ";
362 
363  pandora::CaloHitVector sorted3DHits;
364  LArPandoraOutput::Collect3DHits(pPfo, sorted3DHits);
365 
366  for (const pandora::CaloHit *const pCaloHit3D : sorted3DHits)
367  {
368  if (pandora::TPC_3D != pCaloHit3D->GetHitType()) // TODO decide if this is required, or should I just insert them?
369  throw cet::exception("LArPandora") << " LArPandoraOutput::Collect3DHits --- found a 2D hit in a 3D cluster";
370 
371  pfoToThreeDHitsMap.at(pfoId).push_back(caloHitList.size());
372  caloHitList.push_back(pCaloHit3D);
373  }
374  }
375 
376  return caloHitList;
377 }
378 
379 //------------------------------------------------------------------------------------------------------------------------------------------
380 
381 void LArPandoraOutput::Collect3DHits(const pandora::ParticleFlowObject *const pPfo, pandora::CaloHitVector &caloHits)
382 {
383  // Get the sorted list of 3D hits associated with the pfo
384  pandora::CaloHitList threeDHits;
385  lar_content::LArPfoHelper::GetCaloHits(pPfo, pandora::TPC_3D, threeDHits);
386 
387  caloHits.insert(caloHits.end(), threeDHits.begin(), threeDHits.end());
388  std::sort(caloHits.begin(), caloHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
389 }
390 
391 //------------------------------------------------------------------------------------------------------------------------------------------
392 
393 void LArPandoraOutput::GetPandoraToArtHitMap(const pandora::ClusterList &clusterList, const pandora::CaloHitList &threeDHitList,
394  const IdToHitMap &idToHitMap, CaloHitToArtHitMap &pandoraHitToArtHitMap)
395 {
396  // Collect 2D hits from clusters
397  for (const pandora::Cluster *const pCluster : clusterList)
398  {
399  if (pandora::TPC_3D == lar_content::LArClusterHelper::GetClusterHitType(pCluster))
400  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraToArtHitMap --- found a 3D input cluster ";
401 
402  pandora::CaloHitVector sortedHits;
403  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
404 
405  for (const pandora::CaloHit *const pCaloHit : sortedHits)
406  {
407  if (!pandoraHitToArtHitMap.insert(CaloHitToArtHitMap::value_type(pCaloHit, LArPandoraOutput::GetHit(idToHitMap, pCaloHit))).second)
408  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
409  }
410  }
411 
412  for (const pandora::CaloHit *const pCaloHit : threeDHitList)
413  {
414  if (pCaloHit->GetHitType() != pandora::TPC_3D)
415  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraToArtHitMap --- found a non-3D hit in the input list ";
416 
417  // ATTN get the 2D calo hit from the 3D calo hit then find the art hit!
418  if (!pandoraHitToArtHitMap.insert(CaloHitToArtHitMap::value_type(pCaloHit, LArPandoraOutput::GetHit(idToHitMap, static_cast<const pandora::CaloHit*>(pCaloHit->GetParentAddress())))).second)
419  throw cet::exception("LArPandora") << " LArPandoraOutput::GetPandoraToArtHitMap --- found repeated input hits ";
420  }
421 }
422 
423 //------------------------------------------------------------------------------------------------------------------------------------------
424 
425 art::Ptr<recob::Hit> LArPandoraOutput::GetHit(const IdToHitMap &idToHitMap, const pandora::CaloHit *const pCaloHit)
426 {
427  // TODO make this less evil
428 
429  // ATTN The CaloHit can come from the primary pandora instance (depth = 0) or one of its daughers (depth = 1).
430  // Here we keep trying to access the ART hit increasing the depth step-by-step
431  for (unsigned int depth = 0, maxDepth = 2; depth < maxDepth; ++depth)
432  {
433  // Navigate to the hit address in the pandora master instance (assuming the depth is correct)
434  const pandora::CaloHit *pParentCaloHit = pCaloHit;
435  for (unsigned int i = 0; i < depth; ++i)
436  pParentCaloHit = static_cast<const pandora::CaloHit *>(pCaloHit->GetParentAddress());
437 
438  // Attempt to find the mapping from the "parent" calo hit to the ART hit
439  const void *const pHitAddress(pParentCaloHit->GetParentAddress());
440  const intptr_t hitID_temp((intptr_t)(pHitAddress));
441  const int hitID((int)(hitID_temp));
442 
443  IdToHitMap::const_iterator artIter = idToHitMap.find(hitID);
444 
445  // If there is no such mapping from "parent" calo hit to the ART hit, then increase the depth and try again!
446  if (idToHitMap.end() == artIter)
447  continue;
448 
449  return artIter->second;
450  }
451 
452  throw cet::exception("LArPandora") << " LArPandoraOutput::GetHit --- found a Pandora hit without a parent ART hit ";
453 }
454 
455 //------------------------------------------------------------------------------------------------------------------------------------------
456 
458 {
459  for (size_t vertexId = 0; vertexId < vertexVector.size(); ++vertexId)
460  outputVertices->push_back(LArPandoraOutput::BuildVertex(vertexVector.at(vertexId), vertexId));
461 }
462 
463 //------------------------------------------------------------------------------------------------------------------------------------------
464 
465 void LArPandoraOutput::BuildSpacePoints(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel,
466  const pandora::CaloHitList &threeDHitList, const CaloHitToArtHitMap &pandoraHitToArtHitMap, SpacePointCollection &outputSpacePoints,
467  SpacePointToHitCollection &outputSpacePointsToHits)
468 {
469  pandora::CaloHitVector threeDHitVector;
470  threeDHitVector.insert(threeDHitVector.end(), threeDHitList.begin(), threeDHitList.end());
471 
472  for (unsigned int hitId = 0; hitId < threeDHitVector.size(); hitId++)
473  {
474  const pandora::CaloHit *const pCaloHit(threeDHitVector.at(hitId));
475 
476  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit));
477  if (it == pandoraHitToArtHitMap.end())
478  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSpacePoints --- found a pandora hit without a corresponding art hit ";
479 
480  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, hitId, {it->second}, outputSpacePointsToHits);
481  outputSpacePoints->push_back(LArPandoraOutput::BuildSpacePoint(pCaloHit, hitId));
482  }
483 }
484 
485 //------------------------------------------------------------------------------------------------------------------------------------------
486 
487 void LArPandoraOutput::BuildClusters(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::ClusterList &clusterList,
488  const CaloHitToArtHitMap &pandoraHitToArtHitMap, const IdToIdVectorMap &pfoToClustersMap, ClusterCollection &outputClusters,
489  ClusterToHitCollection &outputClustersToHits, IdToIdVectorMap &pfoToArtClustersMap)
490 {
491  cluster::StandardClusterParamsAlg clusterParamAlgo;
492 
493  // Produce the art clusters
494  size_t nextClusterId(0);
495  IdToIdVectorMap pandoraClusterToArtClustersMap;
496  for (const pandora::Cluster *const pCluster : clusterList)
497  {
498  std::vector<HitVector> hitVectors;
499  const std::vector<recob::Cluster> clusters(LArPandoraOutput::BuildClusters(pCluster, clusterList, pandoraHitToArtHitMap, pandoraClusterToArtClustersMap, hitVectors, nextClusterId, clusterParamAlgo));
500 
501  if (hitVectors.size() != clusters.size())
502  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- invalid hit vectors for clusters produced ";
503 
504  for (unsigned int i = 0; i < clusters.size(); ++i)
505  {
506  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, nextClusterId - 1, hitVectors.at(i), outputClustersToHits);
507  outputClusters->push_back(clusters.at(i));
508  }
509  }
510 
511  // Get mapping from pfo id to art cluster id
512  for (IdToIdVectorMap::const_iterator it = pfoToClustersMap.begin(); it != pfoToClustersMap.end(); ++it)
513  {
514  if (!pfoToArtClustersMap.insert(IdToIdVectorMap::value_type(it->first, {})).second)
515  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- repeated pfo ids ";
516 
517  for (const size_t pandoraClusterId : it->second)
518  {
519  IdToIdVectorMap::const_iterator it2(pandoraClusterToArtClustersMap.find(pandoraClusterId));
520 
521  if (it2 == pandoraClusterToArtClustersMap.end())
522  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- found a pandora cluster with no associated recob cluster ";
523 
524  for (const size_t recobClusterId : it2->second)
525  pfoToArtClustersMap.at(it->first).push_back(recobClusterId);
526  }
527  }
528 }
529 
530 //------------------------------------------------------------------------------------------------------------------------------------------
531 
532 void LArPandoraOutput::BuildPFParticles(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::PfoVector &pfoVector,
533  const IdToIdVectorMap &pfoToVerticesMap, const IdToIdVectorMap &pfoToThreeDHitsMap, const IdToIdVectorMap &pfoToArtClustersMap,
534  PFParticleCollection &outputParticles, PFParticleToVertexCollection &outputParticlesToVertices,
535  PFParticleToSpacePointCollection &outputParticlesToSpacePoints, PFParticleToClusterCollection &outputParticlesToClusters)
536 {
537  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
538  {
539  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
540 
541  outputParticles->push_back(LArPandoraOutput::BuildPFParticle(pPfo, pfoId, pfoVector));
542 
543  // Associations from PFParticle
544  if (pfoToVerticesMap.find(pfoId) != pfoToVerticesMap.end())
545  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, pfoToVerticesMap, outputParticlesToVertices);
546 
547  if (pfoToThreeDHitsMap.find(pfoId) != pfoToThreeDHitsMap.end())
548  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, pfoToThreeDHitsMap, outputParticlesToSpacePoints);
549 
550  if (pfoToArtClustersMap.find(pfoId) != pfoToArtClustersMap.end())
551  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, pfoToArtClustersMap, outputParticlesToClusters);
552  }
553 }
554 
555 //------------------------------------------------------------------------------------------------------------------------------------------
556 
558  const std::string &instanceLabel, const pandora::PfoVector &pfoVector, PFParticleMetadataCollection &outputParticleMetadata,
559  PFParticleToMetadataCollection &outputParticlesToMetadata)
560 {
561  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
562  {
563  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
564 
565  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, outputParticleMetadata->size(), outputParticlesToMetadata);
567  outputParticleMetadata->push_back(pPFParticleMetadata);
568  }
569 }
570 
571 //------------------------------------------------------------------------------------------------------------------------------------------
572 
573 void LArPandoraOutput::BuildSlices(const Settings &settings, const pandora::Pandora *const pPrimaryPandora, const art::Event &event,
574  const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::PfoVector &pfoVector,
575  const IdToHitMap &idToHitMap, SliceCollection &outputSlices, PFParticleToSliceCollection &outputParticlesToSlices,
576  SliceToHitCollection &outputSlicesToHits)
577 {
578  // Check for the special case in which there are no slices, and only the neutrino reconstruction was used on all hits
579  if (settings.m_isNeutrinoRecoOnlyNoSlicing)
580  {
581  LArPandoraOutput::CopyAllHitsToSingleSlice(settings, event, pProducer, instanceLabel, pfoVector, idToHitMap, outputSlices, outputParticlesToSlices, outputSlicesToHits);
582  return;
583  }
584 
585  // Collect the slice pfos - one per slice (if there is no slicing instance, this vector will be empty)
586  pandora::PfoVector slicePfos;
587  LArPandoraOutput::GetPandoraSlices(pPrimaryPandora, slicePfos);
588 
589  // Make one slice per Pandora Slice pfo
590  for (const pandora::ParticleFlowObject *const pSlicePfo : slicePfos)
591  LArPandoraOutput::BuildSlice(pSlicePfo, event, pProducer, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits);
592 
593  // Make a slice for every remaining pfo hierarchy that wasn't already in a slice
594  std::unordered_map<const pandora::ParticleFlowObject *, unsigned int> parentPfoToSliceIndexMap;
595  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
596  {
597  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
598 
599  // If this PFO is the parent of a hierarchy we have yet to use, then add a new slice
601  continue;
602 
603  if (lar_content::LArPfoHelper::GetParentPfo(pPfo) != pPfo)
604  continue;
605 
606  if (!parentPfoToSliceIndexMap.emplace(pPfo, LArPandoraOutput::BuildSlice(pPfo, event, pProducer, instanceLabel, idToHitMap, outputSlices, outputSlicesToHits)).second)
607  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSlices --- found repeated primary particles ";
608  }
609 
610  // Add the associations from PFOs to slices
611  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
612  {
613  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
614 
615  // For PFOs that are from a Pandora slice, add the association and move on to the next PFO
617  {
618  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, LArPandoraOutput::GetSliceIndex(pPfo), outputParticlesToSlices);
619  continue;
620  }
621 
622  // Get the parent of the particle
623  const pandora::ParticleFlowObject *const pParent(lar_content::LArPfoHelper::GetParentPfo(pPfo));
624  if (parentPfoToSliceIndexMap.find(pParent) == parentPfoToSliceIndexMap.end())
625  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSlices --- found pfo without a parent in the input list ";
626 
627  // Add the association from the PFO to the slice
628  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, parentPfoToSliceIndexMap.at(pParent), outputParticlesToSlices);
629  }
630 }
631 
632 //------------------------------------------------------------------------------------------------------------------------------------------
633 
635 {
636  // Make a slice with dummy properties
637  const float bogusFloat(std::numeric_limits<float>::max());
638  const recob::tracking::Point_t bogusPoint(bogusFloat, bogusFloat, bogusFloat);
639  const recob::tracking::Vector_t bogusVector(bogusFloat, bogusFloat, bogusFloat);
640 
641  const unsigned int sliceIndex(outputSlices->size());
642  outputSlices->emplace_back(sliceIndex, bogusPoint, bogusVector, bogusPoint, bogusPoint, bogusFloat, bogusFloat);
643 
644  return sliceIndex;
645 }
646 
647 //------------------------------------------------------------------------------------------------------------------------------------------
648 
649 void LArPandoraOutput::CopyAllHitsToSingleSlice(const Settings &settings, const art::Event &event, const art::EDProducer *const pProducer,
650  const std::string &instanceLabel, const pandora::PfoVector &pfoVector, const IdToHitMap &idToHitMap, SliceCollection &outputSlices,
651  PFParticleToSliceCollection &outputParticlesToSlices, SliceToHitCollection &outputSlicesToHits)
652 {
653  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
654 
655  // Add all of the hits in the events to the slice
656  HitVector hits;
658  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, sliceIndex, hits, outputSlicesToHits);
659 
660  mf::LogDebug("LArPandora") << "Finding hits with label: " << settings.m_hitfinderModuleLabel << std::endl;
661  mf::LogDebug("LArPandora") << " - Found " << hits.size() << std::endl;
662  mf::LogDebug("LArPandora") << " - Making associations " << outputSlicesToHits->size() << std::endl;
663 
664  // Add all of the PFOs to the slice
665  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
666  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, sliceIndex, outputParticlesToSlices);
667 }
668 
669 //------------------------------------------------------------------------------------------------------------------------------------------
670 
671 unsigned int LArPandoraOutput::BuildSlice(const pandora::ParticleFlowObject *const pParentPfo, const art::Event &event,
672  const art::EDProducer *const pProducer, const std::string &instanceLabel, const IdToHitMap &idToHitMap, SliceCollection &outputSlices,
673  SliceToHitCollection &outputSlicesToHits)
674 {
675  const unsigned int sliceIndex(LArPandoraOutput::BuildDummySlice(outputSlices));
676 
677  // Collect the pfos connected to the input primary pfos
678  pandora::PfoList pfosInSlice;
679  lar_content::LArPfoHelper::GetAllConnectedPfos(pParentPfo, pfosInSlice);
680  pfosInSlice.sort(lar_content::LArPfoHelper::SortByNHits);
681 
682  // Collect the hits from the pfos in all views
683  pandora::CaloHitList hits;
684  for (const pandora::ParticleFlowObject *const pPfo : pfosInSlice)
685  {
686  for (const pandora::HitType &hitType : {pandora::TPC_VIEW_U, pandora::TPC_VIEW_V, pandora::TPC_VIEW_W})
687  {
688  lar_content::LArPfoHelper::GetCaloHits(pPfo, hitType, hits);
690  }
691  }
692 
693  // Add the associations to the hits
694  for (const pandora::CaloHit *const pCaloHit : hits)
695  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, sliceIndex, {LArPandoraOutput::GetHit(idToHitMap, pCaloHit)}, outputSlicesToHits);
696 
697  return sliceIndex;
698 }
699 
700 //------------------------------------------------------------------------------------------------------------------------------------------
701 
702 void LArPandoraOutput::BuildT0s(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::PfoVector &pfoVector,
703  T0Collection &outputT0s, const CaloHitToArtHitMap &pandoraHitToArtHitMap,
704  PFParticleToT0Collection &outputParticlesToT0s)
705 {
706  size_t nextT0Id(0);
707  for (unsigned int pfoId = 0; pfoId < pfoVector.size(); ++pfoId)
708  {
709  const pandora::ParticleFlowObject *const pPfo(pfoVector.at(pfoId));
710 
711  anab::T0 t0;
712  if (!LArPandoraOutput::BuildT0(pPfo, pfoVector, nextT0Id, pandoraHitToArtHitMap, t0)) continue;
713 
714  LArPandoraOutput::AddAssociation(event, pProducer, instanceLabel, pfoId, nextT0Id - 1, outputParticlesToT0s);
715  outputT0s->push_back(t0);
716  }
717 }
718 
719 //------------------------------------------------------------------------------------------------------------------------------------------
720 
721 recob::PFParticle LArPandoraOutput::BuildPFParticle(const pandora::ParticleFlowObject *const pPfo, const size_t pfoId, const pandora::PfoVector &pfoVector)
722 {
723  // Get parent Pfo ID
724  const pandora::PfoList &parentList(pPfo->GetParentPfoList());
725  if (parentList.size() > 1)
726  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildPFParticle --- this pfo has multiple parent particles ";
727 
728  const size_t parentId(parentList.empty() ? recob::PFParticle::kPFParticlePrimary : LArPandoraOutput::GetId(parentList.front(), pfoVector));
729 
730  // Get daughters Pfo IDs
731  std::vector<size_t> daughterIds;
732  for (const pandora::ParticleFlowObject *const pDaughterPfo : pPfo->GetDaughterPfoList())
733  daughterIds.push_back(LArPandoraOutput::GetId(pDaughterPfo, pfoVector));
734 
735  std::sort(daughterIds.begin(), daughterIds.end());
736 
737  return recob::PFParticle(pPfo->GetParticleId(), pfoId, parentId, daughterIds);
738 }
739 
740 //------------------------------------------------------------------------------------------------------------------------------------------
741 
742 recob::Vertex LArPandoraOutput::BuildVertex(const pandora::Vertex *const pVertex, const size_t vertexId)
743 {
744  double pos[3] = {pVertex->GetPosition().GetX(), pVertex->GetPosition().GetY(), pVertex->GetPosition().GetZ()};
745  return recob::Vertex(pos, vertexId);
746 }
747 
748 //------------------------------------------------------------------------------------------------------------------------------------------
749 
750 void LArPandoraOutput::GetHitsInCluster(const pandora::Cluster *const pCluster, pandora::CaloHitVector &sortedHits)
751 {
752  if (!sortedHits.empty())
753  throw cet::exception("LArPandora") << " LArPandoraOutput::GetHitsInCluster --- vector to hold hits is not empty ";
754 
755  pandora::CaloHitList hitList;
756  pCluster->GetOrderedCaloHitList().FillCaloHitList(hitList);
757  hitList.insert(hitList.end(), pCluster->GetIsolatedCaloHitList().begin(), pCluster->GetIsolatedCaloHitList().end());
758 
759  sortedHits.insert(sortedHits.end(), hitList.begin(), hitList.end());
760  std::sort(sortedHits.begin(), sortedHits.end(), lar_content::LArClusterHelper::SortHitsByPosition);
761 }
762 
763 //------------------------------------------------------------------------------------------------------------------------------------------
764 
765 std::vector<recob::Cluster> LArPandoraOutput::BuildClusters(const pandora::Cluster *const pCluster, const pandora::ClusterList &clusterList,
766  const CaloHitToArtHitMap &pandoraHitToArtHitMap, IdToIdVectorMap &pandoraClusterToArtClustersMap,
767  std::vector<HitVector> &hitVectors, size_t &nextId, cluster::ClusterParamsAlgBase &algo)
768 {
769  std::vector<recob::Cluster> clusters;
770 
771  // Get the cluster ID and set up the map entry
772  const size_t clusterId(LArPandoraOutput::GetId(pCluster, clusterList));
773  if (!pandoraClusterToArtClustersMap.insert(IdToIdVectorMap::value_type(clusterId, {})).second)
774  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- repeated clusters in input list ";
775 
776  pandora::CaloHitVector sortedHits;
777  LArPandoraOutput::GetHitsInCluster(pCluster, sortedHits);
778 
779  HitArray hitArray; // hits organised by drift volume
780  HitList isolatedHits;
781 
782  for (const pandora::CaloHit *const pCaloHit2D : sortedHits)
783  {
784  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit2D));
785  if (it == pandoraHitToArtHitMap.end())
786  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- couldn't find art hit for input pandora hit ";
787 
788  const art::Ptr<recob::Hit> hit(it->second);
789 
790  const geo::WireID wireID(hit->WireID());
791  const unsigned int volID(100000 * wireID.Cryostat + wireID.TPC);
792  hitArray[volID].push_back(hit);
793 
794  if (pCaloHit2D->IsIsolated())
795  isolatedHits.insert(hit);
796  }
797 
798  if (hitArray.empty())
799  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- found a cluster with no hits ";
800 
801  for (const HitArray::value_type &hitArrayEntry : hitArray)
802  {
803  const HitVector &clusterHits(hitArrayEntry.second);
804 
805  clusters.push_back(LArPandoraOutput::BuildCluster(nextId, clusterHits, isolatedHits, algo));
806  hitVectors.push_back(clusterHits);
807  pandoraClusterToArtClustersMap.at(clusterId).push_back(nextId);
808 
809  nextId++;
810  }
811 
812  return clusters;
813 }
814 
815 //------------------------------------------------------------------------------------------------------------------------------------------
816 
817 recob::Cluster LArPandoraOutput::BuildCluster(const size_t id, const HitVector &hitVector, const HitList &isolatedHits, cluster::ClusterParamsAlgBase &algo)
818 {
819  if (hitVector.empty())
820  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildCluster --- No input hits were provided ";
821 
822  // Fill list of cluster properties
824  geo::PlaneID planeID;
825 
826  double startWire(+std::numeric_limits<float>::max()), sigmaStartWire(0.0);
827  double startTime(+std::numeric_limits<float>::max()), sigmaStartTime(0.0);
828  double endWire(-std::numeric_limits<float>::max()), sigmaEndWire(0.0);
829  double endTime(-std::numeric_limits<float>::max()), sigmaEndTime(0.0);
830 
831  std::vector<recob::Hit const*> hits_for_params;
832  hits_for_params.reserve(hitVector.size());
833 
834  for (const art::Ptr<recob::Hit> &hit : hitVector)
835  {
836  const double thisWire(hit->WireID().Wire);
837  const double thisWireSigma(0.5);
838  const double thisTime(hit->PeakTime());
839  const double thisTimeSigma(double(2.*hit->RMS()));
840  const geo::View_t thisView(hit->View());
841  const geo::PlaneID thisPlaneID(hit->WireID().planeID());
842 
843  if (geo::kUnknown == view)
844  {
845  view = thisView;
846  planeID = thisPlaneID;
847  }
848 
849  if (!(thisView == view && thisPlaneID == planeID))
850  {
851  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildCluster --- Input hits have inconsistent plane IDs ";
852  }
853 
854  hits_for_params.push_back(&*hit);
855 
856  if (isolatedHits.count(hit))
857  continue;
858 
859  if (thisWire < startWire || (thisWire == startWire && thisTime < startTime))
860  {
861  startWire = thisWire;
862  sigmaStartWire = thisWireSigma;
863  startTime = thisTime;
864  sigmaStartTime = thisTimeSigma;
865  }
866 
867  if (thisWire > endWire || (thisWire == endWire && thisTime > endTime))
868  {
869  endWire = thisWire;
870  sigmaEndWire = thisWireSigma;
871  endTime = thisTime;
872  sigmaEndTime = thisTimeSigma;
873  }
874 
875  }
876 
877  // feed the algorithm with all the cluster hits
878  algo.SetHits(hits_for_params);
879 
880  // create the recob::Cluster directly in the vector
882  algo, // algo
883  startWire, // start_wire
884  sigmaStartWire, // sigma_start_wire
885  startTime, // start_tick
886  sigmaStartTime, // sigma_start_tick
887  endWire, // end_wire
888  sigmaEndWire, // sigma_end_wire
889  endTime, // end_tick
890  sigmaEndTime, // sigma_end_tick
891  id, // ID
892  view, // view
893  planeID, // plane
894  recob::Cluster::Sentry // sentry
895  ).move();
896 }
897 
898 //------------------------------------------------------------------------------------------------------------------------------------------
899 
900 recob::SpacePoint LArPandoraOutput::BuildSpacePoint(const pandora::CaloHit *const pCaloHit, const size_t spacePointId)
901 {
902  if (pandora::TPC_3D != pCaloHit->GetHitType())
903  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildSpacePoint --- trying to build a space point from a 2D hit";
904 
905  const pandora::CartesianVector point(pCaloHit->GetPositionVector());
906  double xyz[3] = { point.GetX(), point.GetY(), point.GetZ() };
907 
908  // ATTN using dummy information
909  double dxdydz[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // TODO: Fill in the error matrix
910  double chi2(0.0);
911 
912  return recob::SpacePoint(xyz, dxdydz, chi2, spacePointId);
913 }
914 
915 //------------------------------------------------------------------------------------------------------------------------------------------
916 
917 bool LArPandoraOutput::BuildT0(const pandora::ParticleFlowObject *const pPfo, const pandora::PfoVector &pfoVector, size_t &nextId,
918  const CaloHitToArtHitMap &pandoraHitToArtHitMap, anab::T0 &t0)
919 {
920  pandora::CaloHitVector sorted3DHits;
921  LArPandoraOutput::Collect3DHits(pPfo, sorted3DHits);
922 
923  double sumT(0.), sumN(0.);
924 
925  for (const pandora::CaloHit *const pCaloHit3D : sorted3DHits)
926  {
927  if (pandora::TPC_3D != pCaloHit3D->GetHitType())
928  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildT0 --- found a 2D hit in a 3D cluster";
929 
930  const pandora::CaloHit *const pCaloHit2D = static_cast<const pandora::CaloHit*>(pCaloHit3D->GetParentAddress());
931 
932  CaloHitToArtHitMap::const_iterator it(pandoraHitToArtHitMap.find(pCaloHit2D));
933  if (it == pandoraHitToArtHitMap.end())
934  throw cet::exception("LArPandora") << " LArPandoraOutput::BuildClusters --- couldn't find art hit for input pandora hit ";
935 
936  const art::Ptr<recob::Hit> hit(it->second);
937 
938  HitVector spacePointHits;
939  spacePointHits.push_back(hit);
940 
941  // ATTN: We assume that the 2D Pandora hits have been shifted
942  sumT += LArPandoraOutput::CalculateT0(hit, pCaloHit2D);
943  sumN += 1.;
944  }
945 
946  // ATTN: T0 values are currently calculated in nanoseconds relative to the trigger offset. Only non-zero values are outputted.
947  const double T0((sumN > 0. && std::fabs(sumT) > sumN) ? (sumT / sumN) : 0.);
948 
949  if (std::fabs(T0) <= std::numeric_limits<double>::epsilon()) return false;
950 
951  // Output T0 objects [arguments are: time (nanoseconds); trigger type (3 for TPC stitching!); pfparticle SelfID code; T0 ID code]
952  t0 = anab::T0(T0, 3, LArPandoraOutput::GetId(pPfo, pfoVector), nextId++);
953 
954  return true;
955 }
956 
957 //------------------------------------------------------------------------------------------------------------------------------------------
958 
959 double LArPandoraOutput::CalculateT0(const art::Ptr<recob::Hit> hit, const pandora::CaloHit *const pCaloHit)
960 {
962  auto const* theDetector = lar::providerFrom<detinfo::DetectorPropertiesService>();
963 
964  const geo::WireID hit_WireID(hit->WireID());
965  const geo::TPCGeo &theTpc = theGeometry->Cryostat(hit_WireID.Cryostat).TPC(hit_WireID.TPC);
966 
967  // Calculate shift in x position between input and output hits
968  const double input_xpos_cm(theDetector->ConvertTicksToX(hit->PeakTime(), hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat));
969  const double output_xpos_dm(pCaloHit->GetPositionVector().GetX());
970  const double x0_cm(output_xpos_dm - input_xpos_cm);
971 
972  // The ingredients for the T0 calculation all come from the detector properties service
973  const double dir((theTpc.DriftDirection() == geo::kNegX) ? 1.0 : -1.0);
974  const double cm_per_tick(theDetector->GetXTicksCoefficient());
975  const double ns_per_tick(theDetector->SamplingRate());
976 
977  // This calculation should give the T0 in nanoseconds relative to the initial 2D hit
978  return (- dir * x0_cm * ns_per_tick / cm_per_tick);
979 }
980 
981 //------------------------------------------------------------------------------------------------------------------------------------------
982 //------------------------------------------------------------------------------------------------------------------------------------------
983 
985  m_pPrimaryPandora(nullptr),
986  m_pProducer(nullptr),
987  m_shouldRunStitching(false),
988  m_shouldProduceAllOutcomes(false),
989  m_isNeutrinoRecoOnlyNoSlicing(false)
990 {
991 }
992 
993 //------------------------------------------------------------------------------------------------------------------------------------------
994 
996 {
997  if (!m_pPrimaryPandora)
998  throw cet::exception("LArPandora") << " LArPandoraOutput::Settings::Validate --- primary Pandora instance does not exist ";
999 
1000  if (!m_pProducer)
1001  throw cet::exception("LArPandora") << " LArPandoraOutput::Settings::Validate --- pointer to ART Producer module does not exist ";
1002 
1003  if (!m_shouldProduceAllOutcomes) return;
1004 
1005  if (m_allOutcomesInstanceLabel.empty())
1006  throw cet::exception("LArPandora") << " LArPandoraOutput::Settings::Validate --- all outcomes instance label not set ";
1007 }
1008 
1009 } // namespace lar_pandora
static void BuildPFParticles(const art::Event &event, const art::EDProducer *const pProducer, 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...
code to link reconstructed objects back to the MC truth information
static pandora::VertexVector CollectVertices(const pandora::PfoVector &pfoVector, IdToIdVectorMap &pfoToVerticesMap)
Collect all vertices contained in the input pfo list Order is guaranteed provided pfoVector is ordere...
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 recob::SpacePoint BuildSpacePoint(const pandora::CaloHit *const pCaloHit, const size_t spacePointId)
Convert from a pandora 3D hit to an ART spacepoint.
std::unique_ptr< art::Assns< recob::PFParticle, anab::T0 > > PFParticleToT0Collection
void Validate() const
Check the parameters and throw an exception if they are not valid.
static void CopyAllHitsToSingleSlice(const Settings &settings, const art::Event &event, const art::EDProducer *const pProducer, 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.
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.
std::unique_ptr< std::vector< recob::Cluster > > ClusterCollection
Header file for the pfo helper class.
static recob::Cluster BuildCluster(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.
static void GetPandoraToArtHitMap(const pandora::ClusterList &clusterList, const pandora::CaloHitList &threeDHitList, const IdToHitMap &idToHitMap, CaloHitToArtHitMap &pandoraHitToArtHitMap)
Collect all 2D and 3D hits that were used / produced in the reconstruction and map them to their corr...
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:61
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Unknown view.
Definition: geo_types.h:83
static void GetTwoDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 2D clusters from an input pfo.
Definition: LArPfoHelper.cc:97
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
Declaration of signal hit object.
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
Geometry information for a single TPC.
Definition: TPCGeo.h:37
static unsigned int BuildDummySlice(SliceCollection &outputSlices)
Build a new slice object with dummy information.
static void AddAssociation(const art::Event &event, const art::EDProducer *const pProducer, 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.
static void BuildParticleMetadata(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, PFParticleMetadataCollection &outputParticleMetadata, PFParticleToMetadataCollection &outputParticlesToMetadata)
Build metadata objects from a list of input pfos.
std::string m_allOutcomesInstanceLabel
The label for the instance producing all outcomes.
std::map< size_t, IdVector > IdToIdVectorMap
Algorithm collection class computing cluster parameters.
static void GetHitsInCluster(const pandora::Cluster *const pCluster, pandora::CaloHitVector &sortedHits)
Collect a sorted list of all 2D hits in a cluster.
Set of hits with a 2D structure.
Definition: Cluster.h:71
std::map< int, art::Ptr< recob::Hit > > IdToHitMap
Definition: ILArPandora.h:20
static double CalculateT0(const art::Ptr< recob::Hit > hit, const pandora::CaloHit *const pCaloHit)
Convert X0 correction into T0 correction.
static art::Ptr< recob::Hit > GetHit(const IdToHitMap &idToHitMap, const pandora::CaloHit *const pCaloHit)
Look up ART hit from an input Pandora hit.
bool m_isNeutrinoRecoOnlyNoSlicing
If we are running the neutrino reconstruction only with no slicing.
static size_t GetId(const T *const pT, const std::list< const T * > &tList)
Find the index of an input object in an input list. Throw an exception if it doesn&#39;t exist...
Helper functions for processing outputs from pandora.
Definition: T0.h:19
Drift towards negative X values.
Definition: geo_types.h:109
std::map< const pandora::CaloHit *, art::Ptr< recob::Hit > > CaloHitToArtHitMap
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.
std::unique_ptr< std::vector< recob::SpacePoint > > SpacePointCollection
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:182
std::unique_ptr< std::vector< recob::Slice > > SliceCollection
std::string m_hitfinderModuleLabel
The hit finder module label.
Algorithm collection class computing cluster parameters.
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
static unsigned int BuildSlice(const pandora::ParticleFlowObject *const pParentPfo, const art::Event &event, const art::EDProducer *const pProducer, 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...
static void BuildClusters(const art::Event &event, const art::EDProducer *const pProducer, 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...
std::vector< size_t > IdVector
std::unique_ptr< art::Assns< recob::SpacePoint, recob::Hit > > SpacePointToHitCollection
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. See recob::tracking::Coord_t for more details on the ...
Definition: TrackingTypes.h:29
Int_t max
Definition: plot.C:27
void hits()
Definition: readHits.C:15
intermediate_table::const_iterator const_iterator
Metadata associated to PFParticles.
std::map< int, HitVector > HitArray
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, recob::Slice > > PFParticleToSliceCollection
std::unique_ptr< std::vector< recob::Vertex > > VertexCollection
Helper functions to create a cluster.
static void BuildVertices(const pandora::VertexVector &vertexVector, VertexCollection &outputVertices)
Convert pandora vertices to ART vertices and add them to the output vector.
std::unique_ptr< std::vector< larpandoraobj::PFParticleMetadata > > PFParticleMetadataCollection
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.
std::unique_ptr< std::vector< recob::PFParticle > > PFParticleCollection
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
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.
Header file for the MultiPandoraApi class.
static bool BuildT0(const pandora::ParticleFlowObject *const pPfo, const pandora::PfoVector &pfoVector, size_t &nextId, const CaloHitToArtHitMap &pandoraHitToArtHitMap, anab::T0 &t0)
If required, build a T0 for the input pfo.
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.
std::unique_ptr< art::Assns< recob::PFParticle, larpandoraobj::PFParticleMetadata > > PFParticleToMetadataCollection
std::vector< art::Ptr< recob::Hit > > HitVector
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::Vertex > > PFParticleToVertexCollection
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
Utility object to perform functions of association.
std::unique_ptr< std::vector< anab::T0 > > T0Collection
std::unique_ptr< art::Assns< recob::PFParticle, recob::Cluster > > PFParticleToClusterCollection
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
TDirectory * dir
Definition: macro.C:5
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
bool m_shouldProduceAllOutcomes
If all outcomes should be produced in separate collections (choose false if you only require the cons...
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 art::EDProducer *const pProducer, 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.
std::unique_ptr< art::Assns< recob::Slice, recob::Hit > > SliceToHitCollection
static void BuildT0s(const art::Event &event, const art::EDProducer *const pProducer, const std::string &instanceLabel, const pandora::PfoVector &pfoVector, T0Collection &outputT0s, const CaloHitToArtHitMap &pandoraHitToArtHitMap, PFParticleToT0Collection &outputParticlesToT0s)
Calculate the T0 of each pfos and add them to the output vector Create the associations between PFPar...
std::unique_ptr< art::Assns< recob::PFParticle, recob::SpacePoint > > PFParticleToSpacePointCollection
Interface to class computing cluster parameters.
TCEvent evt
Definition: DataStructs.cxx:5
virtual void SetHits(std::vector< recob::Hit const * > const &hits)=0
Sets the list of input hits.
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...
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:26
static void GetCaloHits(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::CaloHitList &caloHitList)
Get a list of calo hits of a particular hit type from a list of pfos.
recob::Cluster && move()
Prepares the constructed hit to be moved away.
std::set< art::Ptr< recob::Hit > > HitList
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 BuildSpacePoints(const art::Event &event, const art::EDProducer *const pProducer, 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 ...
art framework interface to geometry description
std::unique_ptr< art::Assns< recob::Cluster, recob::Hit > > ClusterToHitCollection
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
static larpandoraobj::PFParticleMetadata GetPFParticleMetadata(const pandora::ParticleFlowObject *const pPfo)
Event finding and building.
std::vector< art::Ptr< recob::Vertex > > VertexVector