Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
SlidingConePfoMopUpAlgorithm.cc
Go to the documentation of this file.
1
10
15
17
19
20using namespace pandora;
21
22namespace lar_content
23{
24
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 {
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
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 =
87 ((pVertexList && (pVertexList->size() == 1) && (VERTEX_3D == (*(pVertexList->begin()))->GetVertexType())) ? *(pVertexList->begin()) : nullptr);
88}
89
90//------------------------------------------------------------------------------------------------------------------------------------------
91
93{
94 for (const std::string &pfoListName : m_inputPfoListNames)
95 {
96 const PfoList *pPfoList(nullptr);
97
98 if (STATUS_CODE_SUCCESS != PandoraContentApi::GetList(*this, pfoListName, pPfoList))
99 continue;
100
101 for (const Pfo *const pPfo : *pPfoList)
102 {
103 ClusterList pfoClusters3D;
104 LArPfoHelper::GetThreeDClusterList(pPfo, pfoClusters3D);
105
106 for (const Cluster *const pCluster3D : pfoClusters3D)
107 {
108 if (LArPfoHelper::IsTrack(pPfo) && (pCluster3D->GetNCaloHits() > m_maxHitsToConsider3DTrack))
109 continue;
110
111 if (!clusterToPfoMap.insert(ClusterToPfoMap::value_type(pCluster3D, pPfo)).second)
112 throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
113
114 clusters3D.push_back(pCluster3D);
115 }
116 }
117 }
118
119 std::sort(clusters3D.begin(), clusters3D.end(), LArClusterHelper::SortByNHits);
120}
121
122//------------------------------------------------------------------------------------------------------------------------------------------
123
124void SlidingConePfoMopUpAlgorithm::GetClusterMergeMap(const Vertex *const pVertex, const ClusterVector &clusters3D,
125 const ClusterToPfoMap &clusterToPfoMap, ClusterMergeMap &clusterMergeMap) const
126{
127 VertexAssociationMap vertexAssociationMap;
128 const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
129
130 for (const Cluster *const pShowerCluster : clusters3D)
131 {
132 if ((pShowerCluster->GetNCaloHits() < m_minHitsToConsider3DShower) || !LArPfoHelper::IsShower(clusterToPfoMap.at(pShowerCluster)))
133 continue;
134
135 float coneLength(0.f);
136 SimpleConeList simpleConeList;
137 bool isShowerVertexAssociated(false);
138
139 try
140 {
141 const ThreeDSlidingConeFitResult slidingConeFitResult3D(pShowerCluster, m_halfWindowLayers, layerPitch);
142
143 const CartesianVector &minLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMinLayerPosition());
144 const CartesianVector &maxLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMaxLayerPosition());
145 coneLength = std::min(m_coneLengthMultiplier * (maxLayerPosition - minLayerPosition).GetMagnitude(), m_maxConeLength);
146
147 const float vertexToMinLayer(!pVertex ? 0.f : (pVertex->GetPosition() - minLayerPosition).GetMagnitude());
148 const float vertexToMaxLayer(!pVertex ? 0.f : (pVertex->GetPosition() - maxLayerPosition).GetMagnitude());
149 const ConeSelection coneSelection(
150 !pVertex ? CONE_BOTH_DIRECTIONS : (vertexToMaxLayer > vertexToMinLayer) ? CONE_FORWARD_ONLY : CONE_BACKWARD_ONLY);
151
152 slidingConeFitResult3D.GetSimpleConeList(m_nConeFitLayers, m_nConeFits, coneSelection, simpleConeList);
153 isShowerVertexAssociated =
154 this->IsVertexAssociated(pShowerCluster, pVertex, vertexAssociationMap, &(slidingConeFitResult3D.GetSlidingFitResult()));
155 }
156 catch (const StatusCodeException &)
157 {
158 continue;
159 }
160
161 for (const Cluster *const pNearbyCluster : clusters3D)
162 {
163 if (pNearbyCluster == pShowerCluster)
164 continue;
165
166 ClusterMerge bestClusterMerge(nullptr, 0.f, 0.f);
167
168 for (const SimpleCone &simpleCone : simpleConeList)
169 {
170 const float boundedFraction1(simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle1));
171 const float boundedFraction2(simpleCone.GetBoundedHitFraction(pNearbyCluster, coneLength, m_coneTanHalfAngle2));
172 const ClusterMerge clusterMerge(pShowerCluster, boundedFraction1, boundedFraction2);
173
174 if (clusterMerge < bestClusterMerge)
175 bestClusterMerge = clusterMerge;
176 }
177
178 if (isShowerVertexAssociated && this->IsVertexAssociated(pNearbyCluster, pVertex, vertexAssociationMap))
179 continue;
180
181 if (bestClusterMerge.GetParentCluster() && (bestClusterMerge.GetBoundedFraction1() > m_coneBoundedFraction1) &&
182 (bestClusterMerge.GetBoundedFraction2() > m_coneBoundedFraction2))
183 clusterMergeMap[pNearbyCluster].push_back(bestClusterMerge);
184 }
185 }
186
187 for (ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
188 std::sort(mapEntry.second.begin(), mapEntry.second.end());
189}
190
191//------------------------------------------------------------------------------------------------------------------------------------------
192
193bool SlidingConePfoMopUpAlgorithm::IsVertexAssociated(const Cluster *const pCluster, const Vertex *const pVertex,
194 VertexAssociationMap &vertexAssociationMap, const ThreeDSlidingFitResult *const pSlidingFitResult) const
195{
196 if (!pVertex)
197 return false;
198
199 VertexAssociationMap::const_iterator iter = vertexAssociationMap.find(pCluster);
200
201 if (vertexAssociationMap.end() != iter)
202 return iter->second;
203
204 const bool isVertexAssociated(this->IsVertexAssociated(pCluster, pVertex->GetPosition(), pSlidingFitResult));
205 (void)vertexAssociationMap.insert(VertexAssociationMap::value_type(pCluster, isVertexAssociated));
206
207 return isVertexAssociated;
208}
209
210//------------------------------------------------------------------------------------------------------------------------------------------
211
213 const Cluster *const pCluster, const CartesianVector &vertexPosition, const ThreeDSlidingFitResult *const pSlidingFitResult) const
214{
215 try
216 {
217 const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
218 const LArPointingCluster pointingCluster(
219 pSlidingFitResult ? LArPointingCluster(*pSlidingFitResult) : LArPointingCluster(pCluster, m_halfWindowLayers, layerPitch));
220
221 const bool useInner((pointingCluster.GetInnerVertex().GetPosition() - vertexPosition).GetMagnitudeSquared() <
222 (pointingCluster.GetOuterVertex().GetPosition() - vertexPosition).GetMagnitudeSquared());
223
224 const LArPointingCluster::Vertex &daughterVertex(useInner ? pointingCluster.GetInnerVertex() : pointingCluster.GetOuterVertex());
226 }
227 catch (const StatusCodeException &)
228 {
229 }
230
231 return false;
232}
233
234//------------------------------------------------------------------------------------------------------------------------------------------
235
236bool SlidingConePfoMopUpAlgorithm::MakePfoMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
237{
238 ClusterVector daughterClusters;
239 for (const ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
240 daughterClusters.push_back(mapEntry.first);
241 std::sort(daughterClusters.begin(), daughterClusters.end(), LArClusterHelper::SortByNHits);
242
243 bool pfosMerged(false);
244 ClusterReplacementMap clusterReplacementMap;
245
246 for (ClusterVector::const_reverse_iterator rIter = daughterClusters.rbegin(), rIterEnd = daughterClusters.rend(); rIter != rIterEnd; ++rIter)
247 {
248 const Cluster *const pDaughterCluster(*rIter);
249
250 if (clusterReplacementMap.count(pDaughterCluster))
251 throw StatusCodeException(STATUS_CODE_FAILURE);
252
253 const Cluster *pParentCluster(clusterMergeMap.at(pDaughterCluster).at(0).GetParentCluster());
254
255 if (clusterReplacementMap.count(pParentCluster))
256 pParentCluster = clusterReplacementMap.at(pParentCluster);
257
258 // ATTN Sign there was a reciprocal relationship in the cluster merge map (already actioned once)
259 if (pDaughterCluster == pParentCluster)
260 continue;
261
262 // Key book-keeping on clusters and use cluster->pfo lookup
263 const Pfo *const pDaughterPfo(clusterToPfoMap.at(pDaughterCluster));
264 const Pfo *const pParentPfo(clusterToPfoMap.at(pParentCluster));
265 this->MergeAndDeletePfos(pParentPfo, pDaughterPfo);
266 pfosMerged = true;
267
268 // Simple/placeholder book-keeping for reciprocal relationships and progressive merges
269 clusterReplacementMap[pDaughterCluster] = pParentCluster;
270
271 for (ClusterReplacementMap::value_type &mapEntry : clusterReplacementMap)
272 {
273 if (pDaughterCluster == mapEntry.second)
274 mapEntry.second = pParentCluster;
275 }
276 }
277
278 return pfosMerged;
279}
280
281//------------------------------------------------------------------------------------------------------------------------------------------
282//------------------------------------------------------------------------------------------------------------------------------------------
283
285{
286 if (!this->GetParentCluster() && !rhs.GetParentCluster())
287 return false;
288
289 if (this->GetParentCluster() && !rhs.GetParentCluster())
290 return true;
291
292 if (!this->GetParentCluster() && rhs.GetParentCluster())
293 return false;
294
295 if (std::fabs(this->GetBoundedFraction1() - rhs.GetBoundedFraction1()) > std::numeric_limits<float>::epsilon())
296 return (this->GetBoundedFraction1() > rhs.GetBoundedFraction1());
297
298 if (std::fabs(this->GetBoundedFraction2() - rhs.GetBoundedFraction2()) > std::numeric_limits<float>::epsilon())
299 return (this->GetBoundedFraction2() > rhs.GetBoundedFraction2());
300
302}
303
304//------------------------------------------------------------------------------------------------------------------------------------------
305//------------------------------------------------------------------------------------------------------------------------------------------
306
308{
310 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputPfoListNames", m_inputPfoListNames));
311
312 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "UseVertex", m_useVertex));
313
314 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxIterations", m_maxIterations));
315
316 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
317 XmlHelper::ReadValue(xmlHandle, "MaxHitsToConsider3DTrack", m_maxHitsToConsider3DTrack));
318
319 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
320 XmlHelper::ReadValue(xmlHandle, "MinHitsToConsider3DShower", m_minHitsToConsider3DShower));
321
323 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitHalfWindow", m_halfWindowLayers));
324
325 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFitLayers", m_nConeFitLayers));
326
327 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFits", m_nConeFits));
328
330 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeLengthMultiplier", m_coneLengthMultiplier));
331
332 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxConeLength", m_maxConeLength));
333
335 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle1", m_coneTanHalfAngle1));
336
338 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction1", m_coneBoundedFraction1));
339
341 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle2", m_coneTanHalfAngle2));
342
344 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction2", m_coneBoundedFraction2));
345
346 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
347 XmlHelper::ReadValue(xmlHandle, "MinVertexLongitudinalDistance", m_minVertexLongitudinalDistance));
348
349 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
350 XmlHelper::ReadValue(xmlHandle, "MaxVertexTransverseDistance", m_maxVertexTransverseDistance));
351
353
354 return PfoMopUpBaseAlgorithm::ReadSettings(xmlHandle);
355}
356
357} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the cluster helper class.
Header file for the geometry helper class.
Header file for the pfo helper class.
Header file for the lar three dimensional sliding cone fit result class.
Header file for the sliding cone pfo mop up algorithm class.
#define PANDORA_THROW_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:55
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
static pandora::StatusCode GetCurrentList(const pandora::Algorithm &algorithm, const T *&pT)
Get the current list.
static pandora::StatusCode GetList(const pandora::Algorithm &algorithm, const std::string &listName, const T *&pT)
Get a named list.
static const pandora::PandoraSettings * GetSettings(const pandora::Algorithm &algorithm)
Get the pandora settings instance.
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,...
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
static bool IsShower(const pandora::ParticleFlowObject *const pPfo)
Return shower flag based on Pfo Particle ID.
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.
LArPointingCluster class.
const Vertex & GetInnerVertex() const
Get the inner vertex.
const Vertex & GetOuterVertex() const
Get the outer vertex.
pandora::StringVector m_daughterListNames
The list of potential daughter object list names.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
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,...
float GetBoundedFraction2() const
Get the bounded fraction for algorithm-specified cone angle 2.
const pandora::Cluster * GetParentCluster() const
Get the address of the candidate parent (shower) cluster.
float GetBoundedFraction1() const
Get the bounded fraction for algorithm-specified cone angle 1.
float m_coneTanHalfAngle1
The cone tan half angle to use when calculating bounded cluster fractions 1.
std::unordered_map< const pandora::Cluster *, ClusterMergeList > ClusterMergeMap
unsigned int m_maxIterations
The maximum allowed number of algorithm iterations.
unsigned int m_nConeFitLayers
The number of layers over which to sum fitted direction to obtain cone fit.
float m_coneLengthMultiplier
The cone length multiplier to use when calculating bounded cluster fractions.
std::unordered_map< const pandora::Cluster *, const pandora::Cluster * > ClusterReplacementMap
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
std::unordered_map< const pandora::Cluster *, const pandora::ParticleFlowObject * > ClusterToPfoMap
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.
float m_coneBoundedFraction2
The minimum cluster bounded fraction for association 2.
float m_coneTanHalfAngle2
The cone tan half angle to use when calculating bounded cluster fractions 2.
bool m_useVertex
Whether to use the interaction vertex to select useful cone directions.
bool MakePfoMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
Make pfo merges based on the provided cluster merge map.
float m_maxVertexTransverseDistance
Vertex association check: max transverse distance cut.
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.
float m_coneBoundedFraction1
The minimum cluster bounded fraction for association 1.
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.
unsigned int m_halfWindowLayers
The number of layers to use for half-window of sliding fit.
float m_maxConeLength
The maximum allowed cone length to use when calculating bounded cluster fractions.
unsigned int m_nConeFits
The number of cone fits to perform, spread roughly uniformly along the shower length.
unsigned int m_maxHitsToConsider3DTrack
The maximum number of hits in a 3d track cluster to warrant inclusion in algorithm.
float m_minVertexLongitudinalDistance
Vertex association check: min longitudinal distance cut.
pandora::StatusCode Run()
Run the algorithm.
pandora::StringVector m_inputPfoListNames
The input pfo list names.
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.
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
const ThreeDSlidingFitResult & GetSlidingFitResult() const
Get the sliding fit result for the full cluster.
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.
const pandora::CartesianVector & GetGlobalMaxLayerPosition() const
Get global position corresponding to the fit result in maximum fit layer.
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.
CartesianVector class.
Cluster class.
Definition Cluster.h:31
bool ShouldDisplayAlgorithmInfo() const
Whether to display algorithm information during processing.
ParticleFlowObject class.
const Pandora & GetPandora() const
Get the associated pandora instance.
Definition Process.h:116
StatusCodeException class.
Vertex class.
Definition Vertex.h:26
const CartesianVector & GetPosition() const
Get the vertex position.
Definition Vertex.h:103
static StatusCode ReadVectorOfValues(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, std::vector< T > &vector)
Read a vector of values from a (space separated) list in an xml element.
Definition XmlHelper.h:229
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
ConeSelection
ConeSelection enum.
std::vector< SimpleCone > SimpleConeList
std::vector< const Cluster * > ClusterVector
MANAGED_CONTAINER< const Cluster * > ClusterList
MANAGED_CONTAINER< const Vertex * > VertexList
StatusCode
The StatusCode enum.
MANAGED_CONTAINER< const ParticleFlowObject * > PfoList