LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
SlidingConeClusterMopUpAlgorithm.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
14 
16 
18 
19 using namespace pandora;
20 
21 namespace lar_content
22 {
23 
24 SlidingConeClusterMopUpAlgorithm::SlidingConeClusterMopUpAlgorithm() :
25  m_useVertex(true),
26  m_maxIterations(1000),
27  m_maxHitsToConsider3DTrack(100),
28  m_minHitsToConsider3DShower(20),
29  m_maxHitsToConsider2DCluster(50),
30  m_halfWindowLayers(20),
31  m_nConeFitLayers(40),
32  m_nConeFits(5),
33  m_coneLengthMultiplier(3.f),
34  m_maxConeLength(126.f),
35  m_coneTanHalfAngle(0.2f),
36  m_coneBoundedFraction(0.5f)
37 {
38 }
39 
40 //------------------------------------------------------------------------------------------------------------------------------------------
41 
43 {
44  const Vertex *pVertex(nullptr);
45  this->GetInteractionVertex(pVertex);
46 
47  if (m_useVertex && !pVertex)
48  {
49  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
50  std::cout << "SlidingConeClusterMopUpAlgorithm - interaction vertex not available for use." << std::endl;
51  return STATUS_CODE_SUCCESS;
52  }
53 
54  ClusterVector clusters3D;
55  ClusterToPfoMap clusterToPfoMap;
56  this->GetThreeDClusters(clusters3D, clusterToPfoMap);
57 
58  ClusterVector availableClusters2D;
59  this->GetAvailableTwoDClusters(availableClusters2D);
60 
61  ClusterMergeMap clusterMergeMap;
62  this->GetClusterMergeMap(pVertex, clusters3D, availableClusters2D, clusterMergeMap);
63 
64  this->MakeClusterMerges(clusterToPfoMap, clusterMergeMap);
65 
66  return STATUS_CODE_SUCCESS;
67 }
68 
69 //------------------------------------------------------------------------------------------------------------------------------------------
70 
72 {
73  if (!m_useVertex)
74  return;
75 
76  const VertexList *pVertexList = nullptr;
77  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetCurrentList(*this, pVertexList));
78 
79  pVertex =
80  ((pVertexList && (pVertexList->size() == 1) && (VERTEX_3D == (*(pVertexList->begin()))->GetVertexType())) ? *(pVertexList->begin()) : nullptr);
81 }
82 
83 //------------------------------------------------------------------------------------------------------------------------------------------
84 
86 {
87  for (const std::string &pfoListName : m_inputPfoListNames)
88  {
89  const PfoList *pPfoList(nullptr);
90 
91  if (STATUS_CODE_SUCCESS != PandoraContentApi::GetList(*this, pfoListName, pPfoList))
92  continue;
93 
94  for (const Pfo *const pPfo : *pPfoList)
95  {
96  ClusterList pfoClusters3D;
97  LArPfoHelper::GetThreeDClusterList(pPfo, pfoClusters3D);
98 
99  for (const Cluster *const pCluster3D : pfoClusters3D)
100  {
101  if (LArPfoHelper::IsTrack(pPfo) && (pCluster3D->GetNCaloHits() > m_maxHitsToConsider3DTrack))
102  continue;
103 
104  if (LArPfoHelper::IsShower(pPfo) && (pCluster3D->GetNCaloHits() < m_minHitsToConsider3DShower))
105  continue;
106 
107  if (!clusterToPfoMap.insert(ClusterToPfoMap::value_type(pCluster3D, pPfo)).second)
108  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
109 
110  clusters3D.push_back(pCluster3D);
111  }
112  }
113  }
114 
115  std::sort(clusters3D.begin(), clusters3D.end(), LArClusterHelper::SortByNHits);
116 }
117 
118 //------------------------------------------------------------------------------------------------------------------------------------------
119 
121 {
122  for (const std::string &clusterListName : m_daughterListNames)
123  {
124  const ClusterList *pClusterList(nullptr);
125 
126  if (STATUS_CODE_SUCCESS != PandoraContentApi::GetList(*this, clusterListName, pClusterList))
127  continue;
128 
129  for (const Cluster *const pCluster : *pClusterList)
130  {
131  if (!PandoraContentApi::IsAvailable(*this, pCluster))
132  continue;
133 
134  if (pCluster->GetNCaloHits() > m_maxHitsToConsider2DCluster)
135  continue;
136 
137  availableClusters2D.push_back(pCluster);
138  }
139  }
140 
141  std::sort(availableClusters2D.begin(), availableClusters2D.end(), LArClusterHelper::SortByNHits);
142 }
143 
144 //------------------------------------------------------------------------------------------------------------------------------------------
145 
146 void SlidingConeClusterMopUpAlgorithm::GetClusterMergeMap(const Vertex *const pVertex, const ClusterVector &clusters3D,
147  const ClusterVector &availableClusters2D, ClusterMergeMap &clusterMergeMap) const
148 {
149  for (const Cluster *const pShowerCluster : clusters3D)
150  {
151  float coneLength3D(0.f);
152  SimpleConeList simpleConeList3D;
153 
154  try
155  {
156  HitType view{LArClusterHelper::GetClusterHitType(pShowerCluster)};
157  if (!(view == TPC_VIEW_U || view == TPC_VIEW_V))
158  view = TPC_VIEW_W;
159  const float layerPitch(LArGeometryHelper::GetWirePitch(this->GetPandora(), view));
160  const ThreeDSlidingConeFitResult slidingConeFitResult3D(pShowerCluster, m_halfWindowLayers, layerPitch);
161 
162  const CartesianVector &minLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMinLayerPosition());
163  const CartesianVector &maxLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMaxLayerPosition());
164  coneLength3D = std::min(m_coneLengthMultiplier * (maxLayerPosition - minLayerPosition).GetMagnitude(), m_maxConeLength);
165 
166  const float vertexToMinLayer(!pVertex ? 0.f : (pVertex->GetPosition() - minLayerPosition).GetMagnitude());
167  const float vertexToMaxLayer(!pVertex ? 0.f : (pVertex->GetPosition() - maxLayerPosition).GetMagnitude());
168  const ConeSelection coneSelection(!pVertex ? CONE_BOTH_DIRECTIONS
169  : (vertexToMaxLayer > vertexToMinLayer) ? CONE_FORWARD_ONLY
171 
172  slidingConeFitResult3D.GetSimpleConeList(m_nConeFitLayers, m_nConeFits, coneSelection, simpleConeList3D);
173  }
174  catch (const StatusCodeException &)
175  {
176  continue;
177  }
178 
179  for (const Cluster *const pNearbyCluster2D : availableClusters2D)
180  {
181  ClusterMerge bestClusterMerge(nullptr, 0.f, 0.f);
182  const HitType hitType(LArClusterHelper::GetClusterHitType(pNearbyCluster2D));
183 
184  for (const SimpleCone &simpleCone3D : simpleConeList3D)
185  {
186  const CartesianVector coneBaseCentre3D(simpleCone3D.GetConeApex() + simpleCone3D.GetConeDirection() * coneLength3D);
187  const CartesianVector coneApex2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), simpleCone3D.GetConeApex(), hitType));
188  const CartesianVector coneBaseCentre2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), coneBaseCentre3D, hitType));
189 
190  const CartesianVector apexToBase2D(coneBaseCentre2D - coneApex2D);
191  const SimpleCone simpleCone2D(coneApex2D, apexToBase2D.GetUnitVector(), apexToBase2D.GetMagnitude(), m_coneTanHalfAngle);
192  const ClusterMerge clusterMerge(
193  pShowerCluster, simpleCone2D.GetBoundedHitFraction(pNearbyCluster2D), simpleCone2D.GetMeanRT(pNearbyCluster2D));
194 
195  if (clusterMerge < bestClusterMerge)
196  bestClusterMerge = clusterMerge;
197  }
198 
199  if (bestClusterMerge.GetParentCluster() && (bestClusterMerge.GetBoundedFraction() > m_coneBoundedFraction))
200  clusterMergeMap[pNearbyCluster2D].push_back(bestClusterMerge);
201  }
202  }
203 
204  for (ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
205  std::sort(mapEntry.second.begin(), mapEntry.second.end());
206 }
207 
208 //------------------------------------------------------------------------------------------------------------------------------------------
209 
210 void SlidingConeClusterMopUpAlgorithm::MakeClusterMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
211 {
212  ClusterVector daughterClusters;
213  for (const ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
214  daughterClusters.push_back(mapEntry.first);
215  std::sort(daughterClusters.begin(), daughterClusters.end(), LArClusterHelper::SortByNHits);
216 
217  for (ClusterVector::const_reverse_iterator rIter = daughterClusters.rbegin(), rIterEnd = daughterClusters.rend(); rIter != rIterEnd; ++rIter)
218  {
219  const Cluster *const pDaughterCluster(*rIter);
220  const HitType daughterHitType(LArClusterHelper::GetClusterHitType(pDaughterCluster));
221  const Cluster *const pParentCluster3D(clusterMergeMap.at(pDaughterCluster).at(0).GetParentCluster());
222 
223  const Pfo *const pParentPfo(clusterToPfoMap.at(pParentCluster3D));
224  const Cluster *const pParentCluster(this->GetParentCluster(pParentPfo->GetClusterList(), daughterHitType));
225 
226  if (pParentCluster)
227  {
228  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
229  PandoraContentApi::MergeAndDeleteClusters(
230  *this, pParentCluster, pDaughterCluster, this->GetListName(pParentCluster), this->GetListName(pDaughterCluster)));
231  }
232  else
233  {
234  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToPfo(*this, pParentPfo, pDaughterCluster));
235  }
236  }
237 }
238 
239 //------------------------------------------------------------------------------------------------------------------------------------------
240 //------------------------------------------------------------------------------------------------------------------------------------------
241 
243 {
244  if (!this->GetParentCluster() && !rhs.GetParentCluster())
245  return false;
246 
247  if (this->GetParentCluster() && !rhs.GetParentCluster())
248  return true;
249 
250  if (!this->GetParentCluster() && rhs.GetParentCluster())
251  return false;
252 
253  if (std::fabs(this->GetBoundedFraction() - rhs.GetBoundedFraction()) > std::numeric_limits<float>::epsilon())
254  return (this->GetBoundedFraction() > rhs.GetBoundedFraction());
255 
256  if (std::fabs(this->GetMeanRT() - rhs.GetMeanRT()) > std::numeric_limits<float>::epsilon())
257  return (this->GetMeanRT() < rhs.GetMeanRT());
258 
260 }
261 
262 //------------------------------------------------------------------------------------------------------------------------------------------
263 //------------------------------------------------------------------------------------------------------------------------------------------
264 
265 StatusCode SlidingConeClusterMopUpAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
266 {
267  PANDORA_RETURN_RESULT_IF_AND_IF(
268  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputPfoListNames", m_inputPfoListNames));
269 
270  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "UseVertex", m_useVertex));
271 
272  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxIterations", m_maxIterations));
273 
274  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
275  XmlHelper::ReadValue(xmlHandle, "MaxHitsToConsider3DTrack", m_maxHitsToConsider3DTrack));
276 
277  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
278  XmlHelper::ReadValue(xmlHandle, "MinHitsToConsider3DShower", m_minHitsToConsider3DShower));
279 
280  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
281  XmlHelper::ReadValue(xmlHandle, "MaxHitsToConsider2DCluster", m_maxHitsToConsider2DCluster));
282 
283  PANDORA_RETURN_RESULT_IF_AND_IF(
284  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitHalfWindow", m_halfWindowLayers));
285 
286  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFitLayers", m_nConeFitLayers));
287 
288  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFits", m_nConeFits));
289 
290  PANDORA_RETURN_RESULT_IF_AND_IF(
291  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeLengthMultiplier", m_coneLengthMultiplier));
292 
293  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxConeLength", m_maxConeLength));
294 
295  PANDORA_RETURN_RESULT_IF_AND_IF(
296  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle", m_coneTanHalfAngle));
297 
298  PANDORA_RETURN_RESULT_IF_AND_IF(
299  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction", m_coneBoundedFraction));
300 
301  return PfoMopUpBaseAlgorithm::ReadSettings(xmlHandle);
302 }
303 
304 } // namespace lar_content
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.
bool m_useVertex
Whether to use the interaction vertex to select useful cone directions.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the pfo helper class.
Header file for the sliding cone cluster mop up algorithm 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...
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::vector< SimpleCone > SimpleConeList
unsigned int m_maxIterations
The maximum allowed number of algorithm iterations.
float GetMeanRT() const
Get the mean transverse distance of all hits (whether contained or not)
pandora::StringVector m_daughterListNames
The list of potential daughter object list names.
static pandora::CartesianVector ProjectPosition(const pandora::Pandora &pandora, const pandora::CartesianVector &position3D, const pandora::HitType view)
Project 3D position into a given 2D view.
float GetBoundedFraction() const
Get the bounded fraction for algorithm-specified cone angle.
unsigned int m_nConeFitLayers
The number of layers over which to sum fitted direction to obtain cone fit.
const ThreeDSlidingFitResult & GetSlidingFitResult() const
Get the sliding fit result for the full cluster.
static pandora::HitType GetClusterHitType(const pandora::Cluster *const pCluster)
Get the hit type associated with a two dimensional cluster.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
std::unordered_map< const pandora::Cluster *, ClusterMergeList > ClusterMergeMap
unsigned int m_maxHitsToConsider2DCluster
The maximum number of hits in a 2d cluster to allow pick-up via sliding cone fits.
Header file for the lar three dimensional sliding cone fit result class.
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
Header file for the geometry helper class.
const std::string GetListName(const T *const pT) const
Find the name of the list hosting a specific object.
static bool IsShower(const pandora::ParticleFlowObject *const pPfo)
Return shower flag based on Pfo Particle ID.
void GetClusterMergeMap(const pandora::Vertex *const pVertex, const pandora::ClusterVector &clusters3D, const pandora::ClusterVector &availableClusters2D, ClusterMergeMap &clusterMergeMap) const
Get the cluster merge map describing all potential 3d cluster merges.
Header file for the cluster helper class.
float m_coneLengthMultiplier
The cone length multiplier to use when calculating bounded cluster fractions.
unsigned int m_halfWindowLayers
The number of layers to use for half-window of sliding fit.
unsigned int m_minHitsToConsider3DShower
The minimum number of hits in a 3d shower cluster to attempt cone fits.
unsigned int m_maxHitsToConsider3DTrack
The maximum number of hits in a 3d track cluster to warrant inclusion in algorithm.
void MakeClusterMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
Make cluster merges based on the provided cluster merge map.
static float GetWirePitch(const pandora::Pandora &pandora, const pandora::HitType view, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
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.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
float m_coneBoundedFraction
The minimum cluster bounded fraction for association.
pandora::StringVector m_inputPfoListNames
The input pfo list names.
HitType
Definition: HitType.h:12
std::unordered_map< const pandora::Cluster *, const pandora::ParticleFlowObject * > ClusterToPfoMap
float m_coneTanHalfAngle
The cone tan half angle to use when calculating bounded cluster fractions.
ConeSelection
ConeSelection enum.
void GetAvailableTwoDClusters(pandora::ClusterVector &availableClusters2D) const
Get all available 2d clusters contained in the input cluster lists.
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...
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
std::vector< art::Ptr< recob::Cluster > > ClusterVector
float m_maxConeLength
The maximum allowed cone length to use when calculating bounded cluster fractions.
std::list< Vertex > VertexList
Definition: DCEL.h:169
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.