LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
NeutrinoHierarchyAlgorithm.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 NeutrinoHierarchyAlgorithm::NeutrinoHierarchyAlgorithm() :
22  m_halfWindowLayers(20),
23  m_displayPfoInfoMap(false)
24 {
25 }
26 
27 //------------------------------------------------------------------------------------------------------------------------------------------
28 
29 void NeutrinoHierarchyAlgorithm::SeparatePfos(const PfoInfoMap &pfoInfoMap, PfoVector &assignedPfos, PfoVector &unassignedPfos) const
30 {
31  PfoVector sortedPfos;
32  for (const auto &mapEntry : pfoInfoMap) sortedPfos.push_back(mapEntry.first);
33  std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
34 
35  for (const Pfo *const pPfo : sortedPfos)
36  {
37  const PfoInfo *const pPfoInfo(pfoInfoMap.at(pPfo));
38 
39  if (pPfoInfo->IsNeutrinoVertexAssociated() || pPfoInfo->GetParentPfo())
40  {
41  assignedPfos.push_back(pPfoInfo->GetThisPfo());
42  }
43  else
44  {
45  unassignedPfos.push_back(pPfoInfo->GetThisPfo());
46  }
47  }
48 }
49 
50 //------------------------------------------------------------------------------------------------------------------------------------------
51 
53 {
54  const ParticleFlowObject *pNeutrinoPfo(nullptr);
55  PfoList candidateDaughterPfoList;
56 
57  try
58  {
59  this->GetNeutrinoPfo(pNeutrinoPfo);
60  this->GetCandidateDaughterPfoList(candidateDaughterPfoList);
61  }
62  catch (StatusCodeException &statusCodeException)
63  {
64  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
65  std::cout << "NeutrinoHierarchyAlgorithm: required input pfos unavailable." << std::endl;
66 
67  if (STATUS_CODE_NOT_FOUND != statusCodeException.GetStatusCode())
68  throw statusCodeException;
69 
70  return STATUS_CODE_SUCCESS;
71  }
72 
73  PfoInfoMap pfoInfoMap;
74 
75  try
76  {
77  if (!pNeutrinoPfo->GetVertexList().empty())
78  {
79  const Vertex *const pNeutrinoVertex(LArPfoHelper::GetVertex(pNeutrinoPfo));
80  this->GetInitialPfoInfoMap(candidateDaughterPfoList, pfoInfoMap);
81 
82  for (PfoRelationTool *const pPfoRelationTool : m_algorithmToolVector)
83  pPfoRelationTool->Run(this, pNeutrinoVertex, pfoInfoMap);
84  }
85 
86  this->ProcessPfoInfoMap(pNeutrinoPfo, candidateDaughterPfoList, pfoInfoMap);
87  }
88  catch (StatusCodeException &statusCodeException)
89  {
90  std::cout << "NeutrinoHierarchyAlgorithm: unable to process input neutrino pfo, " << statusCodeException.ToString() << std::endl;
91  }
92 
94  this->DisplayPfoInfoMap(pNeutrinoPfo, pfoInfoMap);
95 
96  for (auto &mapIter : pfoInfoMap)
97  delete mapIter.second;
98 
99  return STATUS_CODE_SUCCESS;
100 }
101 
102 //------------------------------------------------------------------------------------------------------------------------------------------
103 
104 void NeutrinoHierarchyAlgorithm::GetNeutrinoPfo(const ParticleFlowObject *&pNeutrinoPfo) const
105 {
106  const PfoList *pPfoList = nullptr;
107  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this, m_neutrinoPfoListName, pPfoList));
108 
109  if (!pPfoList || pPfoList->empty())
110  {
111  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
112  std::cout << "NeutrinoHierarchyAlgorithm: unable to find pfo list " << m_neutrinoPfoListName << std::endl;
113 
114  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
115  }
116 
117  // ATTN Enforces that only one pfo, of neutrino-type, be in the specified input list
118  pNeutrinoPfo = ((1 == pPfoList->size()) ? *(pPfoList->begin()) : nullptr);
119 
120  if (!pNeutrinoPfo || !LArPfoHelper::IsNeutrino(pNeutrinoPfo))
121  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
122 }
123 
124 //------------------------------------------------------------------------------------------------------------------------------------------
125 
126 void NeutrinoHierarchyAlgorithm::GetCandidateDaughterPfoList(PfoList &candidateDaughterPfoList) const
127 {
128  for (const std::string &daughterPfoListName : m_daughterPfoListNames)
129  {
130  const PfoList *pCandidatePfoList(nullptr);
131 
132  if (STATUS_CODE_SUCCESS == PandoraContentApi::GetList(*this, daughterPfoListName, pCandidatePfoList))
133  {
134  candidateDaughterPfoList.insert(candidateDaughterPfoList.end(), pCandidatePfoList->begin(), pCandidatePfoList->end());
135  }
136  else if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
137  {
138  std::cout << "NeutrinoHierarchyAlgorithm: unable to find pfo list " << daughterPfoListName << std::endl;
139  }
140  }
141 
142  if (candidateDaughterPfoList.empty())
143  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
144 }
145 
146 //------------------------------------------------------------------------------------------------------------------------------------------
147 
148 void NeutrinoHierarchyAlgorithm::GetInitialPfoInfoMap(const PfoList &pfoList, PfoInfoMap &pfoInfoMap) const
149 {
150  const float layerPitch(LArGeometryHelper::GetWireZPitch(this->GetPandora()));
151 
152  for (const ParticleFlowObject *const pPfo : pfoList)
153  {
154  PfoInfo *pPfoInfo(nullptr);
155 
156  try
157  {
158  pPfoInfo = new PfoInfo(pPfo, m_halfWindowLayers, layerPitch);
159  (void) pfoInfoMap.insert(PfoInfoMap::value_type(pPfo, pPfoInfo));
160  }
161  catch (StatusCodeException &)
162  {
163  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
164  std::cout << "NeutrinoHierarchyAlgorithm: Unable to calculate pfo information " << std::endl;
165 
166  delete pPfoInfo;
167  }
168  }
169 }
170 
171 //------------------------------------------------------------------------------------------------------------------------------------------
172 
173 void NeutrinoHierarchyAlgorithm::ProcessPfoInfoMap(const ParticleFlowObject *const pNeutrinoPfo, const PfoList &candidateDaughterPfoList,
174  const PfoInfoMap &pfoInfoMap) const
175 {
176  PfoVector candidateDaughterPfoVector(candidateDaughterPfoList.begin(), candidateDaughterPfoList.end());
177  std::sort(candidateDaughterPfoVector.begin(), candidateDaughterPfoVector.end(), LArPfoHelper::SortByNHits);
178 
179  // Add neutrino->primary pfo links
180  for (const ParticleFlowObject *const pDaughterPfo : candidateDaughterPfoVector)
181  {
182  PfoInfoMap::const_iterator iter = pfoInfoMap.find(pDaughterPfo);
183 
184  if ((pfoInfoMap.end() != iter) && (iter->second->IsNeutrinoVertexAssociated()))
185  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pNeutrinoPfo, pDaughterPfo));
186  }
187 
188  // Add primary pfo->daughter pfo links
189  PfoVector sortedPfos;
190  for (const auto &mapEntry : pfoInfoMap) sortedPfos.push_back(mapEntry.first);
191  std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
192 
193  for (const Pfo *const pPfo : sortedPfos)
194  {
195  const PfoInfo *const pPfoInfo(pfoInfoMap.at(pPfo));
196 
197  PfoVector daughterPfos(pPfoInfo->GetDaughterPfoList().begin(), pPfoInfo->GetDaughterPfoList().end());
198  std::sort(daughterPfos.begin(), daughterPfos.end(), LArPfoHelper::SortByNHits);
199 
200  for (const ParticleFlowObject *const pDaughterPfo : daughterPfos)
201  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pPfoInfo->GetThisPfo(), pDaughterPfo));
202  }
203 
204  // Deal with any remaining parent-less pfos
205  for (const ParticleFlowObject *const pRemainingPfo : candidateDaughterPfoVector)
206  {
207  if (!pRemainingPfo->GetParentPfoList().empty())
208  continue;
209 
210  // TODO Most appropriate decision - add as daughter of either i) nearest pfo, or ii) the neutrino (current approach)
211  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pNeutrinoPfo, pRemainingPfo));
212  }
213 }
214 
215 //------------------------------------------------------------------------------------------------------------------------------------------
216 
217 void NeutrinoHierarchyAlgorithm::DisplayPfoInfoMap(const ParticleFlowObject *const pNeutrinoPfo, const PfoInfoMap &pfoInfoMap) const
218 {
219  bool display(false);
220  PANDORA_MONITORING_API(SetEveDisplayParameters(this->GetPandora(), false, DETECTOR_VIEW_XZ, -1.f, -1.f, 1.f));
221  std::cout << "-Neutrino Pfo, nDaughters " << pNeutrinoPfo->GetDaughterPfoList().size() << ", nVertices " << pNeutrinoPfo->GetVertexList().size() << std::endl;
222 
223  PfoVector sortedPfos;
224  for (const auto &mapEntry : pfoInfoMap) sortedPfos.push_back(mapEntry.first);
225  std::sort(sortedPfos.begin(), sortedPfos.end(), LArPfoHelper::SortByNHits);
226 
227  for (const Pfo *const pPfo : sortedPfos)
228  {
229  const PfoInfo *const pPfoInfo(pfoInfoMap.at(pPfo));
230 
231  std::cout << "Pfo " << pPfoInfo->GetThisPfo() << ", vtxAssoc " << pPfoInfo->IsNeutrinoVertexAssociated()
232  << ", parent " << pPfoInfo->GetParentPfo() << ", nDaughters " << pPfoInfo->GetDaughterPfoList().size() << " (";
233 
234  for (const ParticleFlowObject *const pDaughterPfo : pPfoInfo->GetDaughterPfoList()) std::cout << pDaughterPfo << " ";
235  std::cout << ") " << std::endl;
236 
237  if (pPfoInfo->IsNeutrinoVertexAssociated())
238  {
239  display = true;
240  const PfoList tempPfoList(1, pPfoInfo->GetThisPfo());
241  PANDORA_MONITORING_API(VisualizeParticleFlowObjects(this->GetPandora(), &tempPfoList, "VertexPfo", RED, true, false));
242  }
243  }
244 
245  if (display)
246  {
247  PANDORA_MONITORING_API(VisualizeVertices(this->GetPandora(), &(pNeutrinoPfo->GetVertexList()), "NeutrinoVertex", ORANGE));
248  PANDORA_MONITORING_API(ViewEvent(this->GetPandora()));
249  display = false;
250  }
251 
252  for (const Pfo *const pPfo : sortedPfos)
253  {
254  const PfoInfo *const pPfoInfo(pfoInfoMap.at(pPfo));
255 
256  if (!pPfoInfo->GetDaughterPfoList().empty())
257  {
258  display = true;
259  const PfoList tempPfoList(1, pPfoInfo->GetThisPfo());
260  PANDORA_MONITORING_API(VisualizeParticleFlowObjects(this->GetPandora(), &tempPfoList, "ParentPfo", RED, true, false));
261  PANDORA_MONITORING_API(VisualizeParticleFlowObjects(this->GetPandora(), &(pPfoInfo->GetDaughterPfoList()), "DaughterPfos", BLUE, true, false));
262  PANDORA_MONITORING_API(ViewEvent(this->GetPandora()));
263  }
264  }
265 }
266 
267 //------------------------------------------------------------------------------------------------------------------------------------------
268 //------------------------------------------------------------------------------------------------------------------------------------------
269 
270 NeutrinoHierarchyAlgorithm::PfoInfo::PfoInfo(const pandora::ParticleFlowObject *const pPfo, const unsigned int halfWindowLayers,
271  const float layerPitch) :
272  m_pThisPfo(pPfo),
273  m_pCluster3D(nullptr),
274  m_pVertex3D(nullptr),
275  m_pSlidingFitResult3D(nullptr),
276  m_isNeutrinoVertexAssociated(false),
277  m_isInnerLayerAssociated(false),
278  m_pParentPfo(nullptr)
279 {
280  ClusterList clusterList3D;
281  LArPfoHelper::GetThreeDClusterList(pPfo, clusterList3D);
282 
283  if (1 != clusterList3D.size())
284  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
285 
286  m_pCluster3D = *(clusterList3D.begin());
287  m_pSlidingFitResult3D = new ThreeDSlidingFitResult(m_pCluster3D, halfWindowLayers, layerPitch);
288 
290  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
291 }
292 
293 //------------------------------------------------------------------------------------------------------------------------------------------
294 
296  m_pThisPfo(rhs.m_pThisPfo),
299  m_pSlidingFitResult3D(nullptr),
304 {
305  if (!rhs.m_pSlidingFitResult3D)
306  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
307 
310 }
311 
312 //------------------------------------------------------------------------------------------------------------------------------------------
313 
315 {
316  if (this != &rhs)
317  {
318  if (!rhs.m_pSlidingFitResult3D)
319  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
320 
321  m_pThisPfo = rhs.m_pThisPfo;
323  m_pVertex3D = rhs.m_pVertex3D;
328 
329  delete m_pSlidingFitResult3D;
332  }
333 
334  return *this;
335 }
336 
337 //------------------------------------------------------------------------------------------------------------------------------------------
338 
340 {
341  delete m_pSlidingFitResult3D;
342 }
343 
344 //------------------------------------------------------------------------------------------------------------------------------------------
345 
346 void NeutrinoHierarchyAlgorithm::PfoInfo::SetNeutrinoVertexAssociation(const bool isNeutrinoVertexAssociated)
347 {
348  m_isNeutrinoVertexAssociated = isNeutrinoVertexAssociated;
349 }
350 
351 //------------------------------------------------------------------------------------------------------------------------------------------
352 
354 {
355  m_isInnerLayerAssociated = isInnerLayerAssociated;
356 }
357 
358 //------------------------------------------------------------------------------------------------------------------------------------------
359 
360 void NeutrinoHierarchyAlgorithm::PfoInfo::SetParentPfo(const pandora::ParticleFlowObject *const pParentPfo)
361 {
362  if (m_pParentPfo)
363  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
364 
365  m_pParentPfo = pParentPfo;
366 }
367 
368 //------------------------------------------------------------------------------------------------------------------------------------------
369 
371 {
372  m_pParentPfo = nullptr;
373 }
374 
375 //------------------------------------------------------------------------------------------------------------------------------------------
376 
377 void NeutrinoHierarchyAlgorithm::PfoInfo::AddDaughterPfo(const pandora::ParticleFlowObject *const pDaughterPfo)
378 {
379  if (m_daughterPfoList.end() != std::find(m_daughterPfoList.begin(), m_daughterPfoList.end(), pDaughterPfo))
380  throw StatusCodeException(STATUS_CODE_ALREADY_PRESENT);
381 
382  m_daughterPfoList.push_back(pDaughterPfo);
383 }
384 
385 //------------------------------------------------------------------------------------------------------------------------------------------
386 
387 void NeutrinoHierarchyAlgorithm::PfoInfo::RemoveDaughterPfo(const pandora::ParticleFlowObject *const pDaughterPfo)
388 {
389  PfoList::iterator eraseIter = std::find(m_daughterPfoList.begin(), m_daughterPfoList.end(), pDaughterPfo);
390 
391  if (m_daughterPfoList.end() == eraseIter)
392  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
393 
394  m_daughterPfoList.erase(eraseIter);
395 }
396 
397 //------------------------------------------------------------------------------------------------------------------------------------------
398 //------------------------------------------------------------------------------------------------------------------------------------------
399 
400 StatusCode NeutrinoHierarchyAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
401 {
402  AlgorithmToolVector algorithmToolVector;
403  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ProcessAlgorithmToolList(*this, xmlHandle,
404  "PfoRelationTools", algorithmToolVector));
405 
406  for (AlgorithmToolVector::const_iterator iter = algorithmToolVector.begin(), iterEnd = algorithmToolVector.end(); iter != iterEnd; ++iter)
407  {
408  PfoRelationTool *const pPfoRelationTool(dynamic_cast<PfoRelationTool*>(*iter));
409 
410  if (!pPfoRelationTool)
411  return STATUS_CODE_INVALID_PARAMETER;
412 
413  m_algorithmToolVector.push_back(pPfoRelationTool);
414  }
415 
416  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle,
417  "NeutrinoPfoListName", m_neutrinoPfoListName));
418 
419  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadVectorOfValues(xmlHandle,
420  "DaughterPfoListNames", m_daughterPfoListNames));
421 
422  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
423  "SlidingFitHalfWindow", m_halfWindowLayers));
424 
425  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
426  "DisplayPfoInfoMap", m_displayPfoInfoMap));
427 
428  return STATUS_CODE_SUCCESS;
429 }
430 
431 } // namespace lar_content
void SetInnerLayerAssociation(const bool isInnerLayerAssociated)
Set the inner layer association flag.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
const pandora::ParticleFlowObject * GetThisPfo() const
Get the address of the pfo.
unsigned int GetLayerFitHalfWindow() const
Get the layer fit half window.
const pandora::Cluster * m_pCluster3D
The address of the three dimensional cluster.
PfoInfo & operator=(const PfoInfo &rhs)
Assignment operator.
static bool SortByNHits(const pandora::ParticleFlowObject *const pLhs, const pandora::ParticleFlowObject *const pRhs)
Sort pfos by number of constituent hits.
Header file for the pfo helper class.
bool m_isNeutrinoVertexAssociated
Whether the pfo is associated with the neutrino vertex.
std::unordered_map< const pandora::ParticleFlowObject *, PfoInfo * > PfoInfoMap
PfoRelationToolVector m_algorithmToolVector
The algorithm tool vector.
const pandora::ParticleFlowObject * m_pThisPfo
The address of the pfo.
intermediate_table::iterator iterator
bool m_displayPfoInfoMap
Whether to display the pfo info map (if monitoring is enabled)
void ProcessPfoInfoMap(const pandora::ParticleFlowObject *const pNeutrinoPfo, const pandora::PfoList &candidateDaughterPfoList, const PfoInfoMap &pfoInfoMap) const
Process the information in a pfo info map, creating pfo parent/daughter links.
void DisplayPfoInfoMap(const pandora::ParticleFlowObject *const pNeutrinoPfo, const PfoInfoMap &pfoInfoMap) const
Display the information in a pfo info map, visualising pfo parent/daughter links. ...
int GetMaxLayer() const
Get the maximum occupied layer in the sliding fit.
static const pandora::Vertex * GetVertex(const pandora::ParticleFlowObject *const pPfo)
Get the pfo vertex.
void SeparatePfos(const NeutrinoHierarchyAlgorithm::PfoInfoMap &pfoInfoMap, pandora::PfoVector &assignedPfos, pandora::PfoVector &unassignedPfos) const
Query the pfo info map and separate/extract pfos currently either acting as parents or associated wit...
unsigned int m_halfWindowLayers
The number of layers to use for half-window of sliding fit.
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
bool m_isInnerLayerAssociated
If associated, whether association to parent (vtx or pfo) is at sliding fit inner layer...
void RemoveDaughterPfo(const pandora::ParticleFlowObject *const pDaughterPfo)
Remove a daughter pfo.
TFile f
Definition: plotHisto.C:6
Header file for the geometry helper class.
ThreeDSlidingFitResult * m_pSlidingFitResult3D
The three dimensional sliding fit result.
intermediate_table::const_iterator const_iterator
pandora::PfoList m_daughterPfoList
The daughter pfo list.
void SetParentPfo(const pandora::ParticleFlowObject *const pParentPfo)
Set the parent pfo.
float GetLayerPitch() const
Get the layer pitch, units cm.
void GetNeutrinoPfo(const pandora::ParticleFlowObject *&pNeutrinoPfo) const
Get the address of the input neutrino pfo - enforces only one pfo present in input list; can return N...
static bool IsNeutrino(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a neutrino or (antineutrino)
int GetMinLayer() const
Get the minimum occupied layer in the sliding fit.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
PfoInfo(const pandora::ParticleFlowObject *const pPfo, const unsigned int halfWindowLayers, const float layerPitch)
Constructor.
Header file for the neutrino hierarchy algorithm class.
std::string m_neutrinoPfoListName
The neutrino pfo list name.
const pandora::Vertex * m_pVertex3D
The address of the three dimensional vertex.
pandora::StringVector m_daughterPfoListNames
The list of daughter pfo list names.
void SetNeutrinoVertexAssociation(const bool isNeutrinoVertexAssociated)
Set the neutrino vertex association flag.
const TwoDSlidingFitResult & GetFirstFitResult() const
Get the first sliding fit result for this cluster.
void AddDaughterPfo(const pandora::ParticleFlowObject *const pDaughterPfo)
Add a daughter pfo.
const pandora::ParticleFlowObject * m_pParentPfo
The address of the parent pfo.
void GetCandidateDaughterPfoList(pandora::PfoList &candidateDaughterPfoList) const
Get the list of candidate daughter pfos.
NeutrinoHierarchyAlgorithm::PfoInfo PfoInfo
void GetInitialPfoInfoMap(const pandora::PfoList &pfoList, PfoInfoMap &pfoInfoMap) const
Process a provided pfo list and populate an initial pfo info map.