9 #include "Pandora/AlgorithmHeaders.h" 24 StitchingCosmicRayMergingTool::StitchingCosmicRayMergingTool() :
25 m_useXcoordinate(false),
26 m_halfWindowLayers(30),
27 m_minLengthSquared(50.
f),
28 m_minCosRelativeAngle(0.966),
29 m_maxLongitudinalDisplacementX(15.
f),
30 m_maxTransverseDisplacement(5.
f),
31 m_relaxCosRelativeAngle(0.906),
32 m_relaxTransverseDisplacement(2.5
f)
40 if (PandoraContentApi::GetSettings(*pAlgorithm)->ShouldDisplayAlgorithmInfo())
41 std::cout <<
"----> Running Algorithm Tool: " << this->GetInstanceName() <<
", " << this->GetType() << std::endl;
43 if (this->GetPandora().GetGeometry()->GetLArTPCMap().size() < 2)
46 if (pfoToLArTPCMap.empty())
47 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
56 this->
BuildTPCMaps(primaryPfos, pfoToLArTPCMap, larTPCToPfoMap);
59 this->
CreatePfoMatches(larTPCToPfoMap, pointingClusterMap, pfoAssociationMatrix);
68 this->
OrderPfoMerges(pfoToLArTPCMap, pointingClusterMap, pfoSelectedMerges, pfoOrderedMerges);
70 this->
StitchPfos(pAlgorithm, pointingClusterMap, pfoOrderedMerges, pfoToLArTPCMap, stitchedPfosToX0Map);
77 for (
const ParticleFlowObject *
const pPfo : *pInputPfoList)
82 if (!pfoToLArTPCMap.count(pPfo))
85 outputPfoList.push_back(pPfo);
95 for (
const ParticleFlowObject *
const pPfo : inputPfoList)
101 if (pfoToLArTPCMap.end() == tpcIter)
102 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
104 const float slidingFitPitch(tpcIter->second->GetWirePitchW());
106 ClusterList clusterList;
109 if (1 != clusterList.size())
110 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
113 (void) pointingClusterMap.insert(ThreeDPointingClusterMap::value_type(pPfo,
LArPointingCluster(slidingFitResult)));
115 catch (
const StatusCodeException &) {}
123 for (
const ParticleFlowObject *
const pPfo : inputPfoList)
127 if (pfoToLArTPCMap.end() != iter)
128 larTPCToPfoMap[iter->second].push_back(pPfo);
137 LArTPCVector larTPCVector;
138 for (
const auto &mapEntry : larTPCToPfoMap) larTPCVector.push_back(mapEntry.first);
143 const LArTPC *
const pLArTPC1(*tpcIter1);
144 const PfoList &pfoList1(larTPCToPfoMap.at(pLArTPC1));
148 const LArTPC *
const pLArTPC2(*tpcIter2);
149 const PfoList &pfoList2(larTPCToPfoMap.at(pLArTPC2));
154 for (
const ParticleFlowObject *
const pPfo1 : pfoList1)
156 for (
const ParticleFlowObject *
const pPfo2 : pfoList2)
157 this->
CreatePfoMatches(*pLArTPC1, *pLArTPC2, pPfo1, pPfo2, pointingClusterMap, pfoAssociationMatrix);
166 const ParticleFlowObject *
const pPfo1,
const ParticleFlowObject *
const pPfo2,
178 if (pointingClusterMap.end() == iter1 || pointingClusterMap.end() == iter2)
195 catch (
const pandora::StatusCodeException &)
207 const float pX1(std::fabs(pointingVertex1.
GetDirection().GetX()));
208 const float pX2(std::fabs(pointingVertex2.
GetDirection().GetX()));
210 if (pX1 < std::numeric_limits<float>::epsilon() || pX2 < std::numeric_limits<float>::epsilon())
214 const float intersectX(0.5 * (pointingVertex1.
GetPosition().GetX() + pointingVertex2.
GetPosition().GetX()));
216 if (std::fabs(intersectX - boundaryCenterX) > maxLongitudinalDisplacementX)
220 float rT1(0.
f), rL1(0.
f), rT2(0.
f), rL2(0.
f);
235 catch (
const pandora::StatusCodeException &)
241 const float minL(-1.
f);
243 (1.
f - pX1 * pX1 > std::numeric_limits<float>::epsilon()) ? pX1 / std::sqrt(1.
f - pX1 * pX1) : minL);
245 (1.
f - pX2 * pX2 > std::numeric_limits<float>::epsilon()) ? pX2 / std::sqrt(1.
f - pX2 * pX2) : minL);
246 const float maxL1(maxLongitudinalDisplacementX / dXdL1);
247 const float maxL2(maxLongitudinalDisplacementX / dXdL2);
249 if (rL1 < minL || rL1 > maxL1 || rL2 < minL || rL2 > maxL2)
256 if (!minPass && !maxPass)
266 pfoAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pPfo2,
PfoAssociation(vertexType1, vertexType2, particleLength2)));
267 pfoAssociationMatrix[pPfo2].insert(PfoAssociationMap::value_type(pPfo1,
PfoAssociation(vertexType2, vertexType1, particleLength1)));
278 PfoVector pfoVector1;
279 for (
const auto &mapEntry : pfoAssociationMatrix) pfoVector1.push_back(mapEntry.first);
282 for (
const ParticleFlowObject *
const pPfo1 : pfoVector1)
286 const ParticleFlowObject *pBestPfoInner(
nullptr);
289 const ParticleFlowObject *pBestPfoOuter(
nullptr);
292 PfoVector pfoVector2;
293 for (
const auto &mapEntry : pfoAssociationMap) pfoVector2.push_back(mapEntry.first);
296 for (
const ParticleFlowObject *
const pPfo2 : pfoVector2)
298 const PfoAssociation &pfoAssociation(pfoAssociationMap.at(pPfo2));
303 if (pfoAssociation.GetFigureOfMerit() > bestAssociationInner.
GetFigureOfMerit())
305 bestAssociationInner = pfoAssociation;
306 pBestPfoInner = pPfo2;
313 if (pfoAssociation.GetFigureOfMerit() > bestAssociationOuter.
GetFigureOfMerit())
315 bestAssociationOuter = pfoAssociation;
316 pBestPfoOuter = pPfo2;
322 (void) bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoInner, bestAssociationInner));
325 (void) bestAssociationMatrix[pPfo1].insert(PfoAssociationMap::value_type(pBestPfoOuter, bestAssociationOuter));
330 PfoVector pfoVector3;
331 for (
const auto &mapEntry : bestAssociationMatrix) pfoVector3.push_back(mapEntry.first);
334 for (
const ParticleFlowObject *
const pParentPfo : pfoVector3)
336 const PfoAssociationMap &parentAssociationMap(bestAssociationMatrix.at(pParentPfo));
338 PfoVector pfoVector4;
339 for (
const auto &mapEntry : parentAssociationMap) pfoVector4.push_back(mapEntry.first);
342 for (
const ParticleFlowObject *
const pDaughterPfo : pfoVector4)
344 const PfoAssociation &parentToDaughterAssociation(parentAssociationMap.at(pDaughterPfo));
347 if (bestAssociationMatrix.end() == iter5)
353 if (daughterAssociationMap.end() == iter6)
358 if (parentToDaughterAssociation.GetParent() == daughterToParentAssociation.
GetDaughter() &&
359 parentToDaughterAssociation.GetDaughter() == daughterToParentAssociation.
GetParent())
361 pfoMatches[pParentPfo].push_back(pDaughterPfo);
373 PfoVector inputPfoVector;
374 for (
const auto &mapEntry : pfoMatches) inputPfoVector.push_back(mapEntry.first);
377 for (
const ParticleFlowObject *
const pInputPfo : inputPfoVector)
379 const PfoList &pfoList(pfoMatches.at(pInputPfo));
381 for (
const ParticleFlowObject *
const pSeedPfo : pfoList)
383 if (vetoSet.count(pSeedPfo))
389 vetoSet.insert(pSeedPfo);
390 PfoList &selectedPfoList(pfoMerges[pSeedPfo]);
391 selectedPfoList.push_back(pSeedPfo);
393 for (
const ParticleFlowObject *
const pAssociatedPfo : mergeList)
396 if (vetoSet.count(pAssociatedPfo) || (selectedPfoList.end() != std::find(selectedPfoList.begin(), selectedPfoList.end(), pAssociatedPfo)))
397 throw StatusCodeException(STATUS_CODE_FAILURE);
399 vetoSet.insert(pAssociatedPfo);
400 selectedPfoList.push_back(pAssociatedPfo);
409 const PfoMergeMap &pfoMergeMap,
const PfoSet &vetoSet, PfoList &associatedList)
const 411 if (vetoSet.count(pCurrentPfo))
416 if (pfoMergeMap.end() == iter1)
419 for (
PfoList::const_iterator iter2 = iter1->second.begin(), iterEnd2 = iter1->second.end(); iter2 != iterEnd2; ++iter2)
421 const ParticleFlowObject *
const pAssociatedPfo = *iter2;
423 if (pAssociatedPfo == pSeedPfo)
426 if (associatedList.end() != std::find(associatedList.begin(), associatedList.end(), pAssociatedPfo))
429 associatedList.push_back(pAssociatedPfo);
440 PfoVector inputPfoVector;
441 for (
const auto &mapEntry : inputPfoMerges) inputPfoVector.push_back(mapEntry.first);
444 for (
const ParticleFlowObject *
const pInputPfo : inputPfoVector)
446 const PfoList &pfoList(inputPfoMerges.at(pInputPfo));
448 float bestLength(0.
f);
449 const ParticleFlowObject *pVertexPfo =
nullptr;
453 const ParticleFlowObject *
const pPfo1(*iter1);
457 if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
458 throw StatusCodeException(STATUS_CODE_FAILURE);
460 const LArTPC *
const pLArTPC1(tpcIter1->second);
465 const ParticleFlowObject *
const pPfo2(*iter2);
469 if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
470 throw StatusCodeException(STATUS_CODE_FAILURE);
472 const LArTPC *
const pLArTPC2(tpcIter2->second);
475 if (pLArTPC1 == pLArTPC2)
480 if (thisLength < bestLength)
483 bestLength = thisLength;
487 pVertexPfo =
nullptr;
494 const float deltaY(farVertex1.GetPosition().GetY() - farVertex2.GetPosition().GetY());
496 if (std::fabs(deltaY) < std::numeric_limits<float>::epsilon())
497 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
499 pVertexPfo = ((deltaY > 0.f) ? pPfo1 : pPfo2);
501 catch (
const pandora::StatusCodeException &) {}
506 outputPfoMerges[pVertexPfo].insert(outputPfoMerges[pVertexPfo].
begin(), pfoList.begin(), pfoList.end());
515 PfoVector pfoVectorToEnlarge;
516 for (
const auto &mapEntry : pfoMerges) pfoVectorToEnlarge.push_back(mapEntry.first);
519 for (
const ParticleFlowObject *
const pPfoToEnlarge : pfoVectorToEnlarge)
521 const PfoList &pfoList(pfoMerges.at(pPfoToEnlarge));
524 for (
const ParticleFlowObject *
const pPfo : pfoList) pfoVector.push_back(pPfo);
533 this->
CalculateX0(pfoToLArTPCMap, pointingClusterMap, pfoVector, x0);
535 catch (
const pandora::StatusCodeException &)
540 for (
const ParticleFlowObject *
const pPfoToShift : pfoVector)
544 for (
const ParticleFlowObject *
const pPfoToDelete : pfoVector)
546 if (pPfoToEnlarge == pPfoToDelete)
549 pAlgorithm->
StitchPfos(pPfoToEnlarge, pPfoToDelete, pfoToLArTPCMap);
550 stitchedPfosToX0Map.insert(PfoToFloatMap::value_type(pPfoToEnlarge, x0));
558 const PfoVector &pfoVector,
float &x0)
const 560 float sumX(0.
f), sumN(0.
f);
564 const ParticleFlowObject *
const pPfo1(*iter1);
568 if (pfoToLArTPCMap.end() == tpcIter1 || pointingClusterMap.end() == pointingIter1)
569 throw StatusCodeException(STATUS_CODE_FAILURE);
571 const LArTPC *
const pLArTPC1(tpcIter1->second);
576 const ParticleFlowObject *
const pPfo2(*iter2);
580 if (pfoToLArTPCMap.end() == tpcIter2 || pointingClusterMap.end() == pointingIter2)
581 throw StatusCodeException(STATUS_CODE_FAILURE);
583 const LArTPC *
const pLArTPC2(tpcIter2->second);
595 pointingVertex1, pointingVertex2);
598 sumX += thisX0; sumN += 1.f;
600 catch (
const pandora::StatusCodeException &) {}
604 if ((sumN < std::numeric_limits<float>::epsilon()) || (std::fabs(sumX) < std::numeric_limits<float>::epsilon()))
605 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
615 m_daughter(daughter),
646 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
649 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
653 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
654 "MinPfoLength", minLength));
657 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
660 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
663 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
666 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
669 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
672 return STATUS_CODE_SUCCESS;
std::unordered_map< const pandora::ParticleFlowObject *, LArPointingCluster > ThreeDPointingClusterMap
void SelectPrimaryPfos(const pandora::PfoList *pInputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, pandora::PfoList &outputPfoList) const
Select primary Pfos from the input list of Pfos.
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.
static float CalculateX0(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC, const LArPointingCluster::Vertex &firstVertex, const LArPointingCluster::Vertex &secondVertex)
Calculate X0 for a pair of vertices.
pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
std::unordered_map< const pandora::ParticleFlowObject *, pandora::PfoList > PfoMergeMap
PfoAssociation(const VertexType parent, const VertexType daughter, const float fom)
Constructor.
void CollectAssociatedPfos(const pandora::ParticleFlowObject *const pSeedPfo, const pandora::ParticleFlowObject *const pCurrentPfo, const PfoMergeMap &pfoMerges, const pandora::PfoSet &vetoSet, pandora::PfoList &associatedList) const
Collect up associations between Pfos.
std::unordered_map< const pandora::LArTPC *, pandora::PfoList > LArTPCToPfoMap
static void GetImpactParametersInYZ(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices using yz-coordinates.
static void GetImpactParameters(const LArPointingCluster::Vertex &pointingVertex, const LArPointingCluster::Vertex &targetVertex, float &longitudinal, float &transverse)
Calculate impact parameters between a pair of pointing vertices.
LArPointingCluster class.
static bool IsTrack(const pandora::ParticleFlowObject *const pPfo)
Return track flag based on Pfo Particle ID.
std::unordered_map< const pandora::ParticleFlowObject *, float > PfoToFloatMap
float m_relaxCosRelativeAngle
void CreatePfoMatches(const LArTPCToPfoMap &larTPCToPfoMap, const ThreeDPointingClusterMap &pointingClusterMap, PfoAssociationMatrix &pfoAssociationMatrix) const
Create associations between Pfos using 3D pointing clusters.
void BuildTPCMaps(const pandora::PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, LArTPCToPfoMap &larTPCToPfoMap) const
Build a list of Pfos for each tpc.
VertexType
Vertex enumeration.
VertexType GetDaughter() const
Get daughter.
float m_relaxTransverseDisplacement
void OrderPfoMerges(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap, const PfoMergeMap &inputPfoMerges, PfoMergeMap &outputPfoMerges) const
Identify the vertex Pfo and then re-order the map of merges so that the vertex Pfo will be enlarged...
Header file for the geometry helper class.
float m_minCosRelativeAngle
Header file for the cluster helper class.
void CalculateX0(const PfoToLArTPCMap &pfoToLArTPCMap, const ThreeDPointingClusterMap &pointingClusterMap, const pandora::PfoVector &pfoVector, float &x0) const
Calculate x0 shift for a group of associated Pfos.
static bool CanTPCsBeStitched(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Whether particles from a given pair of tpcs can be stitched together.
const Vertex & GetOuterVertex() const
Get the outer vertex.
float m_maxTransverseDisplacement
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociation > PfoAssociationMap
static float GetTPCDisplacement(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Calculate distance between central positions of a pair of tpcs.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
static float GetTPCBoundaryCenterX(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Determine centre in X at the boundary between a pair of tpcs.
const Vertex & GetInnerVertex() const
Get the inner vertex.
void ShiftPfoHierarchy(const pandora::ParticleFlowObject *const pParentPfo, const PfoToLArTPCMap &pfoToLArTPCMap, const float x0) const
Shift a Pfo hierarchy by a specified x0 value.
void StitchPfos(const pandora::ParticleFlowObject *const pPfoToEnlarge, const pandora::ParticleFlowObject *const pPfoToDelete, PfoToLArTPCMap &pfoToLArTPCMap) const
Stitch together a pair of pfos.
static void GetThreeDClusterList(const pandora::ParticleFlowObject *const pPfo, pandora::ClusterList &clusterList)
Get the list of 3D clusters from an input pfo.
float GetLengthSquared() const
Get length squared of pointing cluster.
static float GetTPCBoundaryWidthX(const pandora::LArTPC &firstTPC, const pandora::LArTPC &secondTPC)
Determine width in X at the boundary between a pair of tpcs.
void StitchPfos(const MasterAlgorithm *const pAlgorithm, const ThreeDPointingClusterMap &pointingClusterMap, const PfoMergeMap &pfoMerges, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map) const
Apply X0 corrections, and then stitch together Pfos.
const pandora::CartesianVector & GetDirection() const
Get the vertex direction.
void BuildPointingClusterMaps(const pandora::PfoList &inputPfoList, const PfoToLArTPCMap &pfoToLArTPCMap, ThreeDPointingClusterMap &pointingClusterMap) const
Build a 3D pointing cluster for each Pfo.
Header file for the helper class for multiple drift volumes.
float m_maxLongitudinalDisplacementX
void SelectPfoMatches(const PfoAssociationMatrix &pfoAssociationMatrix, PfoMergeMap &pfoSelectedMatches) const
Select the best associations between Pfos; create a mapping between associated Pfos, handling any ambiguities.
static bool IsFinalState(const pandora::ParticleFlowObject *const pPfo)
Whether a pfo is a primary parent particle.
ThreeDSlidingFitResult class.
VertexType GetParent() const
Get parent.
std::unordered_map< const pandora::ParticleFlowObject *, const pandora::LArTPC * > PfoToLArTPCMap
void Run(const MasterAlgorithm *const pAlgorithm, const pandora::PfoList *const pMultiPfoList, PfoToLArTPCMap &pfoToLArTPCMap, PfoToFloatMap &stitchedPfosToX0Map)
Run the algorithm tool.
static bool SortTPCs(const pandora::LArTPC *const pLhs, const pandora::LArTPC *const pRhs)
Sort tpcs by central positions.
bool IsInnerVertex() const
Is this the inner vertex.
float GetFigureOfMerit() const
Get figure of merit.
void SelectPfoMerges(const PfoMergeMap &pfoMatches, PfoMergeMap &pfoMerges) const
Create an initial map of Pfo merges to be made.
std::unordered_map< const pandora::ParticleFlowObject *, PfoAssociationMap > PfoAssociationMatrix
static void GetClosestVertices(const pandora::LArTPC &larTPC1, const pandora::LArTPC &larTPC2, const LArPointingCluster &pointingCluster1, const LArPointingCluster &pointingCluster2, LArPointingCluster::Vertex &closestVertex1, LArPointingCluster::Vertex &closestVertex2)
Given a pair of pointing clusters, find the pair of vertices with smallest yz-separation.
const pandora::CartesianVector & GetPosition() const
Get the vertex position.