9 #include "Pandora/AlgorithmHeaders.h" 21 TwoDSlidingFitSplittingAndSplicingAlgorithm::TwoDSlidingFitSplittingAndSplicingAlgorithm() :
22 m_shortHalfWindowLayers(10),
23 m_longHalfWindowLayers(20),
24 m_minClusterLength(7.5
f),
25 m_vetoDisplacement(1.5
f),
26 m_runCosmicMode(false)
34 const ClusterList *pClusterList = NULL;
35 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::GetCurrentList(*
this, pClusterList));
39 unsigned int nIterations(0);
41 while (++nIterations < 100)
63 this->
BuildClusterExtensionList(clusterVector, branchSlidingFitResultMap, replacementSlidingFitResultMap, intermediateList);
68 if (STATUS_CODE_SUCCESS != this->
RunSplitAndExtension(splitList, branchSlidingFitResultMap, replacementSlidingFitResultMap))
72 return STATUS_CODE_SUCCESS;
81 const Cluster *
const pCluster = *iter;
86 clusterVector.push_back(pCluster);
101 if (slidingFitResultMap.end() == slidingFitResultMap.find(*iter))
107 if (!slidingFitResultMap.insert(TwoDSlidingFitResultMap::value_type(*iter, slidingFitResult)).second)
108 throw StatusCodeException(STATUS_CODE_FAILURE);
110 catch (StatusCodeException &statusCodeException)
112 if (STATUS_CODE_FAILURE == statusCodeException.GetStatusCode())
113 throw statusCodeException;
128 const Cluster *
const pClusterI = *iterI;
132 const Cluster *
const pClusterJ = *iterJ;
134 if (pClusterI == pClusterJ)
144 if (branchSlidingFitResultMap.end() == iterBranchI || branchSlidingFitResultMap.end() == iterBranchJ ||
145 replacementSlidingFitResultMap.end() == iterReplacementI || replacementSlidingFitResultMap.end() == iterReplacementJ)
158 float branchChisqI(0.
f);
159 CartesianVector branchSplitPositionI(0.
f, 0.
f, 0.
f);
160 CartesianVector branchSplitDirectionI(0.
f, 0.
f, 0.
f);
161 CartesianVector replacementStartPositionJ(0.
f, 0.
f, 0.
f);
165 this->
FindBestSplitPosition(branchSlidingFitI, replacementSlidingFitJ, replacementStartPositionJ, branchSplitPositionI, branchSplitDirectionI);
166 branchChisqI = this->
CalculateBranchChi2(pClusterI, branchSplitPositionI, branchSplitDirectionI);
168 catch (StatusCodeException &)
173 float branchChisqJ(0.
f);
174 CartesianVector branchSplitPositionJ(0.
f, 0.
f, 0.
f);
175 CartesianVector branchSplitDirectionJ(0.
f, 0.
f, 0.
f);
176 CartesianVector replacementStartPositionI(0.
f, 0.
f, 0.
f);
180 this->
FindBestSplitPosition(branchSlidingFitJ, replacementSlidingFitI, replacementStartPositionI, branchSplitPositionJ, branchSplitDirectionJ);
181 branchChisqJ = this->
CalculateBranchChi2(pClusterJ, branchSplitPositionJ, branchSplitDirectionJ);
183 catch (StatusCodeException &)
188 if (branchChisqI > 0.
f && branchChisqJ > 0.
f)
190 const CartesianVector relativeDirection((branchSplitPositionJ - branchSplitPositionI).GetUnitVector());
192 if (branchSplitDirectionI.GetDotProduct(relativeDirection) > 0.f && branchSplitDirectionJ.GetDotProduct(relativeDirection) < 0.f)
196 const float newBranchChisqI(this->
CalculateBranchChi2(pClusterI, branchSplitPositionI, relativeDirection));
197 const float newBranchChisqJ(this->
CalculateBranchChi2(pClusterJ, branchSplitPositionJ, relativeDirection * -1.
f));
198 branchChisqI = newBranchChisqI;
199 branchChisqJ = newBranchChisqJ;
201 catch (StatusCodeException &)
208 if (branchChisqI > branchChisqJ)
210 clusterExtensionList.push_back(
211 ClusterExtension(pClusterI, pClusterJ, replacementStartPositionJ, branchSplitPositionI, branchSplitDirectionI));
214 else if (branchChisqJ > branchChisqI)
216 clusterExtensionList.push_back(
217 ClusterExtension(pClusterJ, pClusterI, replacementStartPositionI, branchSplitPositionJ, branchSplitDirectionJ));
228 ClusterList branchList;
229 for (
const auto &mapEntry : branchMap)
230 branchList.push_back(mapEntry.first);
233 ClusterList replacementList;
234 for (
const auto &mapEntry : replacementMap)
235 replacementList.push_back(mapEntry.first);
240 const CartesianVector &branchVertex = thisSplit.GetBranchVertex();
241 const CartesianVector &replacementVertex = thisSplit.GetReplacementVertex();
243 const float distanceSquared((branchVertex - replacementVertex).GetMagnitudeSquared());
246 bool branchVeto(
false), replacementVeto(
false);
249 for (
const Cluster *
const pBranchCluster : branchList)
253 if (slidingFit.GetCluster() == thisSplit.GetReplacementCluster() || slidingFit.GetCluster() == thisSplit.GetBranchCluster())
256 const float minDistanceSquared((replacementVertex - slidingFit.GetGlobalMinLayerPosition()).GetMagnitudeSquared());
257 const float maxDistanceSquared((replacementVertex - slidingFit.GetGlobalMaxLayerPosition()).GetMagnitudeSquared());
259 if (
std::min(minDistanceSquared, maxDistanceSquared) <
std::max(distanceSquared, vetoDistanceSquared))
267 for (
const Cluster *
const pReplacementCluster : replacementList)
271 if (slidingFit.GetCluster() == thisSplit.GetReplacementCluster() || slidingFit.GetCluster() == thisSplit.GetBranchCluster())
274 const float minDistanceSquared((branchVertex - slidingFit.GetGlobalMinLayerPosition()).GetMagnitudeSquared());
275 const float maxDistanceSquared((branchVertex - slidingFit.GetGlobalMaxLayerPosition()).GetMagnitudeSquared());
277 if (
std::min(minDistanceSquared, maxDistanceSquared) <
std::max(distanceSquared, vetoDistanceSquared))
279 replacementVeto =
true;
284 if (branchVeto || replacementVeto)
287 outputList.push_back(thisSplit);
294 const Cluster *
const pCluster,
const CartesianVector &splitPosition,
const CartesianVector &splitDirection)
const 296 CaloHitList principalCaloHitList, branchCaloHitList;
298 this->
SplitBranchCluster(pCluster, splitPosition, splitDirection, principalCaloHitList, branchCaloHitList);
300 float totalChi2(0.
f);
301 float totalHits(0.
f);
305 const CaloHit *
const pCaloHit = *iter;
307 const CartesianVector hitPosition(pCaloHit->GetPositionVector());
308 const CartesianVector projectedPosition(splitPosition + splitDirection * splitDirection.GetDotProduct(hitPosition - splitPosition));
310 totalChi2 += (hitPosition - projectedPosition).GetMagnitudeSquared();
315 return std::sqrt(totalChi2 / totalHits);
317 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
323 const CartesianVector &splitDirection, CaloHitList &principalCaloHitList, CaloHitList &branchCaloHitList)
const 326 CaloHitList caloHitsToDistribute;
327 pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitsToDistribute);
329 for (
CaloHitList::const_iterator iter = caloHitsToDistribute.begin(), iterEnd = caloHitsToDistribute.end(); iter != iterEnd; ++iter)
331 const CaloHit *
const pCaloHit = *iter;
333 if (splitDirection.GetDotProduct((pCaloHit->GetPositionVector() - splitPosition)) > 0.f)
335 branchCaloHitList.push_back(pCaloHit);
339 principalCaloHitList.push_back(pCaloHit);
343 if (branchCaloHitList.empty())
344 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
352 bool foundSplit(
false);
360 const CartesianVector &branchSplitPosition = thisSplit.
GetBranchVertex();
369 if (branchResultMap.end() == iterBranch1 || branchResultMap.end() == iterBranch2 ||
370 replacementResultMap.end() == iterReplacement1 || replacementResultMap.end() == iterReplacement2)
373 PANDORA_RETURN_RESULT_IF(
374 STATUS_CODE_SUCCESS, !=, this->
ReplaceBranch(pBranchCluster, pReplacementCluster, branchSplitPosition, branchSplitDirection));
375 branchResultMap.erase(iterBranch1);
376 branchResultMap.erase(iterBranch2);
378 replacementResultMap.erase(iterReplacement1);
379 replacementResultMap.erase(iterReplacement2);
385 return STATUS_CODE_SUCCESS;
387 return STATUS_CODE_NOT_FOUND;
393 const Cluster *
const pReplacementCluster,
const CartesianVector &branchSplitPosition,
const CartesianVector &branchSplitDirection)
const 395 ClusterList clusterList;
396 clusterList.push_back(pBranchCluster);
397 clusterList.push_back(pReplacementCluster);
399 std::string clusterListToSaveName, clusterListToDeleteName;
400 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=,
401 PandoraContentApi::InitializeFragmentation(*
this, clusterList, clusterListToDeleteName, clusterListToSaveName));
404 PandoraContentApi::Cluster::Parameters principalParameters;
405 pReplacementCluster->GetOrderedCaloHitList().FillCaloHitList(principalParameters.m_caloHitList);
408 PandoraContentApi::Cluster::Parameters residualParameters;
410 pBranchCluster, branchSplitPosition, branchSplitDirection, principalParameters.m_caloHitList, residualParameters.m_caloHitList);
412 const Cluster *pPrincipalCluster(NULL), *pResidualCluster(NULL);
413 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, principalParameters, pPrincipalCluster));
414 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, residualParameters, pResidualCluster));
415 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, clusterListToSaveName, clusterListToDeleteName));
417 return STATUS_CODE_SUCCESS;
424 PANDORA_RETURN_RESULT_IF_AND_IF(
425 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"ShortHalfWindow",
m_shortHalfWindowLayers));
427 PANDORA_RETURN_RESULT_IF_AND_IF(
428 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"LongHalfWindow",
m_longHalfWindowLayers));
430 PANDORA_RETURN_RESULT_IF_AND_IF(
431 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"MinClusterLength",
m_minClusterLength));
433 PANDORA_RETURN_RESULT_IF_AND_IF(
434 STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"VetoDisplacement",
m_vetoDisplacement));
436 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
"CosmicMode",
m_runCosmicMode));
438 return STATUS_CODE_SUCCESS;
static bool SortByNHits(const pandora::Cluster *const pLhs, const pandora::Cluster *const pRhs)
Sort clusters by number of hits, then layer span, then inner layer, then position, then pulse-height.
const pandora::Cluster * GetReplacementCluster() const
return the address of the replacement Cluster
virtual void FindBestSplitPosition(const TwoDSlidingFitResult &branchSlidingFit, const TwoDSlidingFitResult &replacementSlidingFit, pandora::CartesianVector &replacementStartPosition, pandora::CartesianVector &branchSplitPosition, pandora::CartesianVector &branchSplitDirection) const =0
Output the best split positions in branch and replacement clusters.
virtual pandora::StatusCode Run()
std::vector< ClusterExtension > ClusterExtensionList
unsigned int m_longHalfWindowLayers
void BuildSlidingFitResultMap(const pandora::ClusterVector &clusterVector, const unsigned int halfWindowLayers, TwoDSlidingFitResultMap &slidingFitResultMap) const
Build the map of sliding fit results.
void BuildClusterExtensionList(const pandora::ClusterVector &clusterVector, const TwoDSlidingFitResultMap &branchResultMap, const TwoDSlidingFitResultMap &replacementResultMap, ClusterExtensionList &clusterExtensionList) const
Build a list of candidate splits.
const pandora::Cluster * GetBranchCluster() const
return the address of the branch Cluster
const pandora::CartesianVector & GetBranchVertex() const
return the split position of the branch cluster
static float GetWireZPitch(const pandora::Pandora &pandora, const float maxWirePitchDiscrepancy=0.01)
Return the wire pitch.
const pandora::CartesianVector & GetBranchDirection() const
return the split direction of the branch cluster
Header file for the geometry helper class.
void GetListOfCleanClusters(const pandora::ClusterList *const pClusterList, pandora::ClusterVector &clusterVector) const
Populate cluster vector with subset of cluster list, containing clusters judged to be clean...
pandora::StatusCode RunSplitAndExtension(const ClusterExtensionList &splitList, TwoDSlidingFitResultMap &branchResultMap, TwoDSlidingFitResultMap &replacementResultMap) const
Run the machinary that performs the cluster splitting and extending.
virtual pandora::StatusCode ReadSettings(const pandora::TiXmlHandle xmlHandle)
pandora::StatusCode ReplaceBranch(const pandora::Cluster *const pBranchCluster, const pandora::Cluster *const pReplacementCluster, const pandora::CartesianVector &branchSplitPosition, const pandora::CartesianVector &branchSplitDirection) const
Remove a branch from a cluster and replace it with a second cluster.
static int max(int a, int b)
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Header file for the two dimensional sliding fit splitting and splicing algorithm class.
static float GetLengthSquared(const pandora::Cluster *const pCluster)
Get length squared of cluster.
void SplitBranchCluster(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection, pandora::CaloHitList &principalCaloHitList, pandora::CaloHitList &branchCaloHitList) const
Separate cluster into the branch hits to be split from the primary cluster.
float CalculateBranchChi2(const pandora::Cluster *const pCluster, const pandora::CartesianVector &splitPosition, const pandora::CartesianVector &splitDirection) const
Calculate RMS deviation of branch hits relative to the split direction.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
unsigned int m_shortHalfWindowLayers
void PruneClusterExtensionList(const ClusterExtensionList &inputList, const TwoDSlidingFitResultMap &branchResultMap, const TwoDSlidingFitResultMap &replacementResultMap, ClusterExtensionList &outputList) const
Finalize the list of candidate splits.
TwoDSlidingFitResult class.