Now impossible to throw exception if MC start/end momentum is zero - #286
Now impossible to throw exception if MC start/end momentum is zero#286imawby wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens LArMetrics validation tools against rare numerical failures (e.g., extremely small momentum magnitudes) by catching StatusCodeException around opening-angle and related calculations, preventing event processing from aborting.
Changes:
- Added
try/catch (StatusCodeException &)guards around severalGetOpeningAngle(...)computations in track and PFP validation. - Added exception protection for shower direction accuracy calculation in shower validation.
- Introduced sentinel fallbacks when exceptions occur (e.g.,
m_invalidAngle,m_invalidLargeFloat,m_invalidInt).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| larpandoracontent/LArMetrics/TrackValidationTool.cc | Wraps endpoint accuracy, direction accuracies, and orientation opening-angle computations with exception handling to avoid rare crashes. |
| larpandoracontent/LArMetrics/ShowerValidationTool.cc | Adds exception handling around shower direction opening-angle computation for robustness in edge numerical cases. |
| larpandoracontent/LArMetrics/PFPValidationTool.cc | Adds exception handling around signed vertex accuracy opening-angle sign computation to avoid rare failures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const CartesianVector trueDir(pMC->GetMomentum().GetUnitVector()); | ||
| showerTreeVars.m_recoShrDirAcc.push_back(trueDir.GetOpeningAngle(recoShrDir)); | ||
| float recoShrDirAcc(m_invalidLargeFloat); | ||
| try { recoShrDirAcc = trueDir.GetOpeningAngle(recoShrDir); } | ||
| catch (StatusCodeException &) { recoShrDirAcc = m_invalidLargeFloat; } | ||
| showerTreeVars.m_recoShrDirAcc.push_back(recoShrDirAcc); |
There was a problem hiding this comment.
As above, I think we want a check against sqrt(epsilon), rather than a try/catch block..
AndyChappell
left a comment
There was a problem hiding this comment.
Sorry, I thought I'd already submitted this one. I think here, the overall comment is that I think this should be handled conditionally, rather than exceptionally. We know the conditions under which an exception would be thrown going in, so given how heavy exception handling is, we should prefer to pre-empt it, rather than catch it.
| float vertexAcc(m_invalidLargeFloat); | ||
| try | ||
| { | ||
| const CartesianVector &trueVertex((pMCTarget->GetParticleId() == PHOTON) ? pMCTarget->GetEndpoint() : pMCTarget->GetVertex()); | ||
| vertexAcc = (pRecoVertex->GetPosition() - trueVertex).GetMagnitude(); | ||
| const float sign( | ||
| (vertexAcc < std::numeric_limits<float>::epsilon() || pMCTarget->GetMomentum().GetMagnitude() < std::numeric_limits<float>::epsilon()) ? 1.f | ||
| : (pRecoVertex->GetPosition() - trueVertex).GetOpeningAngle(pMCTarget->GetMomentum()) < (M_PI * 0.5) ? 1.f | ||
| : -1.f); | ||
| pfpTreeVars.m_vertexAcc.push_back(vertexAcc * sign); | ||
| : -1.f); | ||
| vertexAcc *= sign; | ||
| } | ||
| catch (StatusCodeException &) { vertexAcc = m_invalidLargeFloat; } | ||
|
|
||
| pfpTreeVars.m_vertexAcc.push_back(vertexAcc); |
There was a problem hiding this comment.
I don't think we should use try/catch blocks here, given we know the value that leads to an exception, if we're going to check a value, we should veto it here (the control flow is not really exceptional). I think I would prefer something like
const CartesianVector &trueVertex((pMCTarget->GetParticleId() == 22) ? pMCTarget->GetEndpoint() : pMCTarget->GetVertex());
const float vertexAcc((pRecoVertex->GetPosition() - trueVertex).GetMagnitude());
const float sqrtEpsilon(std::sqrt(std::numeric_limits<float>::epsilon()));
const float sign(
(vertexAcc < sqrtEpsilon || pMCTarget->GetMomentum().GetMagnitude() < sqrtEpsilon) ? 1.f
: (pRecoVertex->GetPosition() - trueVertex).GetOpeningAngle(pMCTarget->GetMomentum()) < (M_PI * 0.5) ? 1.f
: -1.f);
pfpTreeVars.m_vertexAcc.push_back(vertexAcc * sign);
I think the code here could do with some more tidying for clarity, but I think conceptually this is what we want.
| const CartesianVector trueDir(pMC->GetMomentum().GetUnitVector()); | ||
| showerTreeVars.m_recoShrDirAcc.push_back(trueDir.GetOpeningAngle(recoShrDir)); | ||
| float recoShrDirAcc(m_invalidLargeFloat); | ||
| try { recoShrDirAcc = trueDir.GetOpeningAngle(recoShrDir); } | ||
| catch (StatusCodeException &) { recoShrDirAcc = m_invalidLargeFloat; } | ||
| showerTreeVars.m_recoShrDirAcc.push_back(recoShrDirAcc); |
There was a problem hiding this comment.
As above, I think we want a check against sqrt(epsilon), rather than a try/catch block..
| : (recoEndpoint - trueEndpoint).GetOpeningAngle(pLArMC->GetEndDirection()) < (M_PI * 0.5) ? 1.f | ||
| : -1.f); | ||
| endpointAcc *= sign; | ||
| float endpointAcc(m_invalidLargeFloat); |
There was a problem hiding this comment.
And again throughout this file. I would provisionally revert to the original implementation, adjust to use the sqrt of epsilon, and ideally also try to tidy the code to make it a bit more readable.
Hello,
When running on 6K files, there was one event where the momentum magnitude was > epsilon, but the calculation of the opening angle failed because of a (momentum magnitude * momentum magnitude) denominator in which both momentum magnitudes were very small :'(
I've now protected all instances of this via try/catch blocks. It is very rare that the code flow should enter the catch block.
This should be the end of this issue.
Thanks!