diff --git a/Detectors/Base/include/DetectorsBase/O2Tessellated.h b/Detectors/Base/include/DetectorsBase/O2Tessellated.h index 0a1cee8b3e01f..7a1a3945c80d8 100644 --- a/Detectors/Base/include/DetectorsBase/O2Tessellated.h +++ b/Detectors/Base/include/DetectorsBase/O2Tessellated.h @@ -133,6 +133,14 @@ class O2Tessellated : public TGeoBBox template Double_t SafetyKernel(const Double_t* point, bool in, int* closest_facet_id = nullptr) const; + // cached values for safety + mutable float mLast_x; + mutable float mLast_y; + mutable float mLast_z; + mutable float mCachedSafety; + mutable size_t cached_counter = 0; + mutable size_t call_counter = 0; + ClassDefOverride(O2Tessellated, 1) // tessellated shape class }; diff --git a/Detectors/Base/src/O2Tessellated.cxx b/Detectors/Base/src/O2Tessellated.cxx index 256a70e5a697a..5c52625841868 100644 --- a/Detectors/Base/src/O2Tessellated.cxx +++ b/Detectors/Base/src/O2Tessellated.cxx @@ -1349,8 +1349,30 @@ Double_t O2Tessellated::Safety(const Double_t* point, Bool_t in) const // we could use some caching here (in future) since queries to the solid will likely // be made with some locality + if (in) { + call_counter++; + // distance to last known evaluation + const auto xd = float(point[0]) - mLast_x; + const auto yd = float(point[1]) - mLast_y; + const auto zd = float(point[2]) - mLast_z; + const auto d2 = xd * xd + yd * yd + zd * zd; + + if (d2 < mCachedSafety * mCachedSafety) { + // we moved less than known safety + cached_counter++; + return mCachedSafety - std::sqrt(d2); + } + } + // fall-back to precise safety kernel - return SafetyKernel(point, in); + const auto safety = SafetyKernel(point, in); + if (in) { + mLast_x = point[0]; + mLast_y = point[1]; + mLast_z = point[2]; + mCachedSafety = safety; + } + return safety; } //////////////////////////////////////////////////////////////////////////////// @@ -1506,4 +1528,4 @@ void O2Tessellated::CalculateNormals() } } -// NOLINTEND \ No newline at end of file +// NOLINTEND