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 &&
193 branchSplitDirectionJ.GetDotProduct(relativeDirection) < 0.f )
197 const float newBranchChisqI(this->
CalculateBranchChi2(pClusterI, branchSplitPositionI, relativeDirection));
198 const float newBranchChisqJ(this->
CalculateBranchChi2(pClusterJ, branchSplitPositionJ, relativeDirection * -1.
f));
199 branchChisqI = newBranchChisqI;
200 branchChisqJ = newBranchChisqJ;
202 catch (StatusCodeException &)
209 if (branchChisqI > branchChisqJ)
211 clusterExtensionList.push_back(
ClusterExtension(pClusterI, pClusterJ, replacementStartPositionJ, branchSplitPositionI, branchSplitDirectionI));
214 else if (branchChisqJ > branchChisqI)
216 clusterExtensionList.push_back(
ClusterExtension(pClusterJ, pClusterI, replacementStartPositionI, branchSplitPositionJ, branchSplitDirectionJ));
227 ClusterList branchList;
228 for (
const auto &mapEntry : branchMap) branchList.push_back(mapEntry.first);
231 ClusterList replacementList;
232 for (
const auto &mapEntry : replacementMap) replacementList.push_back(mapEntry.first);
237 const CartesianVector &branchVertex = thisSplit.GetBranchVertex();
238 const CartesianVector &replacementVertex = thisSplit.GetReplacementVertex();
240 const float distanceSquared((branchVertex - replacementVertex).GetMagnitudeSquared());
243 bool branchVeto(
false), replacementVeto(
false);
246 for (
const Cluster *
const pBranchCluster : branchList)
250 if (slidingFit.GetCluster() == thisSplit.GetReplacementCluster() || slidingFit.GetCluster() == thisSplit.GetBranchCluster())
253 const float minDistanceSquared((replacementVertex - slidingFit.GetGlobalMinLayerPosition()).GetMagnitudeSquared());
254 const float maxDistanceSquared((replacementVertex - slidingFit.GetGlobalMaxLayerPosition()).GetMagnitudeSquared());
256 if (
std::min(minDistanceSquared, maxDistanceSquared) <
std::max(distanceSquared, vetoDistanceSquared))
264 for (
const Cluster *
const pReplacementCluster : replacementList)
268 if (slidingFit.GetCluster() == thisSplit.GetReplacementCluster() || slidingFit.GetCluster() == thisSplit.GetBranchCluster())
271 const float minDistanceSquared((branchVertex - slidingFit.GetGlobalMinLayerPosition()).GetMagnitudeSquared());
272 const float maxDistanceSquared((branchVertex - slidingFit.GetGlobalMaxLayerPosition()).GetMagnitudeSquared());
274 if (
std::min(minDistanceSquared, maxDistanceSquared) <
std::max(distanceSquared, vetoDistanceSquared))
276 replacementVeto =
true;
281 if (branchVeto || replacementVeto)
284 outputList.push_back(thisSplit);
291 const CartesianVector &splitDirection)
const 293 CaloHitList principalCaloHitList, branchCaloHitList;
295 this->
SplitBranchCluster(pCluster, splitPosition, splitDirection, principalCaloHitList, branchCaloHitList);
297 float totalChi2(0.
f);
298 float totalHits(0.
f);
302 const CaloHit *
const pCaloHit = *iter;
304 const CartesianVector hitPosition(pCaloHit->GetPositionVector());
305 const CartesianVector projectedPosition(splitPosition + splitDirection * splitDirection.GetDotProduct(hitPosition - splitPosition));
307 totalChi2 += (hitPosition - projectedPosition).GetMagnitudeSquared();
312 return std::sqrt(totalChi2/totalHits);
314 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
320 const CartesianVector &splitDirection, CaloHitList &principalCaloHitList, CaloHitList &branchCaloHitList)
const 323 CaloHitList caloHitsToDistribute;
324 pCluster->GetOrderedCaloHitList().FillCaloHitList(caloHitsToDistribute);
326 for (
CaloHitList::const_iterator iter = caloHitsToDistribute.begin(), iterEnd = caloHitsToDistribute.end(); iter != iterEnd; ++iter)
328 const CaloHit *
const pCaloHit = *iter;
330 if (splitDirection.GetDotProduct((pCaloHit->GetPositionVector() - splitPosition)) > 0.f)
332 branchCaloHitList.push_back(pCaloHit);
336 principalCaloHitList.push_back(pCaloHit);
340 if (branchCaloHitList.empty())
341 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
349 bool foundSplit(
false);
357 const CartesianVector &branchSplitPosition = thisSplit.
GetBranchVertex();
366 if (branchResultMap.end() == iterBranch1 || branchResultMap.end() == iterBranch2 ||
367 replacementResultMap.end() == iterReplacement1 || replacementResultMap.end() == iterReplacement2)
370 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, this->
ReplaceBranch(pBranchCluster, pReplacementCluster,
371 branchSplitPosition, branchSplitDirection));
372 branchResultMap.erase(iterBranch1);
373 branchResultMap.erase(iterBranch2);
375 replacementResultMap.erase(iterReplacement1);
376 replacementResultMap.erase(iterReplacement2);
382 return STATUS_CODE_SUCCESS;
384 return STATUS_CODE_NOT_FOUND;
390 const CartesianVector &branchSplitPosition,
const CartesianVector &branchSplitDirection)
const 392 ClusterList clusterList;
393 clusterList.push_back(pBranchCluster);
394 clusterList.push_back(pReplacementCluster);
396 std::string clusterListToSaveName, clusterListToDeleteName;
397 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::InitializeFragmentation(*
this, clusterList, clusterListToDeleteName,
398 clusterListToSaveName));
401 PandoraContentApi::Cluster::Parameters principalParameters;
402 pReplacementCluster->GetOrderedCaloHitList().FillCaloHitList(principalParameters.m_caloHitList);
405 PandoraContentApi::Cluster::Parameters residualParameters;
406 this->
SplitBranchCluster(pBranchCluster, branchSplitPosition, branchSplitDirection, principalParameters.m_caloHitList, residualParameters.m_caloHitList);
408 const Cluster *pPrincipalCluster(NULL), *pResidualCluster(NULL);
409 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, principalParameters, pPrincipalCluster));
410 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::Cluster::Create(*
this, residualParameters, pResidualCluster));
411 PANDORA_RETURN_RESULT_IF(STATUS_CODE_SUCCESS, !=, PandoraContentApi::EndFragmentation(*
this, clusterListToSaveName, clusterListToDeleteName));
413 return STATUS_CODE_SUCCESS;
420 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
423 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
426 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
429 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
432 PANDORA_RETURN_RESULT_IF_AND_IF(STATUS_CODE_SUCCESS, STATUS_CODE_NOT_FOUND, !=, XmlHelper::ReadValue(xmlHandle,
435 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.
std::unordered_map< const pandora::Cluster *, TwoDSlidingFitResult > TwoDSlidingFitResultMap
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.
std::vector< art::Ptr< recob::Cluster > > ClusterVector
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.
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.