From c82a101bc17c9baf3d6413288b10d73716660829 Mon Sep 17 00:00:00 2001
From: Scott Snyder <scott.snyder@cern.ch>
Date: Wed, 8 May 2024 09:43:39 +0200
Subject: [PATCH] MuonReadoutGeometryR4: Speed up handling of tube transforms.

MuonReadoutGeometryR4: Speed up handling of tube transforms.

Calling toTubeFrame is expensive, since it needs to walk over all children
until it gets to the desired value.  Hence, calling toTubeFrame from within
a loop over tubes is an N^2 operation.  Further, MdtReadoutElement::initElement()
was calling toTubeFrame multiple times for each tube.
This is especially painful in a debug build, where Eigen matrix operations
are very slow.

Speed up by using GeoVolumeCursor to change from the nested O(N^2) iteration
to a single O(N) iteration, and only evaluate the transform once per tube.

Also fix a logic error the prevented the layer-to-layer pitch test from
executing.
---
 .../MuonReadoutGeometryR4/MdtTubeLayer.h          |  5 ++++-
 .../src/MdtReadoutElement.cxx                     | 15 +++++++++++----
 .../MuonReadoutGeometryR4/src/MdtTubeLayer.cxx    |  3 +++
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtTubeLayer.h b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtTubeLayer.h
index b12665bd3515..d3b6f2948796 100644
--- a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtTubeLayer.h
+++ b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/MuonReadoutGeometryR4/MdtTubeLayer.h
@@ -7,6 +7,7 @@
 #include <MuonReadoutGeometryR4/MuonDetectorDefs.h>
 #include <GeoModelKernel/GeoVPhysVol.h>
 #include <GeoModelKernel/GeoTransform.h>
+#include <GeoModelKernel/GeoVolumeCursor.h>
 #include <GeoModelUtilities/TransientConstSharedPtr.h>
 
 #include <set>
@@ -40,6 +41,8 @@ namespace MuonGMR4{
         unsigned int nTubes() const;
         ///@brief: Returns the transformation from the layer to the muon station
         const Amg::Transform3D& layerTransform() const;
+        ///@brief Return a cursor object over the tubes in the layer.
+        GeoVolumeCursor tubeCursor() const;
         ///@brief Returns the transformation of the tube to the muon station
         ///       Index counting [0 - nTubes()-1]
         const Amg::Transform3D tubeTransform(const unsigned int tube) const;
@@ -55,4 +58,4 @@ namespace MuonGMR4{
     };
 
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtReadoutElement.cxx b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtReadoutElement.cxx
index 9fa10513a9b8..a8d172e2f1ed 100644
--- a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtReadoutElement.cxx
+++ b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtReadoutElement.cxx
@@ -70,7 +70,11 @@ StatusCode MdtReadoutElement::initElement() {
 #endif
     /// Cache the transformations to the tube layers
     std::optional<Amg::Vector3D> prevTubePos{std::nullopt};
-    for (unsigned int tube = 1; tube <= numTubesInLay(); ++ tube) {
+    MdtTubeLayer& layer = *m_pars.tubeLayers[lay-1];
+    GeoVolumeCursor tubeCursor = layer.tubeCursor();
+    GeoTrf::Transform3D layerTransform = layer.layerTransform();
+    for (unsigned int tube = 1; tube <= numTubesInLay(); ++ tube, tubeCursor.next()) {
+      assert (!tubeCursor.atEnd());
       const IdentifierHash idHash = measurementHash(lay,tube);
       if (m_pars.removedTubes.count(idHash)) {
          prevTubePos = std::nullopt;
@@ -81,15 +85,16 @@ StatusCode MdtReadoutElement::initElement() {
       ATH_CHECK(strawSurfaceFactory(idHash, m_pars.tubeBounds->make_bounds(innerTubeRadius(), 0.5*tubeLength(idHash))));
 #endif
       ///Ensure that all linear transformations are rotations
-      const AmgSymMatrix(3) tubeRot = toTubeFrame(idHash).linear();
+      GeoTrf::Transform3D tubeFrame = layerTransform*tubeCursor.getDefTransform();
+      const AmgSymMatrix(3) tubeRot = tubeFrame.linear();
       if (std::abs(tubeRot.determinant()- 1.) > std::numeric_limits<float>::epsilon()){
          ATH_MSG_FATAL(__FILE__<<":"<<__LINE__<<" Transformation matrix is not a pure rotation for "<<
                        idHelperSvc()->toStringDetEl(identify())<<" in layer: "<<lay<<", tube: "<<tube
-                       <<Amg::toString(toTubeFrame(idHash)));
+                       <<Amg::toString(tubeFrame));
          return StatusCode::FAILURE;
       }
       /// Ensure that all tubes have the same pitch
-      const Amg::Vector3D tubePos = toTubeFrame(idHash).translation();
+      const Amg::Vector3D tubePos = tubeFrame.translation();
       
       constexpr double pitchTolerance = 20. * Gaudi::Units::micrometer;
       if (prevTubePos) {
@@ -112,6 +117,8 @@ StatusCode MdtReadoutElement::initElement() {
                           <<dR<<" tube position: "<<Amg::toString(tubePos,2)
                           <<" previous:"<<Amg::toString((*prevLayPos), 2));
          }
+      }
+      if (tube == 1) {
          prevLayPos = std::make_optional<Amg::Vector3D>(tubePos);
       }
       prevTubePos = std::make_optional<Amg::Vector3D>(tubePos);
diff --git a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtTubeLayer.cxx b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtTubeLayer.cxx
index 1b7f205314db..a0daaef44f2d 100644
--- a/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtTubeLayer.cxx
+++ b/MuonSpectrometer/MuonPhaseII/MuonDetDescr/MuonReadoutGeometryR4/src/MdtTubeLayer.cxx
@@ -56,6 +56,9 @@ const Amg::Transform3D MdtTubeLayer::tubeTransform(const unsigned int tube) cons
     m_layerNode->exec(&volAcc);
     return layerTransform() * volAcc.getDefTransform();
 }
+GeoVolumeCursor MdtTubeLayer::tubeCursor() const {
+  return GeoVolumeCursor(m_layerNode);
+}
 const Amg::Vector3D MdtTubeLayer::tubePosInLayer(const unsigned int tube) const {
     return  layerTransform().inverse() * tubeTransform(tube).translation();
 }
-- 
GitLab