LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
LocalAsymmetryFeatureTool.cc
Go to the documentation of this file.
1 
9 #include "Pandora/AlgorithmHeaders.h"
10 
13 
15 
16 using namespace pandora;
17 
18 namespace lar_content
19 {
20 
21 LocalAsymmetryFeatureTool::LocalAsymmetryFeatureTool() :
22  m_maxAsymmetryDistance(5.f),
23  m_minAsymmetryCosAngle(0.9962),
24  m_maxAsymmetryNClusters(2)
25 {
26 }
27 
28 //------------------------------------------------------------------------------------------------------------------------------------------
29 
30 void LocalAsymmetryFeatureTool::Run(LArMvaHelper::MvaFeatureVector &featureVector, const VertexSelectionBaseAlgorithm *const pAlgorithm, const Vertex * const pVertex,
33 {
34  if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
35  std::cout << "----> Running Algorithm Tool: " << this->GetInstanceName() << ", " << this->GetType() << std::endl;
36 
37  float localAsymmetry(0.f);
38 
39  localAsymmetry += this->GetLocalAsymmetryForView(LArGeometryHelper::ProjectPosition(this->GetPandora(), pVertex->GetPosition(), TPC_VIEW_U),
40  slidingFitDataListMap.at(TPC_VIEW_U));
41 
42  localAsymmetry += this->GetLocalAsymmetryForView(LArGeometryHelper::ProjectPosition(this->GetPandora(), pVertex->GetPosition(), TPC_VIEW_V),
43  slidingFitDataListMap.at(TPC_VIEW_V));
44 
45  localAsymmetry += this->GetLocalAsymmetryForView(LArGeometryHelper::ProjectPosition(this->GetPandora(), pVertex->GetPosition(), TPC_VIEW_W),
46  slidingFitDataListMap.at(TPC_VIEW_W));
47 
48  featureVector.push_back(localAsymmetry);
49 }
50 
51 //------------------------------------------------------------------------------------------------------------------------------------------
52 
53 float LocalAsymmetryFeatureTool::GetLocalAsymmetryForView(const CartesianVector &vertexPosition2D,
54  const VertexSelectionBaseAlgorithm::SlidingFitDataList &slidingFitDataList) const
55 {
56  bool useEnergy(true), useAsymmetry(true);
57  CartesianVector energyWeightedDirectionSum(0.f, 0.f, 0.f), hitWeightedDirectionSum(0.f, 0.f, 0.f);
58  ClusterVector asymmetryClusters;
59 
60  for (const VertexSelectionBaseAlgorithm::SlidingFitData &slidingFitData : slidingFitDataList)
61  {
62  const Cluster *const pCluster(slidingFitData.GetCluster());
63 
64  if (pCluster->GetElectromagneticEnergy() < std::numeric_limits<float>::epsilon())
65  useEnergy = false;
66 
67  const CartesianVector vertexToMinLayer(slidingFitData.GetMinLayerPosition() - vertexPosition2D);
68  const CartesianVector vertexToMaxLayer(slidingFitData.GetMaxLayerPosition() - vertexPosition2D);
69 
70  const bool minLayerClosest(vertexToMinLayer.GetMagnitudeSquared() < vertexToMaxLayer.GetMagnitudeSquared());
71  const CartesianVector &clusterDirection((minLayerClosest) ? slidingFitData.GetMinLayerDirection() : slidingFitData.GetMaxLayerDirection());
72 
73  if (useAsymmetry && (LArClusterHelper::GetClosestDistance(vertexPosition2D, pCluster) < m_maxAsymmetryDistance))
74  {
75  useAsymmetry &= this->IncrementAsymmetryParameters(pCluster->GetElectromagneticEnergy(), clusterDirection, energyWeightedDirectionSum);
76  useAsymmetry &= this->IncrementAsymmetryParameters(static_cast<float>(pCluster->GetNCaloHits()), clusterDirection, hitWeightedDirectionSum);
77  asymmetryClusters.push_back(pCluster);
78  }
79 
80  if (!useAsymmetry)
81  return 1.f;
82  }
83 
84  // Default: maximum asymmetry (i.e. not suppressed), zero for energy kick (i.e. not suppressed)
85  if ((useEnergy && energyWeightedDirectionSum == CartesianVector(0.f, 0.f, 0.f)) || (!useEnergy && hitWeightedDirectionSum == CartesianVector(0.f, 0.f, 0.f)))
86  return 1.f;
87 
88  const CartesianVector &localWeightedDirectionSum(useEnergy ? energyWeightedDirectionSum : hitWeightedDirectionSum);
89  return this->CalculateLocalAsymmetry(useEnergy, vertexPosition2D, asymmetryClusters, localWeightedDirectionSum);
90 }
91 
92 //------------------------------------------------------------------------------------------------------------------------------------------
93 
94 bool LocalAsymmetryFeatureTool::IncrementAsymmetryParameters(const float weight, const CartesianVector &clusterDirection,
95  CartesianVector &localWeightedDirectionSum) const
96 {
97  // If the new axis direction is at an angle of greater than 90 deg to the current axis direction, flip it 180 degs.
98  CartesianVector newDirection(clusterDirection);
99 
100  if (localWeightedDirectionSum.GetMagnitudeSquared() > std::numeric_limits<float>::epsilon())
101  {
102  const float cosOpeningAngle(localWeightedDirectionSum.GetCosOpeningAngle(clusterDirection));
103 
104  if (std::fabs(cosOpeningAngle) > m_minAsymmetryCosAngle)
105  {
106  if (cosOpeningAngle < 0.f)
107  newDirection *= -1.f;
108  }
109 
110  else
111  return false;
112  }
113 
114  localWeightedDirectionSum += newDirection * weight;
115  return true;
116 }
117 
118 //------------------------------------------------------------------------------------------------------------------------------------------
119 
120 float LocalAsymmetryFeatureTool::CalculateLocalAsymmetry(const bool useEnergyMetrics, const CartesianVector &vertexPosition2D,
121  const ClusterVector &asymmetryClusters, const CartesianVector &localWeightedDirectionSum) const
122 {
123  if (asymmetryClusters.empty() || (asymmetryClusters.size() > m_maxAsymmetryNClusters))
124  return 1.f;
125 
126  // Project every hit onto local event axis direction and record side of the projected vtx position on which it falls
127  float beforeVtxHitEnergy(0.f), afterVtxHitEnergy(0.f);
128  unsigned int beforeVtxHitCount(0), afterVtxHitCount(0);
129 
130  const CartesianVector localWeightedDirection(localWeightedDirectionSum.GetUnitVector());
131  const float evtProjectedVtxPos(vertexPosition2D.GetDotProduct(localWeightedDirection));
132 
133  for (const Cluster *const pCluster : asymmetryClusters)
134  {
135  CaloHitList caloHitList;
136  pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitList);
137 
138  CaloHitVector caloHitVector(caloHitList.begin(), caloHitList.end());
139  std::sort(caloHitVector.begin(), caloHitVector.end(), LArClusterHelper::SortHitsByPosition);
140 
141  for (const CaloHit *const pCaloHit : caloHitVector)
142  {
143  if (pCaloHit->GetPositionVector().GetDotProduct(localWeightedDirection) < evtProjectedVtxPos)
144  {
145  beforeVtxHitEnergy += pCaloHit->GetElectromagneticEnergy();
146  ++beforeVtxHitCount;
147  }
148 
149  else
150  {
151  afterVtxHitEnergy += pCaloHit->GetElectromagneticEnergy();
152  ++afterVtxHitCount;
153  }
154  }
155  }
156 
157  // Use energy metrics if possible, otherwise fall back on hit counting.
158  const float totHitEnergy(afterVtxHitEnergy + beforeVtxHitEnergy);
159  const unsigned int totHitCount(beforeVtxHitCount + afterVtxHitCount);
160 
161  if (useEnergyMetrics && (totHitEnergy > std::numeric_limits<float>::epsilon()))
162  return std::fabs((afterVtxHitEnergy - beforeVtxHitEnergy)) / totHitEnergy;
163 
164  if (0 == totHitCount)
165  throw StatusCodeException(STATUS_CODE_FAILURE);
166 
167  return std::fabs((static_cast<float>(afterVtxHitCount) - static_cast<float>(beforeVtxHitCount))) / static_cast<float>(totHitCount);
168 }
169 
170 //------------------------------------------------------------------------------------------------------------------------------------------
171 
172 StatusCode LocalAsymmetryFeatureTool::ReadSettings(const TiXmlHandle xmlHandle)
173 {
174  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
175  "MaxAsymmetryDistance", m_maxAsymmetryDistance));
176 
177  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
178  "MinAsymmetryCosAngle", m_minAsymmetryCosAngle));
179 
180  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
181  "MaxAsymmetryNClusters", m_maxAsymmetryNClusters));
182 
183  return STATUS_CODE_SUCCESS;
184 }
185 
186 } // namespace lar_content
float m_maxAsymmetryDistance
The max distance between cluster (any hit) and vertex to calculate asymmetry score.
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:58
float CalculateLocalAsymmetry(const bool useEnergyMetrics, const pandora::CartesianVector &vertexPosition2D, const pandora::ClusterVector &asymmetryClusters, const pandora::CartesianVector &localWeightedDirectionSum) const
Calculate the local asymmetry feature.
void Run(LArMvaHelper::MvaFeatureVector &featureVector, const VertexSelectionBaseAlgorithm *const pAlgorithm, const pandora::Vertex *const pVertex, const VertexSelectionBaseAlgorithm::SlidingFitDataListMap &slidingFitDataListMap, const VertexSelectionBaseAlgorithm::ClusterListMap &, const VertexSelectionBaseAlgorithm::KDTreeMap &, const VertexSelectionBaseAlgorithm::ShowerClusterListMap &, const float, float &)
Run the tool.
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 GetLocalAsymmetryForView(const pandora::CartesianVector &vertexPosition2D, const VertexSelectionBaseAlgorithm::SlidingFitDataList &slidingFitDataList) const
Get the local asymmetry feature in a given view.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
std::map< pandora::HitType, const ShowerClusterList > ShowerClusterListMap
Map of shower cluster lists for passing to tools.
static bool SortHitsByPosition(const pandora::CaloHit *const pLhs, const pandora::CaloHit *const pRhs)
Sort calo hits by their position (use Z, followed by X, followed by Y)
Header file for the cluster helper class.
std::map< pandora::HitType, const pandora::ClusterList & > ClusterListMap
Map array of cluster lists for passing to tools.
bool IncrementAsymmetryParameters(const float weight, const pandora::CartesianVector &clusterDirection, pandora::CartesianVector &localWeightedDirectionSum) const
Increment the asymmetry parameters.
Header file for the local asymmetry feature tool class.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
double weight
Definition: plottest35.C:25
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::map< pandora::HitType, const SlidingFitDataList > SlidingFitDataListMap
Map of sliding fit data lists for passing to tools.
float m_minAsymmetryCosAngle
The min opening angle cosine used to determine viability of asymmetry score.
std::map< pandora::HitType, const std::reference_wrapper< HitKDTree2D > > KDTreeMap
Map array of hit kd trees for passing to tools.
unsigned int m_maxAsymmetryNClusters
The max number of associated clusters to calculate the asymmetry.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.