LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SlidingConePfoMopUpAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
15 
17 
19 
20 using namespace pandora;
21 
22 namespace lar_content
23 {
24 
25 SlidingConePfoMopUpAlgorithm::SlidingConePfoMopUpAlgorithm() :
26  m_useVertex(true),
27  m_maxIterations(1000),
28  m_maxHitsToConsider3DTrack(100),
29  m_minHitsToConsider3DShower(20),
30  m_halfWindowLayers(20),
31  m_nConeFitLayers(20),
32  m_nConeFits(5),
33  m_coneLengthMultiplier(7.f),
34  m_maxConeLength(126.f),
35  m_coneTanHalfAngle1(0.5f),
36  m_coneBoundedFraction1(0.5f),
37  m_coneTanHalfAngle2(0.75f),
38  m_coneBoundedFraction2(0.75f),
39  m_minVertexLongitudinalDistance(-2.5f),
40  m_maxVertexTransverseDistance(3.5f)
41 {
42 }
43 
44 //------------------------------------------------------------------------------------------------------------------------------------------
45 
47 {
48  const Vertex *pVertex(nullptr);
49  this->GetInteractionVertex(pVertex);
50 
51  if (m_useVertex && !pVertex)
52  {
53  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
54  std::cout << "SlidingConePfoMopUpAlgorithm - interaction vertex not available for use." << std::endl;
55  return STATUS_CODE_SUCCESS;
56  }
57 
58  unsigned int nIterations(0);
59 
60  while (nIterations++ < m_maxIterations)
61  {
62  ClusterVector clusters3D;
63  ClusterToPfoMap clusterToPfoMap;
64  this->GetThreeDClusters(clusters3D, clusterToPfoMap);
65 
66  ClusterMergeMap clusterMergeMap;
67  this->GetClusterMergeMap(pVertex, clusters3D, clusterToPfoMap, clusterMergeMap);
68 
69  if (!this->MakePfoMerges(clusterToPfoMap, clusterMergeMap))
70  break;
71  }
72 
73  return STATUS_CODE_SUCCESS;
74 }
75 
76 //------------------------------------------------------------------------------------------------------------------------------------------
77 
78 void SlidingConePfoMopUpAlgorithm::GetInteractionVertex(const Vertex *&pVertex) const
79 {
80  if (!m_useVertex)
81  return;
82 
83  const VertexList *pVertexList = nullptr;
84  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetCurrentList(*this, pVertexList));
85 
86  pVertex = ((pVertexList && (pVertexList->size() == 1) && (VERTEX_3D == (*(pVertexList->begin()))->GetVertexType())) ? *(pVertexList->begin()) : nullptr);
87 }
88 
89 //------------------------------------------------------------------------------------------------------------------------------------------
90 
92 {
93  for (const std::string &pfoListName : m_inputPfoListNames)
94  {
95  const PfoList *pPfoList(nullptr);
96 
97  if (STATUS_CODE_SUCCESS != PandoraContentApi::GetList(*this, pfoListName, pPfoList))
98  continue;
99 
100  for (const Pfo *const pPfo : *pPfoList)
101  {
102  ClusterList pfoClusters3D;
103  LArPfoHelper::GetThreeDClusterList(pPfo, pfoClusters3D);
104 
105  for (const Cluster *const pCluster3D : pfoClusters3D)
106  {
107  if (LArPfoHelper::IsTrack(pPfo) && (pCluster3D->GetNCaloHits() > m_maxHitsToConsider3DTrack))
108  continue;
109 
110  if (!clusterToPfoMap.insert(ClusterToPfoMap::value_type(pCluster3D, pPfo)).second)
111  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
112 
113  clusters3D.push_back(pCluster3D);
114  }
115  }
116  }
117 
118  std::sort(clusters3D.begin(), clusters3D.end(), LArClusterHelper::SortByNHits);
119 }
120 
121 //------------------------------------------------------------------------------------------------------------------------------------------
122 
123 void SlidingConePfoMopUpAlgorithm::GetClusterMergeMap(const Vertex *const pVertex, const ClusterVector &clusters3D,
124  const ClusterToPfoMap &clusterToPfoMap, ClusterMergeMap &clusterMergeMap) const
125 {
126  VertexAssociationMap vertexAssociationMap;
127  const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
128 
129  for (const Cluster *const pShowerCluster : clusters3D)
130  {
131  if ((pShowerCluster->GetNCaloHits() < m_minHitsToConsider3DShower) || !LArPfoHelper::IsShower(clusterToPfoMap.at(pShowerCluster)))
132  continue;
133 
134  float coneLength(0.f);
135  SimpleConeList simpleConeList;
136  bool isShowerVertexAssociated(false);
137 
138  try
139  {
140  const ThreeDSlidingConeFitResult slidingConeFitResult3D(pShowerCluster, m_halfWindowLayers, layerPitch);
141 
142  const CartesianVector &minLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMinLayerPosition());
143  const CartesianVector &maxLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMaxLayerPosition());
144  coneLength = std::min(m_coneLengthMultiplier * (maxLayerPosition - minLayerPosition).GetMagnitude(), m_maxConeLength);
145 
146  const float vertexToMinLayer(!pVertex ? 0.f : (pVertex->GetPosition() - minLayerPosition).GetMagnitude());
147  const float vertexToMaxLayer(!pVertex ? 0.f : (pVertex->GetPosition() - maxLayerPosition).GetMagnitude());
148  const ConeSelection coneSelection(!pVertex ? CONE_BOTH_DIRECTIONS : (vertexToMaxLayer > vertexToMinLayer) ? CONE_FORWARD_ONLY : CONE_BACKWARD_ONLY);
149 
150  slidingConeFitResult3D.GetSimpleConeList(m_nConeFitLayers, m_nConeFits, coneSelection, simpleConeList);
151  isShowerVertexAssociated = this->IsVertexAssociated(pShowerCluster, pVertex, vertexAssociationMap, &(slidingConeFitResult3D.GetSlidingFitResult()));
152  }
153  catch (const StatusCodeException &) {continue;}
154 
155  for (const Cluster *const pNearbyCluster : clusters3D)
156  {
157  if (pNearbyCluster == pShowerCluster)
158  continue;
159 
160  ClusterMerge bestClusterMerge(nullptr, 0.f, 0.f);
161 
162  for (const SimpleCone &simpleCone : simpleConeList)
163  {
164  const float boundedFraction1(simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle1));
165  const float boundedFraction2(simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle2));
166  const ClusterMerge clusterMerge(pShowerCluster, boundedFraction1, boundedFraction2);
167 
168  if (clusterMerge < bestClusterMerge)
169  bestClusterMerge = clusterMerge;
170  }
171 
172  if (isShowerVertexAssociated && this->IsVertexAssociated(pNearbyCluster, pVertex, vertexAssociationMap))
173  continue;
174 
175  if (bestClusterMerge.GetParentCluster() && (bestClusterMerge.GetBoundedFraction1() > m_coneBoundedFraction1) && (bestClusterMerge.GetBoundedFraction2() > m_coneBoundedFraction2))
176  clusterMergeMap[pNearbyCluster].push_back(bestClusterMerge);
177  }
178  }
179 
180  for (ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
181  std::sort(mapEntry.second.begin(), mapEntry.second.end());
182 }
183 
184 //------------------------------------------------------------------------------------------------------------------------------------------
185 
186 bool SlidingConePfoMopUpAlgorithm::IsVertexAssociated(const Cluster *const pCluster, const Vertex *const pVertex,
187  VertexAssociationMap &vertexAssociationMap, const ThreeDSlidingFitResult *const pSlidingFitResult) const
188 {
189  if (!pVertex)
190  return false;
191 
192  VertexAssociationMap::const_iterator iter = vertexAssociationMap.find(pCluster);
193 
194  if (vertexAssociationMap.end() != iter)
195  return iter->second;
196 
197  const bool isVertexAssociated(this->IsVertexAssociated(pCluster, pVertex->GetPosition(), pSlidingFitResult));
198  (void) vertexAssociationMap.insert(VertexAssociationMap::value_type(pCluster, isVertexAssociated));
199 
200  return isVertexAssociated;
201 }
202 
203 //------------------------------------------------------------------------------------------------------------------------------------------
204 
205 bool SlidingConePfoMopUpAlgorithm::IsVertexAssociated(const Cluster *const pCluster, const CartesianVector &vertexPosition,
206  const ThreeDSlidingFitResult *const pSlidingFitResult) const
207 {
208  try
209  {
210  const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
211  const LArPointingCluster pointingCluster(pSlidingFitResult ? LArPointingCluster(*pSlidingFitResult) : LArPointingCluster(pCluster, m_halfWindowLayers, layerPitch));
212 
213  const bool useInner((pointingCluster.GetInnerVertex().GetPosition() - vertexPosition).GetMagnitudeSquared() <
214  (pointingCluster.GetOuterVertex().GetPosition() - vertexPosition).GetMagnitudeSquared());
215 
216  const LArPointingCluster::Vertex &daughterVertex(useInner ? pointingCluster.GetInnerVertex() : pointingCluster.GetOuterVertex());
218  }
219  catch (const StatusCodeException &)
220  {
221  }
222 
223  return false;
224 }
225 
226 //------------------------------------------------------------------------------------------------------------------------------------------
227 
228 bool SlidingConePfoMopUpAlgorithm::MakePfoMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
229 {
230  ClusterVector daughterClusters;
231  for (const ClusterMergeMap::value_type &mapEntry : clusterMergeMap) daughterClusters.push_back(mapEntry.first);
232  std::sort(daughterClusters.begin(), daughterClusters.end(), LArClusterHelper::SortByNHits);
233 
234  bool pfosMerged(false);
235  ClusterReplacementMap clusterReplacementMap;
236 
237  for (ClusterVector::const_reverse_iterator rIter = daughterClusters.rbegin(), rIterEnd = daughterClusters.rend(); rIter != rIterEnd; ++rIter)
238  {
239  const Cluster *const pDaughterCluster(*rIter);
240 
241  if (clusterReplacementMap.count(pDaughterCluster))
242  throw StatusCodeException(STATUS_CODE_FAILURE);
243 
244  const Cluster *pParentCluster(clusterMergeMap.at(pDaughterCluster).at(0).GetParentCluster());
245 
246  if (clusterReplacementMap.count(pParentCluster))
247  pParentCluster = clusterReplacementMap.at(pParentCluster);
248 
249  // ATTN Sign there was a reciprocal relationship in the cluster merge map (already actioned once)
250  if (pDaughterCluster == pParentCluster)
251  continue;
252 
253  // Key book-keeping on clusters and use cluster->pfo lookup
254  const Pfo *const pDaughterPfo(clusterToPfoMap.at(pDaughterCluster));
255  const Pfo *const pParentPfo(clusterToPfoMap.at(pParentCluster));
256  this->MergeAndDeletePfos(pParentPfo, pDaughterPfo);
257  pfosMerged = true;
258 
259  // Simple/placeholder book-keeping for reciprocal relationships and progressive merges
260  clusterReplacementMap[pDaughterCluster] = pParentCluster;
261 
262  for (ClusterReplacementMap::value_type &mapEntry : clusterReplacementMap)
263  {
264  if (pDaughterCluster == mapEntry.second)
265  mapEntry.second = pParentCluster;
266  }
267  }
268 
269  return pfosMerged;
270 }
271 
272 //------------------------------------------------------------------------------------------------------------------------------------------
273 //------------------------------------------------------------------------------------------------------------------------------------------
274 
276 {
277  if (!this->GetParentCluster() && !rhs.GetParentCluster())
278  return false;
279 
280  if (this->GetParentCluster() && !rhs.GetParentCluster())
281  return true;
282 
283  if (!this->GetParentCluster() && rhs.GetParentCluster())
284  return false;
285 
286  if (std::fabs(this->GetBoundedFraction1() - rhs.GetBoundedFraction1()) > std::numeric_limits<float>::epsilon())
287  return (this->GetBoundedFraction1() > rhs.GetBoundedFraction1());
288 
289  if (std::fabs(this->GetBoundedFraction2() - rhs.GetBoundedFraction2()) > std::numeric_limits<float>::epsilon())
290  return (this->GetBoundedFraction2() > rhs.GetBoundedFraction2());
291 
293 }
294 
295 //------------------------------------------------------------------------------------------------------------------------------------------
296 //------------------------------------------------------------------------------------------------------------------------------------------
297 
298 StatusCode SlidingConePfoMopUpAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
299 {
300  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
301  "InputPfoListNames", m_inputPfoListNames));
302 
303  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
304  "UseVertex", m_useVertex));
305 
306  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
307  "MaxIterations", m_maxIterations));
308 
309  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
310  "MaxHitsToConsider3DTrack", m_maxHitsToConsider3DTrack));
311 
312  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
313  "MinHitsToConsider3DShower", m_minHitsToConsider3DShower));
314 
315  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
316  "SlidingFitHalfWindow", m_halfWindowLayers));
317 
318  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
319  "NConeFitLayers", m_nConeFitLayers));
320 
321  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
322  "NConeFits", m_nConeFits));
323 
324  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
325  "ConeLengthMultiplier", m_coneLengthMultiplier));
326 
327  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
328  "MaxConeLength", m_maxConeLength));
329 
330  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
331  "ConeTanHalfAngle1", m_coneTanHalfAngle1));
332 
333  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
334  "ConeBoundedFraction1", m_coneBoundedFraction1));
335 
336  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
337  "ConeTanHalfAngle2", m_coneTanHalfAngle2));
338 
339  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
340  "ConeBoundedFraction2", m_coneBoundedFraction2));
341 
342  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
343  "MinVertexLongitudinalDistance", m_minVertexLongitudinalDistance));
344 
345  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
346  "MaxVertexTransverseDistance", m_maxVertexTransverseDistance));
347 
349 
350  return PfoMopUpBaseAlgorithm::ReadSettings(xmlHandle);
351 }
352 
353 } // namespace lar_content
float GetBoundedFraction2() const
Get the bounded fraction for algorithm-specified cone angle 2.
void GetClusterMergeMap(const pandora::Vertex *const pVertex, const pandora::ClusterVector &clusters3D, const ClusterToPfoMap &clusterToPfoMap, ClusterMergeMap &clusterMergeMap) const
Get the cluster merge map describing all potential 3d cluster merges.
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.
float m_coneBoundedFraction2
The minimum cluster bounded fraction for association 2.
void GetInteractionVertex(const pandora::Vertex *&pVertex) const
Get the neutrino interaction vertex if it is available and if the algorithm is configured to do so...
Header file for the pfo helper class.
float m_maxConeLength
The maximum allowed cone length to use when calculating bounded cluster fractions.
float m_maxVertexTransverseDistance
Vertex association check: max transverse distance cut.
float m_coneLengthMultiplier
The cone length multiplier to use when calculating bounded cluster fractions.
std::vector< SimpleCone > SimpleConeList
pandora::StringVector m_daughterListNames
The list of potential daughter object list names.
bool MakePfoMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
Make pfo merges based on the provided cluster merge map.
const ThreeDSlidingFitResult & GetSlidingFitResult() const
Get the sliding fit result for the full cluster.
LArPointingCluster class.
void GetThreeDClusters(pandora::ClusterVector &clusters3D, ClusterToPfoMap &clusterToPfoMap) const
Get all 3d clusters contained in the input pfo lists and a mapping from clusters to pfos...
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
bool m_useVertex
Whether to use the interaction vertex to select useful cone directions.
Header file for the lar three dimensional sliding cone fit result class.
float GetBoundedFraction1() const
Get the bounded fraction for algorithm-specified cone angle 1.
void GetSimpleConeList(const unsigned int nLayersForConeFit, const unsigned int nCones, const ConeSelection coneSelection, SimpleConeList &simpleConeList) const
Get the list of simple cones fitted to the three dimensional cluster.
TFile f
Definition: plotHisto.C:6
bool IsVertexAssociated(const pandora::Cluster *const pCluster, const pandora::Vertex *const pVertex, VertexAssociationMap &vertexAssociationMap, const ThreeDSlidingFitResult *const pSlidingFitResult=nullptr) const
Whether a 3D cluster is nodally associated with a provided vertex.
Header file for the geometry helper class.
std::unordered_map< const pandora::Cluster *, const pandora::ParticleFlowObject * > ClusterToPfoMap
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut.
static bool IsShower(const pandora::ParticleFlowObject *const pPfo)
Return shower flag based on Pfo Particle ID.
intermediate_table::const_iterator const_iterator
unsigned int m_nConeFitLayers
The number of layers over which to sum fitted direction to obtain cone fit.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the cluster helper class.
std::unordered_map< const pandora::Cluster *, const pandora::Cluster * > ClusterReplacementMap
const Vertex & GetOuterVertex() const
Get the outer vertex.
std::unordered_map< const pandora::Cluster *, ClusterMergeList > ClusterMergeMap
unsigned int m_maxHitsToConsider3DTrack
The maximum number of hits in a 3d track cluster to warrant inclusion in algorithm.
const Vertex & GetInnerVertex() const
Get the inner vertex.
float m_coneTanHalfAngle1
The cone tan half angle to use when calculating bounded cluster fractions 1.
pandora::StringVector m_inputPfoListNames
The input pfo list names.
Header file for the sliding cone pfo mop up algorithm class.
static const pandora::Cluster * GetParentCluster(const pandora::ClusterList &clusterList, const pandora::HitType hitType)
Select the parent cluster (same hit type and most hits) using a provided cluster list and hit type...
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
const pandora::CartesianVector & GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
float m_coneBoundedFraction1
The minimum cluster bounded fraction for association 1.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Int_t min
Definition: plot.C:26
unsigned int m_maxIterations
The maximum allowed number of algorithm iterations.
virtual void MergeAndDeletePfos(const pandora::ParticleFlowObject *const pPfoToEnlarge, const pandora::ParticleFlowObject *const pPfoToDelete) const
Merge and delete a pair of pfos, with a specific set of conventions for cluster merging, vertex use, etc.
ConeSelection
ConeSelection enum.
unsigned int m_minHitsToConsider3DShower
The minimum number of hits in a 3d shower cluster to attempt cone fits.
std::unordered_map< const pandora::Cluster *, bool > VertexAssociationMap
bool operator<(const ClusterMerge &rhs) const
operator <
unsigned int m_nConeFits
The number of cone fits to perform, spread roughly uniformly along the shower length.
const pandora::Cluster * GetParentCluster() const
Get the address of the candidate parent (shower) cluster.
std::list< Vertex > VertexList
Definition: DCEL.h:178
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
static bool IsNode(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxTransverseDistance)
Whether pointing vertex is adjacent to a given position.
float m_coneTanHalfAngle2
The cone tan half angle to use when calculating bounded cluster fractions 2.
unsigned int m_halfWindowLayers
The number of layers to use for half-window of sliding fit.
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.