SlidingConeClusterMopUpAlgorithm.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArTwoDReco/LArClusterMopUp/SlidingConeClusterMopUpAlgorithm.cc
3  *
4  * @brief Implementation of the sliding cone cluster mop up algorithm class.
5  *
6  * $Log: $
7  */
8 
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  const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
150 
151  for (const Cluster *const pShowerCluster : clusters3D)
152  {
153  float coneLength3D(0.f);
154  SimpleConeList simpleConeList3D;
155 
156  try
157  {
158  const ThreeDSlidingConeFitResult slidingConeFitResult3D(pShowerCluster, m_halfWindowLayers, layerPitch);
159 
160  const CartesianVector &minLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMinLayerPosition());
161  const CartesianVector &maxLayerPosition(slidingConeFitResult3D.GetSlidingFitResult().GetGlobalMaxLayerPosition());
162  coneLength3D = std::min(m_coneLengthMultiplier * (maxLayerPosition - minLayerPosition).GetMagnitude(), m_maxConeLength);
163 
164  const float vertexToMinLayer(!pVertex ? 0.f : (pVertex->GetPosition() - minLayerPosition).GetMagnitude());
165  const float vertexToMaxLayer(!pVertex ? 0.f : (pVertex->GetPosition() - maxLayerPosition).GetMagnitude());
166  const ConeSelection coneSelection(
167  !pVertex ? CONE_BOTH_DIRECTIONS : (vertexToMaxLayer > vertexToMinLayer) ? CONE_FORWARD_ONLY : CONE_BACKWARD_ONLY);
168 
169  slidingConeFitResult3D.GetSimpleConeList(m_nConeFitLayers, m_nConeFits, coneSelection, simpleConeList3D);
170  }
171  catch (const StatusCodeException &)
172  {
173  continue;
174  }
175 
176  for (const Cluster *const pNearbyCluster2D : availableClusters2D)
177  {
178  ClusterMerge bestClusterMerge(nullptr, 0.f, 0.f);
179  const HitType hitType(LArClusterHelper::GetClusterHitType(pNearbyCluster2D));
180 
181  for (const SimpleCone &simpleCone3D : simpleConeList3D)
182  {
183  const CartesianVector coneBaseCentre3D(simpleCone3D.GetConeApex() + simpleCone3D.GetConeDirection() * coneLength3D);
184  const CartesianVector coneApex2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), simpleCone3D.GetConeApex(), hitType));
185  const CartesianVector coneBaseCentre2D(LArGeometryHelper::ProjectPosition(this->GetPandora(), coneBaseCentre3D, hitType));
186 
187  const CartesianVector apexToBase2D(coneBaseCentre2D - coneApex2D);
188  const SimpleCone simpleCone2D(coneApex2D, apexToBase2D.GetUnitVector(), apexToBase2D.GetMagnitude(), m_coneTanHalfAngle);
189  const ClusterMerge clusterMerge(
190  pShowerCluster, simpleCone2D.GetBoundedHitFraction(pNearbyCluster2D), simpleCone2D.GetMeanRT(pNearbyCluster2D));
191 
192  if (clusterMerge < bestClusterMerge)
193  bestClusterMerge = clusterMerge;
194  }
195 
196  if (bestClusterMerge.GetParentCluster() && (bestClusterMerge.GetBoundedFraction() > m_coneBoundedFraction))
197  clusterMergeMap[pNearbyCluster2D].push_back(bestClusterMerge);
198  }
199  }
200 
201  for (ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
202  std::sort(mapEntry.second.begin(), mapEntry.second.end());
203 }
204 
205 //------------------------------------------------------------------------------------------------------------------------------------------
206 
207 void SlidingConeClusterMopUpAlgorithm::MakeClusterMerges(const ClusterToPfoMap &clusterToPfoMap, const ClusterMergeMap &clusterMergeMap) const
208 {
209  ClusterVector daughterClusters;
210  for (const ClusterMergeMap::value_type &mapEntry : clusterMergeMap)
211  daughterClusters.push_back(mapEntry.first);
212  std::sort(daughterClusters.begin(), daughterClusters.end(), LArClusterHelper::SortByNHits);
213 
214  for (ClusterVector::const_reverse_iterator rIter = daughterClusters.rbegin(), rIterEnd = daughterClusters.rend(); rIter != rIterEnd; ++rIter)
215  {
216  const Cluster *const pDaughterCluster(*rIter);
217  const HitType daughterHitType(LArClusterHelper::GetClusterHitType(pDaughterCluster));
218  const Cluster *const pParentCluster3D(clusterMergeMap.at(pDaughterCluster).at(0).GetParentCluster());
219 
220  const Pfo *const pParentPfo(clusterToPfoMap.at(pParentCluster3D));
221  const Cluster *const pParentCluster(this->GetParentCluster(pParentPfo->GetClusterList(), daughterHitType));
222 
223  if (pParentCluster)
224  {
225  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=,
226  PandoraContentApi::MergeAndDeleteClusters(
227  *this, pParentCluster, pDaughterCluster, this->GetListName(pParentCluster), this->GetListName(pDaughterCluster)));
228  }
229  else
230  {
231  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::AddToPfo(*this, pParentPfo, pDaughterCluster));
232  }
233  }
234 }
235 
236 //------------------------------------------------------------------------------------------------------------------------------------------
237 //------------------------------------------------------------------------------------------------------------------------------------------
238 
240 {
241  if (!this->GetParentCluster() && !rhs.GetParentCluster())
242  return false;
243 
244  if (this->GetParentCluster() && !rhs.GetParentCluster())
245  return true;
246 
247  if (!this->GetParentCluster() && rhs.GetParentCluster())
248  return false;
249 
250  if (std::fabs(this->GetBoundedFraction() - rhs.GetBoundedFraction()) > std::numeric_limits<float>::epsilon())
251  return (this->GetBoundedFraction() > rhs.GetBoundedFraction());
252 
253  if (std::fabs(this->GetMeanRT() - rhs.GetMeanRT()) > std::numeric_limits<float>::epsilon())
254  return (this->GetMeanRT() < rhs.GetMeanRT());
255 
257 }
258 
259 //------------------------------------------------------------------------------------------------------------------------------------------
260 //------------------------------------------------------------------------------------------------------------------------------------------
261 
262 StatusCode SlidingConeClusterMopUpAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
263 {
264  PANDORA_RETURN_RESULT_IF_AND_IF(
265  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadVectorOfValues(xmlHandle, "InputPfoListNames", m_inputPfoListNames));
266 
267  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "UseVertex", m_useVertex));
268 
269  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxIterations", m_maxIterations));
270 
271  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
272  XmlHelper::ReadValue(xmlHandle, "MaxHitsToConsider3DTrack", m_maxHitsToConsider3DTrack));
273 
274  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
275  XmlHelper::ReadValue(xmlHandle, "MinHitsToConsider3DShower", m_minHitsToConsider3DShower));
276 
277  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=,
278  XmlHelper::ReadValue(xmlHandle, "MaxHitsToConsider2DCluster", m_maxHitsToConsider2DCluster));
279 
280  PANDORA_RETURN_RESULT_IF_AND_IF(
281  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "SlidingFitHalfWindow", m_halfWindowLayers));
282 
283  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFitLayers", m_nConeFitLayers));
284 
285  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "NConeFits", m_nConeFits));
286 
287  PANDORA_RETURN_RESULT_IF_AND_IF(
288  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeLengthMultiplier", m_coneLengthMultiplier));
289 
290  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxConeLength", m_maxConeLength));
291 
292  PANDORA_RETURN_RESULT_IF_AND_IF(
293  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeTanHalfAngle", m_coneTanHalfAngle));
294 
295  PANDORA_RETURN_RESULT_IF_AND_IF(
296  STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "ConeBoundedFraction", m_coneBoundedFraction));
297 
298  return PfoMopUpBaseAlgorithm::ReadSettings(xmlHandle);
299 }
300 
301 } // 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.
enum cvn::HType HitType
std::string string
Definition: nybbler.cc:12
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.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
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.
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 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.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
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.
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:182
QTextStream & endl(QTextStream &s)
const pandora::CartesianVector & GetGlobalMinLayerPosition() const
Get global position corresponding to the fit result in minimum fit layer.