CheatingSliceSelectionTool.cc
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/LArCheating/CheatingSliceSelectionTool.cc
3  *
4  * @brief Implementation of the cheating slice selection tool class.
5  *
6  * $Log: $
7  */
8 
9 #include "Pandora/AlgorithmHeaders.h"
10 
12 
14 
15 using namespace pandora;
16 
17 namespace lar_content
18 {
19 
20 CheatingSliceSelectionTool::CheatingSliceSelectionTool() : m_maxSlices{1}, m_threshold{-1.f}, m_cutVariable{"completeness"}
21 {
22 }
23 
24 //-----------------------------------------------------------------------------------------------------------------------------------------
25 
26 void CheatingSliceSelectionTool::SelectSlices(const pandora::Algorithm *const /*pAlgorithm*/, const SliceVector &inputSliceVector, SliceVector &outputSliceVector)
27 {
28  // ATTN Ensure this only runs if slicing enabled
29  unsigned int sliceCounter{0};
30  MetricSliceIndexMap reducedSliceVarIndexMap;
31 
32  FloatVector targetWeights(inputSliceVector.size());
33  FloatVector otherWeights(inputSliceVector.size());
34 
35  // Calculate target and total weight for each slice
36  for (const CaloHitList &sliceHits : inputSliceVector)
37  {
38  CaloHitList localHitList{};
39  // ATTN Must ensure we copy the hit actually owned by master instance; access differs with/without slicing enabled
40  for (const CaloHit *const pSliceCaloHit : sliceHits)
41  localHitList.push_back(static_cast<const CaloHit *>(pSliceCaloHit->GetParentAddress()));
42 
43  for (const CaloHit *const pCaloHit : localHitList)
44  {
45  float thisTargetParticleWeight{0.f}, thisTotalWeight{0.f};
46  const MCParticleWeightMap &hitMCParticleWeightMap(pCaloHit->GetMCParticleWeightMap());
47 
48  if (hitMCParticleWeightMap.empty())
49  continue;
50 
51  MCParticleList mcParticleList;
52  for (const auto &mapEntry : hitMCParticleWeightMap)
53  mcParticleList.push_back(mapEntry.first);
54  mcParticleList.sort(LArMCParticleHelper::SortByMomentum);
55 
56  for (const MCParticle *const pMCParticle : mcParticleList)
57  {
58  const float weight{hitMCParticleWeightMap.at(pMCParticle)};
59  const MCParticle *const pParentMCParticle{LArMCParticleHelper::GetParentMCParticle(pMCParticle)};
60 
61  if (this->IsTarget(pParentMCParticle))
62  thisTargetParticleWeight += weight;
63 
64  thisTotalWeight += weight;
65  }
66 
67  // ATTN normalise arbitrary input weights at this point
68  if (thisTotalWeight > std::numeric_limits<float>::epsilon())
69  {
70  thisTargetParticleWeight *= 1.f / thisTotalWeight;
71  thisTotalWeight = 1.f;
72  }
73  else
74  {
75  thisTargetParticleWeight = 0.f;
76  thisTotalWeight = 0.f;
77  }
78  targetWeights[sliceCounter] += thisTargetParticleWeight;
79  otherWeights[sliceCounter] += (1. - thisTargetParticleWeight);
80  }
81 
82  ++sliceCounter;
83  }
84 
85  float totalTargetWeight{0.f};
86  for (const float weight : targetWeights)
87  totalTargetWeight += weight;
88 
89  // Add slices passing cut threshold to map
90  for (unsigned int i = 0; i < targetWeights.size(); ++i)
91  {
92  const float sliceWeight = targetWeights[i] + otherWeights[i];
93  const float completeness{totalTargetWeight > std::numeric_limits<float>::epsilon() ? targetWeights[i] / totalTargetWeight : 0.f};
94  const float purity{sliceWeight > std::numeric_limits<float>::epsilon() ? targetWeights[i] / sliceWeight : 0.f};
95  // Already checked correctness of variable in ReadSettings
96  if (m_cutVariable == "completeness")
97  {
98  if (completeness >= m_threshold)
99  reducedSliceVarIndexMap.emplace(completeness, i);
100  }
101  else if (m_cutVariable == "purity")
102  {
103  if (purity >= m_threshold)
104  reducedSliceVarIndexMap.emplace(purity, i);
105  }
106  }
107  // Select the best m_maxSlices slices - prefix increment ensures all slices retained if m_maxSlices == 0
108  std::vector<int> reducedSliceIndices{};
109  int i = 0;
110  for (const auto [cutVariable, index] : reducedSliceVarIndexMap)
111  { // ATTN: Map is sorted on cut variable from max to min
112  (void)cutVariable; // GCC 7 support, versions 8+ do not need this
113  reducedSliceIndices.push_back(index);
114  outputSliceVector.push_back(inputSliceVector[index]);
115  if (++i == m_maxSlices)
116  break;
117  }
118 }
119 
120 //------------------------------------------------------------------------------------------------------------------------------------------
121 
122 StatusCode CheatingSliceSelectionTool::ReadSettings(const TiXmlHandle xmlHandle)
123 {
124  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "MaxSlices", m_maxSlices));
125  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "Threshold", m_threshold));
126 
127  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle, "CutVariable", m_cutVariable));
128  std::transform(m_cutVariable.begin(), m_cutVariable.end(), m_cutVariable.begin(), [](unsigned char c) { return std::tolower(c); });
129  if (m_cutVariable != "completeness" && m_cutVariable != "purity")
130  {
131  std::cout << "CheatingSliceSelectionTool::ReadSettings: Unknown cut variable \'" << m_cutVariable << "\'" << std::endl;
132  return STATUS_CODE_INVALID_PARAMETER;
133  }
134 
135  return STATUS_CODE_SUCCESS;
136 }
137 
138 } // namespace lar_content
void SelectSlices(const pandora::Algorithm *const pAlgorithm, const SliceVector &inputSliceVector, SliceVector &outputSliceVector)
Select which slice(s) to use.
std::string m_cutVariable
The variable to cut on ("purity" or "completeness") - default "completeness".
std::vector< pandora::CaloHitList > SliceVector
int m_maxSlices
The maximum number of slices to retain (0 to retain all) - default 0.
std::map< float, int, std::greater< float > > MetricSliceIndexMap
weight
Definition: test.py:257
Header file for the cheating slice selection tool class.
static bool SortByMomentum(const pandora::MCParticle *const pLhs, const pandora::MCParticle *const pRhs)
Sort mc particles by their momentum.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
Header file for the lar monte carlo particle helper helper class.
float m_threshold
The minimum cut threshold to retain a slice (< 0 for no threshold) - default -1.
static const pandora::MCParticle * GetParentMCParticle(const pandora::MCParticle *const pMCParticle)
Get the parent mc particle.
virtual bool IsTarget(const pandora::MCParticle *const mcParticle) const =0
Template method to determine if an MC particle matches the target criteria for slice selection...
Dft::FloatVector FloatVector
QTextStream & endl(QTextStream &s)