Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
CrossGapsExtensionAlgorithm.cc
Go to the documentation of this file.
1
10
14
16
17using namespace pandora;
18
19namespace lar_content
20{
21
23 m_minClusterLength(5.f),
24 m_minGapFraction(0.5f),
25 m_maxGapTolerance(2.f),
26 m_maxTransverseDisplacement(2.5f),
27 m_maxRelativeAngle(10.f)
28{
29}
30
31//------------------------------------------------------------------------------------------------------------------------------------------
32
33void CrossGapsExtensionAlgorithm::GetListOfCleanClusters(const ClusterList *const pClusterList, ClusterVector &clusterVector) const
34{
35 // ATTN May want to opt-out completely if no gap information available
36 // if (PandoraContentApi::GetGeometry(*this)->GetDetectorGapList().empty())
37 // return;
38
39 for (const Cluster *const pCluster : *pClusterList)
40 {
42 continue;
43
44 clusterVector.push_back(pCluster);
45 }
46
47 std::sort(clusterVector.begin(), clusterVector.end(), LArClusterHelper::SortByNHits);
48}
49
50//------------------------------------------------------------------------------------------------------------------------------------------
51
53{
54 // Build lists of pointing clusters in proximity to gaps
55 LArPointingClusterList innerPointingClusterList, outerPointingClusterList;
56 this->BuildPointingClusterList(clusterVector, innerPointingClusterList, outerPointingClusterList);
57
58 // Form associations between pairs of pointing clusters
59 for (const LArPointingCluster &pointingClusterInner : innerPointingClusterList)
60 {
61 const LArPointingCluster::Vertex &pointingVertexInner(pointingClusterInner.GetInnerVertex());
62 const float zInner(pointingVertexInner.GetPosition().GetZ());
63
64 for (const LArPointingCluster &pointingClusterOuter : outerPointingClusterList)
65 {
66 const LArPointingCluster::Vertex &pointingVertexOuter(pointingClusterOuter.GetOuterVertex());
67 const float zOuter(pointingVertexOuter.GetPosition().GetZ());
68
69 if (!this->IsAcrossGap(zOuter, zInner, LArClusterHelper::GetClusterHitType(pointingClusterInner.GetCluster())))
70 continue;
71
72 if (!this->IsAssociated(pointingVertexInner, pointingVertexOuter))
73 continue;
74
75 const Cluster *const pClusterInner(pointingClusterInner.GetCluster());
76 const Cluster *const pClusterOuter(pointingClusterOuter.GetCluster());
77
78 const float lengthSquaredInner(LArClusterHelper::GetLengthSquared(pClusterInner));
79 const float lengthSquaredOuter(LArClusterHelper::GetLengthSquared(pClusterOuter));
80
81 (void)clusterAssociationMatrix[pClusterInner].insert(ClusterAssociationMap::value_type(pClusterOuter,
82 ClusterAssociation(ClusterAssociation::INNER, ClusterAssociation::OUTER, ClusterAssociation::STRONG, lengthSquaredOuter)));
83 (void)clusterAssociationMatrix[pClusterOuter].insert(ClusterAssociationMap::value_type(pClusterInner,
84 ClusterAssociation(ClusterAssociation::OUTER, ClusterAssociation::INNER, ClusterAssociation::STRONG, lengthSquaredInner)));
85 }
86 }
87}
88
89//------------------------------------------------------------------------------------------------------------------------------------------
90
92 LArPointingClusterList &innerPointingClusterList, LArPointingClusterList &outerPointingClusterList) const
93{
94 // Convert each input cluster into a pointing cluster
95 LArPointingClusterList pointingClusterList;
96
97 for (const Cluster *const pCluster : clusterVector)
98 {
99 try
100 {
101 pointingClusterList.push_back(LArPointingCluster(pCluster));
102 }
103 catch (StatusCodeException &)
104 {
105 }
106 }
107
108 // Identify clusters adjacent to detector gaps
109 this->BuildPointingClusterList(true, pointingClusterList, innerPointingClusterList);
110 this->BuildPointingClusterList(false, pointingClusterList, outerPointingClusterList);
111}
112
113//------------------------------------------------------------------------------------------------------------------------------------------
114
116 const bool useInner, const LArPointingClusterList &inputPointingClusterList, LArPointingClusterList &outputPointingClusterList) const
117{
118 for (const LArPointingCluster &pointingCluster : inputPointingClusterList)
119 {
120 const LArPointingCluster::Vertex &pointingVertex(useInner ? pointingCluster.GetInnerVertex() : pointingCluster.GetOuterVertex());
121 const HitType hitType(LArClusterHelper::GetClusterHitType(pointingCluster.GetCluster()));
122
123 if (LArGeometryHelper::IsInGap(this->GetPandora(), pointingVertex.GetPosition(), hitType, m_maxGapTolerance))
124 outputPointingClusterList.push_back(pointingCluster);
125 }
126}
127
128//------------------------------------------------------------------------------------------------------------------------------------------
129
131{
132 const float maxLongitudinalDisplacement((pointingVertex2.GetPosition() - pointingVertex1.GetPosition()).GetMagnitude());
133
134 const bool isAssociated1(LArPointingClusterHelper::IsEmission(pointingVertex1.GetPosition(), pointingVertex2, -1.f,
135 maxLongitudinalDisplacement + 1.f, m_maxTransverseDisplacement, m_maxRelativeAngle));
136 const bool isAssociated2(LArPointingClusterHelper::IsEmission(pointingVertex2.GetPosition(), pointingVertex1, -1.f,
137 maxLongitudinalDisplacement + 1.f, m_maxTransverseDisplacement, m_maxRelativeAngle));
138
139 return (isAssociated1 && isAssociated2);
140}
141
142//------------------------------------------------------------------------------------------------------------------------------------------
143
144bool CrossGapsExtensionAlgorithm::IsAcrossGap(const float minZ, const float maxZ, const HitType hitType) const
145{
146 if (maxZ - minZ < std::numeric_limits<float>::epsilon())
147 return false;
148
149 const float gapDeltaZ(LArGeometryHelper::CalculateGapDeltaZ(this->GetPandora(), minZ, maxZ, hitType));
150
151 if (gapDeltaZ / (maxZ - minZ) < m_minGapFraction)
152 return false;
153
154 return true;
155}
156
157//------------------------------------------------------------------------------------------------------------------------------------------
158
159void CrossGapsExtensionAlgorithm::FillClusterMergeMap(const ClusterAssociationMatrix &inputAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
160{
161 // Decide which associations will become merges
162 // To make the merge A <-> B, both A -> B and B -> A must be strong associations
163 // with the largest figures of merit of all the A -> X and B -> Y associations
164
165 // First step: remove double-counting from the map of associations
166 // i.e. if the map has A <-> B, B <-> C, A <-> C, then remove A <-> C
167 ClusterAssociationMatrix clusterAssociationMatrix;
168
169 ClusterVector sortedInputClusters;
170 for (const auto &mapEntry : inputAssociationMatrix)
171 sortedInputClusters.push_back(mapEntry.first);
172 std::sort(sortedInputClusters.begin(), sortedInputClusters.end(), LArClusterHelper::SortByNHits);
173
174 for (const Cluster *const pCluster1 : sortedInputClusters)
175 {
176 const ClusterAssociationMap &associationMap1(inputAssociationMatrix.at(pCluster1));
177
178 for (const Cluster *const pCluster2 : sortedInputClusters)
179 {
180 if (pCluster1 == pCluster2)
181 continue;
182
183 const ClusterAssociationMap &associationMap2(inputAssociationMatrix.at(pCluster2));
184
185 ClusterAssociationMap::const_iterator iter12 = associationMap1.find(pCluster2);
186 if (associationMap1.end() == iter12)
187 continue;
188
189 ClusterAssociationMap::const_iterator iter21 = associationMap2.find(pCluster1);
190 if (associationMap2.end() == iter21)
191 continue;
192
193 const ClusterAssociation &association12(iter12->second);
194 const ClusterAssociation &association21(iter21->second);
195
196 bool isAssociated(true);
197
198 ClusterVector sortedAssociationClusters;
199 for (const auto &mapEntry : associationMap1)
200 sortedAssociationClusters.push_back(mapEntry.first);
201 std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
202
203 for (const Cluster *const pCluster3 : sortedAssociationClusters)
204 {
205 const ClusterAssociation &association13(associationMap1.at(pCluster3));
206
207 ClusterAssociationMap::const_iterator iter23 = associationMap2.find(pCluster3);
208 if (associationMap2.end() == iter23)
209 continue;
210
211 const ClusterAssociation &association23(iter23->second);
212
213 if (association12.GetParent() == association13.GetParent() && association23.GetParent() == association21.GetParent() &&
214 association13.GetDaughter() != association23.GetDaughter())
215 {
216 isAssociated = false;
217 break;
218 }
219 }
220
221 if (isAssociated)
222 {
223 (void)clusterAssociationMatrix[pCluster1].insert(ClusterAssociationMap::value_type(pCluster2, association12));
224 (void)clusterAssociationMatrix[pCluster2].insert(ClusterAssociationMap::value_type(pCluster1, association21));
225 }
226 }
227 }
228
229 // Second step: find the best associations A -> X and B -> Y
230 ClusterAssociationMatrix intermediateAssociationMatrix;
231
232 ClusterVector sortedClusters;
233 for (const auto &mapEntry : clusterAssociationMatrix)
234 sortedClusters.push_back(mapEntry.first);
235 std::sort(sortedClusters.begin(), sortedClusters.end(), LArClusterHelper::SortByNHits);
236
237 for (const Cluster *const pParentCluster : sortedClusters)
238 {
239 const ClusterAssociationMap &clusterAssociationMap(clusterAssociationMatrix.at(pParentCluster));
240
241 const Cluster *pBestClusterInner(nullptr);
242 ClusterAssociation bestAssociationInner(ClusterAssociation::UNDEFINED, ClusterAssociation::UNDEFINED, ClusterAssociation::NONE, 0.f);
243
244 const Cluster *pBestClusterOuter(nullptr);
245 ClusterAssociation bestAssociationOuter(ClusterAssociation::UNDEFINED, ClusterAssociation::UNDEFINED, ClusterAssociation::NONE, 0.f);
246
247 ClusterVector sortedAssociationClusters;
248 for (const auto &mapEntry : clusterAssociationMap)
249 sortedAssociationClusters.push_back(mapEntry.first);
250 std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
251
252 for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
253 {
254 const ClusterAssociation &clusterAssociation(clusterAssociationMap.at(pDaughterCluster));
255
256 // Inner associations
257 if (clusterAssociation.GetParent() == ClusterAssociation::INNER)
258 {
259 if (clusterAssociation.GetFigureOfMerit() > bestAssociationInner.GetFigureOfMerit())
260 {
261 bestAssociationInner = clusterAssociation;
262 pBestClusterInner = pDaughterCluster;
263 }
264 }
265
266 // Outer associations
267 if (clusterAssociation.GetParent() == ClusterAssociation::OUTER)
268 {
269 if (clusterAssociation.GetFigureOfMerit() > bestAssociationOuter.GetFigureOfMerit())
270 {
271 bestAssociationOuter = clusterAssociation;
272 pBestClusterOuter = pDaughterCluster;
273 }
274 }
275 }
276
277 if (pBestClusterInner)
278 (void)intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterInner, bestAssociationInner));
279
280 if (pBestClusterOuter)
281 (void)intermediateAssociationMatrix[pParentCluster].insert(ClusterAssociationMap::value_type(pBestClusterOuter, bestAssociationOuter));
282 }
283
284 // Third step: make the merge if A -> X and B -> Y is in fact A -> B and B -> A
285 ClusterVector intermediateSortedClusters;
286 for (const auto &mapEntry : intermediateAssociationMatrix)
287 intermediateSortedClusters.push_back(mapEntry.first);
288 std::sort(intermediateSortedClusters.begin(), intermediateSortedClusters.end(), LArClusterHelper::SortByNHits);
289
290 for (const Cluster *const pParentCluster : intermediateSortedClusters)
291 {
292 const ClusterAssociationMap &parentAssociationMap(intermediateAssociationMatrix.at(pParentCluster));
293
294 ClusterVector sortedAssociationClusters;
295 for (const auto &mapEntry : parentAssociationMap)
296 sortedAssociationClusters.push_back(mapEntry.first);
297 std::sort(sortedAssociationClusters.begin(), sortedAssociationClusters.end(), LArClusterHelper::SortByNHits);
298
299 for (const Cluster *const pDaughterCluster : sortedAssociationClusters)
300 {
301 const ClusterAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterCluster));
302
303 ClusterAssociationMatrix::const_iterator iter5 = intermediateAssociationMatrix.find(pDaughterCluster);
304
305 if (intermediateAssociationMatrix.end() == iter5)
306 continue;
307
308 const ClusterAssociationMap &daughterAssociationMap(iter5->second);
309
310 ClusterAssociationMap::const_iterator iter6 = daughterAssociationMap.find(pParentCluster);
311
312 if (daughterAssociationMap.end() == iter6)
313 continue;
314
315 const ClusterAssociation &daughterToParentAssociation(iter6->second);
316
317 if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.GetDaughter() &&
318 parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.GetParent())
319 {
320 ClusterList &parentList(clusterMergeMap[pParentCluster]);
321
322 if (parentList.end() == std::find(parentList.begin(), parentList.end(), pDaughterCluster))
323 parentList.push_back(pDaughterCluster);
324 }
325 }
326 }
327}
328
329//------------------------------------------------------------------------------------------------------------------------------------------
330
332{
334 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinClusterLength", m_minClusterLength));
335
336 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MinGapFraction", m_minGapFraction));
337
338 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxGapTolerance", m_maxGapTolerance));
339
340 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
341 XmlHelper::ReadValue(xmlHandle, "MaxTransverseDisplacement", m_maxTransverseDisplacement));
342
343 float maxCosRelativeAngle(std::cos(m_maxRelativeAngle * M_PI / 180.0));
345 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxCosRelativeAngle", maxCosRelativeAngle));
346 m_maxRelativeAngle = (180.0 / M_PI) * std::acos(maxCosRelativeAngle);
347
349}
350
351} // namespace lar_content
Grouping of header files for many classes of use in particle flow algorithms.
Header file for the cross gaps extension algorithm class.
Header file for the cluster helper class.
Header file for the geometry helper class.
#define PANDORA_RETURN_RESULT_IF_AND_IF(StatusCode1, StatusCode2, Operator, Command)
Definition StatusCodes.h:31
std::unordered_map< const pandora::Cluster *, ClusterAssociationMap > ClusterAssociationMatrix
std::unordered_map< const pandora::Cluster *, ClusterAssociation > ClusterAssociationMap
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Read the algorithm settings.
void GetListOfCleanClusters(const pandora::ClusterList *const pClusterList, pandora::ClusterVector &clusterVector) const
Populate cluster vector with subset of cluster list, containing clusters judged to be clean.
void BuildPointingClusterList(const pandora::ClusterVector &clusterVector, LArPointingClusterList &innerPointingClusterList, LArPointingClusterList &outerPointingClusterList) const
Build lists of pointing clusters that are adjacent to a detector gap.
bool IsAcrossGap(const float minZ, const float maxZ, const pandora::HitType hitType) const
Determine whether a start and end position sit either side of a gap.
void FillClusterMergeMap(const ClusterAssociationMatrix &clusterAssociationMatrix, ClusterMergeMap &clusterMergeMap) const
Fill the cluster merge map.
bool IsAssociated(const LArPointingCluster::Vertex &pointingVertex1, const LArPointingCluster::Vertex &pointingVertex2) const
Use pointing information to determine whether two clusters are associated.
void FillClusterAssociationMatrix(const pandora::ClusterVector &clusterVector, ClusterAssociationMatrix &clusterAssociationMatrix) const
Fill the cluster association matrix.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
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 GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
static bool IsInGap(const pandora::Pandora &pandora, const pandora::CartesianVector &testPoint2D, const pandora::HitType hitType, const float gapTolerance=0.f)
Whether a 2D test point lies in a registered gap with the associated hit type.
static float CalculateGapDeltaZ(const pandora::Pandora &pandora, const float minZ, const float maxZ, const pandora::HitType hitType)
Calculate the total distance within a given 2D region that is composed of detector gaps.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.
static bool IsEmission(const pandora::CartesianVector &parentVertex, const LArPointingCluster::Vertex &daughterVertex, const float minLongitudinalDistance, const float maxLongitudinalDistance, const float maxTransverseDistance, const float angularAllowance)
Whether pointing vertex is emitted from a given position.
LArPointingCluster class.
float GetZ() const
Get the cartesian z coordinate.
Cluster class.
Definition Cluster.h:31
const Pandora & GetPandora() const
Get the associated pandora instance.
Definition Process.h:116
StatusCodeException class.
static StatusCode ReadValue(const TiXmlHandle &xmlHandle, const std::string &xmlElementName, T &t)
Read a value from an xml element.
Definition XmlHelper.h:136
std::unordered_map< const pandora::Cluster *, pandora::ClusterList > ClusterMergeMap
std::vector< LArPointingCluster > LArPointingClusterList
HitType
Calorimeter hit type enum.
std::vector< const Cluster * > ClusterVector
MANAGED_CONTAINER< const Cluster * > ClusterList
StatusCode
The StatusCode enum.