LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
DeltaRayIdentificationAlgorithm.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 DeltaRayIdentificationAlgorithm::DeltaRayIdentificationAlgorithm() :
22  m_distanceForMatching(3.f),
23  m_minParentLengthSquared(10.f * 10.f),
24  m_maxDaughterLengthSquared(175.f * 175.f)
25 {
26 }
27 
28 //------------------------------------------------------------------------------------------------------------------------------------------
29 
31 {
32  PfoVector parentPfos, daughterPfos;
33  this->GetPfos(m_parentPfoListName, parentPfos);
34  this->GetPfos(m_daughterPfoListName, daughterPfos);
35 
36  if (parentPfos.empty())
37  {
38  if (PandoraContentApi::GetSettings(*this)->ShouldDisplayAlgorithmInfo())
39  std::cout << "DeltaRayIdentificationAlgorithm: pfo list " << m_parentPfoListName << " unavailable." << std::endl;
40  return STATUS_CODE_SUCCESS;
41  }
42 
43  // Build parent/daughter associations (currently using length and proximity)
44  PfoAssociationMap pfoAssociationMap;
45  this->BuildAssociationMap(parentPfos, daughterPfos, pfoAssociationMap);
46 
47  // Create the parent/daughter links
48  PfoList newDaughterPfoList;
49  this->BuildParentDaughterLinks(pfoAssociationMap, newDaughterPfoList);
50 
51  if (!newDaughterPfoList.empty())
52  {
53  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SaveList(*this, m_parentPfoListName, m_daughterPfoListName,
54  newDaughterPfoList));
55  }
56 
57  return STATUS_CODE_SUCCESS;
58 }
59 
60 //------------------------------------------------------------------------------------------------------------------------------------------
61 
62 void DeltaRayIdentificationAlgorithm::GetPfos(const std::string &inputPfoListName, PfoVector &outputPfoVector) const
63 {
64  const PfoList *pPfoList = NULL;
65  PANDORA_THROW_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_INITIALIZED, !=, PandoraContentApi::GetList(*this,
66  inputPfoListName, pPfoList));
67 
68  if (NULL == pPfoList)
69  return;
70 
71  outputPfoVector.insert(outputPfoVector.end(), pPfoList->begin(), pPfoList->end());
72  std::sort(outputPfoVector.begin(), outputPfoVector.end(), LArPfoHelper::SortByNHits);
73 }
74 
75 //------------------------------------------------------------------------------------------------------------------------------------------
76 
77 void DeltaRayIdentificationAlgorithm::BuildAssociationMap(const PfoVector &parentPfos, const PfoVector &daughterPfos,
78  PfoAssociationMap &pfoAssociationMap) const
79 {
80  PfoSet parentPfoList, daughterPfoList;
81  parentPfoList.insert(parentPfos.begin(), parentPfos.end());
82  daughterPfoList.insert(daughterPfos.begin(), daughterPfos.end());
83 
84  PfoVector allPfos(parentPfos.begin(), parentPfos.end());
85  allPfos.insert(allPfos.end(), daughterPfos.begin(), daughterPfos.end());
86 
87  // Loop over possible daughter Pfos in primary list
88  for (PfoVector::const_iterator iter1 = parentPfos.begin(), iterEnd1 = parentPfos.end(); iter1 != iterEnd1; ++iter1)
89  {
90  const ParticleFlowObject *const pDaughterPfo = *iter1;
91 
92  // Find the best parent Pfo using combined list
93  const ParticleFlowObject *pBestParentPfo = NULL;
94  float bestDisplacement(std::numeric_limits<float>::max());
95 
96  for (PfoVector::const_iterator iter2 = allPfos.begin(), iterEnd2 = allPfos.end(); iter2 != iterEnd2; ++iter2)
97  {
98  const ParticleFlowObject *const pThisParentPfo = *iter2;
99  float thisDisplacement(std::numeric_limits<float>::max());
100 
101  if (pDaughterPfo == pThisParentPfo)
102  continue;
103 
104  if (!this->IsAssociated(pDaughterPfo, pThisParentPfo, thisDisplacement))
105  continue;
106 
107  if (thisDisplacement < bestDisplacement)
108  {
109  bestDisplacement = thisDisplacement;
110  pBestParentPfo = pThisParentPfo;
111  }
112  }
113 
114  if (!pBestParentPfo)
115  continue;
116 
117  // Case 1: candidate parent comes from primary list
118  if (pBestParentPfo->GetParentPfoList().empty())
119  {
120  // Check: parent shouldn't live in the secondary list
121  if (daughterPfoList.count(pBestParentPfo))
122  throw StatusCodeException(STATUS_CODE_FAILURE);
123 
124  pfoAssociationMap.insert(PfoAssociationMap::value_type(pDaughterPfo, pBestParentPfo));
125  }
126 
127  // Case 2: candidate parent comes from secondary list
128  else
129  {
130  // Check: parent shouldn't live in the primary list
131  if (parentPfoList.count(pBestParentPfo))
132  throw StatusCodeException(STATUS_CODE_FAILURE);
133 
134  // Check: there should only be one parent
135  if (pBestParentPfo->GetParentPfoList().size() != 1)
136  throw StatusCodeException(STATUS_CODE_FAILURE);
137 
138  // Check: get the new parent (and check there is no grand-parent)
139  PfoList::const_iterator pIter = pBestParentPfo->GetParentPfoList().begin();
140  const ParticleFlowObject *const pReplacementParentPfo = *pIter;
141  if (pReplacementParentPfo->GetParentPfoList().size() != 0)
142  throw StatusCodeException(STATUS_CODE_FAILURE);
143 
144  pfoAssociationMap.insert(PfoAssociationMap::value_type(pDaughterPfo, pReplacementParentPfo));
145  }
146  }
147 }
148 
149 //------------------------------------------------------------------------------------------------------------------------------------------
150 
151 bool DeltaRayIdentificationAlgorithm::IsAssociated(const ParticleFlowObject *const pDaughterPfo, const ParticleFlowObject *const pParentPfo,
152  float &displacement) const
153 {
154  displacement = std::numeric_limits<float>::max();
155 
156  if (pDaughterPfo == pParentPfo)
157  return false;
158 
159  const float daughterLengthSquared(LArPfoHelper::GetTwoDLengthSquared(pDaughterPfo));
160  const float parentLengthSquared(LArPfoHelper::GetTwoDLengthSquared(pParentPfo));
161 
162  if (daughterLengthSquared > m_maxDaughterLengthSquared || parentLengthSquared < m_minParentLengthSquared ||
163  daughterLengthSquared > 0.5 * parentLengthSquared)
164  return false;
165 
166  const float transitionLengthSquared(125.f);
167  const float displacementCut((daughterLengthSquared > transitionLengthSquared) ? m_distanceForMatching :
168  m_distanceForMatching * (2.f - daughterLengthSquared / transitionLengthSquared));
169 
170  try
171  {
172  displacement = this->GetTwoDSeparation(pDaughterPfo, pParentPfo);
173  }
174  catch(StatusCodeException &statusCodeException)
175  {
176  if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
177  throw statusCodeException;
178  }
179 
180  if (displacement > displacementCut)
181  return false;
182 
183  return true;
184 }
185 
186 //------------------------------------------------------------------------------------------------------------------------------------------
187 
188 float DeltaRayIdentificationAlgorithm::GetTwoDSeparation(const ParticleFlowObject *const pDaughterPfo, const ParticleFlowObject *const pParentPfo) const
189 {
190  CartesianPointVector vertexVectorU, vertexVectorV, vertexVectorW;
191  this->GetTwoDVertices(pDaughterPfo, TPC_VIEW_U, vertexVectorU);
192  this->GetTwoDVertices(pDaughterPfo, TPC_VIEW_V, vertexVectorV);
193  this->GetTwoDVertices(pDaughterPfo, TPC_VIEW_W, vertexVectorW);
194 
195  ClusterList clusterListU, clusterListV, clusterListW;
196  LArPfoHelper::GetClusters(pParentPfo, TPC_VIEW_U, clusterListU);
197  LArPfoHelper::GetClusters(pParentPfo, TPC_VIEW_V, clusterListV);
198  LArPfoHelper::GetClusters(pParentPfo, TPC_VIEW_W, clusterListW);
199 
200  float sumViews(0.f);
201  float sumDisplacementSquared(0.f);
202 
203  if (!vertexVectorU.empty())
204  {
205  const float thisDisplacement(this->GetClosestDistance(vertexVectorU, clusterListU));
206  sumDisplacementSquared += thisDisplacement * thisDisplacement;
207  sumViews += 1.f;
208  }
209 
210  if (!vertexVectorV.empty())
211  {
212  const float thisDisplacement(this->GetClosestDistance(vertexVectorV, clusterListV));
213  sumDisplacementSquared += thisDisplacement * thisDisplacement;
214  sumViews += 1.f;
215  }
216 
217  if (!vertexVectorW.empty())
218  {
219  const float thisDisplacement(this->GetClosestDistance(vertexVectorW, clusterListW));
220  sumDisplacementSquared += thisDisplacement * thisDisplacement;
221  sumViews += 1.f;
222  }
223 
224  if (sumViews < std::numeric_limits<float>::epsilon())
225  throw StatusCodeException(STATUS_CODE_FAILURE);
226 
227  return std::sqrt(sumDisplacementSquared / sumViews);
228 }
229 
230 //------------------------------------------------------------------------------------------------------------------------------------------
231 
232 void DeltaRayIdentificationAlgorithm::GetTwoDVertices(const ParticleFlowObject *const pPfo, const HitType &hitType, CartesianPointVector &vertexVector) const
233 {
234  ClusterList clusterList;
235  LArPfoHelper::GetClusters(pPfo, hitType, clusterList);
236 
237  for (ClusterList::const_iterator iter = clusterList.begin(), iterEnd = clusterList.end(); iter != iterEnd; ++iter)
238  {
239  const Cluster *const pCluster = *iter;
240 
241  CartesianVector firstCoordinate(0.f,0.f,0.f), secondCoordinate(0.f,0.f,0.f);
242  LArClusterHelper::GetExtremalCoordinates(pCluster, firstCoordinate, secondCoordinate);
243 
244  vertexVector.push_back(firstCoordinate);
245  vertexVector.push_back(secondCoordinate);
246  }
247 }
248 
249 //------------------------------------------------------------------------------------------------------------------------------------------
250 
251 float DeltaRayIdentificationAlgorithm::GetClosestDistance(const CartesianPointVector &vertexVector, const ClusterList &clusterList) const
252 {
253  if (vertexVector.empty() || clusterList.empty())
254  throw StatusCodeException(STATUS_CODE_NOT_FOUND);
255 
256  float bestDisplacement(std::numeric_limits<float>::max());
257 
258  for (CartesianPointVector::const_iterator iter1 = vertexVector.begin(), iterEnd1 = vertexVector.end(); iter1 != iterEnd1; ++iter1)
259  {
260  const CartesianVector &thisVertex = *iter1;
261 
262  for (ClusterList::const_iterator iter2 = clusterList.begin(), iterEnd2 = clusterList.end(); iter2 != iterEnd2; ++iter2)
263  {
264  const Cluster *const pCluster = *iter2;
265  const float thisDisplacement(LArClusterHelper::GetClosestDistance(thisVertex, pCluster));
266 
267  if (thisDisplacement < bestDisplacement)
268  bestDisplacement = thisDisplacement;
269  }
270  }
271 
272  return bestDisplacement;
273 }
274 
275 //------------------------------------------------------------------------------------------------------------------------------------------
276 
277 void DeltaRayIdentificationAlgorithm::BuildParentDaughterLinks(const PfoAssociationMap &pfoAssociationMap, PfoList &daughterPfoList) const
278 {
279  PfoList pfoList;
280  for (const auto &mapEntry : pfoAssociationMap) pfoList.push_back(mapEntry.first);
281  pfoList.sort(LArPfoHelper::SortByNHits);
282 
283  for (const ParticleFlowObject *const pDaughterPfo : pfoList)
284  {
285  const ParticleFlowObject *const pParentPfo(this->GetParent(pfoAssociationMap, pDaughterPfo));
286 
287  if (!pParentPfo)
288  throw StatusCodeException(STATUS_CODE_FAILURE);
289 
290  if (!LArPfoHelper::IsTrack(pParentPfo))
291  continue;
292 
293  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::SetPfoParentDaughterRelationship(*this, pParentPfo, pDaughterPfo));
294 
295  PandoraContentApi::ParticleFlowObject::Metadata metadata;
296  metadata.m_particleId = E_MINUS;
297  PANDORA_THROW_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::ParticleFlowObject::AlterMetadata(*this, pDaughterPfo, metadata));
298 
299  daughterPfoList.push_back(pDaughterPfo);
300  }
301 }
302 
303 //------------------------------------------------------------------------------------------------------------------------------------------
304 
305 const ParticleFlowObject *DeltaRayIdentificationAlgorithm::GetParent(const PfoAssociationMap &pfoAssociationMap,
306  const ParticleFlowObject *const pPfo) const
307 {
308  const ParticleFlowObject *pParentPfo = nullptr;
309  const ParticleFlowObject *pDaughterPfo = pPfo;
310 
311  while(1)
312  {
313  PfoAssociationMap::const_iterator iter = pfoAssociationMap.find(pDaughterPfo);
314  if (pfoAssociationMap.end() == iter)
315  break;
316 
317  pParentPfo = iter->second;
318  pDaughterPfo = pParentPfo;
319  }
320 
321  return pParentPfo;
322 }
323 
324 //------------------------------------------------------------------------------------------------------------------------------------------
325 
326 StatusCode DeltaRayIdentificationAlgorithm::ReadSettings(const TiXmlHandle xmlHandle)
327 {
328  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "ParentPfoListName", m_parentPfoListName));
329  PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, XmlHelper::ReadValue(xmlHandle, "DaughterPfoListName", m_daughterPfoListName));
330 
331  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
332  "DistanceForMatching", m_distanceForMatching));
333 
334  float minParentLength = std::sqrt(m_minParentLengthSquared);
335  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
336  "MinParentLength", minParentLength));
337  m_minParentLengthSquared = minParentLength * minParentLength;
338 
339  float maxDaughterLength = std::sqrt(m_maxDaughterLengthSquared);
340  PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
341  "MaxDaughterLength", maxDaughterLength));
342  m_maxDaughterLengthSquared = maxDaughterLength * maxDaughterLength;
343 
344  return STATUS_CODE_SUCCESS;
345 }
346 
347 } // namespace lar_content
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.
float m_distanceForMatching
Maximum allowed distance of delta ray from parent cosmic ray.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
static void GetClusters(const pandora::PfoList &pfoList, const pandora::HitType &hitType, pandora::ClusterList &clusterList)
Get a list of clusters of a particular hit type from a list of pfos.
void GetPfos(const std::string &inputPfoListName, pandora::PfoVector &outputPfoVector) const
Get the vector of Pfos, given the input list name.
const pandora::ParticleFlowObject * GetParent(const PfoAssociationMap &pfoAssociationMap, const pandora::ParticleFlowObject *const pPfo) const
For a given daughter, follow the parent/daughter links to find the overall parent.
float GetTwoDSeparation(const pandora::ParticleFlowObject *const pDaughterPfo, const pandora::ParticleFlowObject *const pParentPfo) const
Calculate 2D separation between two Pfos.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
std::string m_parentPfoListName
The parent pfo list name.
static float GetTwoDLengthSquared(const pandora::ParticleFlowObject *const pPfo)
Calculate length of Pfo using 2D clusters.
float m_maxDaughterLengthSquared
Maximum allowed length of daughter delta ray.
TFile f
Definition: plotHisto.C:6
std::string m_daughterPfoListName
The daughter pfo list name.
Int_t max
Definition: plot.C:27
intermediate_table::const_iterator const_iterator
Header file for the cluster helper class.
void GetTwoDVertices(const pandora::ParticleFlowObject *const pPfo, const pandora::HitType &hitType, pandora::CartesianPointVector &vertexVector) const
Calculate 2D separation between two Pfos.
bool IsAssociated(const pandora::ParticleFlowObject *const pDaughterPfo, const pandora::ParticleFlowObject *const pParentPfo, float &displacement) const
Determine if a given pair of Pfos have a parent/daughter association.
static void GetExtremalCoordinates(const pandora::ClusterList &clusterList, pandora::CartesianVector &innerCoordinate, pandora::CartesianVector &outerCoordinate)
Get positions of the two most distant calo hits in a list of cluster (ordered by Z) ...
void BuildParentDaughterLinks(const PfoAssociationMap &pfoAssociationMap, pandora::PfoList &outputPfoList) const
Build the parent/daughter links from the map of parent/daughter associations.
void BuildAssociationMap(const pandora::PfoVector &inputPfos, const pandora::PfoVector &outputPfos, PfoAssociationMap &pfoAssociationMap) const
Build parent/daughter associations between PFOs.
float m_minParentLengthSquared
Minimum allowed length of parent cosmic ray.
float GetClosestDistance(const pandora::CartesianPointVector &vertexVector, const pandora::ClusterList &clusterList) const
Calculate closest 2D separation between a set of vertices and a set of clusters.
std::unordered_map< const pandora::ParticleFlowObject *, const pandora::ParticleFlowObject * > PfoAssociationMap
Header file for the delta ray identification algorithm class.
static float GetClosestDistance(const pandora::ClusterList &clusterList1, const pandora::ClusterList &clusterList2)
Get closest distance between clusters in a pair of cluster lists.