From a1f2ed50625817bcb0709bb97e9373375a2d1593 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Fri, 7 Oct 2016 13:13:34 +0200
Subject: [PATCH 01/68] Updated FTMeasurement and FTHitExpectation to new FT
 geometry

---
 Tr/TrackFitEvent/src/FTMeasurement.cpp |  18 +--
 Tr/TrackFitEvent/xml/FTMeasurement.xml |   4 +-
 Tr/TrackTools/src/FTHitExpectation.cpp | 198 ++++++++-----------------
 Tr/TrackTools/src/FTHitExpectation.h   |  24 +--
 4 files changed, 76 insertions(+), 168 deletions(-)

diff --git a/Tr/TrackFitEvent/src/FTMeasurement.cpp b/Tr/TrackFitEvent/src/FTMeasurement.cpp
index d18b805574..139b861bff 100644
--- a/Tr/TrackFitEvent/src/FTMeasurement.cpp
+++ b/Tr/TrackFitEvent/src/FTMeasurement.cpp
@@ -5,7 +5,7 @@
 
 // from Event
 #include "Event/FTCluster.h"
-#include "Kernel/LineTraj.h"
+
 // local
 #include "Event/FTMeasurement.h"
 
@@ -18,17 +18,13 @@ using namespace LHCb;
 //-----------------------------------------------------------------------------
 void FTMeasurement::init( const DeFTDetector& geom ) {
 
-  const DeFTFibreMat* ftMat = geom.findFibreMat( m_cluster.channelID() );
-  m_detectorElement = ftMat;
-  DetectorSegment mySeg = ftMat->createDetSegment( m_cluster.channelID(), m_cluster.fraction() );
-  Gaudi::XYZPoint begPoint( mySeg.x( mySeg.yMin() ), mySeg.yMin(), mySeg.z( mySeg.yMin() ) );
-  Gaudi::XYZPoint endPoint( mySeg.x( mySeg.yMax() ), mySeg.yMax(), mySeg.z( mySeg.yMax() ) );
-
+  const DeFTModule* ftModule = geom.findModule( m_cluster.channelID() );
+  m_detectorElement = ftModule;
   m_size = m_cluster.size();
-  m_errMeasure = 0.050 + .030 * m_size;
-  m_trajectory.reset( new LHCb::LineTraj( begPoint, endPoint ) );
-  m_z = ftMat->layerCenterZ();
-  m_measure = mySeg.x( 0. );
+  m_errMeasure = 0.080; // + .030 * m_size;
+  m_trajectory = ftModule->trajectory(m_cluster.channelID(), m_cluster.fraction());
+  m_z = ftModule->globalZ();
+  m_measure = 0. ; // JvT: I believe this is purely historical. Should remove it?
 
 }
 
diff --git a/Tr/TrackFitEvent/xml/FTMeasurement.xml b/Tr/TrackFitEvent/xml/FTMeasurement.xml
index 35da749802..fdf1ab42bd 100644
--- a/Tr/TrackFitEvent/xml/FTMeasurement.xml
+++ b/Tr/TrackFitEvent/xml/FTMeasurement.xml
@@ -44,7 +44,7 @@
         </code>
       </method>
 
-      <method
+      <!--method
         type  = 'double'
         name  = 'charge'
         desc  = 'Retrieve the cluster charge'
@@ -52,7 +52,7 @@
         <code>
           return m_cluster.charge();
         </code>
-      </method>
+      </method-->
 
 
       <constructor
diff --git a/Tr/TrackTools/src/FTHitExpectation.cpp b/Tr/TrackTools/src/FTHitExpectation.cpp
index 30bf0692ae..adc48dd349 100644
--- a/Tr/TrackTools/src/FTHitExpectation.cpp
+++ b/Tr/TrackTools/src/FTHitExpectation.cpp
@@ -5,18 +5,13 @@
 #include "Event/Track.h"
 #include "Event/State.h"
 
-//#include "Kernel/ISTChannelIDSelector.h"
-
 // Tsa
 #include "TsaKernel/Line.h"
 #include "TsaKernel/Parabola.h"
 #include "TsaKernel/Line3D.h"
-//#include "TsaKernel/IITExpectedHits.h"
 
 #include "LHCbMath/GeomFun.h"
 #include "FTDet/DeFTDetector.h"
-#include "FTDet/DeFTLayer.h"
-#include "FTDet/DeFTFibreMat.h"
 
 // local
 #include "FTHitExpectation.h"
@@ -40,15 +35,9 @@ FTHitExpectation::FTHitExpectation(const std::string& type,
 				   const IInterface* parent
 				   ):
 THitExpectation(type, name, parent),
-  m_ftDet( NULL ),
-  m_layers(),
-  m_fibremats()
-  //  m_selector(NULL)
+  m_ftDet( NULL )
 {
   // constructor
-  //declareProperty( "SelectorType", m_selectorType = "STSelectChannelIDByElement" );
-  //declareProperty( "SelectorName", m_selectorName = "ALL" );
-  //declareProperty( "allStrips", m_allStrips = false);
 }
 
 //=============================================================================
@@ -63,30 +52,14 @@ FTHitExpectation::~FTHitExpectation(){
 //=============================================================================
 StatusCode FTHitExpectation::initialize()
 {
-
   StatusCode sc = THitExpectation::initialize();
-  if (sc.isFailure()){
-    return Error("Failed to initialize", sc);
-  }
-
-  //m_expectedITHits = tool<Tf::Tsa::IITExpectedHits>("Tf::Tsa::ITExpectedHits");
+  if (sc.isFailure()) return Error("Failed to initialize", sc);
 
-  // need to know the z of T stations....
+  // Get all layers (need to know the z-plane of each layer)
   m_ftDet = getDet<DeFTDetector>(DeFTDetectorLocation::Default);
-  if ( m_ftDet -> version() < 20 ){
-    return Error("FTDetector version not implemented (different than v2 or v5)",StatusCode::FAILURE);
-  }
-
-  m_layers    = m_ftDet -> layers();
-  m_fibremats = m_ftDet -> fibremats();
+  if ( m_ftDet -> version() < 60 )
+    return Error("This version requires FTDet v6.0 or higher", StatusCode::FAILURE);
 
-  /*
-  // (selector
-  if (m_selectorName != "ALL"){
-    info() << "Selector name " << m_selectorName << endmsg;
-    m_selector  = tool< ISTChannelIDSelector >( m_selectorType,m_selectorName );
-  }
-  */
   return StatusCode::SUCCESS;
 }
 
@@ -96,135 +69,94 @@ IHitExpectation::Info FTHitExpectation::expectation(const LHCb::Track& aTrack) c
   IHitExpectation::Info info;
   info.likelihood = 0.0;
   info.nFound = 0;
-  info.nExpected = 0;;
-
+  info.nExpected = 0;
 
   const auto& ids = aTrack.lhcbIDs();
   std::vector<LHCb::LHCbID> ftHits; ftHits.reserve(ids.size());
   std::copy_if( ids.begin(), ids.end(), std::back_inserter(ftHits),
                 [](const LHCb::LHCbID& id) { return id.isFT(); } );
 
-  for ( auto iterL = m_layers.begin(); iterL != m_layers.end() ; ++iterL )
-    {
-      LHCb::FTChannelID elemID( (unsigned int)std::distance( m_layers.begin(), iterL ), 0u, 0u, 0u, 0u );
-      double layerZ = ((*iterL)->geometry()->toGlobal( Gaudi::XYZPoint(0. ,0., 0.) )).z();
-
-      Tf::Tsa::Line     line    = yLine    ( aTrack, layerZ );
-      Tf::Tsa::Parabola aParab  = xParabola( aTrack, layerZ );
-      Tf::Tsa::Line tanLine     = aParab.tangent( layerZ );
-      Tf::Tsa::Line3D aLine3D   = Tf::Tsa::createLine3D( tanLine, line, layerZ );
-      std::vector<std::pair<LHCb::FTChannelID, double> > vectFTPairs;
-
-      collectHits( aLine3D, elemID, vectFTPairs );
-
-      int old = -1;
-      for ( const auto& p : vectFTPairs )
-	{
-	  if ( int(p.second) != old) {
-	    old = int(p.second);
-	    if ( p.first ) {
-	      ++(info.nExpected);
-	      auto itIter = std::find( ftHits.begin(), ftHits.end(), p.first);
-	      if (itIter != ftHits.end() ) ++info.nFound;
-	    }
-	  }
-	}  // pairs
-    }//layers
-  return info;
-}
+  // Loop over all layers
+  for( auto station : m_ftDet->stations() ) {
+    for( auto layer : station->layers() ) {
 
-void FTHitExpectation::collectHits( Tf::Tsa::Line3D aLine3D,
-				    LHCb::FTChannelID chan,
-				    std::vector<std::pair<LHCb::FTChannelID, double> >& vectFTPairs
-				    ) const{
-
-  for ( const auto& f : m_fibremats)
-    {
-      if( (unsigned int)(f -> layer()) != chan.layer() ) continue;
-      // propagate to z of sector
-      Gaudi::Plane3D entryplane, exitplane;
-      EntryExitPlanes( *f, entryplane, exitplane );
-
-      Gaudi::XYZPoint globalEntry = intersection( aLine3D, entryplane );
-      Gaudi::XYZPoint globalExit  = intersection( aLine3D, exitplane );
-
-      LHCb::MCHit hit;
-      hit.setEntry( globalEntry );
-      hit.setDisplacement ( globalExit-globalEntry  );
-      hit.setEnergy( 1.0 );
-      if( f -> isInside( hit.midPoint() ) ){
-        f -> calculateHits( hit, vectFTPairs ).ignore();
+      const DeFTModule* module;
+      Gaudi::XYZPoint intersectionPoint;
+      bool expectHit = findIntersectingModule(layer, aTrack, module, intersectionPoint);
+
+      if( expectHit ) {
+        ++(info.nExpected);
+
+        // Check of this layer is present in the hits
+        auto itIter = std::find_if( ftHits.begin(), ftHits.end(),
+            [&module] (const LHCb::LHCbID& id) {return id.ftID().station() == module->stationID() &&
+                                                 id.ftID().layer() == module->layerID(); } );
+        if (itIter != ftHits.end() ) ++info.nFound;
       }
     }
-}
-
+  }
 
-void FTHitExpectation::EntryExitPlanes( DeFTFibreMat& mat,  Gaudi::Plane3D& entry,  Gaudi::Plane3D& exit ) const
-{
-  double xmin = mat.fibreMatMinX();
-  double ymin = mat.fibreMatMinY();
-  double xmax = mat.fibreMatMaxX();
-  double ymax = mat.fibreMatMaxY();
-
-  double xLower = -0.5*(xmax-xmin);
-  double xUpper =  0.5*(xmax-xmin);
-  double yLower = -0.5*(ymax-ymin);
-  double yUpper =  0.5*(ymax-ymin);
-
-  const Gaudi::XYZPoint g1 = mat.geometry() -> toGlobal( Gaudi::XYZPoint( xLower, yLower, 0. ) );
-  const Gaudi::XYZPoint g2 = mat.geometry() -> toGlobal( Gaudi::XYZPoint( xLower, yUpper, 0. ) );
-  // trajectory of middle
-  //const Gaudi::XYZPoint g3 = mat.geometry()->toGlobal(xLower, 0., 0.);
-  const Gaudi::XYZPoint g4 = mat.geometry()->toGlobal(Gaudi::XYZPoint( xUpper, 0., 0.) );
-  // plane
-  Gaudi::Plane3D plane(g1,g2,g4);
-
-  double thickness = 1.2;
-  entry = Gaudi::Plane3D(plane.Normal(), mat.geometry()->toGlobal( Gaudi::XYZPoint(0.,0.,-0.5*thickness)));
-  exit  = Gaudi::Plane3D(plane.Normal(), mat.geometry()->toGlobal( Gaudi::XYZPoint(0.,0., 0.5*thickness)));
+  return info;
 }
 
 
-void FTHitExpectation::collect(const LHCb::Track& aTrack ,std::vector<LHCb::LHCbID>& ids) const{
+bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb::Track& aTrack,
+    const DeFTModule*& module, Gaudi::XYZPoint& intersectionPoint) const {
 
- for ( auto iterL = m_layers.begin(); iterL != m_layers.end() ; ++iterL )
-    {
-      LHCb::FTChannelID elemID( (unsigned int)std::distance( m_layers.begin(), iterL ), 0u, 0u, 0u, 0u );
-      double layerZ = ((*iterL)->geometry()->toGlobal( Gaudi::XYZPoint(0. ,0., 0.) )).z();
+  // make a Line3D from the track
+  double layerZ = layer->globalZ();
+  Tf::Tsa::Line     line    = yLine    ( aTrack, layerZ );
+  Tf::Tsa::Parabola aParab  = xParabola( aTrack, layerZ );
+  Tf::Tsa::Line tanLine     = aParab.tangent( layerZ );
+  Tf::Tsa::Line3D aLine3D   = Tf::Tsa::createLine3D( tanLine, line, layerZ );
 
-      Tf::Tsa::Line     line    = yLine    ( aTrack, layerZ );
-      Tf::Tsa::Parabola aParab  = xParabola( aTrack, layerZ );
-      Tf::Tsa::Line tanLine     = aParab.tangent( layerZ );
-      Tf::Tsa::Line3D aLine3D   = Tf::Tsa::createLine3D( tanLine, line, layerZ );
-      std::vector<std::pair<LHCb::FTChannelID, double> > vectFTPairs;
+  // find intersection point of track and plane of layer
+  intersectionPoint = intersection(aLine3D, layer->plane);
 
-      collectHits( aLine3D, elemID, vectFTPairs );
+  // find the module that is hit
+  module = layer->findModule( intersectionPoint );
+  if( module == nullptr ) return false;
 
+  // find intersection point of track and plane of module
+  // (to account for misalignments between module and layer)
+  tanLine     = aParab.tangent( intersectionPoint.z() );
+  aLine3D   = Tf::Tsa::createLine3D( tanLine, line, intersectionPoint.z() );
+  intersectionPoint = intersection(aLine3D, module->plane);
 
-      int old = -1;
-      ids.reserve(vectFTPairs.size());
-      for ( std::vector<std::pair<LHCb::FTChannelID, double> >::iterator iter = vectFTPairs.begin();
-	    iter != vectFTPairs.end();
-	    ++iter )
-	{
-	  if ( int(iter->second) != old ) {
-	    old = int(iter->second);
-	    if ( iter->first) ids.push_back( LHCb::LHCbID(iter->first) );
-	  }
-	}  // pairs
-    }//layers
+  // check if intersection point is inside the fibres of the module
+  return module->isInsideSensitive( intersectionPoint );  // TODO
 }
 
+void FTHitExpectation::collect(const LHCb::Track& aTrack,
+                               std::vector<LHCb::LHCbID>& ids) const{
+  // Loop over all layers
+  for( auto station : m_ftDet->stations() ) {
+    for( auto layer : station->layers() ) {
 
+      const DeFTModule* module;
+      Gaudi::XYZPoint intersectionPoint;
+      bool expectHit = findIntersectingModule(layer, aTrack, module, intersectionPoint);
 
-unsigned int FTHitExpectation::nExpected(const LHCb::Track& aTrack) const{
+      // Find the channel that is closest
+      Gaudi::XYZPoint localP = module->geometry()->toLocal( intersectionPoint );
+      double frac;
+      LHCb::FTChannelID ftChan = module->calculateChannelAndFrac(localP.x(), frac);
+
+      // Add the channels
+      // JvT: Without the fraction the bare FTChannelID is pretty useless...
+      if( std::abs(frac) <= 0.5 ) ids.push_back( LHCb::LHCbID(ftChan) );
+    }
+  }
+}
 
+
+unsigned int FTHitExpectation::nExpected(const LHCb::Track& aTrack) const{
   return expectation(aTrack).nExpected;
 }
 
+
 Gaudi::XYZPoint FTHitExpectation::intersection(const Tf::Tsa::Line3D& line,
 					       const Gaudi::Plane3D& aPlane) const{
-  // make a plane
   Gaudi::XYZPoint inter;
   double mu = 0;
   Gaudi::Math::intersection( line, aPlane, inter, mu );
diff --git a/Tr/TrackTools/src/FTHitExpectation.h b/Tr/TrackTools/src/FTHitExpectation.h
index baf230b516..b7f5c629a2 100644
--- a/Tr/TrackTools/src/FTHitExpectation.h
+++ b/Tr/TrackTools/src/FTHitExpectation.h
@@ -52,7 +52,6 @@ public:
   */
   virtual unsigned int nExpected ( const LHCb::Track& aTrack ) const;
 
-
   /** Returns number of hits expected
   *
   *  @param aTrack Reference to the Track to test
@@ -72,33 +71,14 @@ public:
                                                                           
 private:
 
+  bool findIntersectingModule(const DeFTLayer* layer, const LHCb::Track& aTrack,
+      const DeFTModule*& module, Gaudi::XYZPoint& intersectionPoint) const ;
 
-  //bool select(const LHCb::FTChannelID& chan) const;
-
-  void EntryExitPlanes( DeFTFibreMat& mat,  Gaudi::Plane3D& entry,  Gaudi::Plane3D& exit ) const;
-  void collectHits( Tf::Tsa::Line3D aLine3D,
-		    LHCb::FTChannelID chan,
-		    std::vector<std::pair<LHCb::FTChannelID, double> >& vectFTPairs
-		    ) const;
   Gaudi::XYZPoint intersection(const Tf::Tsa::Line3D& line, const Gaudi::Plane3D& aPlane) const;
 
-
   DeFTDetector* m_ftDet;
-  std::vector<DeFTLayer*>    m_layers;
-  std::vector<DeFTFibreMat*> m_fibremats;
-
-  // Tf::Tsa::IITExpectedHits* m_expectedITHits;
-  // std::string m_selectorType;
-  //  std::string m_selectorName;
-  //  ISTChannelIDSelector* m_selector;
-  //  bool m_allStrips;  
  
 };
 
-/*
-inline bool ITHitExpectation::select(const LHCb::STChannelID& chan) const{
-  return m_selector == 0 ? true : m_selector->select(chan); 
-}
-*/
 
 #endif
-- 
GitLab


From ba99d8bae82775e025562d752fac5f3e6a76a652 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Tue, 11 Oct 2016 13:53:50 +0200
Subject: [PATCH 02/68] Modified PrAlgorithms, PrMCTools and TrackTools for the
 new FTDet

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp     | 159 +++++++--------------
 Pr/PrAlgorithms/src/PrFTHitManager.h       |   8 --
 Pr/PrMCTools/src/PrClustersResidual.cpp    |  39 ++---
 Pr/PrMCTools/src/PrDebugTrackingLosses.cpp |   3 +-
 Pr/PrMCTools/src/PrPlotFTHits.cpp          |  14 +-
 Tr/TrackTools/src/FTHitExpectation.cpp     |  26 ++--
 6 files changed, 81 insertions(+), 168 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 087d4840b0..8adf2efe17 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -6,8 +6,6 @@
 // local
 #include "PrFTHitManager.h"
 
-//#include  "Kernel/FTChannelID.h"
-
 //-----------------------------------------------------------------------------
 // Implementation file for class : PrFTHitManager
 //
@@ -17,19 +15,15 @@
 // Declaration of the Tool Factory
 DECLARE_TOOL_FACTORY( PrFTHitManager )
 
-
 //=============================================================================
 // Standard constructor, initializes variables
 //=============================================================================
 PrFTHitManager::PrFTHitManager( const std::string& type,
-                                  const std::string& name,
-                                  const IInterface* parent )
+                                const std::string& name,
+                                const IInterface* parent )
 : PrHitManager ( type, name , parent )
 {
   declareInterface<PrFTHitManager>(this);
-  declareProperty( "XSmearing",   m_xSmearing = -1. );
-  declareProperty( "ZSmearing",   m_zSmearing = -1. );
-
 }
 
 //=========================================================================
@@ -39,58 +33,38 @@ void PrFTHitManager::buildGeometry ( ) {
   
   // -- only build geometry once.
   if(m_geometryBuilt) return;
-  
 
-  IRndmGenSvc* randSvc = svc<IRndmGenSvc>( "RndmGenSvc", true );
-  StatusCode sc = m_gauss.initialize( randSvc, Rndm::Gauss( 0., 1. ) );
-  if ( sc.isFailure() ){
-    error() << "Could not initialize Rndm::Gauss generator" << endmsg;
+  // Retrieve and initialize DeFT (no test: exception in case of failure)
+  m_ftDet = getDet<DeFTDetector>( DeFTDetectorLocation::Default );
+  if( m_ftDet->version() < 60 ) {
+    error() << "This version requires FTDet v6.0 or higher" << endmsg;
     return;
   }
-  
-    
-  m_ftDet = getDet<DeFTDetector>( DeFTDetectorLocation::Default );
-  //version 20 is the detector with monolayer and fibremat structure, including the dead regions
-  if ( msgLevel( MSG::DEBUG) )  debug() << "DETECTOR VERSION: " << m_ftDet->version() << endmsg;  
-  //Different Detector Segments has to be used to set the geometry of zone Up and Down to be consistent with new DeFTFibreMat
-  DetectorSegment segUp;
-  DetectorSegment segDown;
-  for ( std::vector<DeFTLayer*>::const_iterator itL = m_ftDet->layers().begin();  //loop over layers
-	m_ftDet->layers().end() != itL; ++itL ) {
-    int id = (*itL)->params()->param<int>("layerID");  //ask layerID
-    
-    //FTChannelID (layer,module,mat,SiPMID,netCellID)
-    LHCb::FTChannelID ChUp( id, 0u, 0u, 0u, 0u ); //"0u" means "unsigned 0" 
-    const DeFTFibreMat* ftMatUp = m_ftDet->findFibreMat(ChUp);
-    segUp = ftMatUp->createDetSegment( ChUp, 0. );
-    
-    LHCb::FTChannelID ChDown( id, 0u, 1u, 0u, 0u ); //"0u" means "unsigned 0"
-    const DeFTFibreMat* ftMatDown = m_ftDet->findFibreMat(ChDown);
-    segDown = ftMatDown->createDetSegment( ChDown, 0. );
-
-    if ( msgLevel( MSG::DEBUG) ) debug() << "STEREO ANGLE Up: " <<  ftMatUp->angle() << endmsg;
-    if ( msgLevel( MSG::DEBUG) ) debug() << "STEREO ANGLE Down: " <<  ftMatDown->angle() << endmsg;
-    
-    //The setGeometry defines the z at y=0, the dxDy and the dzDy, as well as the isX properties of the zone. 
-    //This is important, since these are used in the following. 
-    //They are set once for each zone in this method.
-    zone( 2*id   )->setGeometry( segUp ); // ex:layers 0  down (up with new FTChannelID)
-    zone( 2*id+1 )->setGeometry( segDown ); // ex:layers 0  up (down with new FTChannelID)
-    //The boundaries are needed in case you will use the m_xMin, m_xMax, m_yMin, m_yMax of the zone, 
-    //or methods that are indirectly using them, like dxOnAFibre() or isInside(x,y) 
-    //(see https://svnweb.cern.ch/trac/lhcb/browser/Rec/trunk/Pr/PrKernel/PrKernel/PrHitZone.h?rev=164716). 
-    //These are currently not used anywhere in the seeding algorithm.
-    //The isInside(x,y) method is used in the forward algorithm. 
-    zone( 2*id+1 )->setBoundaries( -4090., 4090., -3030., 50. ); //check these boudaries for zone down (with new FTChannelID)
-    zone( 2*id   )->setBoundaries( -4090., 4090., -50., 3030. ); //check these boudaries for zone up (with new FTChannelID) 
-    if ( msgLevel( MSG::DEBUG) ) debug() << "Layer " << id << " z " << zone(2*id)->z() 
-                                         << " angle " << zone(2*id)->dxDy() << endmsg;
+
+  // Loop over all layers
+  for( auto station : m_ftDet->stations() ) {
+    for( auto layer : station->layers() ) {
+      int id = 4*(station->stationID() - 1) + layer->layerID();
+
+      DetectorSegment seg(0, layer->globalZ(), layer->dxdy(), layer->dzdy(), 0., 0.);
+      zone( 2*id   )->setGeometry( seg );
+      zone( 2*id+1 )->setGeometry( seg );
+
+      //The boundaries are needed in case you will use the m_xMin, m_xMax, m_yMin, m_yMax of the zone,
+      //or methods that are indirectly using them, like dxOnAFibre() or isInside(x,y)
+      //(see https://svnweb.cern.ch/trac/lhcb/browser/Rec/trunk/Pr/PrKernel/PrKernel/PrHitZone.h?rev=164716).
+      //These are currently not used anywhere in the seeding algorithm.
+      //The isInside(x,y) method is used in the forward algorithm.
+      float xmax = 0.5*layer->sizeX();
+      float ymax = 0.5*layer->sizeY();
+      zone( 2*id+1 )->setBoundaries( -xmax, xmax, -ymax, 25. ); // Small overlap (25 mm) for stereo layers
+      zone( 2*id   )->setBoundaries( -xmax, xmax, -25., ymax ); // Small overlap (25 mm) for stereo layers
+      if ( msgLevel( MSG::DEBUG) ) debug() << "Layer " << id << " z " << zone(2*id)->z()
+                                           << " angle " << zone(2*id)->dxDy() << endmsg;
+    }
   }
-  if ( msgLevel( MSG::DEBUG) ) debug() << "XSmearing " << m_xSmearing << " ZSmearing " << m_zSmearing << endmsg;
   
   m_geometryBuilt = true;
-  
-
 }
 
 
@@ -100,72 +74,43 @@ void PrFTHitManager::buildGeometry ( ) {
 void PrFTHitManager::decodeData ( ) {
   
   if(m_decodedData) return;
-
-  if ( msgLevel( MSG::DEBUG) ) debug() << "I AM IN DECODEDATA " << endmsg;
   
   typedef FastClusterContainer<LHCb::FTLiteCluster,int> FTLiteClusters;
-  FTLiteClusters* clus = get<FTLiteClusters>( LHCb::FTLiteClusterLocation::Default );
-  if ( msgLevel( MSG::DEBUG) ) debug() << "Retrieved " << clus->size() << " clusters" << endmsg;
-  const DeFTFibreMat* ftMat = nullptr;
-  const DeFTFibreMat* anaFtMat = nullptr;
-  unsigned int oldFibreMatID = 99999999;
-    
-  DetectorSegment seg ; 
+  FTLiteClusters* clusters = get<FTLiteClusters>( LHCb::FTLiteClusterLocation::Default );
+  if ( msgLevel( MSG::DEBUG) ) debug() << "Retrieved " << clusters->size() << " clusters" << endmsg;
   
-  for ( FTLiteClusters::iterator itC = clus->begin(); clus->end() != itC; ++itC ) {
-    /// find fibremat to which the cluster belongs 
-    anaFtMat = m_ftDet->findFibreMat( (*itC).channelID() );
-    if(anaFtMat->FibreMatID() != oldFibreMatID)  { 
-      oldFibreMatID =  anaFtMat->FibreMatID();
-      ftMat =  anaFtMat; 
-      if ( nullptr == ftMat ) {
-        info() << "FiberMat not found for FT channelID " << (*itC).channelID() << endmsg; 
-        oldFibreMatID = 99999999;   
-      } 
+  const DeFTModule* module = nullptr;
+  unsigned int prevModuleID = 99999999;
+  for ( auto clus : *clusters ) {
+    if( clus.channelID().uniqueModule() != prevModuleID ) {
+      module = m_ftDet->findModule( clus.channelID() );
+      prevModuleID = module->elementID().uniqueModule();
     }
 
+    double fraction = clus.fraction();
+    LHCb::FTChannelID id = clus.channelID();
 
-  
-    double fraction = (*itC).fraction() + 0.125;   // Truncated to 4 bits = 0.25. Add half of it
-    LHCb::FTChannelID id = (*itC).channelID();
-
-    int lay  = (*itC).channelID().layer();  
-    int zone = (int)((*itC).channelID().mat() > 0);  //if yes, it is bottom (now bottom is 1)
+    int lay  = 4*(id.station()-1) + id.layer();
+    int zone = int(module->isBottom());
     int code = 2*lay + zone;
 
-    //variables
-    const double fibreMatHalfSizeY = ftMat->getFibreMatHalfSizeY();
-    const double cellSizeX = ftMat->getCellSizeX();
-    const float dzDy = ftMat->getDzDy();
-    const float dxDy = -ftMat->getTanAngle();// = -m_tanAngle
-    const double hitLocalX = ftMat->cellLocalX(id) + fraction*cellSizeX;
-    double xx, xy, xz, dx, yx, yy, yz, dy, zx, zy, zz, dz;
-    ftMat->geometry()->toGlobalMatrix().GetComponents( xx, xy, xz, dx, yx, yy, yz, dy, zx, zy, zz, dz );
-
-    //const float yBorder = yx* hitLocalX + yy * (2*zone-1)*fibreMatHalfSizeY + dy;
-    const float yMin = yx* hitLocalX - yy *fibreMatHalfSizeY + dy;
-    const float yMax = yx* hitLocalX + yy *fibreMatHalfSizeY + dy;
-
-    //calculate hit x,z at y=0 in global frame (as local y=0 NOT global y=0)
-    const double hitGlobala_X = hitLocalX * xx + dx;
-    const double hitGlobalb_X = hitGlobala_X + fibreMatHalfSizeY*xy;
-    const double hitGlobala_Y = hitLocalX * yx+ dy;
-    const double hitGlobalb_Y = hitGlobala_Y + fibreMatHalfSizeY*yy;
-    const double hitGlobala_Z = hitLocalX * zx + dz;
-    const double hitGlobalb_Z = hitGlobala_Z + fibreMatHalfSizeY*zy;
-    const double axy = (hitGlobala_X-hitGlobalb_X)/(hitGlobala_Y-hitGlobalb_Y);
-    const double azy = (hitGlobala_Z-hitGlobalb_Z)/(hitGlobala_Y-hitGlobalb_Y);
-    const float x0 = hitGlobalb_X-axy*hitGlobalb_Y;
-    const float z0 = hitGlobalb_Z-azy*hitGlobalb_Y;
+    auto endPoints = module->endPoints(id, fraction);
+    double invdy = 1./(endPoints.first.x()-endPoints.second.x());
+    double dxdy  = (endPoints.first.x()-endPoints.second.x())*invdy;
+    double dzdy  = (endPoints.first.z()-endPoints.second.z())*invdy;
+    float x0     = endPoints.first.x()-dxdy*endPoints.first.y();
+    float z0     = endPoints.first.z()-dzdy*endPoints.first.y();
+    float yMin   = std::min(endPoints.first.y(), endPoints.second.y());
+    float yMax   = std::max(endPoints.first.y(), endPoints.second.y());
 
     PrHit* aHit = newHitInZone( code );
-    float errX = 0.05 + .03 * (*itC).size();
-    aHit->setHit( LHCb::LHCbID( (*itC).channelID() ), x0, z0, dxDy, dzDy, yMin, yMax, errX , zone, lay );
+    float errX = 0.08; // TODO: get this from a tool
+    aHit->setHit( LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
 
-    if ( UNLIKELY(msgLevel( MSG::DEBUG)) ) info() << " .. hit " << (*itC).channelID() << " zone " << zone << " x " << seg.x(0.) << endmsg;
+    if ( UNLIKELY(msgLevel( MSG::VERBOSE)) )
+      verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
   }
 
-
   for ( unsigned int lay = 0; nbZones() > lay ; ++lay ) {
      std::sort( getIterator_Begin(lay), getIterator_End(lay), PrHit::LowerByX0() );
   }
diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.h b/Pr/PrAlgorithms/src/PrFTHitManager.h
index 7107b32301..dc63b6830f 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.h
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.h
@@ -12,10 +12,6 @@ static const InterfaceID IID_PrFTHitManager ( "PrFTHitManager", 1, 0 );
 /** @class PrFTHitManager PrFTHitManager.h
  *  Tool that transforms clusters into 'hits' (spatial positions) which are then used by the pattern
  *  recognition algorithms involving the FT.
- *  
- *  Parameters:
- *  - XSmearing: Amount of gaussian smearing in x
- *  - ZSmearing: Switch on displacement in z (not used at the moment)
  *
  *  @author Olivier Callot
  *  @date   2012-03-13
@@ -38,14 +34,10 @@ public:
   /** @brief Construct the hits and apply smearing to hit position (if enabled)
    */
   void decodeData();
-  
 
 protected:
 
 private:
   DeFTDetector* m_ftDet;
-  Rndm::Numbers m_gauss; ///< Random number generator for gaussian smearing
-  float m_xSmearing;  ///< Amount of smearing in x
-  float m_zSmearing; 
 };
 #endif // PRFTHITMANAGER_H
diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index 87d550ca37..18b332a1a3 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -1,4 +1,4 @@
-// Include files 
+// Include files
 
 // from Gaudi
 #include "GaudiKernel/AlgFactory.h"
@@ -178,21 +178,7 @@ void PrClustersResidual::Occupancy(){
       hit = &(*itH);
       nHits[layer]++;
       LHCb::FTLiteCluster liteCluster = getLiteCluster(hit->id());
-      // int SipmCell = liteCluster.channelID().sipmCell();
-      int Module = liteCluster.channelID().module();
-      int Quarter = liteCluster.channelID().quarter();
-      // int Mat = liteCluster.channelID().mat();
-      int SipmID = liteCluster.channelID().sipmId();
-      int layer = liteCluster.channelID().layer();
-      int module2 = Module;
-      if(Module == 11 && Module > 4 ) module2 = 1;
-      if(Module != 11 && Module > 4 ) module2 = Module-3;
-      if(Module <  5  ) module2 = 6-Module;
-      if(Module == 10 ) module2 = 1;
-      int index = Quarter*128 + 16*module2+ std::floor(SipmID);
-      // if(index<0 || index>){
-      //   always()<<"Problem in Sipm Index; Correct for that"<<endmsg;
-      // }
+      int index = liteCluster.channelID().uniqueSiPM() & 511;
       sprintf(layerName,"Layer%i/AllContributions",layer);
       sprintf(Title,"Sipm Index Layer %i;SiPm Id;Clusters/Sipm/Event",layer);
       plot1D(index,layerName,Title,0.5,512.5,512);
@@ -426,12 +412,11 @@ void PrClustersResidual::TrackStudy(){
       
       //ChannelID of track hits
       std::vector<double> ChID_Fraction;
-      std::vector<double> ChID_Charge;
       std::vector<double> ChID_SipmCell;
       std::vector<double> ChID_Module;
       std::vector<double> ChID_Layer;
       std::vector<double> ChID_Quarter;
-      std::vector<double> ChID_Mat;
+      std::vector<double> ChID_Station;
       std::vector<double> ChID_SipmID;
       std::vector<double> ChID_ID;
       
@@ -484,14 +469,13 @@ void PrClustersResidual::TrackStudy(){
             }
             LHCb::FTLiteCluster liteCluster = getLiteCluster(hit->id());
             ChID_Fraction.push_back(liteCluster.fraction());
-            ChID_SipmCell.push_back(liteCluster.channelID().sipmCell());
+            ChID_SipmCell.push_back(liteCluster.channelID().channel());
             ChID_Module.push_back(liteCluster.channelID().module());
             ChID_Layer.push_back(liteCluster.channelID().layer());
             ChID_Quarter.push_back(liteCluster.channelID().quarter());
-            ChID_Mat.push_back(liteCluster.channelID().mat());
-            ChID_SipmID.push_back(liteCluster.channelID().sipmId());
+            ChID_Station.push_back(liteCluster.channelID().station());
+            ChID_SipmID.push_back(liteCluster.channelID().sipm());
             ChID_ID.push_back(liteCluster.channelID());
-            ChID_Charge.push_back(liteCluster.charge());
             PrHit_LHCBID.push_back(hit->id().ftID());
             PrHit_Xat0.push_back(hit->x());
             PrHit_Zat0.push_back(hit->z());
@@ -558,8 +542,7 @@ void PrClustersResidual::TrackStudy(){
       tuple->farray("ChID_Module",ChID_Module,"ChID",100); 
       tuple->farray("ChID_Layer",ChID_Layer,"ChID",100); 
       tuple->farray("ChID_Quarter",ChID_Quarter,"ChID",100); 
-      tuple->farray("ChID_Charge",ChID_Charge,"ChID",100);
-      tuple->farray("ChID_Mat",ChID_Mat,"ChID",100); 
+      tuple->farray("ChID_Station",ChID_Station,"ChID",100);
       tuple->farray("ChID_SipmID",ChID_SipmID,"ChID",100); 
       tuple->farray("ChID_ID",ChID_ID,"ChID",100);
 
@@ -1082,13 +1065,12 @@ void  PrClustersResidual::ClusterResidual(){
       //get Cluster associated to the Hit
       if(msgLevel(MSG::DEBUG)) debug()<<"Getting LiteCluster from PrHit"<<endmsg;
       LHCb::FTLiteCluster litecluster = getLiteCluster( (*iHit).id());
-      tuple->column("ClusterCharge",litecluster.charge());
       tuple->column("ClusterSize",litecluster.size());
       tuple->column("ClusterFraction",litecluster.fraction());
       tuple->column("ClusterChannelID",litecluster.channelID());
-      tuple->column("ClusterChannelIDSipmCell",litecluster.channelID().sipmCell());
-      tuple->column("ClusterChannelIDSipmID",litecluster.channelID().sipmId());
-      tuple->column("ClusterChannelIDMat",litecluster.channelID().mat());
+      tuple->column("ClusterChannelIDSipmCell",litecluster.channelID().channel());
+      tuple->column("ClusterChannelIDSipmID",litecluster.channelID().sipm());
+      tuple->column("ClusterChannelIDStation",litecluster.channelID().station());
       tuple->column("ClusterChannelIDModule",litecluster.channelID().module());
       tuple->column("ClusterChannelLayer",litecluster.channelID().layer());
       tuple->column("ClusterChannelQuarter",litecluster.channelID().quarter());
@@ -1294,3 +1276,4 @@ LHCb::FTLiteCluster PrClustersResidual::getLiteCluster(const LHCb::LHCbID id)
 
   return idTracks;
 }
+
diff --git a/Pr/PrMCTools/src/PrDebugTrackingLosses.cpp b/Pr/PrMCTools/src/PrDebugTrackingLosses.cpp
index e17b7ccae0..04c86ba89f 100644
--- a/Pr/PrMCTools/src/PrDebugTrackingLosses.cpp
+++ b/Pr/PrMCTools/src/PrDebugTrackingLosses.cpp
@@ -218,7 +218,7 @@ StatusCode PrDebugTrackingLosses::execute() {
           } else if ( (*itId).isFT() ) {
             LHCb::FTChannelID ftID = (*itId).ftID();
             info() << format( "    FT St%2d La%2d Pm%2d Cel%4d    ",
-                              ftID.layer()/4, ftID.layer()&3, ftID.sipmId(), ftID.sipmCell() );
+                              ftID.station(), ftID.layer(), ftID.sipm(), ftID.channel() );
           } else if ( (*itId).isOT() ) {
             LHCb::OTChannelID otID = (*itId).otID();
             info() << format( "    OT St%2d La%2d mo%2d Str%4d    ",
@@ -285,3 +285,4 @@ StatusCode PrDebugTrackingLosses::finalize() {
 }
 
 //=============================================================================
+
diff --git a/Pr/PrMCTools/src/PrPlotFTHits.cpp b/Pr/PrMCTools/src/PrPlotFTHits.cpp
index dda0e2d213..bfb5b0da90 100644
--- a/Pr/PrMCTools/src/PrPlotFTHits.cpp
+++ b/Pr/PrMCTools/src/PrPlotFTHits.cpp
@@ -164,19 +164,7 @@ void PrPlotFTHits::plotOccupancy(){
       hit = &*itH;   
       nHits[layer]++;                       
       LHCb::FTLiteCluster liteCluster = getLiteCluster(hit->id());
-      int Module = liteCluster.channelID().module();
-      int Quarter = liteCluster.channelID().quarter();          
-      int SipmID = liteCluster.channelID().sipmId();
-      int layer = liteCluster.channelID().layer();
-      int module2 = Module;        
-      if(Module == 11 && Module > 4 ) module2 = 1;
-      if(Module != 11 && Module > 4 ) module2 = Module-3;
-      if(Module <  5  ) module2 = 6-Module;
-      if(Module == 10 ) module2 = 1;
-      int index = Quarter*128 + 16*module2+ std::floor(SipmID);
-      // if(index<0 || index>){
-      //   always()<<"Problem in Sipm Index; Correct for that"<<endmsg;
-      // }
+      int index = liteCluster.channelID().uniqueSiPM() & 511;
       sprintf(layerName,"Layer%i/AllContributions",layer);
       sprintf(Title,"Sipm Index Layer %i;SiPm Id;Clusters/Sipm/Event",layer);
       m_histoTool->plot1D(index,layerName,Title,0.5,512.5,512);
diff --git a/Tr/TrackTools/src/FTHitExpectation.cpp b/Tr/TrackTools/src/FTHitExpectation.cpp
index adc48dd349..aed5a2c5b3 100644
--- a/Tr/TrackTools/src/FTHitExpectation.cpp
+++ b/Tr/TrackTools/src/FTHitExpectation.cpp
@@ -111,7 +111,8 @@ bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb
   Tf::Tsa::Line3D aLine3D   = Tf::Tsa::createLine3D( tanLine, line, layerZ );
 
   // find intersection point of track and plane of layer
-  intersectionPoint = intersection(aLine3D, layer->plane);
+  const Gaudi::Plane3D layerPlane = layer->plane();
+  intersectionPoint = intersection(aLine3D, layerPlane);
 
   // find the module that is hit
   module = layer->findModule( intersectionPoint );
@@ -121,10 +122,11 @@ bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb
   // (to account for misalignments between module and layer)
   tanLine     = aParab.tangent( intersectionPoint.z() );
   aLine3D   = Tf::Tsa::createLine3D( tanLine, line, intersectionPoint.z() );
-  intersectionPoint = intersection(aLine3D, module->plane);
+  const Gaudi::Plane3D modulePlane = module->plane();
+  intersectionPoint = intersection(aLine3D, modulePlane);
 
   // check if intersection point is inside the fibres of the module
-  return module->isInsideSensitive( intersectionPoint );  // TODO
+  return module->isInsideSensitive( intersectionPoint );
 }
 
 void FTHitExpectation::collect(const LHCb::Track& aTrack,
@@ -137,14 +139,16 @@ void FTHitExpectation::collect(const LHCb::Track& aTrack,
       Gaudi::XYZPoint intersectionPoint;
       bool expectHit = findIntersectingModule(layer, aTrack, module, intersectionPoint);
 
-      // Find the channel that is closest
-      Gaudi::XYZPoint localP = module->geometry()->toLocal( intersectionPoint );
-      double frac;
-      LHCb::FTChannelID ftChan = module->calculateChannelAndFrac(localP.x(), frac);
-
-      // Add the channels
-      // JvT: Without the fraction the bare FTChannelID is pretty useless...
-      if( std::abs(frac) <= 0.5 ) ids.push_back( LHCb::LHCbID(ftChan) );
+      if( expectHit ) {
+        // Find the channel that is closest
+        Gaudi::XYZPoint localP = module->geometry()->toLocal( intersectionPoint );
+        double frac;
+        LHCb::FTChannelID ftChan = module->calculateChannelAndFrac(localP.x(), frac);
+
+        // Add the channels
+        // JvT: Without the fraction the bare FTChannelID is pretty useless...
+        if( std::abs(frac) <= 0.5 ) ids.push_back( LHCb::LHCbID(ftChan) );
+      }
     }
   }
 }
-- 
GitLab


From 01da6dea5160627f9b2e1eabea0141ee19cbb5e7 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Thu, 13 Oct 2016 13:20:16 +0200
Subject: [PATCH 03/68] Fix typo in PrFTHitManager

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 8adf2efe17..727f484c7d 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -95,7 +95,7 @@ void PrFTHitManager::decodeData ( ) {
     int code = 2*lay + zone;
 
     auto endPoints = module->endPoints(id, fraction);
-    double invdy = 1./(endPoints.first.x()-endPoints.second.x());
+    double invdy = 1./(endPoints.first.y()-endPoints.second.y());
     double dxdy  = (endPoints.first.x()-endPoints.second.x())*invdy;
     double dzdy  = (endPoints.first.z()-endPoints.second.z())*invdy;
     float x0     = endPoints.first.x()-dxdy*endPoints.first.y();
-- 
GitLab


From 3de64676c68a1913b614cd6f139d2cc6e986a6ad Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Thu, 13 Oct 2016 17:41:30 +0200
Subject: [PATCH 04/68] Fixed -> in PrFTHitManager

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 4c256892de..602653ddce 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -55,8 +55,12 @@ void PrFTHitManager::buildGeometry ( ) {
       MakeZone( 2*id,   seg, -xmax, xmax, -25., ymax ); // Small overlap (25 mm) for stereo layers
       MakeZone( 2*id+1, seg, -xmax, xmax, -ymax, 25. ); // Small overlap (25 mm) for stereo layers
 
-      if ( msgLevel( MSG::DEBUG) ) debug() << "Layer " << id << " z " << zone(2*id)->z()
-                                           << " angle " << zone(2*id)->dxDy() << endmsg;
+      //----> Debug zones
+      if( msgLevel(MSG::DEBUG)){
+        debug() << "Layer " << id << " z " << zone(2*id).z()
+                << " angle " << zone(2*id).dxDy() << endmsg;
+      }
+      //----> Debug zones
     }
   }
   
@@ -101,8 +105,7 @@ void PrFTHitManager::decodeData ( ) {
 
     float errX = 0.08; // TODO: get this from a tool
     addHitInZone( code, LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
-
-    if ( UNLIKELY(msgLevel( MSG::VERBOSE)) )
+    if ( msgLevel(MSG::VERBOSE) )
       verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
   }
 
-- 
GitLab


From 7105dc03cbd4d3bdb51d24a8e3ab859e324c8429 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Thu, 13 Oct 2016 18:03:23 +0200
Subject: [PATCH 05/68] Changed resolution to 140 micron

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 602653ddce..6b42d79a75 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -103,7 +103,7 @@ void PrFTHitManager::decodeData ( ) {
     float yMin   = std::min(endPoints.first.y(), endPoints.second.y());
     float yMax   = std::max(endPoints.first.y(), endPoints.second.y());
 
-    float errX = 0.08; // TODO: get this from a tool
+    float errX = 0.14; // TODO: get this from a tool
     addHitInZone( code, LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
     if ( msgLevel(MSG::VERBOSE) )
       verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
-- 
GitLab


From 6ec74b7a7f6a28217161652341e29aef2d4c8677 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Wed, 19 Oct 2016 09:28:27 +0200
Subject: [PATCH 06/68] Change PrHit resolution to 170 micron in
 PrFTHitManager. Removed unnecessary sort in FTMeasurementProvider. Adjusted
 plot ranges in PrClustersResidual.

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp      |  2 +-
 Pr/PrMCTools/src/PrClustersResidual.cpp     | 12 ++++----
 Tr/TrackTools/src/FTMeasurementProvider.cpp | 32 +++++++++++----------
 3 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 6b42d79a75..8f4639ba2c 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -103,7 +103,7 @@ void PrFTHitManager::decodeData ( ) {
     float yMin   = std::min(endPoints.first.y(), endPoints.second.y());
     float yMax   = std::max(endPoints.first.y(), endPoints.second.y());
 
-    float errX = 0.14; // TODO: get this from a tool
+    float errX = 0.17; // TODO: this should be ~80 micron; get this from a tool
     addHitInZone( code, LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
     if ( msgLevel(MSG::VERBOSE) )
       verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index 18b332a1a3..faaf8592bc 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -201,29 +201,29 @@ void PrClustersResidual::Occupancy(){
       if(RecobleMCParticle){
         sprintf(layerName,"Layer%i/FromRecobleMCParticle",layer);
         sprintf(Title,"Sipm Index Layer %i;Sipm ID;Clusters/Sipm/Event",layer);
-        plot1D( index,layerName,Title,0.5,512.5,512);
+        plot1D( index,layerName,Title,-0.5,511.5,512);
         //0.5,96.5,96);
         if(mcPart->originVertex()->isPrimary() || mcPart->originVertex()->isDecay()){
           sprintf(layerName,"Layer%i/FromRecobleMCParticleWanted",layer);                                                                
           sprintf(Title,"Sipm Index Layer %i;Sipm ID;Clusters/Sipm/Event",layer);                                                                                      
-          plot1D( index,layerName,Title,0.5,512.5,512);                                    
+          plot1D( index,layerName,Title,-0.5,511.5,512);
         }
       }
       if(fromMCParticleContrib){
         sprintf(layerName,"Layer%i/FromMCParticle",layer);
         sprintf(Title,"Sipm Index Layer %i;Sipm ID;Clusters/Sipm/Event",layer);
-        plot1D( index,layerName,Title,0.5,512.5,512);//0.5,96.5,96);
+        plot1D( index,layerName,Title,-0.5,511.5,512);//0.5,96.5,96);
       }
       if(NoiseCluster){
         sprintf(layerName,"Layer%i/FromNoise",layer);
         sprintf(Title,"Sipm Index Layer %i;Sipm ID;Clusters/Sipm/Event",layer);
-        plot1D(index,layerName,Title,0.5,512.5,512);//0.5,96.5,96);
+        plot1D(index,layerName,Title,-0.5,511.5,512);//0.5,96.5,96);
       }
       if(spillCluster)
       {
         sprintf(layerName,"Layer%i/FromSpill",layer);
         sprintf(Title,"Sipm Index Layer %i;Sipm ID;Clusters/Sipm/Event",layer);
-        plot1D(index,layerName,Title,0.5,96.5,96);
+        plot1D(index,layerName,Title,-0.5,511.5,512);
       }
     }
   }
@@ -1023,7 +1023,7 @@ void  PrClustersResidual::ClusterResidual(){
         nMCHitToCluster++;
         Gaudi::XYZPoint pMid = mcHit->midPoint();
         Residual_X.push_back( (*iHit).x(pMid.y()) - pMid.x()); //x at y - y at z
-        Residual_Z.push_back( (*iHit).z(pMid.z()) - pMid.y());
+        Residual_Z.push_back( (*iHit).z(pMid.y()) - pMid.y());
         SlopeX.push_back( mcHit->dxdz());
         SlopeY.push_back( mcHit->dydz());
         pathlength.push_back( mcHit->pathLength());
diff --git a/Tr/TrackTools/src/FTMeasurementProvider.cpp b/Tr/TrackTools/src/FTMeasurementProvider.cpp
index 8ca833120a..b2dda2eb4b 100644
--- a/Tr/TrackTools/src/FTMeasurementProvider.cpp
+++ b/Tr/TrackTools/src/FTMeasurementProvider.cpp
@@ -28,12 +28,15 @@ public:
 
   /// constructer
   FTMeasurementProvider(const std::string& type,
-			  const std::string& name,
-			  const IInterface* parent);
+                        const std::string& name,
+			                  const IInterface* parent);
 
   StatusCode initialize() final;
-  LHCb::Measurement* measurement( const LHCb::LHCbID& id, bool localY=false ) const  final;
-  LHCb::Measurement* measurement( const LHCb::LHCbID& id, const LHCb::ZTrajectory& refvector, bool localY=false) const final;
+  LHCb::Measurement* measurement( const LHCb::LHCbID& id,
+                                  bool localY=false ) const  final;
+  LHCb::Measurement* measurement( const LHCb::LHCbID& id,
+                                  const LHCb::ZTrajectory& refvector,
+                                  bool localY=false) const final;
   inline LHCb::FTMeasurement* ftmeasurement( const LHCb::LHCbID& id ) const  ;
 
   void handle ( const Incident& incident ) final;
@@ -103,13 +106,10 @@ const FastClusterContainer<LHCb::FTLiteCluster,int>* FTMeasurementProvider::clus
 {
   /// If there is a new event, get the clusters and sort them according to their channel ID
   if( UNLIKELY(!m_clusters) ){
-    m_clusters = getIfExists<FastClusterContainer<LHCb::FTLiteCluster,int> >( LHCb::FTLiteClusterLocation::Default );
-    if(m_clusters){ //TODO: sort before putting clusters on the TES!
-      std::sort(m_clusters->begin(), m_clusters->end(),
-                [](const LHCb::FTLiteCluster& lhs, const LHCb::FTLiteCluster& rhs){ return lhs.channelID() < rhs.channelID(); });
-    }else{
-      error() << "Could not find FTLiteClusters at: " <<  LHCb::FTLiteClusterLocation::Default << endmsg;
-    }
+    m_clusters = getIfExists<FastClusterContainer<LHCb::FTLiteCluster,int> >
+                 ( LHCb::FTLiteClusterLocation::Default );
+    if(!m_clusters) error() << "Could not find FTLiteClusters at: "
+                            << LHCb::FTLiteClusterLocation::Default << endmsg;
   }
   return m_clusters ;
 }
@@ -123,8 +123,8 @@ LHCb::FTMeasurement* FTMeasurementProvider::ftmeasurement( const LHCb::LHCbID& i
     error() << "Not an FT measurement" << endmsg ;
     return nullptr;
   }
-  /// The clusters are sorted, so we can use a binary search (lower bound search) to find the element
-  /// corresponding to the channel ID
+  /// The clusters are sorted, so we can use a binary search (lower bound search)
+  /// to find the element corresponding to the channel ID
   const auto& c = *clusters();
   auto itH = std::lower_bound( c.begin(),  c.end(), id.ftID(),
                       [](const LHCb::FTLiteCluster clus, const LHCb::FTChannelID id){
@@ -136,7 +136,8 @@ LHCb::FTMeasurement* FTMeasurementProvider::ftmeasurement( const LHCb::LHCbID& i
 //-----------------------------------------------------------------------------
 /// Return the measurement
 //-----------------------------------------------------------------------------
-LHCb::Measurement* FTMeasurementProvider::measurement( const LHCb::LHCbID& id, bool /*localY*/ ) const {
+LHCb::Measurement* FTMeasurementProvider::measurement( const LHCb::LHCbID& id,
+                                                       bool /*localY*/ ) const {
   return ftmeasurement(id) ;
 }
 
@@ -145,7 +146,8 @@ LHCb::Measurement* FTMeasurementProvider::measurement( const LHCb::LHCbID& id, b
 //-----------------------------------------------------------------------------
 
 LHCb::Measurement* FTMeasurementProvider::measurement( const LHCb::LHCbID& id,
-                                                       const LHCb::ZTrajectory& /* reftraj */, bool /*localY*/ ) const {
+                                                       const LHCb::ZTrajectory& /* reftraj */,
+                                                       bool /*localY*/ ) const {
   // default implementation
   return ftmeasurement(id) ;
 }
-- 
GitLab


From 57ad224039d868bef585c8ae7e953b00a827f002 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Thu, 27 Oct 2016 20:38:25 +0200
Subject: [PATCH 07/68] Adapt to FT_61 geometry

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp  | 16 ++++++-------
 Pr/PrMCTools/src/PrClustersResidual.cpp |  4 ++++
 Tr/TrackFitEvent/src/FTMeasurement.cpp  |  8 +++----
 Tr/TrackTools/src/FTHitExpectation.cpp  | 32 +++++++++++++------------
 Tr/TrackTools/src/FTHitExpectation.h    |  4 ++--
 5 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 8f4639ba2c..b02e774009 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -79,22 +79,22 @@ void PrFTHitManager::decodeData ( ) {
   FTLiteClusters* clusters = get<FTLiteClusters>( LHCb::FTLiteClusterLocation::Default );
   if ( msgLevel( MSG::DEBUG) ) debug() << "Retrieved " << clusters->size() << " clusters" << endmsg;
   
-  const DeFTModule* module = nullptr;
-  unsigned int prevModuleID = 99999999;
+  const DeFTMat* mat = nullptr;
+  unsigned int prevMatID = 99999999;
   for ( auto clus : *clusters ) {
-    if( clus.channelID().uniqueModule() != prevModuleID ) {
-      module = m_ftDet->findModule( clus.channelID() );
-      prevModuleID = module->elementID().uniqueModule();
+    if( clus.channelID().uniqueMat() != prevMatID ) {
+      mat = m_ftDet->findMat( clus.channelID() );
+      prevMatID = mat->elementID().uniqueMat();
     }
 
     double fraction = clus.fraction();
     LHCb::FTChannelID id = clus.channelID();
 
     int lay  = 4*(id.station()-1) + id.layer();
-    int zone = int(module->isBottom());
+    int zone = int(mat->isBottom());
     int code = 2*lay + zone;
 
-    auto endPoints = module->endPoints(id, fraction);
+    auto endPoints = mat->endPoints(id, fraction);
     double invdy = 1./(endPoints.first.y()-endPoints.second.y());
     double dxdy  = (endPoints.first.x()-endPoints.second.x())*invdy;
     double dzdy  = (endPoints.first.z()-endPoints.second.z())*invdy;
@@ -103,7 +103,7 @@ void PrFTHitManager::decodeData ( ) {
     float yMin   = std::min(endPoints.first.y(), endPoints.second.y());
     float yMax   = std::max(endPoints.first.y(), endPoints.second.y());
 
-    float errX = 0.17; // TODO: this should be ~80 micron; get this from a tool
+    float errX = 0.170; // TODO: this should be ~80 micron; get this from a tool
     addHitInZone( code, LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
     if ( msgLevel(MSG::VERBOSE) )
       verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index faaf8592bc..16aea72a32 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -413,6 +413,7 @@ void PrClustersResidual::TrackStudy(){
       //ChannelID of track hits
       std::vector<double> ChID_Fraction;
       std::vector<double> ChID_SipmCell;
+      std::vector<double> ChID_Mat;
       std::vector<double> ChID_Module;
       std::vector<double> ChID_Layer;
       std::vector<double> ChID_Quarter;
@@ -471,6 +472,7 @@ void PrClustersResidual::TrackStudy(){
             ChID_Fraction.push_back(liteCluster.fraction());
             ChID_SipmCell.push_back(liteCluster.channelID().channel());
             ChID_Module.push_back(liteCluster.channelID().module());
+            ChID_Mat.push_back(liteCluster.channelID().mat());
             ChID_Layer.push_back(liteCluster.channelID().layer());
             ChID_Quarter.push_back(liteCluster.channelID().quarter());
             ChID_Station.push_back(liteCluster.channelID().station());
@@ -540,6 +542,7 @@ void PrClustersResidual::TrackStudy(){
       tuple->farray("ChID_Fraction",ChID_Fraction,"ChID",100);
       tuple->farray("ChID_SipmCell",ChID_SipmCell,"ChID",100); 
       tuple->farray("ChID_Module",ChID_Module,"ChID",100); 
+      tuple->farray("ChID_Mat",ChID_Mat,"ChID",100);
       tuple->farray("ChID_Layer",ChID_Layer,"ChID",100); 
       tuple->farray("ChID_Quarter",ChID_Quarter,"ChID",100); 
       tuple->farray("ChID_Station",ChID_Station,"ChID",100);
@@ -1070,6 +1073,7 @@ void  PrClustersResidual::ClusterResidual(){
       tuple->column("ClusterChannelID",litecluster.channelID());
       tuple->column("ClusterChannelIDSipmCell",litecluster.channelID().channel());
       tuple->column("ClusterChannelIDSipmID",litecluster.channelID().sipm());
+      tuple->column("ClusterChannelIDMat",litecluster.channelID().mat());
       tuple->column("ClusterChannelIDStation",litecluster.channelID().station());
       tuple->column("ClusterChannelIDModule",litecluster.channelID().module());
       tuple->column("ClusterChannelLayer",litecluster.channelID().layer());
diff --git a/Tr/TrackFitEvent/src/FTMeasurement.cpp b/Tr/TrackFitEvent/src/FTMeasurement.cpp
index 139b861bff..de28cfd7b4 100644
--- a/Tr/TrackFitEvent/src/FTMeasurement.cpp
+++ b/Tr/TrackFitEvent/src/FTMeasurement.cpp
@@ -18,12 +18,12 @@ using namespace LHCb;
 //-----------------------------------------------------------------------------
 void FTMeasurement::init( const DeFTDetector& geom ) {
 
-  const DeFTModule* ftModule = geom.findModule( m_cluster.channelID() );
-  m_detectorElement = ftModule;
+  const DeFTMat* ftMat = geom.findMat( m_cluster.channelID() );
+  m_detectorElement = ftMat;
   m_size = m_cluster.size();
   m_errMeasure = 0.080; // + .030 * m_size;
-  m_trajectory = ftModule->trajectory(m_cluster.channelID(), m_cluster.fraction());
-  m_z = ftModule->globalZ();
+  m_trajectory = ftMat->trajectory(m_cluster.channelID(), m_cluster.fraction());
+  m_z = ftMat->globalZ();
   m_measure = 0. ; // JvT: I believe this is purely historical. Should remove it?
 
 }
diff --git a/Tr/TrackTools/src/FTHitExpectation.cpp b/Tr/TrackTools/src/FTHitExpectation.cpp
index aed5a2c5b3..88c41c2717 100644
--- a/Tr/TrackTools/src/FTHitExpectation.cpp
+++ b/Tr/TrackTools/src/FTHitExpectation.cpp
@@ -57,8 +57,8 @@ StatusCode FTHitExpectation::initialize()
 
   // Get all layers (need to know the z-plane of each layer)
   m_ftDet = getDet<DeFTDetector>(DeFTDetectorLocation::Default);
-  if ( m_ftDet -> version() < 60 )
-    return Error("This version requires FTDet v6.0 or higher", StatusCode::FAILURE);
+  if ( m_ftDet -> version() < 61 )
+    return Error("This version requires FTDet v6.1 or higher", StatusCode::FAILURE);
 
   return StatusCode::SUCCESS;
 }
@@ -80,17 +80,16 @@ IHitExpectation::Info FTHitExpectation::expectation(const LHCb::Track& aTrack) c
   for( auto station : m_ftDet->stations() ) {
     for( auto layer : station->layers() ) {
 
-      const DeFTModule* module;
+      const DeFTMat* mat;
       Gaudi::XYZPoint intersectionPoint;
-      bool expectHit = findIntersectingModule(layer, aTrack, module, intersectionPoint);
+      bool expectHit = findIntersectingMat(layer, aTrack, mat, intersectionPoint);
 
       if( expectHit ) {
         ++(info.nExpected);
 
         // Check of this layer is present in the hits
-        auto itIter = std::find_if( ftHits.begin(), ftHits.end(),
-            [&module] (const LHCb::LHCbID& id) {return id.ftID().station() == module->stationID() &&
-                                                 id.ftID().layer() == module->layerID(); } );
+        auto itIter = std::find_if( ftHits.begin(), ftHits.end(), [&mat] (const LHCb::LHCbID& id)
+            {return id.ftID().uniqueLayer() == mat->elementID().uniqueLayer(); } );
         if (itIter != ftHits.end() ) ++info.nFound;
       }
     }
@@ -100,8 +99,8 @@ IHitExpectation::Info FTHitExpectation::expectation(const LHCb::Track& aTrack) c
 }
 
 
-bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb::Track& aTrack,
-    const DeFTModule*& module, Gaudi::XYZPoint& intersectionPoint) const {
+bool FTHitExpectation::findIntersectingMat(const DeFTLayer* layer, const LHCb::Track& aTrack,
+    const DeFTMat*& mat, Gaudi::XYZPoint& intersectionPoint) const {
 
   // make a Line3D from the track
   double layerZ = layer->globalZ();
@@ -115,7 +114,7 @@ bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb
   intersectionPoint = intersection(aLine3D, layerPlane);
 
   // find the module that is hit
-  module = layer->findModule( intersectionPoint );
+  const DeFTModule* module = layer->findModule( intersectionPoint );
   if( module == nullptr ) return false;
 
   // find intersection point of track and plane of module
@@ -125,8 +124,11 @@ bool FTHitExpectation::findIntersectingModule(const DeFTLayer* layer, const LHCb
   const Gaudi::Plane3D modulePlane = module->plane();
   intersectionPoint = intersection(aLine3D, modulePlane);
 
+  // Find the corresponding mat
+  mat = module->findMat(intersectionPoint);
+
   // check if intersection point is inside the fibres of the module
-  return module->isInsideSensitive( intersectionPoint );
+  return (mat == nullptr ) ? false : mat->isInside( intersectionPoint );
 }
 
 void FTHitExpectation::collect(const LHCb::Track& aTrack,
@@ -135,15 +137,15 @@ void FTHitExpectation::collect(const LHCb::Track& aTrack,
   for( auto station : m_ftDet->stations() ) {
     for( auto layer : station->layers() ) {
 
-      const DeFTModule* module;
+      const DeFTMat* mat;
       Gaudi::XYZPoint intersectionPoint;
-      bool expectHit = findIntersectingModule(layer, aTrack, module, intersectionPoint);
+      bool expectHit = findIntersectingMat(layer, aTrack, mat, intersectionPoint);
 
       if( expectHit ) {
         // Find the channel that is closest
-        Gaudi::XYZPoint localP = module->geometry()->toLocal( intersectionPoint );
+        Gaudi::XYZPoint localP = mat->geometry()->toLocal( intersectionPoint );
         double frac;
-        LHCb::FTChannelID ftChan = module->calculateChannelAndFrac(localP.x(), frac);
+        LHCb::FTChannelID ftChan = mat->calculateChannelAndFrac(localP.x(), frac);
 
         // Add the channels
         // JvT: Without the fraction the bare FTChannelID is pretty useless...
diff --git a/Tr/TrackTools/src/FTHitExpectation.h b/Tr/TrackTools/src/FTHitExpectation.h
index b7f5c629a2..f7ae500130 100644
--- a/Tr/TrackTools/src/FTHitExpectation.h
+++ b/Tr/TrackTools/src/FTHitExpectation.h
@@ -71,8 +71,8 @@ public:
                                                                           
 private:
 
-  bool findIntersectingModule(const DeFTLayer* layer, const LHCb::Track& aTrack,
-      const DeFTModule*& module, Gaudi::XYZPoint& intersectionPoint) const ;
+  bool findIntersectingMat(const DeFTLayer* layer, const LHCb::Track& aTrack,
+      const DeFTMat*& mat, Gaudi::XYZPoint& intersectionPoint) const ;
 
   Gaudi::XYZPoint intersection(const Tf::Tsa::Line3D& line, const Gaudi::Plane3D& aPlane) const;
 
-- 
GitLab


From d6fe082b9b70aaf60a2ddd7dec36262321fce516 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Fri, 28 Oct 2016 21:39:59 +0200
Subject: [PATCH 08/68] Updated version in PrFTHitManager

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index b02e774009..38da87501a 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -35,8 +35,8 @@ void PrFTHitManager::buildGeometry ( ) {
 
   // Retrieve and initialize DeFT (no test: exception in case of failure)
   m_ftDet = getDet<DeFTDetector>( DeFTDetectorLocation::Default );
-  if( m_ftDet->version() < 60 ) {
-    error() << "This version requires FTDet v6.0 or higher" << endmsg;
+  if( m_ftDet->version() < 61 ) {
+    error() << "This version requires FTDet v6.1 or higher" << endmsg;
     return;
   }
 
-- 
GitLab


From f02bbcf84c8f94f72d22a0f5ad98d31fdd20b7f9 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Wed, 2 Nov 2016 16:38:21 +0100
Subject: [PATCH 09/68] Changed debug statement

---
 Pr/PrAlgorithms/src/PrFTHitManager.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.cpp b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
index 38da87501a..5f23bcc0db 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.cpp
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.cpp
@@ -78,7 +78,7 @@ void PrFTHitManager::decodeData ( ) {
   typedef FastClusterContainer<LHCb::FTLiteCluster,int> FTLiteClusters;
   FTLiteClusters* clusters = get<FTLiteClusters>( LHCb::FTLiteClusterLocation::Default );
   if ( msgLevel( MSG::DEBUG) ) debug() << "Retrieved " << clusters->size() << " clusters" << endmsg;
-  
+
   const DeFTMat* mat = nullptr;
   unsigned int prevMatID = 99999999;
   for ( auto clus : *clusters ) {
@@ -106,7 +106,7 @@ void PrFTHitManager::decodeData ( ) {
     float errX = 0.170; // TODO: this should be ~80 micron; get this from a tool
     addHitInZone( code, LHCb::LHCbID( id ), x0, z0, dxdy, dzdy, yMin, yMax, errX , zone, lay );
     if ( msgLevel(MSG::VERBOSE) )
-      verbose() << " .. hit " << id << " zone " << zone << " x " << x0 << endmsg;
+      verbose() << " .. hit " << id << " code=" << code << " x=" << x0 << " z=" << z0 << endmsg;
   }
 
   for ( unsigned int lay = 0; nbZones() > lay ; ++lay ) {
-- 
GitLab


From 4ae38cc1701305bf937aba96a2a0c791bdd8762b Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Tue, 15 Nov 2016 18:05:38 +0100
Subject: [PATCH 10/68] Adapted code to new Linker location

---
 Pr/PrMCTools/src/PrCheatedSciFiTracking.cpp |  4 ++--
 Pr/PrMCTools/src/PrClustersResidual.cpp     | 14 +++++++-------
 Pr/PrMCTools/src/PrPlotFTHits.cpp           | 10 +++++-----
 Pr/PrMCTools/src/PrTStationDebugTool.cpp    |  6 +++---
 Tr/TrackFitEvent/src/FTMeasurement.cpp      |  2 +-
 5 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/Pr/PrMCTools/src/PrCheatedSciFiTracking.cpp b/Pr/PrMCTools/src/PrCheatedSciFiTracking.cpp
index 0adeff80b8..6c08a4010f 100644
--- a/Pr/PrMCTools/src/PrCheatedSciFiTracking.cpp
+++ b/Pr/PrMCTools/src/PrCheatedSciFiTracking.cpp
@@ -4,7 +4,7 @@
 #include "Event/Track.h"
 #include "Event/StateParameters.h"
 #include "PrCheatedSciFiTracking.h"
-#include "Event/FTCluster.h"
+#include "Event/FTLiteCluster.h"
 #include "Linker/LinkedTo.h"
 #include "Event/MCTrackInfo.h"
 
@@ -93,7 +93,7 @@ StatusCode PrCheatedSciFiTracking::finalize() {
 //=========================================================================
 void PrCheatedSciFiTracking::makeLHCbTracks ( LHCb::Tracks* result ) {
 
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
   LHCb::MCParticles* mcParts = getIfExists<LHCb::MCParticles> ( LHCb::MCParticleLocation::Default );
 
   MCTrackInfo trackInfo( evtSvc(), msgSvc() );
diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index 16aea72a32..ab532fe688 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -123,8 +123,8 @@ void PrClustersResidual::Occupancy(){
   const LHCb::MCHits* mcHitsPrev = getIfExists<LHCb::MCHits>("Prev/"+LHCb::MCHitLocation::FT);//"/Event/Prev/MC/FT/Hits"
 
   LinkedFrom<LHCb::MCHit,LHCb::MCParticle> myMCHitLink( evtSvc(), msgSvc(), LHCb::MCParticleLocation::Default + "2MC" + "FT" + "Hits" );
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
-  LinkedTo<LHCb::MCHit, LHCb::FTCluster> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
+  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
   //"/Event/Prev/MC/FT/Hits"
   // mcHitsNext = getIfExists<MCHits>("Next/"+LHCb::MCHitLocation::FT);
   // mcHitsPrev = getIfExists<MCHits>("Prev/"+LHCb::MCHitLocation::FT);
@@ -277,8 +277,8 @@ void PrClustersResidual::TrackStudy(){
   LHCb::ODIN* odin=getIfExists<LHCb::ODIN>(LHCb::ODINLocation::Default);
   //Linker for the MCHit
   LinkedFrom<LHCb::MCHit,LHCb::MCParticle> myMCHitLink( evtSvc(), msgSvc(), LHCb::MCParticleLocation::Default + "2MC" + "FT" + "Hits" );
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
-  LinkedTo<LHCb::MCHit, LHCb::FTCluster> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
+  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
   //Get the linker for the generation of the track to study (the one after the linker)
   //Get the McParticles
   LHCb::MCParticles* mcParts = getIfExists<LHCb::MCParticles> ( LHCb::MCParticleLocation::Default );
@@ -927,10 +927,10 @@ void  PrClustersResidual::ClusterResidual(){
   //LinkedTo<LHCb::MCParticle, LHCb::Track> myForwardLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Forward);
   //LinkedTo<LHCb::MCParticle, LHCb::Track> mySeedLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Seed);
   if(msgLevel(MSG::DEBUG)) debug()<<" Get ClusterLinker "<<endmsg;
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
   if(msgLevel(MSG::DEBUG)) debug()<<" Get Cluster to MCHit Linker "<<endmsg;
                   
-  LinkedTo<LHCb::MCHit, LHCb::FTCluster> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
   MCTrackInfo trackInfo( evtSvc(), msgSvc() );
   if(msgLevel(MSG::DEBUG)) debug()<<" Add MCHitAndTrackStudy "<<endmsg;
   Tuples::Tuple tuple = GaudiTupleAlg::nTuple("ClusterMCHitAndTrackStudy","Events");
@@ -1068,7 +1068,7 @@ void  PrClustersResidual::ClusterResidual(){
       //get Cluster associated to the Hit
       if(msgLevel(MSG::DEBUG)) debug()<<"Getting LiteCluster from PrHit"<<endmsg;
       LHCb::FTLiteCluster litecluster = getLiteCluster( (*iHit).id());
-      tuple->column("ClusterSize",litecluster.size());
+      tuple->column("ClusterSize",litecluster.isLarge());
       tuple->column("ClusterFraction",litecluster.fraction());
       tuple->column("ClusterChannelID",litecluster.channelID());
       tuple->column("ClusterChannelIDSipmCell",litecluster.channelID().channel());
diff --git a/Pr/PrMCTools/src/PrPlotFTHits.cpp b/Pr/PrMCTools/src/PrPlotFTHits.cpp
index bfb5b0da90..de6475f5ea 100644
--- a/Pr/PrMCTools/src/PrPlotFTHits.cpp
+++ b/Pr/PrMCTools/src/PrPlotFTHits.cpp
@@ -116,8 +116,8 @@ void PrPlotFTHits::plotOccupancy(){
   //"/Event/Prev/MC/FT/Hits"
   LinkedFrom<LHCb::MCHit,LHCb::MCParticle> myMCHitLink( evtSvc(), msgSvc(), LHCb::MCParticleLocation::Default + "2MC" + "FT" + "Hits" );   
     
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );         
-  LinkedTo<LHCb::MCHit, LHCb::FTCluster> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
+  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
   //"/Event/Prev/MC/FT/Hits"                                             
   char layerName[100];                                                   
   char Title[100];                                                       
@@ -340,7 +340,7 @@ void PrPlotFTHits::plotHitEfficiency(){
   // -- Link different track containers to MCParticles
   LinkedTo<LHCb::MCParticle, LHCb::Track> myForwardLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Forward);
   LinkedTo<LHCb::MCParticle, LHCb::Track> mySeedLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Seed);
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
   MCTrackInfo trackInfo( evtSvc(), msgSvc() );
 
   // -----------------------------------------------------------------------------------
@@ -727,8 +727,8 @@ void PrPlotFTHits::plotMCHits () {
   
   
   // -- MC linking
-  LinkedTo<LHCb::MCHit, LHCb::FTCluster> myMCHitLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default + "2MCHits");
-  LinkedTo<LHCb::MCParticle, LHCb::FTCluster> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+  LinkedTo<LHCb::MCHit> myMCHitLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
 
   MCTrackInfo trackInfo( evtSvc(), msgSvc() );
 
diff --git a/Pr/PrMCTools/src/PrTStationDebugTool.cpp b/Pr/PrMCTools/src/PrTStationDebugTool.cpp
index 8ec8b8f576..ccdcc199c4 100644
--- a/Pr/PrMCTools/src/PrTStationDebugTool.cpp
+++ b/Pr/PrMCTools/src/PrTStationDebugTool.cpp
@@ -5,7 +5,7 @@
 #include "Linker/LinkedTo.h"
 #include "Kernel/LHCbID.h"
 #include "Event/OTTime.h"
-#include "Event/FTCluster.h"
+#include "Event/FTLiteCluster.h"
 #include "Event/MCParticle.h"
 
 // local
@@ -51,7 +51,7 @@ bool PrTStationDebugTool::matchKey ( LHCb::LHCbID id, int key ) {
       part = oLink.next();
     }
   } else if ( id.isFT() ) {    
-    LinkedTo<LHCb::MCParticle> fLink( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+    LinkedTo<LHCb::MCParticle> fLink( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
     LHCb::FTChannelID idO = id.ftID();
     
     LHCb::MCParticle* part = fLink.first( idO );
@@ -77,7 +77,7 @@ void PrTStationDebugTool::printKey( MsgStream& msg, LHCb::LHCbID id ) {
       part = oLink.next();
     }
   } else if ( id.isFT() ) {
-    LinkedTo<LHCb::MCParticle> fLink( evtSvc(), msgSvc(), LHCb::FTClusterLocation::Default );
+    LinkedTo<LHCb::MCParticle> fLink( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
     LHCb::FTChannelID idO = id.ftID();
   
     LHCb::MCParticle* part = fLink.first( idO );
diff --git a/Tr/TrackFitEvent/src/FTMeasurement.cpp b/Tr/TrackFitEvent/src/FTMeasurement.cpp
index de28cfd7b4..bb21204db0 100644
--- a/Tr/TrackFitEvent/src/FTMeasurement.cpp
+++ b/Tr/TrackFitEvent/src/FTMeasurement.cpp
@@ -20,7 +20,7 @@ void FTMeasurement::init( const DeFTDetector& geom ) {
 
   const DeFTMat* ftMat = geom.findMat( m_cluster.channelID() );
   m_detectorElement = ftMat;
-  m_size = m_cluster.size();
+  m_size = m_cluster.isLarge();
   m_errMeasure = 0.080; // + .030 * m_size;
   m_trajectory = ftMat->trajectory(m_cluster.channelID(), m_cluster.fraction());
   m_z = ftMat->globalZ();
-- 
GitLab


From fae38bea01157e7d1bdcf3bb5076b9c997d0ea12 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Wed, 16 Nov 2016 18:20:45 +0100
Subject: [PATCH 11/68] Updated new linker location

---
 Pr/PrMCTools/src/PrLHCbID2MCParticle.cpp     | 3 +--
 Tr/TrackMCTools/src/LHCbIDsToMCHits.cpp      | 4 ++--
 Tr/TrackMCTools/src/LHCbIDsToMCHits.h        | 3 +--
 Tr/TrackMCTools/src/LHCbIDsToMCParticles.cpp | 4 ++--
 Tr/TrackMCTools/src/LHCbIDsToMCParticles.h   | 3 +--
 5 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/Pr/PrMCTools/src/PrLHCbID2MCParticle.cpp b/Pr/PrMCTools/src/PrLHCbID2MCParticle.cpp
index a8838df294..96751f5d2e 100755
--- a/Pr/PrMCTools/src/PrLHCbID2MCParticle.cpp
+++ b/Pr/PrMCTools/src/PrLHCbID2MCParticle.cpp
@@ -8,7 +8,6 @@
 #include "Event/VPCluster.h"
 #include "Event/STCluster.h"
 #include "Event/OTTime.h"
-#include "Event/FTCluster.h"
 #include "Event/FTLiteCluster.h"
 
 // local
@@ -164,7 +163,7 @@ StatusCode PrLHCbID2MCParticle::execute() {
   
   //== FT
   if ( exist<FastClusterContainer<LHCb::FTLiteCluster,int> >(LHCb::FTLiteClusterLocation::Default) ) {
-    LinkedTo<LHCb::MCParticle> ftLink( evtSvc(), msgSvc(),LHCb::FTClusterLocation::Default );
+    LinkedTo<LHCb::MCParticle> ftLink( evtSvc(), msgSvc(),LHCb::FTLiteClusterLocation::Default );
     if ( !ftLink.notFound() ) {
       m_detectorLink = &ftLink;
       typedef FastClusterContainer<LHCb::FTLiteCluster,int> FTLiteClusters;
diff --git a/Tr/TrackMCTools/src/LHCbIDsToMCHits.cpp b/Tr/TrackMCTools/src/LHCbIDsToMCHits.cpp
index bf50c89052..489f0ee166 100755
--- a/Tr/TrackMCTools/src/LHCbIDsToMCHits.cpp
+++ b/Tr/TrackMCTools/src/LHCbIDsToMCHits.cpp
@@ -10,7 +10,7 @@
 #include "Event/VPCluster.h"
 #include "Event/OTTime.h"
 #include "Event/MuonCoord.h"
-#include "Event/FTCluster.h"
+#include "Event/FTLiteCluster.h"
 
 
 DECLARE_TOOL_FACTORY( LHCbIDsToMCHits )
@@ -219,7 +219,7 @@ void LHCbIDsToMCHits::linkFT(const LHCbID& lhcbid, LinkMap& output) const
 {
   if (!m_configuredFT){   
     m_configuredFT = true;
-    m_ftLinks = FTLinks( evtSvc(), msgSvc(),LHCb::FTClusterLocation::Default+m_endString);
+    m_ftLinks = FTLinks( evtSvc(), msgSvc(),LHCb::FTLiteClusterLocation::Default+m_endString);
     if (m_ftLinks.notFound()) {
       throw GaudiException("no FTLinker", "LHCbIDsToMCHits" ,
                            StatusCode::FAILURE);
diff --git a/Tr/TrackMCTools/src/LHCbIDsToMCHits.h b/Tr/TrackMCTools/src/LHCbIDsToMCHits.h
index 7d85e58a2e..59b049eb06 100755
--- a/Tr/TrackMCTools/src/LHCbIDsToMCHits.h
+++ b/Tr/TrackMCTools/src/LHCbIDsToMCHits.h
@@ -25,7 +25,6 @@ namespace LHCb{
   class MuonCoord;
   class VPCluster;
   class UTCluster;  
-  class FTCluster;
 }
 
 class LHCbIDsToMCHits: public GaudiTool, virtual public ILHCbIDsToMCHits,
@@ -90,7 +89,7 @@ private:
   typedef LinkedTo<LHCb::MCHit,LHCb::VeloCluster> VeloLinks;
   typedef LinkedTo<LHCb::MCHit,LHCb::VPCluster> VPLinks;
   typedef LinkedTo<LHCb::MCHit,LHCb::MuonCoord> MuonLinks;
-  typedef LinkedTo<LHCb::MCHit,LHCb::FTCluster> FTLinks;
+  typedef LinkedTo<LHCb::MCHit> FTLinks;
   
 
 
diff --git a/Tr/TrackMCTools/src/LHCbIDsToMCParticles.cpp b/Tr/TrackMCTools/src/LHCbIDsToMCParticles.cpp
index f23be3735a..6793cb7c66 100755
--- a/Tr/TrackMCTools/src/LHCbIDsToMCParticles.cpp
+++ b/Tr/TrackMCTools/src/LHCbIDsToMCParticles.cpp
@@ -8,7 +8,7 @@
 #include "Event/STCluster.h"
 #include "Event/VeloCluster.h"
 #include "Event/VPCluster.h"
-#include "Event/FTCluster.h"
+#include "Event/FTLiteCluster.h"
 #include "Event/OTTime.h"
 #include "Event/MuonCoord.h"
 
@@ -237,7 +237,7 @@ StatusCode LHCbIDsToMCParticles::linkFT(const LHCbID& lhcbid, LinkMap& output) c
   if (!m_configuredFT){
     m_configuredFT = true;
     m_ftLinks = FTLinks(evtSvc(), msgSvc(),
-                            LHCb::FTClusterLocation::Default);
+                            LHCb::FTLiteClusterLocation::Default);
     if (m_ftLinks.notFound()) {
       return Error("no FTLinker",StatusCode::FAILURE,10);
     }
diff --git a/Tr/TrackMCTools/src/LHCbIDsToMCParticles.h b/Tr/TrackMCTools/src/LHCbIDsToMCParticles.h
index 2ef15bb77f..e941842c82 100755
--- a/Tr/TrackMCTools/src/LHCbIDsToMCParticles.h
+++ b/Tr/TrackMCTools/src/LHCbIDsToMCParticles.h
@@ -24,7 +24,6 @@ namespace LHCb{
   class VeloCluster;
   class MuonCoord;
   class VPCluster;
-  class FTCluster; 
 }
 
 class LHCbIDsToMCParticles: public GaudiTool, virtual public ILHCbIDsToMCParticles,
@@ -90,7 +89,7 @@ private:
   typedef LinkedTo<LHCb::MCParticle,LHCb::MuonCoord> MuonLinks;
   // -- upgrade
   typedef LinkedTo<LHCb::MCParticle,LHCb::VPCluster> VPLinks;
-  typedef LinkedTo<LHCb::MCParticle,LHCb::FTCluster> FTLinks;
+  typedef LinkedTo<LHCb::MCParticle> FTLinks;
 
   template<typename ID, typename LINKER>
   void linkToDetTruth(const ID& id, LINKER& aLinker, LinkMap& output ) const;
-- 
GitLab


From 5c59feafff943df33ab8220d9a7f8746f7dc311b Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Wed, 14 Dec 2016 13:59:49 +0100
Subject: [PATCH 12/68] Updated release notes

---
 Pr/PrAlgorithms/doc/release.notes  | 4 ++++
 Pr/PrMCTools/doc/release.notes     | 4 ++++
 Tr/TrackFitEvent/doc/release.notes | 3 +++
 Tr/TrackMCTools/doc/release.notes  | 4 ++++
 Tr/TrackTools/doc/release.notes    | 4 ++++
 5 files changed, 19 insertions(+)

diff --git a/Pr/PrAlgorithms/doc/release.notes b/Pr/PrAlgorithms/doc/release.notes
index 8f2dbf7572..9b78e544d5 100644
--- a/Pr/PrAlgorithms/doc/release.notes
+++ b/Pr/PrAlgorithms/doc/release.notes
@@ -3,6 +3,10 @@
 ! Responsible : Yasmine Amhis
 ! Purpose     : Pattern reconstruction for the upgrade
 !-----------------------------------------------------------------------------
+
+! 2016-12-14 - Jeroen van Tilburg
+ - Adapt to new FT geometry and numbering scheme
+
 2016-04-18 Renato Quagliani
  - Fix warnings for unused variables
 2016-04-18 Renato Quagliani
diff --git a/Pr/PrMCTools/doc/release.notes b/Pr/PrMCTools/doc/release.notes
index 93dd0ad667..429d61f803 100644
--- a/Pr/PrMCTools/doc/release.notes
+++ b/Pr/PrMCTools/doc/release.notes
@@ -4,6 +4,10 @@
 ! Purpose     : MC tools for pattern recognition for the Upgrade
 !-----------------------------------------------------------------------------
 
+! 2016-12-14 - Jeroen van Tilburg
+ - Adapt to new FT geometry and numbering scheme
+ - Changed location of Linker tables. 
+
 !========================= PrMCTools v2r12 2016-01-28 =========================
 ! 2016-01-21 Marco Cattaneo
  - Use std::abs instead of fabs for int argument, to silence clang warning
diff --git a/Tr/TrackFitEvent/doc/release.notes b/Tr/TrackFitEvent/doc/release.notes
index ebe90661e0..861836c30a 100755
--- a/Tr/TrackFitEvent/doc/release.notes
+++ b/Tr/TrackFitEvent/doc/release.notes
@@ -4,6 +4,9 @@
 ! Purpose     : Package for the tracking fitting-related classes
 !-----------------------------------------------------------------------------
 
+! 2016-12-14 - Jeroen van Tilburg
+ - Adapt to new FT geometry and numbering scheme
+
 !========================= TrackFitEvent v6r6 2016-01-28 =========================
 ! 2015-12-05 - Gerhard Raven
  - reduce mention of 'static' and 'std::auto_ptr' 
diff --git a/Tr/TrackMCTools/doc/release.notes b/Tr/TrackMCTools/doc/release.notes
index 4e14d1a888..d631e91644 100755
--- a/Tr/TrackMCTools/doc/release.notes
+++ b/Tr/TrackMCTools/doc/release.notes
@@ -4,6 +4,10 @@
 ! Purpose     : package for tracking tools accessing MC information
 !-----------------------------------------------------------------------------
 
+! 2016-12-14 - Jeroen van Tilburg
+ - Adapt to new FT geometry and numbering scheme
+ - Changed location of Linker tables. 
+
 !========================= TrackMCTools v3r13 2016-03-18 =========================
 ! 2016-02-08 - Adam Davis
  - Add more debugging tools for PatLongLivedTracking
diff --git a/Tr/TrackTools/doc/release.notes b/Tr/TrackTools/doc/release.notes
index 403a8e9a81..944ec15f97 100755
--- a/Tr/TrackTools/doc/release.notes
+++ b/Tr/TrackTools/doc/release.notes
@@ -4,6 +4,10 @@
 ! Purpose     : Package for tracking tools not accessing MC information
 !-----------------------------------------------------------------------------
 
+! 2016-12-14 - Jeroen van Tilburg
+ - Adapt to new FT geometry and numbering scheme
+ - Changed location of Linker tables. 
+
 ! 2016-06-22 - David Hutchcroft
  - Added code to set the pT of the VELO only tracks with a sign based on the first strip 
    in the first cluster rather than the track key (which was random). Also an option to reverse the sign 
-- 
GitLab


From 918076c9b1d27b231d39c25dd6162deb56990509 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Thu, 15 Dec 2016 13:28:52 +0100
Subject: [PATCH 13/68] Fixing initialization with nullptr

---
 Pr/PrAlgorithms/src/PrFTHitManager.h   | 2 +-
 Tr/TrackTools/src/FTHitExpectation.cpp | 3 +--
 Tr/TrackTools/src/FTHitExpectation.h   | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/Pr/PrAlgorithms/src/PrFTHitManager.h b/Pr/PrAlgorithms/src/PrFTHitManager.h
index 8240041be7..7a84e409b0 100644
--- a/Pr/PrAlgorithms/src/PrFTHitManager.h
+++ b/Pr/PrAlgorithms/src/PrFTHitManager.h
@@ -37,6 +37,6 @@ public:
 protected:
 
  private:
-  DeFTDetector* m_ftDet;
+  DeFTDetector* m_ftDet = nullptr;
 };
 #endif // PRFTHITMANAGER_H
diff --git a/Tr/TrackTools/src/FTHitExpectation.cpp b/Tr/TrackTools/src/FTHitExpectation.cpp
index 88c41c2717..03961af6c9 100644
--- a/Tr/TrackTools/src/FTHitExpectation.cpp
+++ b/Tr/TrackTools/src/FTHitExpectation.cpp
@@ -34,8 +34,7 @@ FTHitExpectation::FTHitExpectation(const std::string& type,
 				   const std::string& name,
 				   const IInterface* parent
 				   ):
-THitExpectation(type, name, parent),
-  m_ftDet( NULL )
+THitExpectation(type, name, parent)
 {
   // constructor
 }
diff --git a/Tr/TrackTools/src/FTHitExpectation.h b/Tr/TrackTools/src/FTHitExpectation.h
index a4df836833..2ed2daac5d 100644
--- a/Tr/TrackTools/src/FTHitExpectation.h
+++ b/Tr/TrackTools/src/FTHitExpectation.h
@@ -76,7 +76,7 @@ private:
 
   Gaudi::XYZPoint intersection(const Tf::Tsa::Line3D& line, const Gaudi::Plane3D& aPlane) const;
 
-  DeFTDetector* m_ftDet;
+  DeFTDetector* m_ftDet = nullptr;
  
 };
 
-- 
GitLab


From 23163654b723af9f3386a0e87829025dad4ac82e Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:20:29 +0000
Subject: [PATCH 14/68] Make sure sequence memers are reset

---
 .../RichFutureRecSys/ConfiguredRichReco.py    |   9 +-
 Rich/RichRecTests/CMakeLists.txt              |  46 ++++++++
 Rich/RichRecTests/src/PhotonReco/main.cpp     | 110 ++++++++++++++++++
 3 files changed, 160 insertions(+), 5 deletions(-)
 create mode 100644 Rich/RichRecTests/CMakeLists.txt
 create mode 100644 Rich/RichRecTests/src/PhotonReco/main.cpp

diff --git a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
index d4124f78e8..e99f4138a7 100644
--- a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
+++ b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
@@ -243,9 +243,6 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
     if algprops["Detectors"][0] : pixname += "RICH1"
     if algprops["Detectors"][1] : pixname += "RICH2"
 
-    # The complete sequence
-    all = GaudiSequencer( "RichRecoSeq" + GroupName, MeasureTime = MeasureTime )
-
     # ==================================================================
     # RICH Pixel Treatment. Common to all track types and instanciations
     # of the RICH sequences.
@@ -291,8 +288,9 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
     pixels = GaudiSequencer( "RichPixels"+GroupName,
                              MeasureTime = MeasureTime,
                              Members = [ richCluster, richGloPoints, richLocPoints ] )
-    # Add to final sequence
-    all.Members += [ pixels ]
+        # The complete sequence
+    all = GaudiSequencer( "RichRecoSeq" + GroupName, MeasureTime = MeasureTime )
+    all.Members = [pixels]
 
     # Loop over tracks
     for tktype,trackLocation in inputTrackLocations.iteritems() :
@@ -308,6 +306,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
 
         # Sequencer for this track type
         tkSeq = GaudiSequencer( "Rich"+name+"Reco", MeasureTime = MeasureTime )
+        tkSeq.Members = [ ] # make sure empty
         all.Members += [ tkSeq ]
         
         # ==================================================================
diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
new file mode 100644
index 0000000000..2c8215cc26
--- /dev/null
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -0,0 +1,46 @@
+################################################################################
+# Package: RichRecTests
+################################################################################
+gaudi_subdir(RichRecTests v1r0)
+
+gaudi_depends_on_subdirs(Det/RichDet
+                         GaudiKernel
+                         Kernel/LHCbKernel
+                         Kernel/LHCbMath
+                         Kernel/VectorClass
+                         Kernel/Vc
+                         Rich/RichRecUtils)
+
+#find_package(vectorclass)
+find_package(Boost)
+find_package(GSL)
+find_package(Eigen)
+find_package(Vc)
+find_package(ROOT COMPONENTS MathCore GenVector)
+
+message(STATUS "Using Vc ${Vc_INCLUDE_DIR} ${Vc_LIB_DIR}")
+message(STATUS "Vc DEFINITIONS ${Vc_DEFINITIONS}")
+message(STATUS "Vc COMPILE flags ${Vc_COMPILE_FLAGS}")
+message(STATUS "Vc ARCHITECTURE flags ${Vc_ARCHITECTURE_FLAGS}")
+
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
+                           ${EIGEN_INCLUDE_DIRS} ${Vc_INCLUDE_DIR})
+
+if(GAUDI_BUILD_TESTS)
+
+  gaudi_add_executable(RichPhotonRecoTest
+                       src/PhotonReco/*.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichPhotonRecoTest -lrt ) 
+
+  set_property(SOURCE src/RayTracing/main.cpp PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes" )
+  #set_property(SOURCE src/RayTracing/main.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 -O3 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " ) 
+
+  gaudi_add_executable(RichRayTracingTest
+                       src/RayTracing/*.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichRayTracingTest "-lrt ${Vc_LIB_DIR}/libVc.a" )
+
+endif()
diff --git a/Rich/RichRecTests/src/PhotonReco/main.cpp b/Rich/RichRecTests/src/PhotonReco/main.cpp
new file mode 100644
index 0000000000..01257568e5
--- /dev/null
+++ b/Rich/RichRecTests/src/PhotonReco/main.cpp
@@ -0,0 +1,110 @@
+
+// Quartic Solver
+#include "RichRecUtils/QuarticSolver.h"
+
+// STL
+#include <random>
+#include <vector>
+#include <iostream>
+#include <string>
+#include <typeinfo>
+
+// Make an instance of the quartic solver
+Rich::Rec::QuarticSolver qSolver;
+
+Gaudi::XYZPoint sphReflPoint;
+
+unsigned long long int time_diff( struct timespec *start, 
+                                  struct timespec *stop ) 
+{
+  if ((stop->tv_nsec - start->tv_nsec) < 0) {
+    return 1000000000ULL * (stop->tv_sec - start->tv_sec - 1) +
+      stop->tv_nsec - start->tv_nsec + 1000000000ULL;
+  } else {
+    return 1000000000ULL * (stop->tv_sec - start->tv_sec) +
+      stop->tv_nsec - start->tv_nsec;
+  }
+}
+
+class Data
+{
+public:
+  typedef std::vector<Data> Vector;
+public:
+  Gaudi::XYZPoint emissPnt;
+  Gaudi::XYZPoint centOfCurv;
+  Gaudi::XYZPoint virtDetPoint;
+  double           radius;
+public:
+  Data() 
+  {
+    // randomn generator
+    static std::default_random_engine gen;
+    // Distributions for each member
+    static std::uniform_real_distribution<double> r_emiss_x(-800,800), r_emiss_y(-600,600), r_emiss_z(10000,10500);
+    static std::uniform_real_distribution<double> r_coc_x(-3000,3000), r_coc_y(-20,20),     r_coc_z(3300,3400);
+    static std::uniform_real_distribution<double> r_vdp_x(-3000,3000), r_vdp_y(-200,200),   r_vdp_z(8100,8200);
+    static std::uniform_real_distribution<float>  r_rad(8500,8600);
+    // setup data
+    emissPnt     = Gaudi::XYZPoint( r_emiss_x(gen), r_emiss_y(gen), r_emiss_z(gen) );
+    centOfCurv   = Gaudi::XYZPoint( r_coc_x(gen),   r_coc_y(gen),   r_coc_z(gen)   );
+    virtDetPoint = Gaudi::XYZPoint( r_vdp_x(gen),   r_vdp_y(gen),   r_vdp_z(gen)   );
+    radius       = r_rad(gen);
+  }
+};
+
+template< class TYPE >
+inline void solve( const Data& data )
+{
+  qSolver.solve<TYPE>( data.emissPnt, 
+                       data.centOfCurv, 
+                       data.virtDetPoint,
+                       data.radius, 
+                       sphReflPoint );
+}
+
+template< class TYPE >
+unsigned long long int __attribute__((noinline)) solve( const Data::Vector & dataV )
+{
+  unsigned long long int best_dur{ 99999999999999999 };
+
+  timespec start, end;
+
+  const unsigned int nTests = 1000;
+  for ( unsigned int i = 0; i < nTests; ++i )
+  {
+    clock_gettime(CLOCK_MONOTONIC_RAW,&start);
+    // iterate over the data and solve it...
+    for ( const auto& data : dataV ) { solve<TYPE>(data); }
+    clock_gettime(CLOCK_MONOTONIC_RAW,&end);
+    const auto duration = time_diff(&start,&end);
+    if ( duration < best_dur ) { best_dur = duration; }
+  }
+
+  return best_dur ;
+}
+
+int main ( int /*argc*/, char** /*argv*/ )
+{
+  const unsigned int nPhotons = 1e4;
+  
+  Data::Vector dataV;
+  dataV.reserve( nPhotons );
+  // Construct the data to work on
+  std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
+  for ( unsigned int i = 0; i < nPhotons; ++i ) { dataV.push_back( Data() ); }
+
+  // run the solver for floats
+  auto fTime = solve<float>( dataV );
+  std::cout << "Float  " << fTime << std::endl;
+
+  // run the solver for doubles
+  auto dTime = solve<double>( dataV );
+  std::cout << "Double " << dTime << std::endl;
+
+  // make sure we are not optimized away
+  asm volatile ("" : "+x"(fTime));
+  asm volatile ("" : "+x"(dTime));
+
+  return 0;
+}
-- 
GitLab


From ce10e2492bfb317abfbaa29bf14f137337bf89d4 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:21:22 +0000
Subject: [PATCH 15/68] Protect debug statement

---
 Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.cpp
index 14b9006693..65b1025f2b 100755
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.cpp
@@ -40,7 +40,7 @@ StatusCode BaseTrSegMaker::initialize()
 
   if ( !usedRads(Rich::Aerogel) )
   {
-    debug() << "Track segments for Aerogel are disabled" << endmsg;
+    _ri_debug << "Track segments for Aerogel are disabled" << endmsg;
     //Warning("Track segments for Aerogel are disabled",StatusCode::SUCCESS).ignore();
     //made into debug as it is still too verbose as a warning
   }
-- 
GitLab


From 04780b1e1a7e8066002b4db2985ab31520dbd12e Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:21:50 +0000
Subject: [PATCH 16/68] Move test applications to Rich/RichRecTests

---
 Rich/RichRecPhotonTools/CMakeLists.txt | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/Rich/RichRecPhotonTools/CMakeLists.txt b/Rich/RichRecPhotonTools/CMakeLists.txt
index c551830b1f..231f8c58a3 100644
--- a/Rich/RichRecPhotonTools/CMakeLists.txt
+++ b/Rich/RichRecPhotonTools/CMakeLists.txt
@@ -24,9 +24,3 @@ gaudi_add_module(RichRecPhotonTools
                  INCLUDE_DIRS Eigen Boost GSL VectorClass src
                  LINK_LIBRARIES Boost GSL RichDetLib GaudiKernel LHCbKernel LHCbMathLib RichKernelLib RichRecBase)
 
-if(GAUDI_BUILD_TESTS)
-  gaudi_add_executable(RichPhotonRecoTest
-                       src/application/PhotonReco/*.cpp
-                       INCLUDE_DIRS ROOT Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel ROOT)
-endif()
-- 
GitLab


From 59a5f1a007dc30496aad5023dc7d6d35e736a9c1 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:22:21 +0000
Subject: [PATCH 17/68] Add ray tracing test application

---
 Rich/RichRecTests/src/RayTracing/main.cpp | 252 ++++++++++++++++++++++
 1 file changed, 252 insertions(+)
 create mode 100644 Rich/RichRecTests/src/RayTracing/main.cpp

diff --git a/Rich/RichRecTests/src/RayTracing/main.cpp b/Rich/RichRecTests/src/RayTracing/main.cpp
new file mode 100644
index 0000000000..7b109c29e2
--- /dev/null
+++ b/Rich/RichRecTests/src/RayTracing/main.cpp
@@ -0,0 +1,252 @@
+
+// STL
+#include <random>
+#include <vector>
+#include <iostream>
+#include <string>
+#include <typeinfo>
+
+// LHCbMath
+#include "LHCbMath/EigenTypes.h"
+#include "LHCbMath/VectorClassTypes.h"
+
+// Rich Utils
+#include "RichUtils/RichRayTracingUtils.h"
+#include "RichUtils/ZipRange.h"
+
+#include <Vc/Vc>
+
+unsigned long long int time_diff( struct timespec *start, 
+                                  struct timespec *stop ) 
+{
+  if ((stop->tv_nsec - start->tv_nsec) < 0) {
+    return 1000000000ULL * (stop->tv_sec - start->tv_sec - 1) +
+      stop->tv_nsec - start->tv_nsec + 1000000000ULL;
+  } else {
+    return 1000000000ULL * (stop->tv_sec - start->tv_sec) +
+      stop->tv_nsec - start->tv_nsec;
+  }
+}
+
+// randomn generator
+static std::default_random_engine gen;
+// Distributions for each member
+static std::uniform_real_distribution<double> p_x(-800,800),  p_y(-600,600), p_z(10000,10500);
+static std::uniform_real_distribution<double> d_x(-0.2,0.2),  d_y(-0.1,0.1), d_z(0.95,0.99);
+static std::uniform_real_distribution<double> c_x(3100,3200), c_y(10,15),    c_z(3200,3300);
+static std::uniform_real_distribution<double> r_rad(8500,8600);
+static std::uniform_real_distribution<double> p0(-0.002,0.002), p1(-0.2,0.2), p2(0.97,0.99), p3(-1300,1300);
+
+template < typename POINT, typename VECTOR, typename PLANE, typename FTYPE >
+class Data
+{
+public:
+  typedef std::vector<Data> Vector;
+public:
+  POINT position;
+  VECTOR direction;
+  POINT CoC;
+  PLANE plane;
+  FTYPE radius{0};
+public:
+  template< typename INDATA >
+  Data( const INDATA & ind )
+    : position(ind.position),
+      direction(ind.direction),
+      CoC(ind.CoC),
+      plane(ind.plane),
+      radius(ind.radius) { }
+  Data( )
+    : position  ( p_x(gen), p_y(gen), p_z(gen) ),
+      direction ( d_x(gen), d_y(gen), d_z(gen) ),
+      CoC       ( c_x(gen), c_y(gen), c_z(gen) ),
+      plane     ( p0(gen),  p1(gen),  p2(gen), p3(gen) ), 
+      radius    ( r_rad(gen) ) { }
+};
+
+template < typename DATA >
+inline void trace( DATA & dataV )
+{
+  using namespace Rich::RayTracingUtils;
+  for ( auto & data : dataV )
+  {
+    reflectSpherical( data.position, data.direction, data.CoC, data.radius );
+  }
+}
+
+
+template < typename DATA >
+unsigned long long int __attribute__((noinline)) rayTrace( const DATA & in_dataV )
+{
+  timespec start, end;
+
+  unsigned long long int best_dur{ 99999999999999999 };
+
+  const unsigned int nTests = 10000;
+  for ( unsigned int i = 0; i < nTests; ++i )
+  {
+    auto dataV = in_dataV; // copy data, as it will be modified
+    clock_gettime(CLOCK_MONOTONIC_RAW,&start);
+    trace( dataV );
+    clock_gettime(CLOCK_MONOTONIC_RAW,&end);
+    const auto duration = time_diff(&start,&end);
+    if ( duration < best_dur ) { best_dur = duration; }
+  }
+
+  return best_dur ;
+}
+
+int main ( int /*argc*/, char** /*argv*/ )
+{
+
+  const unsigned int nPhotons = 96 * 1e2;
+  std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
+
+  // Vc
+  using VcXYZPointD  = ROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorD = ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZPointF  = ROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorF = ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+
+  //if ( false )
+  {
+
+    // Data in 'ROOT' SMatrix double format
+    Data<Gaudi::XYZPoint,Gaudi::XYZVector,Gaudi::Plane3D,Gaudi::XYZVector::Scalar>::Vector root_dataV( nPhotons );
+    auto resROOT = rayTrace( root_dataV );
+    std::cout << "ROOT double        " << resROOT << std::endl;
+
+    // Same data in Eigen double format
+    Data<LHCb::Math::Eigen::XYZPoint<double>,LHCb::Math::Eigen::XYZVector<double>,double>::Vector eigen_dataV( nPhotons );
+    auto resEIGEN = rayTrace( eigen_dataV );
+    std::cout << "Eigen double       " << resEIGEN << " speedup " << (float)resROOT/(float)resEIGEN << std::endl;
+ 
+    // _mm256_zeroupper();
+
+    // Same data in VectorClass double format
+    Data<LHCb::Math::VectorClass::XYZPoint<double>,LHCb::Math::VectorClass::XYZVector<double>,double>::Vector vclass_dataV( nPhotons );
+    auto resVClass = rayTrace( vclass_dataV );
+    std::cout << "VectorClass double " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
+
+    // Vc float
+    Data<VcXYZPointD,VcXYZVectorD,Vc::double_v>::Vector VC_dataV( nPhotons / Vc::double_v::Size );
+    auto resVC = rayTrace( VC_dataV );
+    std::cout << "Vc double          " << resVC << " speedup " << (float)resROOT/(float)resVC << std::endl;
+
+    // make sure we are not optimized away
+    asm volatile ("" : "+x"(resROOT));
+    asm volatile ("" : "+x"(resEIGEN));
+    asm volatile ("" : "+x"(resVClass));
+    asm volatile ("" : "+x"(resVC));
+
+  }
+
+  //if ( false )
+  {
+
+   // Data in 'ROOT' SMatrix double format
+    Data<Gaudi::XYZPointF,Gaudi::XYZVectorF,Gaudi::Plane3DF,Gaudi::XYZVectorF::Scalar>::Vector root_dataV( nPhotons );
+    auto resROOT = rayTrace( root_dataV );
+    std::cout << "ROOT float         " << resROOT << std::endl;
+
+    // Same data in Eigen double format
+    Data<LHCb::Math::Eigen::XYZPoint<float>,LHCb::Math::Eigen::XYZVector<float>,float>::Vector eigen_dataV( nPhotons );
+    auto resEIGEN = rayTrace( eigen_dataV );
+    std::cout << "Eigen float        " << resEIGEN << " speedup " << (float)resROOT/(float)resEIGEN << std::endl;
+
+    // Same data in VectorClass double format
+    Data<LHCb::Math::VectorClass::XYZPoint<float>,LHCb::Math::VectorClass::XYZVector<float>,float>::Vector vclass_dataV( nPhotons );
+    auto resVClass = rayTrace( vclass_dataV );
+    std::cout << "VectorClass float  " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
+
+    // Vc float
+    Data<VcXYZPointF,VcXYZVectorF,Vc::float_v>::Vector VC_dataV( nPhotons / Vc::float_v::Size );
+    auto resVC = rayTrace( VC_dataV );
+    std::cout << "Vc float           " << resVC << " speedup " << (float)resROOT/(float)resVC << std::endl;
+
+    // make sure we are not optimized away
+    asm volatile ("" : "+x"(resROOT));
+    asm volatile ("" : "+x"(resEIGEN));
+    asm volatile ("" : "+x"(resVClass));
+    asm volatile ("" : "+x"(resVC));
+
+  }
+
+  // Basic checks
+  if ( false )
+  {
+
+    std::vector< Vc::float_v > a = { 1, 2, 3, 4, 5, 6, 7, 8 };
+    std::vector< Vc::float_v > b = { 1, 2, 3, 4, 5, 6, 7, 8 };
+    
+    std::cout << "Size " << a.size() << " " << Vc::float_v::Size << std::endl;
+    
+    for ( unsigned int i = 0; i < (a.size()/Vc::float_v::Size); ++i )
+    {
+      a[i] += b[i];
+      std::cout << "Filling " << i << " " << a[i] << " " << b[i] << std::endl;
+    }
+    
+    for ( unsigned int i = 0; i < a.size(); ++i )
+    {
+      std::cout << "Reading " << i << " " << a[i] << " " << b[i] << std::endl;
+    }
+
+  }
+
+
+  // VC example
+  if ( false )
+  {
+    
+    using Vc::float_v;
+    //! [includes]
+    
+    //! [memory allocation]
+
+    // allocate memory for our initial x and y coordinates. Note that you can also put it into a
+    // normal float C-array but that you then must ensure alignment to Vc::VectorAlignment!
+    Vc::Memory<float_v, 100> x_mem;
+    Vc::Memory<float_v, 100> y_mem;
+    Vc::Memory<float_v, 100> r_mem;
+    Vc::Memory<float_v, 100> phi_mem;
+    //! [memory allocation]
+
+    //! [random init]
+    // fill the memory with values from -1.f to 1.f
+    std::cout << "vectorsCount = " << x_mem.vectorsCount() << std::endl;
+    for (size_t i = 0; i < x_mem.vectorsCount(); ++i)
+    {
+      x_mem.vector(i) = float_v::Random() * 2.f - 1.f;
+      y_mem.vector(i) = float_v::Random() * 2.f - 1.f;
+    }
+    //! [random init]
+
+    //! [conversion]
+    // calculate the polar coordinates for all coordinates and overwrite the euclidian coordinates
+    // with the result
+    for (size_t i = 0; i < x_mem.vectorsCount(); ++i) 
+    {
+      const float_v x = x_mem.vector(i);
+      const float_v y = y_mem.vector(i);
+      
+      r_mem.vector(i) = Vc::sqrt(x * x + y * y);
+      float_v phi = Vc::atan2(y, x) * 57.295780181884765625f; // 180/pi
+      phi(phi < 0.f) += 360.f;
+      phi_mem.vector(i) = phi;
+    }
+    //! [conversion]
+    
+    //! [output]
+    // print the results
+    std::cout << "entriesCount = " << x_mem.entriesCount() << std::endl;
+    for (size_t i = 0; i < x_mem.entriesCount(); ++i) {
+      std::cout << std::setw(3) << i << ": ";
+      std::cout << std::setw(10) << x_mem[i] << ", " << std::setw(10) << y_mem[i] << " -> ";
+      std::cout << std::setw(10) << r_mem[i] << ", " << std::setw(10) << phi_mem[i] << '\n';
+    }
+    
+  }
+
+  return 0;
+}
-- 
GitLab


From 9e09fcf9d8d2ac60a6767894f96b689967c93d53 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:22:49 +0000
Subject: [PATCH 18/68] Minor updates to QuarticSolver.h

---
 .../RichRecUtils/RichRecUtils/QuarticSolver.h | 197 +++++++++---------
 1 file changed, 95 insertions(+), 102 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
index 4fbabe905e..067801e216 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
@@ -7,8 +7,7 @@
  */
 //----------------------------------------------------------------------
 
-#ifndef RICHRECPHOTONTOOLS_QuarticSolver_H
-#define RICHRECPHOTONTOOLS_QuarticSolver_H 1
+#pragma once
 
 // Gaudi
 #include "GaudiKernel/Kernel.h"
@@ -52,100 +51,6 @@ namespace Rich
     class QuarticSolver final
     {
 
-    public:
-
-      // Use eigen types
-      typedef LHCb::Math::Eigen::XYZPoint  Point;   ///< Point type
-      typedef LHCb::Math::Eigen::XYZVector Vector;  ///< vector type
-
-    public:
-
-      /** Solves the characteristic quartic equation for the RICH optical system.
-       *
-       *  See note LHCB/98-040 RICH section 3 for more details
-       *
-       *  @param emissionPoint Assumed photon emission point on track
-       *  @param CoC           Spherical mirror centre of curvature
-       *  @param virtDetPoint  Virtual detection point
-       *  @param radius        Spherical mirror radius of curvature
-       *  @param sphReflPoint  The reconstructed reflection pont on the spherical mirror
-       *
-       *  @return boolean indicating status of the quartic solution
-       *  @retval true  Calculation was successful. sphReflPoint is valid.
-       *  @retval false Calculation failed. sphReflPoint is not valid.
-       */
-      template< class TYPE >
-      inline void solve( const Gaudi::XYZPoint& emissionPoint,
-                         const Gaudi::XYZPoint& CoC,
-                         const Gaudi::XYZPoint& virtDetPoint,
-                         const TYPE radius,
-                         Gaudi::XYZPoint& sphReflPoint ) const
-      {
-
-        // typedefs vectorised types
-        typedef Eigen::Matrix< TYPE , 3 , 1 > Eigen3Vector;
-        using Vec4x = 
-          typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
-
-        // vector from mirror centre of curvature to assumed emission point
-        const Vector evec( emissionPoint - CoC );
-        const TYPE e2 = evec.dot(evec);
-
-        // vector from mirror centre of curvature to virtual detection point
-        const Vector dvec( virtDetPoint - CoC );
-        const TYPE d2 = dvec.dot(dvec);
-
-        // various quantities needed to create quartic equation
-        // see LHCB/98-040 section 3, equation 3
-        const auto ed2 = e2 * d2;
-        const TYPE cosgamma2 = ( ed2 > 0 ? std::pow(evec.dot(dvec),2)/ed2 : 1.0 );
-        // vectorise 4 square roots into 1
-        const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
-                                           cosgamma2 < 1.0 ? 1.0-cosgamma2 : 0.0,
-                                           cosgamma2 ) );
-        const auto e         = tmp_sqrt[0];
-        const auto d         = tmp_sqrt[1];
-        const auto singamma  = tmp_sqrt[2];
-        const auto cosgamma  = tmp_sqrt[3];
-
-        const auto dx        = d * cosgamma;
-        const auto dy        = d * singamma;
-        const auto r2        = radius * radius;
-        const auto dy2       = dy * dy;
-        const auto edx       = e + dx;
-
-        // Fill array for quartic equation
-        const auto a0      =     4.0 * ed2;
-        const auto inv_a0  =   ( a0 > 0 ? 1.0 / a0 : std::numeric_limits<TYPE>::max() );
-        const auto dyrad2  =     2.0 * dy * radius;
-        const auto a1      = - ( 2.0 * dyrad2 * e2 ) * inv_a0;
-        const auto a2      =   ( (dy2 * r2) + ( edx * edx * r2 ) - a0 ) * inv_a0;
-        const auto a3      =   ( dyrad2 * e * (e-dx) ) * inv_a0;
-        const auto a4      =   ( ( e2 - r2 ) * dy2 ) * inv_a0;
-
-        // use simplified RICH version of quartic solver
-        const auto sinbeta = solve_quartic_RICH<TYPE>( a1, // a
-                                                       a2, // b
-                                                       a3, // c
-                                                       a4  // d
-                                                       );
-
-        // (normalised) normal vector to reflection plane
-        auto n = evec.cross3(dvec);
-        n /= std::sqrt( n.dot(n) );
-
-        // construct rotation transformation
-        // Set vector magnitude to radius
-        // rotate vector and update reflection point
-        const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
-                                                Eigen3Vector(n[0],n[1],n[2]) );
-        sphReflPoint = ( CoC + 
-                         Gaudi::XYZVector( angleaxis *
-                                           Eigen3Vector(evec[0],evec[1],evec[2]) *
-                                           ( radius / e ) ) );
-
-      }
-
     private:
 
       /// The cube root implementaton to use
@@ -169,10 +74,10 @@ namespace Rich
        */
       //----------------------------------------------------------------------
       template < class TYPE >
-      inline TYPE solve_quartic_RICH ( const TYPE& a,
-                                       const TYPE& b,
-                                       const TYPE& c,
-                                       const TYPE& d ) const 
+      inline TYPE solve_quartic_RICH ( const TYPE a,
+                                       const TYPE b,
+                                       const TYPE c,
+                                       const TYPE d ) const 
       {
 
         constexpr const TYPE r4 = 1.0 / 4.0;
@@ -237,9 +142,97 @@ namespace Rich
                  res );
       }
 
+    public:
+
+      /** Solves the characteristic quartic equation for the RICH optical system.
+       *
+       *  See note LHCB/98-040 RICH section 3 for more details
+       *
+       *  @param emissionPoint Assumed photon emission point on track
+       *  @param CoC           Spherical mirror centre of curvature
+       *  @param virtDetPoint  Virtual detection point
+       *  @param radius        Spherical mirror radius of curvature
+       *  @param sphReflPoint  The reconstructed reflection pont on the spherical mirror
+       *
+       *  @return boolean indicating status of the quartic solution
+       *  @retval true  Calculation was successful. sphReflPoint is valid.
+       *  @retval false Calculation failed. sphReflPoint is not valid.
+       */
+      template< class TYPE >
+      inline void solve( const Gaudi::XYZPoint& emissionPoint,
+                         const Gaudi::XYZPoint& CoC,
+                         const Gaudi::XYZPoint& virtDetPoint,
+                         const TYPE radius,
+                         Gaudi::XYZPoint& sphReflPoint ) const
+      {
+ 
+        // typedefs vectorised types
+        using Eigen3Vector = Eigen::Matrix< TYPE , 3 , 1 >;
+        using Vector = LHCb::Math::Eigen::XYZVector<TYPE>;
+        using Point  = LHCb::Math::Eigen::XYZPoint<TYPE>;
+        using Vec4x  = 
+          typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
+
+        // vector from mirror centre of curvature to assumed emission point
+        const Vector evec( emissionPoint - CoC );
+        const TYPE e2 = evec.dot(evec);
+
+        // vector from mirror centre of curvature to virtual detection point
+        const Vector dvec( virtDetPoint - CoC );
+        const TYPE d2 = dvec.dot(dvec);
+
+        // various quantities needed to create quartic equation
+        // see LHCB/98-040 section 3, equation 3
+        const auto ed2 = e2 * d2;
+        const TYPE cosgamma2 = ( ed2 > 0 ? std::pow(evec.dot(dvec),2)/ed2 : 1.0 );
+        // vectorise 4 square roots into 1
+        const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
+                                           cosgamma2 < 1.0 ? 1.0-cosgamma2 : 0.0,
+                                           cosgamma2 ) );
+        const auto e         = tmp_sqrt[0];
+        const auto d         = tmp_sqrt[1];
+        const auto singamma  = tmp_sqrt[2];
+        const auto cosgamma  = tmp_sqrt[3];
+
+        const auto dx        = d * cosgamma;
+        const auto dy        = d * singamma;
+        const auto r2        = radius * radius;
+        const auto dy2       = dy * dy;
+        const auto edx       = e + dx;
+
+        // Fill array for quartic equation
+        const auto a0      =     4.0 * ed2;
+        const auto inv_a0  =   ( a0 > 0 ? 1.0 / a0 : std::numeric_limits<TYPE>::max() );
+        const auto dyrad2  =     2.0 * dy * radius;
+        const auto a1      = - ( 2.0 * dyrad2 * e2 ) * inv_a0;
+        const auto a2      =   ( (dy2 * r2) + ( edx * edx * r2 ) - a0 ) * inv_a0;
+        const auto a3      =   ( dyrad2 * e * (e-dx) ) * inv_a0;
+        const auto a4      =   ( ( e2 - r2 ) * dy2 ) * inv_a0;
+
+        // use simplified RICH version of quartic solver
+        const auto sinbeta = solve_quartic_RICH<TYPE>( a1, // a
+                                                       a2, // b
+                                                       a3, // c
+                                                       a4  // d
+                                                       );
+
+        // (normalised) normal vector to reflection plane
+        auto n = evec.cross3(dvec);
+        n /= std::sqrt( n.dot(n) );
+
+        // construct rotation transformation
+        // Set vector magnitude to radius
+        // rotate vector and update reflection point
+        const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
+                                                Eigen3Vector(n[0],n[1],n[2]) );
+        sphReflPoint = ( CoC + 
+                         Gaudi::XYZVector( angleaxis *
+                                           Eigen3Vector(evec[0],evec[1],evec[2]) *
+                                           ( radius / e ) ) );
+
+      }
+
     };
 
   }
 }
-
-#endif // RICHRECPHOTONTOOLS_QuarticSolver_H
-- 
GitLab


From 06c90270d2591bf86dc63fbd17f9fc1223ffb0a1 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:23:19 +0000
Subject: [PATCH 19/68] update scripts

---
 Rich/RichFutureRecSys/examples/Brunel.py     | 6 +++---
 Rich/RichFutureRecSys/examples/RichFuture.py | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Rich/RichFutureRecSys/examples/Brunel.py b/Rich/RichFutureRecSys/examples/Brunel.py
index a522b3d505..afccb289d4 100644
--- a/Rich/RichFutureRecSys/examples/Brunel.py
+++ b/Rich/RichFutureRecSys/examples/Brunel.py
@@ -45,13 +45,13 @@ Brunel().MCCheckSequence = richs+["PROTO"]
 #############################################################################
 
 # Timestamps in messages
-LHCbApp().TimeStamp = True
+#LHCbApp().TimeStamp = True
 
 Brunel().OutputType = 'None'
 importOptions("$APPCONFIGOPTS/Persistency/Compression-ZLIB-1.py")
 
-Brunel().EvtMax     = 5000
-Brunel().PrintFreq  = 500
+Brunel().EvtMax     = 500
+Brunel().PrintFreq  = 100
 
 #Brunel().Histograms = "Expert"
 
diff --git a/Rich/RichFutureRecSys/examples/RichFuture.py b/Rich/RichFutureRecSys/examples/RichFuture.py
index 0186612021..43d45a745e 100644
--- a/Rich/RichFutureRecSys/examples/RichFuture.py
+++ b/Rich/RichFutureRecSys/examples/RichFuture.py
@@ -94,7 +94,7 @@ RichCheck = RichRecCheckers( inputTrackLocations = tkLocs,
 # The final sequence to run
 all = GaudiSequencer( "All", Members = [ fetcher, odinDecode, richDecode, 
                                          tkUnpack, tkFilt, RichRec ] )
-all.Members += [ RichMoni ]
+#all.Members += [ RichMoni ]
 #all.Members += [ mcPUnpack, RichCheck ]
 all.MeasureTime = True
 
-- 
GitLab


From f83255de2ce63f0d2c568e07ee5e9a3b1e6e5b46 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:23:40 +0000
Subject: [PATCH 20/68] Fix doxygen comment

---
 .../src/RichTrackFunctionalCherenkovResolutions.h               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h b/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
index c8fc19ba0f..c5f3e88bef 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
@@ -53,7 +53,7 @@ namespace Rich
     namespace Rec
     {
 
-      /** @class RichTrackFunctionalCherenkovResolutions RichRichTrackFunctionalCherenkovResolutions.h
+      /** @class FunctionalCherenkovResolutions RichRichTrackFunctionalCherenkovResolutions.h
        *
        *  Computes the expected Cherenkov resolutions for the given track segments
        *
-- 
GitLab


From f5f46c8764569ff1a50bf04f7c86d322093f2970 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:24:21 +0000
Subject: [PATCH 21/68] remove moved file

---
 .../src/application/PhotonReco/main.cpp       | 81 -------------------
 1 file changed, 81 deletions(-)
 delete mode 100644 Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp

diff --git a/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp b/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp
deleted file mode 100644
index 20a2eb747d..0000000000
--- a/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-
-// Quartic Solver
-#include "RichRecUtils/QuarticSolver.h"
-
-// STL
-#include <random>
-#include <vector>
-#include <iostream>
-#include <string>
-#include <typeinfo>
-
-// Make an instance of the quartic solver
-Rich::Rec::QuarticSolver qSolver;
-
-Gaudi::XYZPoint sphReflPoint;
-
-class Data
-{
-public:
-  typedef std::vector<Data> Vector;
-public:
-  Gaudi::XYZPoint emissPnt;
-  Gaudi::XYZPoint centOfCurv;
-  Gaudi::XYZPoint virtDetPoint;
-  double           radius;
-public:
-  Data() 
-  {
-    // randomn generator
-    static std::default_random_engine gen;
-    // Distributions for each member
-    static std::uniform_real_distribution<double> r_emiss_x(-800,800), r_emiss_y(-600,600), r_emiss_z(10000,10500);
-    static std::uniform_real_distribution<double> r_coc_x(-3000,3000), r_coc_y(-20,20),     r_coc_z(3300,3400);
-    static std::uniform_real_distribution<double> r_vdp_x(-3000,3000), r_vdp_y(-200,200),   r_vdp_z(8100,8200);
-    static std::uniform_real_distribution<float>  r_rad(8500,8600);
-    // setup data
-    emissPnt     = Gaudi::XYZPoint( r_emiss_x(gen), r_emiss_y(gen), r_emiss_z(gen) );
-    centOfCurv   = Gaudi::XYZPoint( r_coc_x(gen),   r_coc_y(gen),   r_coc_z(gen)   );
-    virtDetPoint = Gaudi::XYZPoint( r_vdp_x(gen),   r_vdp_y(gen),   r_vdp_z(gen)   );
-    radius       = r_rad(gen);
-  }
-};
-
-template< class TYPE >
-void solve( const Data& data )
-{
-  qSolver.solve<TYPE>( data.emissPnt, 
-                       data.centOfCurv, 
-                       data.virtDetPoint,
-                       data.radius, 
-                       sphReflPoint );
-}
-
-template< class TYPE >
-void solve( const Data::Vector & dataV )
-{
-  std::cout << "Solving Quartic Equation for " 
-            << typeid(TYPE).name() 
-            << " Photons ..." << std::endl;
-  // iterate over the data and solve it...
-  for ( const auto& data : dataV ) { solve<TYPE>(data); }
-}
-
-int main ( int /*argc*/, char** /*argv*/ )
-{
-  const unsigned int nPhotons = 1e6;
-  
-  Data::Vector dataV;
-  dataV.reserve( nPhotons );
-  // Construct the data to work on
-  std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
-  for ( unsigned int i = 0; i < nPhotons; ++i ) { dataV.push_back( Data() ); }
-
-  // run the solver for floats
-  solve<float>( dataV );
-
-  // run the solver for doubles
-  solve<double>( dataV );
-
-  return 0;
-}
-- 
GitLab


From 83bba98f23cb07e920ee6ce840116196b219ed0c Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:24:41 +0000
Subject: [PATCH 22/68] Add Rich/RichRecTests to package list

---
 RecSys/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/RecSys/CMakeLists.txt b/RecSys/CMakeLists.txt
index 939db4b274..fce2385570 100644
--- a/RecSys/CMakeLists.txt
+++ b/RecSys/CMakeLists.txt
@@ -60,6 +60,7 @@ gaudi_depends_on_subdirs(Calo/CaloMoniDst
                          Rich/RichFutureRecSys
                          Rich/RichFutureRecMonitors
                          Rich/RichFutureRecCheckers
+                         Rich/RichRecTests
                          Tf/FastPV
                          Tf/FastVelo
                          Tf/PatAlgorithms
-- 
GitLab


From 980ae285ac340bfc627eea252788fd1f56548c30 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 14:25:09 +0000
Subject: [PATCH 23/68] Update alignment scripts

---
 .../RefractAndHPDJobs/CommonOptions.py        |   2 +-
 .../scripts/RefractAndHPDJobs/GetLFNsByRun.py | 158 +++++++++++-------
 2 files changed, 96 insertions(+), 64 deletions(-)

diff --git a/Rich/RichAlignment/scripts/RefractAndHPDJobs/CommonOptions.py b/Rich/RichAlignment/scripts/RefractAndHPDJobs/CommonOptions.py
index a051222bc3..af38d34c09 100644
--- a/Rich/RichAlignment/scripts/RefractAndHPDJobs/CommonOptions.py
+++ b/Rich/RichAlignment/scripts/RefractAndHPDJobs/CommonOptions.py
@@ -31,7 +31,7 @@ importOptions("$L0TCK/L0DUConfig.opts")
 # For 2016 data
 importOptions("$APPCONFIGOPTS/Brunel/DataType-2016.py")
 LHCbApp().DDDBtag    = "dddb-20150724"
-LHCbApp().CondDBtag  = "cond-20160517"
+LHCbApp().CondDBtag  = "cond-20170120-1"
 
 # Aerogel Sub Tiles
 #CondDB().LocalTags["LHCBCOND"] = ["rich1-20110624"]
diff --git a/Rich/RichAlignment/scripts/RefractAndHPDJobs/GetLFNsByRun.py b/Rich/RichAlignment/scripts/RefractAndHPDJobs/GetLFNsByRun.py
index 516bc597b7..ef223eb1d1 100755
--- a/Rich/RichAlignment/scripts/RefractAndHPDJobs/GetLFNsByRun.py
+++ b/Rich/RichAlignment/scripts/RefractAndHPDJobs/GetLFNsByRun.py
@@ -42,6 +42,8 @@ elif 2013 == year :
   ConfigV = ['Collision13','Protonion13','Ionproton13','Ionsmog']
 elif 2015 == year :
   ConfigV = ['Collision15','Collision15em','Protonhelium15','Protonneon15','Protonargon15','Lead15']
+elif 2016 == year :
+  ConfigV = ['Collision16']
 else:
   print 'Unknown year', year
   DIRAC.exit(2)
@@ -51,6 +53,10 @@ allOK = True
 # Dictionary for LFNs by Run
 RunLFNs = { }
 
+polarity = "MagUp"
+#polarity = "MagDown"
+#polarity = "All"
+
 startDate = getDate(year,startmonth,startday)
 endDate   = getDate(year,lastmonth,lastday)
 dict = { 'StartDate'        : startDate,
@@ -81,80 +87,106 @@ else:
   for run in runs :
 
     if maxrun == -1 or run <= maxrun :
-      
+        
       nRun += 1
 
-      for config in ConfigV :
-
-        type = 91000000 # EXPRESS Stream
-        if year == 2009 : type = 90000000 # Use full stream for 2009
-        if run > 71473  and run < 72332 : # Use FULL for first 14nb-1 in 2010
-          type = 90000000 # FULL Stream
-        if run > 77595  and run < 77624 : # Express disappeared for unknown reasons
-          type = 90000000 # FULL Stream
-        if run > 100256 and run < 102177 : # Express turned off by accident after 09/2011 TS
-          type = 90000000 # FULL Stream
-        if config == 'Collision11_25' : # No express for 2011 25ns tests
-          type = 90000000 # FULL Stream
-        if config == 'Protonion12' : # (Currently) no express stream for pA data
-          type = 90000000 # FULL Stream
-        if config == 'Protonion13' or config == 'Ionproton13' :
-          type = 90000000 # FULL Stream
-        #if  run > 77595  and run < 77624 : # Express disappeared for unknown reasons
-        if run > 157596 : # Express stream turned off in Run II
-          type = 90000000 # FULL Stream
-
-        typeS = "EXPRESS"
-        if type == 90000000 : typeS = "FULL"
-
-        # Processing pass. For 2011 express stream data used a Merged location
-        procpass = 'Real Data'
-        if year == 2011 and type != 90000000 :
-          procpass = 'Real Data/Merging'
-
-        # Raw files
-        bkDict = { 'ConfigName'        : 'LHCb',
-                   'ConfigVersion'     : config,
-                   'ProcessingPass'    : procpass,
-                   'FileType'          : 'ALL',
-                   'StartRun'          : run,
-                   'EndRun'            : run,
-                   'EventType'         : type }
-        resultB = database.getFilesWithGivenDataSets(bkDict)
-
-        if not resultB['OK']:
-          print "Error querying BK with", bkDict, resultB['Message']
-          allOK = False
-        else:
-          tmpLFNList = [ ]
-          for lfn in resultB['Value']:
-            filetype = lfn.split('.')[1]
-            if filetype == 'dst' or filetype == 'raw':
-              tmpLFNList += ["LFN:"+lfn.encode("ascii")]
-          tmpLFNList.sort()
-          if len(tmpLFNList) > 0 :
-            if run not in RunLFNs.keys() : RunLFNs[run] = [ ]
-            RunLFNs[run] += tmpLFNList
-
-      if not allOK : break
+      # Polarity ?
+      res = database.getRunInformations(int(run))
+      if polarity == "All" or polarity in res['Value']['DataTakingDescription'] :
+        
+        for config in ConfigV :
+
+          type = 91000000 # EXPRESS Stream
+          if year == 2009 : type = 90000000 # Use full stream for 2009
+          if run > 71473  and run < 72332 : # Use FULL for first 14nb-1 in 2010
+            type = 90000000 # FULL Stream
+          if run > 77595  and run < 77624 : # Express disappeared for unknown reasons
+            type = 90000000 # FULL Stream
+          if run > 100256 and run < 102177 : # Express turned off by accident after 09/2011 TS
+            type = 90000000 # FULL Stream
+          if config == 'Collision11_25' : # No express for 2011 25ns tests
+            type = 90000000 # FULL Stream
+          if config == 'Protonion12' : # (Currently) no express stream for pA data
+            type = 90000000 # FULL Stream
+          if config == 'Protonion13' or config == 'Ionproton13' :
+            type = 90000000 # FULL Stream
+          #if  run > 77595  and run < 77624 : # Express disappeared for unknown reasons
+          if run > 157596 : # Express stream turned off in Run II
+            type = 90000000 # FULL Stream
+          if  config == 'Collision16' :
+            type = 90000000 # FULL Stream
+
+          typeS = "EXPRESS"
+          if type == 90000000 : typeS = "FULL"
+
+          # Processing pass. For 2011 express stream data used a Merged location
+          procpass = 'Real Data'
+          if year == 2011 and type != 90000000 :
+            procpass = 'Real Data/Merging'
+
+          # Raw files
+          bkDict = { 'ConfigName'        : 'LHCb',
+                     'ConfigVersion'     : config,
+                     'ProcessingPass'    : procpass,
+                     'FileType'          : 'ALL',
+                     'StartRun'          : run,
+                     'EndRun'            : run,
+                     'EventType'         : type }
+          resultB = database.getFilesWithGivenDataSets(bkDict)
+
+          if not resultB['OK']:
+
+            print "Error querying BK with", bkDict, resultB['Message']
+            allOK = False
+
+          else:
+
+            tmpLFNList = [ ]
             
-      nLFNs = 0
-      if run in RunLFNs.keys() : nLFNs = len(RunLFNs[run])
-      if nLFNs > 0 :
-        print "(", nRun, "of", len(runs), ") Selected", nLFNs, "LFNs for run", run, ConfigV
-        print RunLFNs[run]
-      else:
-        print "(", nRun, "of", len(runs), ") No data selected for run", run, ConfigV
+            lfns = resultB['Value']
+            tmplfns = list( set(lfns) )
+            if len(tmplfns) != len(lfns) :
+              print "WARNING : run", run, "has duplicate LFNs"
+              print bkDict
+              print resultB['Value']
+              lfns = tmplfns
+
+            for lfn in lfns:
+              filetype = lfn.split('.')[1]
+              if filetype == 'dst' or filetype == 'raw':
+                tmpLFNList += ["LFN:"+lfn.encode("ascii")]
+
+            tmpLFNList.sort()
+            if len(tmpLFNList) > 0 :
+              if run not in RunLFNs.keys() : RunLFNs[run] = [ ]
+              RunLFNs[run] += tmpLFNList
+
+        if not allOK : break
+      
+        nLFNs = 0
+        if run in RunLFNs.keys() : nLFNs = len(RunLFNs[run])
+        if nLFNs > 0 :
+          print "(", nRun, "of", len(runs), ") Selected", nLFNs, "LFNs for run", run, ConfigV
+           #print RunLFNs[run]
+        else:
+          print "(", nRun, "of", len(runs), ") No data selected for run", run, ConfigV
 
-    else:
+      else :
+
+        print "(", nRun, "of", len(runs), ") Run", run, "has wrong polarity"
 
+    else:
+      
       print "Skipping run", run
         
 if allOK :
     
   # Pickle the data
   if len(RunLFNs.keys()) > 0:
-    filename = "RunData/RunLFNs_"+startDate+"_"+endDate+".pck.bz2"
+    if polarity == "All" :
+      filename = "RunData/RunLFNs_"+startDate+"_"+endDate+".pck.bz2"
+    else :
+      filename = "RunData/RunLFNs_"+polarity+"_"+startDate+"_"+endDate+".pck.bz2"
     file = bz2.BZ2File(filename,"w")
     pickle.dump(RunLFNs,file)
     file.close()
-- 
GitLab


From 594cfb11a38fbd5bab65fd0182ba3297bb46d28d Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Fri, 24 Feb 2017 19:07:26 +0000
Subject: [PATCH 24/68] update test application

---
 Rich/RichRecTests/src/RayTracing/main.cpp | 31 +++++++++++++++--------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/Rich/RichRecTests/src/RayTracing/main.cpp b/Rich/RichRecTests/src/RayTracing/main.cpp
index 7b109c29e2..8340ef59ab 100644
--- a/Rich/RichRecTests/src/RayTracing/main.cpp
+++ b/Rich/RichRecTests/src/RayTracing/main.cpp
@@ -10,6 +10,10 @@
 #include "LHCbMath/EigenTypes.h"
 #include "LHCbMath/VectorClassTypes.h"
 
+// LHCb TemplatedGenVector
+#include "TemplatedGenVector/DisplacementVector3D.h"
+#include "TemplatedGenVector/PositionVector3D.h"
+
 // Rich Utils
 #include "RichUtils/RichRayTracingUtils.h"
 #include "RichUtils/ZipRange.h"
@@ -37,7 +41,7 @@ static std::uniform_real_distribution<double> c_x(3100,3200), c_y(10,15),    c_z
 static std::uniform_real_distribution<double> r_rad(8500,8600);
 static std::uniform_real_distribution<double> p0(-0.002,0.002), p1(-0.2,0.2), p2(0.97,0.99), p3(-1300,1300);
 
-template < typename POINT, typename VECTOR, typename PLANE, typename FTYPE >
+template < typename POINT, typename VECTOR, typename FTYPE >
 class Data
 {
 public:
@@ -46,7 +50,7 @@ public:
   POINT position;
   VECTOR direction;
   POINT CoC;
-  PLANE plane;
+  //PLANE plane;
   FTYPE radius{0};
 public:
   template< typename INDATA >
@@ -54,13 +58,13 @@ public:
     : position(ind.position),
       direction(ind.direction),
       CoC(ind.CoC),
-      plane(ind.plane),
+      //  plane(ind.plane),
       radius(ind.radius) { }
   Data( )
     : position  ( p_x(gen), p_y(gen), p_z(gen) ),
       direction ( d_x(gen), d_y(gen), d_z(gen) ),
       CoC       ( c_x(gen), c_y(gen), c_z(gen) ),
-      plane     ( p0(gen),  p1(gen),  p2(gen), p3(gen) ), 
+      //plane     ( p0(gen),  p1(gen),  p2(gen), p3(gen) ), 
       radius    ( r_rad(gen) ) { }
 };
 
@@ -102,17 +106,24 @@ int main ( int /*argc*/, char** /*argv*/ )
   const unsigned int nPhotons = 96 * 1e2;
   std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
 
+  // Templated GenVector
+  using LHCbXYZPointD  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<double>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using LHCbXYZVectorD = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<double>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using LHCbXYZPointF  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using LHCbXYZVectorF = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  //using LHCbPlan
+
   // Vc
-  using VcXYZPointD  = ROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZVectorD = ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZPointF  = ROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZVectorF = ROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZPointD  = LHCbROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorD = LHCbROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZPointF  = LHCbROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorF = LHCbROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
 
   //if ( false )
   {
 
     // Data in 'ROOT' SMatrix double format
-    Data<Gaudi::XYZPoint,Gaudi::XYZVector,Gaudi::Plane3D,Gaudi::XYZVector::Scalar>::Vector root_dataV( nPhotons );
+    Data<LHCbXYZPointD,LHCbXYZVectorD,Gaudi::XYZVector::Scalar>::Vector root_dataV( nPhotons );
     auto resROOT = rayTrace( root_dataV );
     std::cout << "ROOT double        " << resROOT << std::endl;
 
@@ -145,7 +156,7 @@ int main ( int /*argc*/, char** /*argv*/ )
   {
 
    // Data in 'ROOT' SMatrix double format
-    Data<Gaudi::XYZPointF,Gaudi::XYZVectorF,Gaudi::Plane3DF,Gaudi::XYZVectorF::Scalar>::Vector root_dataV( nPhotons );
+    Data<Gaudi::XYZPointF,Gaudi::XYZVectorF,Gaudi::XYZVectorF::Scalar>::Vector root_dataV( nPhotons );
     auto resROOT = rayTrace( root_dataV );
     std::cout << "ROOT float         " << resROOT << std::endl;
 
-- 
GitLab


From 9240da05695973d5b18e78dd00760b2db82f2dfa Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 25 Feb 2017 13:40:47 +0000
Subject: [PATCH 25/68] Extend test applications to be built with multiple
 instruction sets

---
 Rich/RichRecTests/CMakeLists.txt              | 59 ++++++++++++++---
 .../src/PhotonReco/{main.cpp => main.icpp}    |  0
 Rich/RichRecTests/src/PhotonReco/main_avx.cpp |  2 +
 .../RichRecTests/src/PhotonReco/main_avx2.cpp |  2 +
 .../src/PhotonReco/main_avx2fma.cpp           |  2 +
 .../RichRecTests/src/PhotonReco/main_sse4.cpp |  2 +
 .../src/RayTracing/{main.cpp => main.icpp}    | 64 ++++++++++---------
 Rich/RichRecTests/src/RayTracing/main_avx.cpp |  2 +
 .../RichRecTests/src/RayTracing/main_avx2.cpp |  2 +
 .../src/RayTracing/main_avx2fma.cpp           |  2 +
 .../RichRecTests/src/RayTracing/main_sse4.cpp |  2 +
 11 files changed, 101 insertions(+), 38 deletions(-)
 rename Rich/RichRecTests/src/PhotonReco/{main.cpp => main.icpp} (100%)
 create mode 100644 Rich/RichRecTests/src/PhotonReco/main_avx.cpp
 create mode 100644 Rich/RichRecTests/src/PhotonReco/main_avx2.cpp
 create mode 100644 Rich/RichRecTests/src/PhotonReco/main_avx2fma.cpp
 create mode 100644 Rich/RichRecTests/src/PhotonReco/main_sse4.cpp
 rename Rich/RichRecTests/src/RayTracing/{main.cpp => main.icpp} (73%)
 create mode 100644 Rich/RichRecTests/src/RayTracing/main_avx.cpp
 create mode 100644 Rich/RichRecTests/src/RayTracing/main_avx2.cpp
 create mode 100644 Rich/RichRecTests/src/RayTracing/main_avx2fma.cpp
 create mode 100644 Rich/RichRecTests/src/RayTracing/main_sse4.cpp

diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
index 2c8215cc26..88264c4108 100644
--- a/Rich/RichRecTests/CMakeLists.txt
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -28,19 +28,62 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
 
 if(GAUDI_BUILD_TESTS)
 
-  gaudi_add_executable(RichPhotonRecoTest
-                       src/PhotonReco/*.cpp
+  gaudi_add_executable(RichPhotonRecoTestSSE4
+                       src/PhotonReco/main_sse4.cpp
                        INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
-  target_link_libraries( RichPhotonRecoTest -lrt ) 
+  target_link_libraries( RichPhotonRecoTestSSE4 -lrt )
+  set_property(SOURCE src/RayTracing/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4.2 " )  
 
-  set_property(SOURCE src/RayTracing/main.cpp PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes" )
-  #set_property(SOURCE src/RayTracing/main.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 -O3 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " ) 
+  gaudi_add_executable(RichPhotonRecoTestAVX
+                       src/PhotonReco/main_avx.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichPhotonRecoTestAVX -lrt )
+  set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+
+  gaudi_add_executable(RichPhotonRecoTestAVX2
+                       src/PhotonReco/main_avx2.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichPhotonRecoTestAVX2 -lrt )
+  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+
+  gaudi_add_executable(RichPhotonRecoTestAVX2FMA
+                       src/PhotonReco/main_avx2fma.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichPhotonRecoTestAVX2FMA -lrt )
+  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+
+
+
+  gaudi_add_executable(RichRayTracingTestSSE4
+                       src/RayTracing/main_sse4.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichRayTracingTestSSE4 "-lrt ${Vc_LIB_DIR}/libVc.a" )
+  set_property(SOURCE src/RayTracing/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -msse4.2 " )
+
+  gaudi_add_executable(RichRayTracingTestAVX
+                       src/RayTracing/main_avx.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichRayTracingTestAVX "-lrt ${Vc_LIB_DIR}/libVc.a" )
+  set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+
+  gaudi_add_executable(RichRayTracingTestAVX2
+                       src/RayTracing/main_avx2.cpp
+                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+  target_link_libraries( RichRayTracingTestAVX2 "-lrt ${Vc_LIB_DIR}/libVc.a" )
+  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
-  gaudi_add_executable(RichRayTracingTest
-                       src/RayTracing/*.cpp
+  gaudi_add_executable(RichRayTracingTestAVX2FMA
+                       src/RayTracing/main_avx2fma.cpp
                        INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
-  target_link_libraries( RichRayTracingTest "-lrt ${Vc_LIB_DIR}/libVc.a" )
+  target_link_libraries( RichRayTracingTestAVX2FMA "-lrt ${Vc_LIB_DIR}/libVc.a" )
+  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
 endif()
diff --git a/Rich/RichRecTests/src/PhotonReco/main.cpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
similarity index 100%
rename from Rich/RichRecTests/src/PhotonReco/main.cpp
rename to Rich/RichRecTests/src/PhotonReco/main.icpp
diff --git a/Rich/RichRecTests/src/PhotonReco/main_avx.cpp b/Rich/RichRecTests/src/PhotonReco/main_avx.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/PhotonReco/main_avx.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/PhotonReco/main_avx2.cpp b/Rich/RichRecTests/src/PhotonReco/main_avx2.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/PhotonReco/main_avx2.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/PhotonReco/main_avx2fma.cpp b/Rich/RichRecTests/src/PhotonReco/main_avx2fma.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/PhotonReco/main_avx2fma.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/PhotonReco/main_sse4.cpp b/Rich/RichRecTests/src/PhotonReco/main_sse4.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/PhotonReco/main_sse4.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/RayTracing/main.cpp b/Rich/RichRecTests/src/RayTracing/main.icpp
similarity index 73%
rename from Rich/RichRecTests/src/RayTracing/main.cpp
rename to Rich/RichRecTests/src/RayTracing/main.icpp
index 8340ef59ab..8f446edfb7 100644
--- a/Rich/RichRecTests/src/RayTracing/main.cpp
+++ b/Rich/RichRecTests/src/RayTracing/main.icpp
@@ -8,11 +8,12 @@
 
 // LHCbMath
 #include "LHCbMath/EigenTypes.h"
-#include "LHCbMath/VectorClassTypes.h"
+//#include "LHCbMath/VectorClassTypes.h"
 
 // LHCb TemplatedGenVector
 #include "TemplatedGenVector/DisplacementVector3D.h"
 #include "TemplatedGenVector/PositionVector3D.h"
+#include "TemplatedGenVector/Plane3D.h"
 
 // Rich Utils
 #include "RichUtils/RichRayTracingUtils.h"
@@ -41,16 +42,16 @@ static std::uniform_real_distribution<double> c_x(3100,3200), c_y(10,15),    c_z
 static std::uniform_real_distribution<double> r_rad(8500,8600);
 static std::uniform_real_distribution<double> p0(-0.002,0.002), p1(-0.2,0.2), p2(0.97,0.99), p3(-1300,1300);
 
-template < typename POINT, typename VECTOR, typename FTYPE >
+template < typename POINT, typename VECTOR, typename PLANE, typename FTYPE >
 class Data
 {
 public:
-  typedef std::vector<Data> Vector;
+  typedef std::vector< Data, Vc::Allocator<Data> > Vector;
 public:
   POINT position;
   VECTOR direction;
   POINT CoC;
-  //PLANE plane;
+  PLANE plane;
   FTYPE radius{0};
 public:
   template< typename INDATA >
@@ -58,13 +59,13 @@ public:
     : position(ind.position),
       direction(ind.direction),
       CoC(ind.CoC),
-      //  plane(ind.plane),
+      plane(ind.plane),
       radius(ind.radius) { }
   Data( )
     : position  ( p_x(gen), p_y(gen), p_z(gen) ),
       direction ( d_x(gen), d_y(gen), d_z(gen) ),
       CoC       ( c_x(gen), c_y(gen), c_z(gen) ),
-      //plane     ( p0(gen),  p1(gen),  p2(gen), p3(gen) ), 
+      plane     ( p0(gen),  p1(gen),  p2(gen), p3(gen) ), 
       radius    ( r_rad(gen) ) { }
 };
 
@@ -75,6 +76,7 @@ inline void trace( DATA & dataV )
   for ( auto & data : dataV )
   {
     reflectSpherical( data.position, data.direction, data.CoC, data.radius );
+    reflectPlane    ( data.position, data.direction, data.plane );
   }
 }
 
@@ -104,6 +106,7 @@ int main ( int /*argc*/, char** /*argv*/ )
 {
 
   const unsigned int nPhotons = 96 * 1e2;
+  //const unsigned int nPhotons = 8;
   std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
 
   // Templated GenVector
@@ -111,43 +114,44 @@ int main ( int /*argc*/, char** /*argv*/ )
   using LHCbXYZVectorD = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<double>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using LHCbXYZPointF  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using LHCbXYZVectorF = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
-  //using LHCbPlan
+  using LHCbPlane3DD   = LHCbROOT::Math::Plane3D<double>;
+  using LHCbPlane3DF   = LHCbROOT::Math::Plane3D<float>;
 
   // Vc
-  using VcXYZPointD  = LHCbROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZVectorD = LHCbROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::double_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZPointF  = LHCbROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
-  using VcXYZVectorF = LHCbROOT::Math::DisplacementVector3D<ROOT::Math::Cartesian3D<Vc::float_v>,ROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZPointD  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<Vc::double_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorD = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<Vc::double_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZPointF  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<Vc::float_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using VcXYZVectorF = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<Vc::float_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
+  using VcPlane3DD   = LHCbROOT::Math::Plane3D<Vc::double_v>;
+  using VcPlane3DF   = LHCbROOT::Math::Plane3D<Vc::float_v>;
 
   //if ( false )
   {
 
     // Data in 'ROOT' SMatrix double format
-    Data<LHCbXYZPointD,LHCbXYZVectorD,Gaudi::XYZVector::Scalar>::Vector root_dataV( nPhotons );
+    Data<LHCbXYZPointD,LHCbXYZVectorD,LHCbPlane3DD,LHCbXYZPointD::Scalar>::Vector root_dataV( nPhotons );
     auto resROOT = rayTrace( root_dataV );
     std::cout << "ROOT double        " << resROOT << std::endl;
 
     // Same data in Eigen double format
-    Data<LHCb::Math::Eigen::XYZPoint<double>,LHCb::Math::Eigen::XYZVector<double>,double>::Vector eigen_dataV( nPhotons );
+    Data<LHCb::Math::Eigen::XYZPoint<double>,LHCb::Math::Eigen::XYZVector<double>,LHCb::Math::Eigen::Plane3D<double>,double>::Vector eigen_dataV( nPhotons );
     auto resEIGEN = rayTrace( eigen_dataV );
     std::cout << "Eigen double       " << resEIGEN << " speedup " << (float)resROOT/(float)resEIGEN << std::endl;
- 
-    // _mm256_zeroupper();
 
     // Same data in VectorClass double format
-    Data<LHCb::Math::VectorClass::XYZPoint<double>,LHCb::Math::VectorClass::XYZVector<double>,double>::Vector vclass_dataV( nPhotons );
-    auto resVClass = rayTrace( vclass_dataV );
-    std::cout << "VectorClass double " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
+    //Data<LHCb::Math::VectorClass::XYZPoint<double>,LHCb::Math::VectorClass::XYZVector<double>,double>::Vector vclass_dataV( nPhotons );
+    //auto resVClass = rayTrace( vclass_dataV );
+    //std::cout << "VectorClass double " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
 
     // Vc float
-    Data<VcXYZPointD,VcXYZVectorD,Vc::double_v>::Vector VC_dataV( nPhotons / Vc::double_v::Size );
+    Data<VcXYZPointD,VcXYZVectorD,VcPlane3DD,Vc::double_v>::Vector VC_dataV( nPhotons / Vc::double_v::Size );
     auto resVC = rayTrace( VC_dataV );
     std::cout << "Vc double          " << resVC << " speedup " << (float)resROOT/(float)resVC << std::endl;
 
     // make sure we are not optimized away
     asm volatile ("" : "+x"(resROOT));
     asm volatile ("" : "+x"(resEIGEN));
-    asm volatile ("" : "+x"(resVClass));
+    //asm volatile ("" : "+x"(resVClass));
     asm volatile ("" : "+x"(resVC));
 
   }
@@ -155,30 +159,30 @@ int main ( int /*argc*/, char** /*argv*/ )
   //if ( false )
   {
 
-   // Data in 'ROOT' SMatrix double format
-    Data<Gaudi::XYZPointF,Gaudi::XYZVectorF,Gaudi::XYZVectorF::Scalar>::Vector root_dataV( nPhotons );
+   // Data in 'ROOT' SMatrix float format
+    Data<LHCbXYZPointF,LHCbXYZVectorF,LHCbPlane3DF,LHCbXYZPointF::Scalar>::Vector root_dataV( nPhotons );
     auto resROOT = rayTrace( root_dataV );
     std::cout << "ROOT float         " << resROOT << std::endl;
 
-    // Same data in Eigen double format
-    Data<LHCb::Math::Eigen::XYZPoint<float>,LHCb::Math::Eigen::XYZVector<float>,float>::Vector eigen_dataV( nPhotons );
+    // Same data in Eigen float format
+    Data<LHCb::Math::Eigen::XYZPoint<float>,LHCb::Math::Eigen::XYZVector<float>,LHCb::Math::Eigen::Plane3D<float>,float>::Vector eigen_dataV( nPhotons );
     auto resEIGEN = rayTrace( eigen_dataV );
     std::cout << "Eigen float        " << resEIGEN << " speedup " << (float)resROOT/(float)resEIGEN << std::endl;
 
-    // Same data in VectorClass double format
-    Data<LHCb::Math::VectorClass::XYZPoint<float>,LHCb::Math::VectorClass::XYZVector<float>,float>::Vector vclass_dataV( nPhotons );
-    auto resVClass = rayTrace( vclass_dataV );
-    std::cout << "VectorClass float  " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
+    // Same data in VectorClass float format
+    //Data<LHCb::Math::VectorClass::XYZPoint<float>,LHCb::Math::VectorClass::XYZVector<float>,float>::Vector vclass_dataV( nPhotons );
+    //auto resVClass = rayTrace( vclass_dataV );
+    //std::cout << "VectorClass float  " << resVClass << " speedup " << (float)resROOT/(float)resVClass << std::endl;
 
     // Vc float
-    Data<VcXYZPointF,VcXYZVectorF,Vc::float_v>::Vector VC_dataV( nPhotons / Vc::float_v::Size );
+    Data<VcXYZPointF,VcXYZVectorF,VcPlane3DF,Vc::float_v>::Vector VC_dataV( nPhotons / Vc::float_v::Size );
     auto resVC = rayTrace( VC_dataV );
     std::cout << "Vc float           " << resVC << " speedup " << (float)resROOT/(float)resVC << std::endl;
 
     // make sure we are not optimized away
     asm volatile ("" : "+x"(resROOT));
     asm volatile ("" : "+x"(resEIGEN));
-    asm volatile ("" : "+x"(resVClass));
+    //asm volatile ("" : "+x"(resVClass));
     asm volatile ("" : "+x"(resVC));
 
   }
diff --git a/Rich/RichRecTests/src/RayTracing/main_avx.cpp b/Rich/RichRecTests/src/RayTracing/main_avx.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/RayTracing/main_avx.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/RayTracing/main_avx2.cpp b/Rich/RichRecTests/src/RayTracing/main_avx2.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/RayTracing/main_avx2.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/RayTracing/main_avx2fma.cpp b/Rich/RichRecTests/src/RayTracing/main_avx2fma.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/RayTracing/main_avx2fma.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
diff --git a/Rich/RichRecTests/src/RayTracing/main_sse4.cpp b/Rich/RichRecTests/src/RayTracing/main_sse4.cpp
new file mode 100644
index 0000000000..c673656633
--- /dev/null
+++ b/Rich/RichRecTests/src/RayTracing/main_sse4.cpp
@@ -0,0 +1,2 @@
+
+#include "main.icpp"
-- 
GitLab


From 0e1e553fbb960372eb5833869d2b9c22cf72eebf Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 1 Mar 2017 23:44:52 +0100
Subject: [PATCH 26/68] Add developmental version of a SIMD implementation of
 the Cherenkov cone ray tracing algorithm

---
 .../CMakeLists.txt                            |   2 +-
 .../RichFutureRecSys/ConfiguredRichReco.py    |  15 +-
 .../CMakeLists.txt                            |  21 +-
 .../src/RichRayTraceCherenkovConesSIMD.cpp    |  90 ++++++
 .../src/RichRayTraceCherenkovConesSIMD.h      | 201 ++++++++++++++
 .../src/RichRayTraceCherenkovConesSIMD.icpp   | 261 ++++++++++++++++++
 .../src/avx/RichRayTraceCherenkovCones.cpp    |  14 +
 .../src/avx2/RichRayTraceCherenkovCones.cpp   |  14 +
 .../generic/RichRayTraceCherenkovCones.cpp    |  14 +
 .../src/sse4/RichRayTraceCherenkovCones.cpp   |  14 +
 Rich/RichRecTests/CMakeLists.txt              |  35 +--
 Rich/RichRecTests/src/RayTracing/main.icpp    |  19 +-
 12 files changed, 667 insertions(+), 33 deletions(-)
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
 create mode 100644 Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp

diff --git a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
index 5ccf26d32e..a3c59f6df2 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
+++ b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
@@ -17,7 +17,7 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
                                                  ${EIGEN_INCLUDE_DIRS})
 
 # For testing high vectorisation and optimisation levels
-#set_property(SOURCE src/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4 -O3 " )
+#set_property(SOURCE src/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -O3 -mavx2 -mfma -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
 gaudi_add_module(RichFutureRecPhotonAlgorithms
                  src/*.cpp
diff --git a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
index e99f4138a7..9fc833512e 100644
--- a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
+++ b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
@@ -137,7 +137,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
                       preloadGeometry = False,
 
                       # Number points for mass hypothesis ring ray tracing
-                      NRingPoints = ( 100, 100, 100 ),
+                      NRingPoints = ( 96, 96, 96 ),
 
                       # Track Extrapolator type
                       trackExtrapolator = "TrackRungeKuttaExtrapolator",
@@ -322,6 +322,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         from Configurables import Rich__Future__Rec__TrackEmittedCherenkovAngles as EmittedCherenkovAngles
         from Configurables import Rich__Future__Rec__TrackSignalCherenkovAngles as SignalCherenkovAngles
         from Configurables import Rich__Future__Rec__RayTraceCherenkovCones as EmittedMassCones
+        from Configurables import Rich__Future__Rec__RayTraceCherenkovConesSIMD as EmittedMassConesSIMD
         from Configurables import Rich__Future__Rec__GeomEffCKMassRings as GeomEff
         from Configurables import Rich__Future__Rec__TrackFunctionalCherenkovResolutions as TrackCKResolutions
         from Configurables import Rich__Future__Rec__SelectTrackSegments as SelectTrackSegments
@@ -386,6 +387,16 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         # Options
         emitMassCones.NRingPoints = NRingPoints
 
+        # Cherenkov mass cones using emitted spectra SIMD
+        emitMassConesSIMD = makeRichAlg( EmittedMassConesSIMD, "RichMassConesSIMD"+name, algprops )
+        # Input
+        emitMassConesSIMD.TrackSegmentsLocation   = locs["TrackSegmentsLocation"]
+        emitMassConesSIMD.CherenkovAnglesLocation = locs["EmittedCherenkovAnglesLocation"]
+        # Output
+        emitMassConesSIMD.MassHypothesisRingsLocation = locs["EmittedMassHypothesisRingsLocation"]+"SIMD"
+        # Options
+        emitMassConesSIMD.NRingPoints = NRingPoints
+
         # Detectable photon yields
         detY = makeRichAlg( DetectableYields, "RichDetectableYields"+name, algprops )
         # Inputs
@@ -454,7 +465,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         segs = GaudiSequencer( "RichTracks" + name,
                                MeasureTime = MeasureTime,
                                Members = [ segCr, tkGloPnts, tkLocPnts, emitY, 
-                                           emitChAngles, emitMassCones, detY, 
+                                           emitChAngles, emitMassCones, emitMassConesSIMD, detY, 
                                            geomEff, tkSel, sigYields, sigChAngles, tkRes ] )
         # Add to final sequence
         tkSeq.Members += [ segs ]
diff --git a/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt b/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
index d0eb77b7e8..9873e24314 100644
--- a/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
+++ b/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
@@ -8,17 +8,28 @@ gaudi_depends_on_subdirs(Rich/RichFutureRecBase
                          Rich/RichUtils
                          Rich/RichFutureUtils
                          Tr/TrackKernel
-                         Tr/TrackInterfaces)
+                         Tr/TrackInterfaces
+                         Kernel/TemplatedGenVector
+                         Kernel/Vc
+                         Kernel/VectorClass)
 
 find_package(ROOT)
 find_package(Boost)
 find_package(GSL)
 find_package(VDT)
+find_package(Vc)
 
-include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
+include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${Vc_INCLUDE_DIR})
 
 gaudi_add_module(RichFutureRecTrackAlgorithms
-                 src/*.cpp
-                 INCLUDE_DIRS Boost GSL VDT Rich/RichFutureRecBase Rich/RichUtils Rich/RichFutureUtils Tr/TrackInterfaces Tr/TrackKernel
-                 LINK_LIBRARIES Boost GSL VDT RichFutureRecBase RichUtils RichFutureUtils)
+                 src/*.cpp src/generic/*.cpp src/sse4/*.cpp src/avx/*.cpp src/avx2/*.cpp
+                 INCLUDE_DIRS Vc Boost GSL VDT Kernel/VectorClass Rich/RichFutureRecBase Rich/RichUtils Rich/RichFutureUtils Tr/TrackInterfaces Tr/TrackKernel
+                 LINK_LIBRARIES Boost GSL VDT RichFutureRecBase RichUtils RichFutureUtils TemplatedGenVectorLib )
 
+target_link_libraries( RichFutureRecTrackAlgorithms "${Vc_LIB_DIR}/libVc.a" )
+
+set_property(SOURCE src/RichRayTraceCherenkovConesSIMD.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes " )
+set_property(SOURCE src/generic/RichRayTraceCherenkovCones.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes " )
+set_property(SOURCE src/sse4/RichRayTraceCherenkovCones.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -msse4.2 " )
+set_property(SOURCE src/avx/RichRayTraceCherenkovCones.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+set_property(SOURCE src/avx2/RichRayTraceCherenkovCones.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx2 -mfma -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
new file mode 100644
index 0000000000..f73429cae1
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
@@ -0,0 +1,90 @@
+
+// local
+#include "RichRayTraceCherenkovConesSIMD.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future::Rec;
+
+//=============================================================================
+
+RayTraceCherenkovConesSIMD::RayTraceCherenkovConesSIMD( const std::string& name, 
+                                                ISvcLocator* pSvcLocator )
+  : Transformer ( name, pSvcLocator,
+                  { KeyValue{ "TrackSegmentsLocation",       LHCb::RichTrackSegmentLocation::Default },
+                    KeyValue{ "CherenkovAnglesLocation",     CherenkovAnglesLocation::Emitted } },
+                  { KeyValue{ "MassHypothesisRingsLocation", MassHypoRingsLocation::Emitted } } )
+{
+  //declareProperty( "RayTracingTool", m_rayTrace );
+  // debugging
+  //setProperty( "OutputLevel", MSG::VERBOSE );
+}
+
+//=============================================================================
+
+StatusCode RayTraceCherenkovConesSIMD::initialize()
+{
+  // Sets up various tools and services
+  auto sc = Transformer::initialize();
+  if ( !sc ) return sc;
+
+  // load tools
+  //sc = sc && m_rayTrace.retrieve();
+  sc = sc && m_idTool.retrieve();
+  sc = sc && m_mirrorSegFinder.retrieve();
+
+  // RICH detector elements
+  m_rich[Rich::Rich1]   = getDet<DeRich>( DeRichLocations::Rich1 );
+  m_rich[Rich::Rich2]   = getDet<DeRich>( DeRichLocations::Rich2 );
+
+  // loop over radiators
+  for ( const auto rad : Rich::radiators() )
+  {
+    // Check # photon is exactly divisible by 8 (for SIMD vectors without padding)
+    if ( m_nPoints[rad] % 8 != 0 )
+    {
+      return Error( "# photons must be a multiple of 8 to avoid need for SIMD padding" );
+    }
+    // Fill cos and sin values
+    m_cosSinPhiV[rad].clear();
+    m_cosSinPhiV[rad].reserve( m_nPoints[rad] );
+    const auto incPhi = Gaudi::Units::twopi / static_cast<double>(m_nPoints[rad]);
+    double ckPhi = 0.0;
+    for ( unsigned int iPhot = 0; iPhot < m_nPoints[rad]; ++iPhot, ckPhi+=incPhi )
+    { m_cosSinPhiV[rad].emplace_back( ckPhi ); }
+    // bailout number
+    m_nBailout[rad] = static_cast<unsigned int> ( m_bailoutFrac[rad] * m_nPoints[rad] ); 
+  }
+
+  // // the ray-tracing mode
+  // LHCb::RichTraceMode tmpMode ( LHCb::RichTraceMode::RespectHPDTubes,
+  //                               ( m_useDetailedHPDsForRayT ?
+  //                                 LHCb::RichTraceMode::SphericalHPDs :
+  //                                 LHCb::RichTraceMode::FlatHPDs ) );
+  // if ( m_checkBeamPipe ) { tmpMode.setBeamPipeIntersects(true); }
+  // m_traceModeRad[Rich::Aerogel]  = tmpMode;
+  // m_traceModeRad[Rich::Aerogel].setAeroRefraction(true);
+  // m_traceModeRad[Rich::Rich1Gas] = tmpMode;
+  // m_traceModeRad[Rich::Rich2Gas] = tmpMode;
+  // _ri_debug << "Aerogel  Track " << m_traceModeRad[Rich::Aerogel]  << endmsg;
+  // _ri_debug << "Rich1Gas Track " << m_traceModeRad[Rich::Rich1Gas] << endmsg;
+  // _ri_debug << "Rich2Gas Track " << m_traceModeRad[Rich::Rich2Gas] << endmsg;
+
+  // Get the CPU capabilities and set dispatch method
+  enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
+  const auto cpuLevel = instrset_detect();
+  _ri_debug << "Instruction set level = " << cpuLevel << endmsg;
+  if      ( cpuLevel >= AVX2 ) { m_run = &RayTraceCherenkovConesSIMD::run_avx2; }
+  else if ( cpuLevel >= AVX  ) { m_run = &RayTraceCherenkovConesSIMD::run_avx; }
+  else if ( cpuLevel >= SSE4 ) { m_run = &RayTraceCherenkovConesSIMD::run_sse4; }
+  else                         { m_run = &RayTraceCherenkovConesSIMD::run_generic; }
+
+  // return
+  return sc;
+}
+
+//=============================================================================
+
+// Declaration of the Algorithm Factory
+DECLARE_ALGORITHM_FACTORY( RayTraceCherenkovConesSIMD )
+
+//=============================================================================
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
new file mode 100644
index 0000000000..ad0d403d01
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
@@ -0,0 +1,201 @@
+
+#pragma once
+
+// Gaudi
+#include "GaudiKernel/ParsersFactory.h"
+#include "GaudiKernel/StdArrayAsProperty.h"
+#include "GaudiAlg/Transformer.h"
+#include "GaudiKernel/PhysicalConstants.h"
+
+// Base class
+#include "RichFutureRecBase/RichRecAlgBase.h"
+
+// Event Model
+#include "RichFutureRecEvent/RichRecCherenkovAngles.h"
+#include "RichFutureRecEvent/RichRecMassHypoRings.h"
+
+// Utils
+#include "RichUtils/RichTrackSegment.h"
+#include "RichFutureUtils/RichGeomPhoton.h"
+#include "RichUtils/ZipRange.h"
+#include "RichUtils/RichRayTracingUtils.h"
+
+// Rec Utils
+#include "RichRecUtils/RichRadCorrLocalPositions.h"
+
+// RichDet
+#include "RichDet/DeRich.h"
+
+// Interfaces
+//#include "RichFutureInterfaces/IRichRayTracing.h"
+#include "RichInterfaces/IRichSmartIDTool.h"
+#include "RichInterfaces/IRichMirrorSegFinderLookUpTable.h"
+
+// VDT
+#include "vdt/sincos.h"
+
+// Vector Class
+#include "VectorClass/instrset.h"
+
+// Vc
+#include <Vc/Vc>
+
+// LHCb TemplatedGenVector
+#include "TemplatedGenVector/DisplacementVector3D.h"
+#include "TemplatedGenVector/PositionVector3D.h"
+#include "TemplatedGenVector/Plane3D.h"
+
+namespace Rich
+{
+  namespace Future
+  {
+
+    // Use the functional framework
+    using namespace Gaudi::Functional;
+
+    namespace Rec
+    {
+
+      /** @class RayTraceCherenkovConesSIMD RichRayTraceCherenkovConesSIMD.h
+       *
+       *  Creates the Cherenkov cones for each segment and mass hypothesis,
+       *  using photon raytracing.
+       *
+       *  @author Chris Jones
+       *  @date   2016-09-30
+       */
+
+      class RayTraceCherenkovConesSIMD final :
+        public Transformer< MassHypoRingsVector( const LHCb::RichTrackSegment::Vector&,
+                                                 const CherenkovAngles::Vector& ),
+                            Traits::BaseClass_t<AlgBase> >
+      {
+
+      public:
+
+        /// Standard constructor
+        RayTraceCherenkovConesSIMD( const std::string& name,
+                                    ISvcLocator* pSvcLocator );
+
+        /// Initialization after creation
+        StatusCode initialize() override;
+
+      public:
+
+        /// Functional operator
+        inline MassHypoRingsVector
+          operator()( const LHCb::RichTrackSegment::Vector& segments,
+                      const CherenkovAngles::Vector& ckAngles ) const override
+        {
+          return (this->*m_run)( segments, ckAngles );
+        }
+
+      private:
+
+        /// Generic dispatch function
+        MassHypoRingsVector
+          run_generic( const LHCb::RichTrackSegment::Vector& segments,
+                       const CherenkovAngles::Vector& ckAngles ) const;
+
+        /// SSE4 dispatch function
+        MassHypoRingsVector
+          run_sse4( const LHCb::RichTrackSegment::Vector& segments,
+                    const CherenkovAngles::Vector& ckAngles ) const;
+
+        /// AVX dispatch function
+        MassHypoRingsVector
+          run_avx( const LHCb::RichTrackSegment::Vector& segments,
+                   const CherenkovAngles::Vector& ckAngles ) const;
+
+        /// AVX2 dispatch function
+        MassHypoRingsVector
+          run_avx2( const LHCb::RichTrackSegment::Vector& segments,
+                    const CherenkovAngles::Vector& ckAngles ) const;
+
+        /** Pointer to dispatch function for the operator call
+         *  Default to lowest common denominator. 
+         *  Reset in initialize() according to runtime support */
+        MassHypoRingsVector (RayTraceCherenkovConesSIMD::*m_run)
+          ( const LHCb::RichTrackSegment::Vector& segments,
+            const CherenkovAngles::Vector& ckAngles ) const 
+          = &RayTraceCherenkovConesSIMD::run_generic;
+
+      private: // helper classes
+
+        /** @class CosSinPhi RichRayTraceCherenkovCone.h
+         *
+         *  Utility class to cache cos and sin values
+         *
+         *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
+         *  @date   17/02/2008
+         */
+        template< typename TYPE >
+        class CosSinPhi
+        {
+        public:
+          typedef std::vector<CosSinPhi> Vector;
+        public:
+          explicit CosSinPhi( const TYPE _phi ) : phi(_phi)
+          {
+            vdt::fast_sincos( phi, sinPhi, cosPhi );
+          }
+        public:
+          TYPE phi    = 0; ///< CK phi
+          TYPE cosPhi = 0; ///< Cos(CK phi)
+          TYPE sinPhi = 0; ///< Sin(CK phi)
+        };
+
+        /// Vc Vector
+        template < typename TYPE >
+        using VcAllocVector = std::vector< TYPE, Vc::Allocator<TYPE> >;
+        
+      private:
+
+        /// Rich1 and Rich2 pointers
+        Rich::DetectorArray<const DeRich*> m_rich{{nullptr,nullptr}};
+
+        /// Number of points to ray trace on each ring, for each radiator
+        Gaudi::Property< RadiatorArray<unsigned int> > m_nPoints
+        { this, "NRingPoints", { 100u, 100u, 100u } };
+
+        /// Bailout number
+        RadiatorArray<unsigned int> m_nBailout = {{}};
+
+        /// Cached cos and sin values around the ring, for each radiator
+        RadiatorArray< CosSinPhi<double>::Vector > m_cosSinPhiV;
+
+        /// Mirror segment finder tool
+        ToolHandle<const IMirrorSegFinderLookUpTable> m_mirrorSegFinder
+        { "Rich::Future::MirrorSegFinderLookUpTable/MirrorFinder:PUBLIC", this };
+
+        /// Cached trace modes for each radiator
+        //RadiatorArray<LHCb::RichTraceMode> m_traceModeRad = {{}};
+
+        /// Flag to turn on or off checking of intersections with beampipe
+        //Gaudi::Property<bool> m_checkBeamPipe { this, "CheckBeamPipe", true };
+
+        /// Flag to switch between simple or detail HPD description in ray tracing
+        //Gaudi::Property<bool> m_useDetailedHPDsForRayT { this, "UseDetailedHPDs", false };
+
+        /** Bailout fraction. If no ray tracings have worked after this fraction have been
+         *  perfromed, then give up */
+        Gaudi::Property< RadiatorArray<float> > m_bailoutFrac
+        { this, "BailoutFraction", { 0.75, 0.75, 0.75 } };
+
+        /// Flag to control if the secondary mirrors are treated as if they are completely flat
+        Gaudi::Property< DetectorArray<bool> > m_treatSecMirrsFlat 
+        { this, "AssumeFlatSecondaryMirrors", { true, false } };
+
+        /// Ray tracing tool
+        //ToolHandle<const IRayTracing> m_rayTrace
+        //{ "Rich::Future::RayTracing/RayTracing", this };
+
+        /// RichSmartID Tool
+        ToolHandle<const ISmartIDTool> m_idTool
+        { "Rich::Future::SmartIDTool/SmartIDTool:PUBLIC", this };
+
+      };
+
+    }
+  }
+}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
new file mode 100644
index 0000000000..c5f11bb638
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
@@ -0,0 +1,261 @@
+
+{
+
+  // types
+  using ScFloat  = float;
+  using VcFloat  = Vc::float_v;
+  using VcInt    = Vc::int_v;
+  using ScInt    = int;
+  using VcPoint  = LHCbROOT::Math::PositionVector3D    < LHCbROOT::Math::Cartesian3D<VcFloat> >;
+  using VcVector = LHCbROOT::Math::DisplacementVector3D< LHCbROOT::Math::Cartesian3D<VcFloat> >;
+  using VcPlane  = LHCbROOT::Math::Impl::Plane3D<VcFloat>;
+
+  // Ray tracing utils
+  using namespace Rich::RayTracingUtils;
+
+  // The data to return
+  MassHypoRingsVector ringsV;
+  ringsV.reserve( segments.size() );
+  
+  // Temporary working photon object. Need to eventually remove need for this.
+  GeomPhoton photon;
+  
+  // local position corrector
+  // longer term need to remove this
+  const Rich::Rec::RadPositionCorrector corrector;
+ 
+  // loop over the input data
+  for ( const auto && data : Ranges::ConstZip(segments,ckAngles) )
+  {
+    const auto & segment = std::get<0>(data);
+    const auto & ckTheta = std::get<1>(data);
+    
+    // Add a set of mass hypo rings for this segment
+    ringsV.emplace_back( );
+    auto & rings = ringsV.back();
+    
+    // which rich and radiator
+    const auto rich = segment.rich();
+    const auto rad  = segment.radiator();
+    
+    // best emission point
+    const auto & ePnt = segment.bestPoint();
+
+    // Start detector side
+    const auto side = m_rich[rich]->side(ePnt);
+
+    // Number of VcVector objects
+    const auto NVC = m_nPoints[rad] / VcFloat::Size;
+       
+    // Loop over PID types
+    for ( const auto id : activeParticles() )
+    {
+      // Above threshold ?
+      if ( ckTheta[id] > 0 )
+      {
+        
+        // compute sin and cos theta
+        double sinTheta(0), cosTheta(0);
+        vdt::fast_sincos( ckTheta[id], sinTheta, cosTheta );
+        
+        // reserve size in the points container
+        rings[id].reserve( m_nPoints[rad] );
+
+        // Form the starting detector sides
+        VcAllocVector<VcInt> photSides( NVC, VcInt(side) );
+        
+        // Form the starting points
+        VcAllocVector<VcPoint> startPoints( NVC, VcPoint(ePnt.x(),ePnt.y(),ePnt.z()) );
+        
+        // Form the starting points and directions.
+        VcAllocVector<VcVector> startDirs;
+        // Will be able to vectorise this better once GenVector in ROOT has my updates
+        {
+          unsigned int nPhot(0);
+          // Vc vectors for (x,y,z)
+          VcFloat x,y,z;
+          for ( auto iP = m_cosSinPhiV[rad].begin(); iP != m_cosSinPhiV[rad].end(); ++iP, ++nPhot )
+          {
+            // Vc index
+            const auto ivc = nPhot % VcFloat::Size;
+            // Photon direction around loop
+            const auto photDir =
+              segment.vectorAtCosSinThetaPhi( cosTheta,     sinTheta,
+                                              (*iP).cosPhi, (*iP).sinPhi );
+            // Fill Vc words
+            x[ivc] = photDir.x();
+            y[ivc] = photDir.y();
+            z[ivc] = photDir.z();
+            // If last index, make a new entry in the vector and fill
+            if ( VcFloat::Size-1 == ivc ) { startDirs.emplace_back(x,y,z);  }
+          }
+        }
+
+        // Starting CoC values
+        VcAllocVector<VcPoint> CoCs( NVC, VcPoint( m_rich[rich]->nominalCentreOfCurvature(side) ) );
+
+        // Starting RoC values
+        VcAllocVector<VcFloat> RoCs( NVC, VcFloat( m_rich[rich]->sphMirrorRadius() ) );
+
+        // Intersect with the spherical mirrors to find the reflection points and use these
+        // to find the mirror segments to use for the primary mirrors
+        for ( auto && data : Ranges::Zip(startPoints,startDirs,CoCs,RoCs,photSides) )
+        {
+          auto & startP = std::get<0>(data);
+          auto & startD = std::get<1>(data);
+          auto & CoC    = std::get<2>(data);
+          auto & RoC    = std::get<3>(data);
+          auto & sides  = std::get<4>(data);
+
+          // interset with nominal primary
+          VcPoint nomSphInter;
+          auto mask = intersectSpherical( startP, startD, CoC, RoC, nomSphInter );
+          if ( any_of(mask) )
+          {
+            
+            // Check if we are on the same detector side or not
+            VcInt newSides(sides);
+            // To Do - Fix RichDet Vc support
+            //m_rich[rich]->sides( nomSphInter, newSides );
+            {
+              VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
+              for ( std::size_t i = 0; i < VcFloat::Size; ++i )
+              {
+                // Check the detector side for the intersection point
+                const auto nside = m_rich[rich]->side( (ScFloat)nomSphInter.x()[i],
+                                                       (ScFloat)nomSphInter.y()[i] );
+                newSides[i] = ScInt( nside );
+                if ( newSides[i] != sides[i] )
+                {
+                  // Update CoC and RoC for this entry
+                  const auto& nCoC = m_rich[rich]->nominalCentreOfCurvature(nside);
+                  x[i] = nCoC.x();
+                  y[i] = nCoC.y();
+                  z[i] = nCoC.z();
+                  RoC[i] = m_rich[rich]->sphMirrorRadius();
+                }
+              }
+              // Update the CoC point
+              CoC = VcPoint(x,y,z);
+            }
+            // if any think changed rerun the intersection
+            if ( UNLIKELY( any_of( sides != newSides ) ) )
+            {
+              sides = newSides;
+              mask &= intersectSpherical( startP, startD, CoC, RoC, nomSphInter );
+            }
+
+            if ( any_of(mask) )
+            {
+
+              {
+                // Copy the CoC parameters
+                VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
+                // Find primary mirror segments to update CoC and RoC foreach photon
+                for ( std::size_t i = 0; i < VcFloat::Size; ++i )
+                {
+                  // Find the primary mirror segment for this point
+                  const auto * sphSegment = 
+                    m_mirrorSegFinder.get()->findSphMirror( rich, side,
+                                                            (ScFloat)nomSphInter.x()[i],
+                                                            (ScFloat)nomSphInter.y()[i] );
+                  // update the mirror parameters
+                  const auto& nCoC = sphSegment->centreOfCurvature();
+                  x[i]   = nCoC.x();
+                  y[i]   = nCoC.y();
+                  z[i]   = nCoC.z();
+                  RoC[i] = sphSegment->radius();
+                }
+                // Update the CoC point
+                CoC = VcPoint(x,y,z);    
+              }
+              
+              // perform the final reflection on the primaries
+              mask &= reflectSpherical( startP, startD, CoC, RoC );
+
+              if ( any_of(mask) )
+              {
+                // move on to the secondary mirrors
+ 
+                // nominal intersection point
+                VcPoint planeInt;
+                const auto& plane = m_rich[rich]->nominalPlane(side);
+                VcPlane vcplane( plane.A(), plane.B(), plane.C(), plane.D() );
+                mask &= intersectPlane( startP, startD, vcplane, planeInt );
+
+                if ( any_of(mask) )
+                {
+                  // Find the exact secondary mirror segments
+
+                  // Copy the nominal plane parameters
+                  auto A(vcplane.A()), B(vcplane.B()), C(vcplane.C()), D(vcplane.D());
+                  // Copy the CoC parameters
+                  VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
+                  for ( std::size_t i = 0; i < VcFloat::Size; ++i )
+                  {
+                    // find secondary mirror segment
+                    const auto * secSegment =
+                      m_mirrorSegFinder.get()->findSecMirror( rich, side,
+                                                              (ScFloat)planeInt.x()[i],
+                                                              (ScFloat)planeInt.y()[i] );
+                    // flat versus spherical treatment
+                    if ( m_treatSecMirrsFlat[rich] )
+                    {
+                      // Update the normal plane
+                      const auto & npl = secSegment->centreNormalPlane();
+                      A[i] = npl.A();
+                      B[i] = npl.B();
+                      C[i] = npl.C();
+                      D[i] = npl.D();
+                    }
+                    else
+                    {
+                      // update speherical parameters for the secondary mirrors
+                      const auto& nCoC = secSegment->centreOfCurvature();
+                      x[i]   = nCoC.x();
+                      y[i]   = nCoC.y();
+                      z[i]   = nCoC.z();
+                      RoC[i] = secSegment->radius();
+                    }
+                  }
+                  
+                  // reflect off the secondary mirrors
+                  mask &= ( m_treatSecMirrsFlat[rich] ?
+                            reflectPlane    ( startP, startD, VcPlane(A,B,C,D) ) :
+                            reflectSpherical( startP, startD, VcPoint(x,y,z), RoC ) );
+
+
+                  // If OK, proceed to getting the hit position
+                  if ( any_of(mask) )
+                  {
+
+
+
+
+
+
+                  }
+                  
+                }
+
+              }
+
+            }
+            
+          } // first intersection ok
+          
+        } // loop over photons
+        
+
+
+
+
+        
+      }
+      
+    }
+    
+  }
+  
+  return ringsV;
+}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
new file mode 100644
index 0000000000..067b58c58b
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
@@ -0,0 +1,14 @@
+
+// local
+#include "../RichRayTraceCherenkovConesSIMD.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future::Rec;
+
+MassHypoRingsVector
+RayTraceCherenkovConesSIMD::
+run_avx( const LHCb::RichTrackSegment::Vector& segments,
+         const CherenkovAngles::Vector& ckAngles ) const
+{
+#include "../RichRayTraceCherenkovConesSIMD.icpp"
+}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
new file mode 100644
index 0000000000..f7db884820
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
@@ -0,0 +1,14 @@
+
+// local
+#include "../RichRayTraceCherenkovConesSIMD.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future::Rec;
+
+MassHypoRingsVector
+RayTraceCherenkovConesSIMD::
+run_avx2( const LHCb::RichTrackSegment::Vector& segments,
+          const CherenkovAngles::Vector& ckAngles ) const
+{
+#include "../RichRayTraceCherenkovConesSIMD.icpp"
+}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
new file mode 100644
index 0000000000..311c28b8d8
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
@@ -0,0 +1,14 @@
+
+// local
+#include "../RichRayTraceCherenkovConesSIMD.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future::Rec;
+
+MassHypoRingsVector
+RayTraceCherenkovConesSIMD::
+run_generic( const LHCb::RichTrackSegment::Vector& segments,
+             const CherenkovAngles::Vector& ckAngles ) const
+{
+#include "../RichRayTraceCherenkovConesSIMD.icpp"
+}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp
new file mode 100644
index 0000000000..4b59308297
--- /dev/null
+++ b/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp
@@ -0,0 +1,14 @@
+
+// local
+#include "../RichRayTraceCherenkovConesSIMD.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future::Rec;
+
+MassHypoRingsVector
+RayTraceCherenkovConesSIMD::
+run_sse4( const LHCb::RichTrackSegment::Vector& segments,
+          const CherenkovAngles::Vector& ckAngles ) const
+{
+#include "../RichRayTraceCherenkovConesSIMD.icpp"
+}
diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
index 88264c4108..a227c20223 100644
--- a/Rich/RichRecTests/CMakeLists.txt
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -8,6 +8,7 @@ gaudi_depends_on_subdirs(Det/RichDet
                          Kernel/LHCbKernel
                          Kernel/LHCbMath
                          Kernel/VectorClass
+                         Kernel/TemplatedGenVector
                          Kernel/Vc
                          Rich/RichRecUtils)
 
@@ -16,7 +17,7 @@ find_package(Boost)
 find_package(GSL)
 find_package(Eigen)
 find_package(Vc)
-find_package(ROOT COMPONENTS MathCore GenVector)
+find_package(ROOT COMPONENTS MathCore GenVector )
 
 message(STATUS "Using Vc ${Vc_INCLUDE_DIR} ${Vc_LIB_DIR}")
 message(STATUS "Vc DEFINITIONS ${Vc_DEFINITIONS}")
@@ -30,29 +31,29 @@ if(GAUDI_BUILD_TESTS)
 
   gaudi_add_executable(RichPhotonRecoTestSSE4
                        src/PhotonReco/main_sse4.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestSSE4 -lrt )
   set_property(SOURCE src/RayTracing/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4.2 " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX
                        src/PhotonReco/main_avx.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX -lrt )
   set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX2
                        src/PhotonReco/main_avx2.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2 -lrt )
   set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX2FMA
                        src/PhotonReco/main_avx2fma.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2FMA -lrt )
   set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
 
@@ -60,29 +61,29 @@ if(GAUDI_BUILD_TESTS)
 
   gaudi_add_executable(RichRayTracingTestSSE4
                        src/RayTracing/main_sse4.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestSSE4 "-lrt ${Vc_LIB_DIR}/libVc.a" )
   set_property(SOURCE src/RayTracing/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -msse4.2 " )
 
   gaudi_add_executable(RichRayTracingTestAVX
                        src/RayTracing/main_avx.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX "-lrt ${Vc_LIB_DIR}/libVc.a" )
   set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
   gaudi_add_executable(RichRayTracingTestAVX2
                        src/RayTracing/main_avx2.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2 "-lrt ${Vc_LIB_DIR}/libVc.a" )
   set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
   gaudi_add_executable(RichRayTracingTestAVX2FMA
                        src/RayTracing/main_avx2fma.cpp
-                       INCLUDE_DIRS ROOT Vc Eigen GSL VectorClass src
-                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel)
+                       INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
+                       LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2FMA "-lrt ${Vc_LIB_DIR}/libVc.a" )
   set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
 
diff --git a/Rich/RichRecTests/src/RayTracing/main.icpp b/Rich/RichRecTests/src/RayTracing/main.icpp
index 8f446edfb7..802a83b2b7 100644
--- a/Rich/RichRecTests/src/RayTracing/main.icpp
+++ b/Rich/RichRecTests/src/RayTracing/main.icpp
@@ -77,6 +77,7 @@ inline void trace( DATA & dataV )
   {
     reflectSpherical( data.position, data.direction, data.CoC, data.radius );
     reflectPlane    ( data.position, data.direction, data.plane );
+    std::cout << data.position << std::endl;
   }
 }
 
@@ -88,10 +89,12 @@ unsigned long long int __attribute__((noinline)) rayTrace( const DATA & in_dataV
 
   unsigned long long int best_dur{ 99999999999999999 };
 
-  const unsigned int nTests = 10000;
+  const unsigned int nTests = 1;
+  std::cout << "Running " << nTests << " tests on " << in_dataV.size() << " data objects" << std::endl;
+  DATA dataV; // working data copy;
   for ( unsigned int i = 0; i < nTests; ++i )
   {
-    auto dataV = in_dataV; // copy data, as it will be modified
+    dataV = in_dataV; // copy data, as it will be modified
     clock_gettime(CLOCK_MONOTONIC_RAW,&start);
     trace( dataV );
     clock_gettime(CLOCK_MONOTONIC_RAW,&end);
@@ -105,8 +108,8 @@ unsigned long long int __attribute__((noinline)) rayTrace( const DATA & in_dataV
 int main ( int /*argc*/, char** /*argv*/ )
 {
 
-  const unsigned int nPhotons = 96 * 1e2;
-  //const unsigned int nPhotons = 8;
+  //const unsigned int nPhotons = 96 * 1e2;
+  const unsigned int nPhotons = 8;
   std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
 
   // Templated GenVector
@@ -114,16 +117,16 @@ int main ( int /*argc*/, char** /*argv*/ )
   using LHCbXYZVectorD = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<double>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using LHCbXYZPointF  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using LHCbXYZVectorF = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<float>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
-  using LHCbPlane3DD   = LHCbROOT::Math::Plane3D<double>;
-  using LHCbPlane3DF   = LHCbROOT::Math::Plane3D<float>;
+  using LHCbPlane3DD   = LHCbROOT::Math::Impl::Plane3D<double>;
+  using LHCbPlane3DF   = LHCbROOT::Math::Impl::Plane3D<float>;
 
   // Vc
   using VcXYZPointD  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<Vc::double_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using VcXYZVectorD = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<Vc::double_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using VcXYZPointF  = LHCbROOT::Math::PositionVector3D<LHCbROOT::Math::Cartesian3D<Vc::float_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
   using VcXYZVectorF = LHCbROOT::Math::DisplacementVector3D<LHCbROOT::Math::Cartesian3D<Vc::float_v>,LHCbROOT::Math::DefaultCoordinateSystemTag>;
-  using VcPlane3DD   = LHCbROOT::Math::Plane3D<Vc::double_v>;
-  using VcPlane3DF   = LHCbROOT::Math::Plane3D<Vc::float_v>;
+  using VcPlane3DD   = LHCbROOT::Math::Impl::Plane3D<Vc::double_v>;
+  using VcPlane3DF   = LHCbROOT::Math::Impl::Plane3D<Vc::float_v>;
 
   //if ( false )
   {
-- 
GitLab


From a7d91483f5f313a6a5b0f7c9f641d10a190ccdbe Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Thu, 2 Mar 2017 00:12:18 +0100
Subject: [PATCH 27/68] remove unused features

---
 .../src/RichRayTraceCherenkovConesSIMD.cpp    | 15 -------------
 .../src/RichRayTraceCherenkovConesSIMD.h      | 22 ++++---------------
 .../src/RichRayTraceCherenkovConesSIMD.icpp   |  4 ----
 3 files changed, 4 insertions(+), 37 deletions(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
index f73429cae1..bbcb2f5cd1 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
@@ -14,7 +14,6 @@ RayTraceCherenkovConesSIMD::RayTraceCherenkovConesSIMD( const std::string& name,
                     KeyValue{ "CherenkovAnglesLocation",     CherenkovAnglesLocation::Emitted } },
                   { KeyValue{ "MassHypothesisRingsLocation", MassHypoRingsLocation::Emitted } } )
 {
-  //declareProperty( "RayTracingTool", m_rayTrace );
   // debugging
   //setProperty( "OutputLevel", MSG::VERBOSE );
 }
@@ -55,20 +54,6 @@ StatusCode RayTraceCherenkovConesSIMD::initialize()
     m_nBailout[rad] = static_cast<unsigned int> ( m_bailoutFrac[rad] * m_nPoints[rad] ); 
   }
 
-  // // the ray-tracing mode
-  // LHCb::RichTraceMode tmpMode ( LHCb::RichTraceMode::RespectHPDTubes,
-  //                               ( m_useDetailedHPDsForRayT ?
-  //                                 LHCb::RichTraceMode::SphericalHPDs :
-  //                                 LHCb::RichTraceMode::FlatHPDs ) );
-  // if ( m_checkBeamPipe ) { tmpMode.setBeamPipeIntersects(true); }
-  // m_traceModeRad[Rich::Aerogel]  = tmpMode;
-  // m_traceModeRad[Rich::Aerogel].setAeroRefraction(true);
-  // m_traceModeRad[Rich::Rich1Gas] = tmpMode;
-  // m_traceModeRad[Rich::Rich2Gas] = tmpMode;
-  // _ri_debug << "Aerogel  Track " << m_traceModeRad[Rich::Aerogel]  << endmsg;
-  // _ri_debug << "Rich1Gas Track " << m_traceModeRad[Rich::Rich1Gas] << endmsg;
-  // _ri_debug << "Rich2Gas Track " << m_traceModeRad[Rich::Rich2Gas] << endmsg;
-
   // Get the CPU capabilities and set dispatch method
   enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
   const auto cpuLevel = instrset_detect();
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
index ad0d403d01..5284a5a7ee 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
@@ -27,7 +27,6 @@
 #include "RichDet/DeRich.h"
 
 // Interfaces
-//#include "RichFutureInterfaces/IRichRayTracing.h"
 #include "RichInterfaces/IRichSmartIDTool.h"
 #include "RichInterfaces/IRichMirrorSegFinderLookUpTable.h"
 
@@ -156,10 +155,10 @@ namespace Rich
 
         /// Number of points to ray trace on each ring, for each radiator
         Gaudi::Property< RadiatorArray<unsigned int> > m_nPoints
-        { this, "NRingPoints", { 100u, 100u, 100u } };
+        { this, "NRingPoints", { 96u, 96u, 96u } };
 
         /// Bailout number
-        RadiatorArray<unsigned int> m_nBailout = {{}};
+        //RadiatorArray<unsigned int> m_nBailout = {{}};
 
         /// Cached cos and sin values around the ring, for each radiator
         RadiatorArray< CosSinPhi<double>::Vector > m_cosSinPhiV;
@@ -168,28 +167,15 @@ namespace Rich
         ToolHandle<const IMirrorSegFinderLookUpTable> m_mirrorSegFinder
         { "Rich::Future::MirrorSegFinderLookUpTable/MirrorFinder:PUBLIC", this };
 
-        /// Cached trace modes for each radiator
-        //RadiatorArray<LHCb::RichTraceMode> m_traceModeRad = {{}};
-
-        /// Flag to turn on or off checking of intersections with beampipe
-        //Gaudi::Property<bool> m_checkBeamPipe { this, "CheckBeamPipe", true };
-
-        /// Flag to switch between simple or detail HPD description in ray tracing
-        //Gaudi::Property<bool> m_useDetailedHPDsForRayT { this, "UseDetailedHPDs", false };
-
         /** Bailout fraction. If no ray tracings have worked after this fraction have been
          *  perfromed, then give up */
-        Gaudi::Property< RadiatorArray<float> > m_bailoutFrac
-        { this, "BailoutFraction", { 0.75, 0.75, 0.75 } };
+        //Gaudi::Property< RadiatorArray<float> > m_bailoutFrac
+        //{ this, "BailoutFraction", { 0.75, 0.75, 0.75 } };
 
         /// Flag to control if the secondary mirrors are treated as if they are completely flat
         Gaudi::Property< DetectorArray<bool> > m_treatSecMirrsFlat 
         { this, "AssumeFlatSecondaryMirrors", { true, false } };
 
-        /// Ray tracing tool
-        //ToolHandle<const IRayTracing> m_rayTrace
-        //{ "Rich::Future::RayTracing/RayTracing", this };
-
         /// RichSmartID Tool
         ToolHandle<const ISmartIDTool> m_idTool
         { "Rich::Future::SmartIDTool/SmartIDTool:PUBLIC", this };
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
index c5f11bb638..339693b184 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
@@ -246,10 +246,6 @@
           
         } // loop over photons
         
-
-
-
-
         
       }
       
-- 
GitLab


From 95bb3ebfd903eaddc755dd525acd4e83a33bb23b Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Thu, 2 Mar 2017 00:20:35 +0100
Subject: [PATCH 28/68] remove unused features

---
 .../src/RichRayTraceCherenkovConesSIMD.cpp                      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
index bbcb2f5cd1..d8b5571d91 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
@@ -51,7 +51,7 @@ StatusCode RayTraceCherenkovConesSIMD::initialize()
     for ( unsigned int iPhot = 0; iPhot < m_nPoints[rad]; ++iPhot, ckPhi+=incPhi )
     { m_cosSinPhiV[rad].emplace_back( ckPhi ); }
     // bailout number
-    m_nBailout[rad] = static_cast<unsigned int> ( m_bailoutFrac[rad] * m_nPoints[rad] ); 
+    //m_nBailout[rad] = static_cast<unsigned int> ( m_bailoutFrac[rad] * m_nPoints[rad] ); 
   }
 
   // Get the CPU capabilities and set dispatch method
-- 
GitLab


From a7305554fce429feef8c00525dcb61405d82aaba Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 11:37:30 +0100
Subject: [PATCH 29/68] Remove SIMD CK cone ray tracing algorithm. Vectorised
 ray tracing moved to RichFutureTools.

---
 .../src/RichRayTraceCherenkovConesSIMD.cpp    |  75 -----
 .../src/RichRayTraceCherenkovConesSIMD.h      | 187 -------------
 .../src/RichRayTraceCherenkovConesSIMD.icpp   | 257 ------------------
 .../src/avx/RichRayTraceCherenkovCones.cpp    |  14 -
 .../src/avx2/RichRayTraceCherenkovCones.cpp   |  14 -
 .../generic/RichRayTraceCherenkovCones.cpp    |  14 -
 .../src/sse4/RichRayTraceCherenkovCones.cpp   |  14 -
 7 files changed, 575 deletions(-)
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
 delete mode 100644 Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
deleted file mode 100644
index d8b5571d91..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-
-// local
-#include "RichRayTraceCherenkovConesSIMD.h"
-
-// All code is in general Rich reconstruction namespace
-using namespace Rich::Future::Rec;
-
-//=============================================================================
-
-RayTraceCherenkovConesSIMD::RayTraceCherenkovConesSIMD( const std::string& name, 
-                                                ISvcLocator* pSvcLocator )
-  : Transformer ( name, pSvcLocator,
-                  { KeyValue{ "TrackSegmentsLocation",       LHCb::RichTrackSegmentLocation::Default },
-                    KeyValue{ "CherenkovAnglesLocation",     CherenkovAnglesLocation::Emitted } },
-                  { KeyValue{ "MassHypothesisRingsLocation", MassHypoRingsLocation::Emitted } } )
-{
-  // debugging
-  //setProperty( "OutputLevel", MSG::VERBOSE );
-}
-
-//=============================================================================
-
-StatusCode RayTraceCherenkovConesSIMD::initialize()
-{
-  // Sets up various tools and services
-  auto sc = Transformer::initialize();
-  if ( !sc ) return sc;
-
-  // load tools
-  //sc = sc && m_rayTrace.retrieve();
-  sc = sc && m_idTool.retrieve();
-  sc = sc && m_mirrorSegFinder.retrieve();
-
-  // RICH detector elements
-  m_rich[Rich::Rich1]   = getDet<DeRich>( DeRichLocations::Rich1 );
-  m_rich[Rich::Rich2]   = getDet<DeRich>( DeRichLocations::Rich2 );
-
-  // loop over radiators
-  for ( const auto rad : Rich::radiators() )
-  {
-    // Check # photon is exactly divisible by 8 (for SIMD vectors without padding)
-    if ( m_nPoints[rad] % 8 != 0 )
-    {
-      return Error( "# photons must be a multiple of 8 to avoid need for SIMD padding" );
-    }
-    // Fill cos and sin values
-    m_cosSinPhiV[rad].clear();
-    m_cosSinPhiV[rad].reserve( m_nPoints[rad] );
-    const auto incPhi = Gaudi::Units::twopi / static_cast<double>(m_nPoints[rad]);
-    double ckPhi = 0.0;
-    for ( unsigned int iPhot = 0; iPhot < m_nPoints[rad]; ++iPhot, ckPhi+=incPhi )
-    { m_cosSinPhiV[rad].emplace_back( ckPhi ); }
-    // bailout number
-    //m_nBailout[rad] = static_cast<unsigned int> ( m_bailoutFrac[rad] * m_nPoints[rad] ); 
-  }
-
-  // Get the CPU capabilities and set dispatch method
-  enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
-  const auto cpuLevel = instrset_detect();
-  _ri_debug << "Instruction set level = " << cpuLevel << endmsg;
-  if      ( cpuLevel >= AVX2 ) { m_run = &RayTraceCherenkovConesSIMD::run_avx2; }
-  else if ( cpuLevel >= AVX  ) { m_run = &RayTraceCherenkovConesSIMD::run_avx; }
-  else if ( cpuLevel >= SSE4 ) { m_run = &RayTraceCherenkovConesSIMD::run_sse4; }
-  else                         { m_run = &RayTraceCherenkovConesSIMD::run_generic; }
-
-  // return
-  return sc;
-}
-
-//=============================================================================
-
-// Declaration of the Algorithm Factory
-DECLARE_ALGORITHM_FACTORY( RayTraceCherenkovConesSIMD )
-
-//=============================================================================
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
deleted file mode 100644
index 5284a5a7ee..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.h
+++ /dev/null
@@ -1,187 +0,0 @@
-
-#pragma once
-
-// Gaudi
-#include "GaudiKernel/ParsersFactory.h"
-#include "GaudiKernel/StdArrayAsProperty.h"
-#include "GaudiAlg/Transformer.h"
-#include "GaudiKernel/PhysicalConstants.h"
-
-// Base class
-#include "RichFutureRecBase/RichRecAlgBase.h"
-
-// Event Model
-#include "RichFutureRecEvent/RichRecCherenkovAngles.h"
-#include "RichFutureRecEvent/RichRecMassHypoRings.h"
-
-// Utils
-#include "RichUtils/RichTrackSegment.h"
-#include "RichFutureUtils/RichGeomPhoton.h"
-#include "RichUtils/ZipRange.h"
-#include "RichUtils/RichRayTracingUtils.h"
-
-// Rec Utils
-#include "RichRecUtils/RichRadCorrLocalPositions.h"
-
-// RichDet
-#include "RichDet/DeRich.h"
-
-// Interfaces
-#include "RichInterfaces/IRichSmartIDTool.h"
-#include "RichInterfaces/IRichMirrorSegFinderLookUpTable.h"
-
-// VDT
-#include "vdt/sincos.h"
-
-// Vector Class
-#include "VectorClass/instrset.h"
-
-// Vc
-#include <Vc/Vc>
-
-// LHCb TemplatedGenVector
-#include "TemplatedGenVector/DisplacementVector3D.h"
-#include "TemplatedGenVector/PositionVector3D.h"
-#include "TemplatedGenVector/Plane3D.h"
-
-namespace Rich
-{
-  namespace Future
-  {
-
-    // Use the functional framework
-    using namespace Gaudi::Functional;
-
-    namespace Rec
-    {
-
-      /** @class RayTraceCherenkovConesSIMD RichRayTraceCherenkovConesSIMD.h
-       *
-       *  Creates the Cherenkov cones for each segment and mass hypothesis,
-       *  using photon raytracing.
-       *
-       *  @author Chris Jones
-       *  @date   2016-09-30
-       */
-
-      class RayTraceCherenkovConesSIMD final :
-        public Transformer< MassHypoRingsVector( const LHCb::RichTrackSegment::Vector&,
-                                                 const CherenkovAngles::Vector& ),
-                            Traits::BaseClass_t<AlgBase> >
-      {
-
-      public:
-
-        /// Standard constructor
-        RayTraceCherenkovConesSIMD( const std::string& name,
-                                    ISvcLocator* pSvcLocator );
-
-        /// Initialization after creation
-        StatusCode initialize() override;
-
-      public:
-
-        /// Functional operator
-        inline MassHypoRingsVector
-          operator()( const LHCb::RichTrackSegment::Vector& segments,
-                      const CherenkovAngles::Vector& ckAngles ) const override
-        {
-          return (this->*m_run)( segments, ckAngles );
-        }
-
-      private:
-
-        /// Generic dispatch function
-        MassHypoRingsVector
-          run_generic( const LHCb::RichTrackSegment::Vector& segments,
-                       const CherenkovAngles::Vector& ckAngles ) const;
-
-        /// SSE4 dispatch function
-        MassHypoRingsVector
-          run_sse4( const LHCb::RichTrackSegment::Vector& segments,
-                    const CherenkovAngles::Vector& ckAngles ) const;
-
-        /// AVX dispatch function
-        MassHypoRingsVector
-          run_avx( const LHCb::RichTrackSegment::Vector& segments,
-                   const CherenkovAngles::Vector& ckAngles ) const;
-
-        /// AVX2 dispatch function
-        MassHypoRingsVector
-          run_avx2( const LHCb::RichTrackSegment::Vector& segments,
-                    const CherenkovAngles::Vector& ckAngles ) const;
-
-        /** Pointer to dispatch function for the operator call
-         *  Default to lowest common denominator. 
-         *  Reset in initialize() according to runtime support */
-        MassHypoRingsVector (RayTraceCherenkovConesSIMD::*m_run)
-          ( const LHCb::RichTrackSegment::Vector& segments,
-            const CherenkovAngles::Vector& ckAngles ) const 
-          = &RayTraceCherenkovConesSIMD::run_generic;
-
-      private: // helper classes
-
-        /** @class CosSinPhi RichRayTraceCherenkovCone.h
-         *
-         *  Utility class to cache cos and sin values
-         *
-         *  @author Chris Jones   Christopher.Rob.Jones@cern.ch
-         *  @date   17/02/2008
-         */
-        template< typename TYPE >
-        class CosSinPhi
-        {
-        public:
-          typedef std::vector<CosSinPhi> Vector;
-        public:
-          explicit CosSinPhi( const TYPE _phi ) : phi(_phi)
-          {
-            vdt::fast_sincos( phi, sinPhi, cosPhi );
-          }
-        public:
-          TYPE phi    = 0; ///< CK phi
-          TYPE cosPhi = 0; ///< Cos(CK phi)
-          TYPE sinPhi = 0; ///< Sin(CK phi)
-        };
-
-        /// Vc Vector
-        template < typename TYPE >
-        using VcAllocVector = std::vector< TYPE, Vc::Allocator<TYPE> >;
-        
-      private:
-
-        /// Rich1 and Rich2 pointers
-        Rich::DetectorArray<const DeRich*> m_rich{{nullptr,nullptr}};
-
-        /// Number of points to ray trace on each ring, for each radiator
-        Gaudi::Property< RadiatorArray<unsigned int> > m_nPoints
-        { this, "NRingPoints", { 96u, 96u, 96u } };
-
-        /// Bailout number
-        //RadiatorArray<unsigned int> m_nBailout = {{}};
-
-        /// Cached cos and sin values around the ring, for each radiator
-        RadiatorArray< CosSinPhi<double>::Vector > m_cosSinPhiV;
-
-        /// Mirror segment finder tool
-        ToolHandle<const IMirrorSegFinderLookUpTable> m_mirrorSegFinder
-        { "Rich::Future::MirrorSegFinderLookUpTable/MirrorFinder:PUBLIC", this };
-
-        /** Bailout fraction. If no ray tracings have worked after this fraction have been
-         *  perfromed, then give up */
-        //Gaudi::Property< RadiatorArray<float> > m_bailoutFrac
-        //{ this, "BailoutFraction", { 0.75, 0.75, 0.75 } };
-
-        /// Flag to control if the secondary mirrors are treated as if they are completely flat
-        Gaudi::Property< DetectorArray<bool> > m_treatSecMirrsFlat 
-        { this, "AssumeFlatSecondaryMirrors", { true, false } };
-
-        /// RichSmartID Tool
-        ToolHandle<const ISmartIDTool> m_idTool
-        { "Rich::Future::SmartIDTool/SmartIDTool:PUBLIC", this };
-
-      };
-
-    }
-  }
-}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
deleted file mode 100644
index 339693b184..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovConesSIMD.icpp
+++ /dev/null
@@ -1,257 +0,0 @@
-
-{
-
-  // types
-  using ScFloat  = float;
-  using VcFloat  = Vc::float_v;
-  using VcInt    = Vc::int_v;
-  using ScInt    = int;
-  using VcPoint  = LHCbROOT::Math::PositionVector3D    < LHCbROOT::Math::Cartesian3D<VcFloat> >;
-  using VcVector = LHCbROOT::Math::DisplacementVector3D< LHCbROOT::Math::Cartesian3D<VcFloat> >;
-  using VcPlane  = LHCbROOT::Math::Impl::Plane3D<VcFloat>;
-
-  // Ray tracing utils
-  using namespace Rich::RayTracingUtils;
-
-  // The data to return
-  MassHypoRingsVector ringsV;
-  ringsV.reserve( segments.size() );
-  
-  // Temporary working photon object. Need to eventually remove need for this.
-  GeomPhoton photon;
-  
-  // local position corrector
-  // longer term need to remove this
-  const Rich::Rec::RadPositionCorrector corrector;
- 
-  // loop over the input data
-  for ( const auto && data : Ranges::ConstZip(segments,ckAngles) )
-  {
-    const auto & segment = std::get<0>(data);
-    const auto & ckTheta = std::get<1>(data);
-    
-    // Add a set of mass hypo rings for this segment
-    ringsV.emplace_back( );
-    auto & rings = ringsV.back();
-    
-    // which rich and radiator
-    const auto rich = segment.rich();
-    const auto rad  = segment.radiator();
-    
-    // best emission point
-    const auto & ePnt = segment.bestPoint();
-
-    // Start detector side
-    const auto side = m_rich[rich]->side(ePnt);
-
-    // Number of VcVector objects
-    const auto NVC = m_nPoints[rad] / VcFloat::Size;
-       
-    // Loop over PID types
-    for ( const auto id : activeParticles() )
-    {
-      // Above threshold ?
-      if ( ckTheta[id] > 0 )
-      {
-        
-        // compute sin and cos theta
-        double sinTheta(0), cosTheta(0);
-        vdt::fast_sincos( ckTheta[id], sinTheta, cosTheta );
-        
-        // reserve size in the points container
-        rings[id].reserve( m_nPoints[rad] );
-
-        // Form the starting detector sides
-        VcAllocVector<VcInt> photSides( NVC, VcInt(side) );
-        
-        // Form the starting points
-        VcAllocVector<VcPoint> startPoints( NVC, VcPoint(ePnt.x(),ePnt.y(),ePnt.z()) );
-        
-        // Form the starting points and directions.
-        VcAllocVector<VcVector> startDirs;
-        // Will be able to vectorise this better once GenVector in ROOT has my updates
-        {
-          unsigned int nPhot(0);
-          // Vc vectors for (x,y,z)
-          VcFloat x,y,z;
-          for ( auto iP = m_cosSinPhiV[rad].begin(); iP != m_cosSinPhiV[rad].end(); ++iP, ++nPhot )
-          {
-            // Vc index
-            const auto ivc = nPhot % VcFloat::Size;
-            // Photon direction around loop
-            const auto photDir =
-              segment.vectorAtCosSinThetaPhi( cosTheta,     sinTheta,
-                                              (*iP).cosPhi, (*iP).sinPhi );
-            // Fill Vc words
-            x[ivc] = photDir.x();
-            y[ivc] = photDir.y();
-            z[ivc] = photDir.z();
-            // If last index, make a new entry in the vector and fill
-            if ( VcFloat::Size-1 == ivc ) { startDirs.emplace_back(x,y,z);  }
-          }
-        }
-
-        // Starting CoC values
-        VcAllocVector<VcPoint> CoCs( NVC, VcPoint( m_rich[rich]->nominalCentreOfCurvature(side) ) );
-
-        // Starting RoC values
-        VcAllocVector<VcFloat> RoCs( NVC, VcFloat( m_rich[rich]->sphMirrorRadius() ) );
-
-        // Intersect with the spherical mirrors to find the reflection points and use these
-        // to find the mirror segments to use for the primary mirrors
-        for ( auto && data : Ranges::Zip(startPoints,startDirs,CoCs,RoCs,photSides) )
-        {
-          auto & startP = std::get<0>(data);
-          auto & startD = std::get<1>(data);
-          auto & CoC    = std::get<2>(data);
-          auto & RoC    = std::get<3>(data);
-          auto & sides  = std::get<4>(data);
-
-          // interset with nominal primary
-          VcPoint nomSphInter;
-          auto mask = intersectSpherical( startP, startD, CoC, RoC, nomSphInter );
-          if ( any_of(mask) )
-          {
-            
-            // Check if we are on the same detector side or not
-            VcInt newSides(sides);
-            // To Do - Fix RichDet Vc support
-            //m_rich[rich]->sides( nomSphInter, newSides );
-            {
-              VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
-              for ( std::size_t i = 0; i < VcFloat::Size; ++i )
-              {
-                // Check the detector side for the intersection point
-                const auto nside = m_rich[rich]->side( (ScFloat)nomSphInter.x()[i],
-                                                       (ScFloat)nomSphInter.y()[i] );
-                newSides[i] = ScInt( nside );
-                if ( newSides[i] != sides[i] )
-                {
-                  // Update CoC and RoC for this entry
-                  const auto& nCoC = m_rich[rich]->nominalCentreOfCurvature(nside);
-                  x[i] = nCoC.x();
-                  y[i] = nCoC.y();
-                  z[i] = nCoC.z();
-                  RoC[i] = m_rich[rich]->sphMirrorRadius();
-                }
-              }
-              // Update the CoC point
-              CoC = VcPoint(x,y,z);
-            }
-            // if any think changed rerun the intersection
-            if ( UNLIKELY( any_of( sides != newSides ) ) )
-            {
-              sides = newSides;
-              mask &= intersectSpherical( startP, startD, CoC, RoC, nomSphInter );
-            }
-
-            if ( any_of(mask) )
-            {
-
-              {
-                // Copy the CoC parameters
-                VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
-                // Find primary mirror segments to update CoC and RoC foreach photon
-                for ( std::size_t i = 0; i < VcFloat::Size; ++i )
-                {
-                  // Find the primary mirror segment for this point
-                  const auto * sphSegment = 
-                    m_mirrorSegFinder.get()->findSphMirror( rich, side,
-                                                            (ScFloat)nomSphInter.x()[i],
-                                                            (ScFloat)nomSphInter.y()[i] );
-                  // update the mirror parameters
-                  const auto& nCoC = sphSegment->centreOfCurvature();
-                  x[i]   = nCoC.x();
-                  y[i]   = nCoC.y();
-                  z[i]   = nCoC.z();
-                  RoC[i] = sphSegment->radius();
-                }
-                // Update the CoC point
-                CoC = VcPoint(x,y,z);    
-              }
-              
-              // perform the final reflection on the primaries
-              mask &= reflectSpherical( startP, startD, CoC, RoC );
-
-              if ( any_of(mask) )
-              {
-                // move on to the secondary mirrors
- 
-                // nominal intersection point
-                VcPoint planeInt;
-                const auto& plane = m_rich[rich]->nominalPlane(side);
-                VcPlane vcplane( plane.A(), plane.B(), plane.C(), plane.D() );
-                mask &= intersectPlane( startP, startD, vcplane, planeInt );
-
-                if ( any_of(mask) )
-                {
-                  // Find the exact secondary mirror segments
-
-                  // Copy the nominal plane parameters
-                  auto A(vcplane.A()), B(vcplane.B()), C(vcplane.C()), D(vcplane.D());
-                  // Copy the CoC parameters
-                  VcFloat x(CoC.x()), y(CoC.y()), z(CoC.z());
-                  for ( std::size_t i = 0; i < VcFloat::Size; ++i )
-                  {
-                    // find secondary mirror segment
-                    const auto * secSegment =
-                      m_mirrorSegFinder.get()->findSecMirror( rich, side,
-                                                              (ScFloat)planeInt.x()[i],
-                                                              (ScFloat)planeInt.y()[i] );
-                    // flat versus spherical treatment
-                    if ( m_treatSecMirrsFlat[rich] )
-                    {
-                      // Update the normal plane
-                      const auto & npl = secSegment->centreNormalPlane();
-                      A[i] = npl.A();
-                      B[i] = npl.B();
-                      C[i] = npl.C();
-                      D[i] = npl.D();
-                    }
-                    else
-                    {
-                      // update speherical parameters for the secondary mirrors
-                      const auto& nCoC = secSegment->centreOfCurvature();
-                      x[i]   = nCoC.x();
-                      y[i]   = nCoC.y();
-                      z[i]   = nCoC.z();
-                      RoC[i] = secSegment->radius();
-                    }
-                  }
-                  
-                  // reflect off the secondary mirrors
-                  mask &= ( m_treatSecMirrsFlat[rich] ?
-                            reflectPlane    ( startP, startD, VcPlane(A,B,C,D) ) :
-                            reflectSpherical( startP, startD, VcPoint(x,y,z), RoC ) );
-
-
-                  // If OK, proceed to getting the hit position
-                  if ( any_of(mask) )
-                  {
-
-
-
-
-
-
-                  }
-                  
-                }
-
-              }
-
-            }
-            
-          } // first intersection ok
-          
-        } // loop over photons
-        
-        
-      }
-      
-    }
-    
-  }
-  
-  return ringsV;
-}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
deleted file mode 100644
index 067b58c58b..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/avx/RichRayTraceCherenkovCones.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-// local
-#include "../RichRayTraceCherenkovConesSIMD.h"
-
-// All code is in general Rich reconstruction namespace
-using namespace Rich::Future::Rec;
-
-MassHypoRingsVector
-RayTraceCherenkovConesSIMD::
-run_avx( const LHCb::RichTrackSegment::Vector& segments,
-         const CherenkovAngles::Vector& ckAngles ) const
-{
-#include "../RichRayTraceCherenkovConesSIMD.icpp"
-}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
deleted file mode 100644
index f7db884820..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/avx2/RichRayTraceCherenkovCones.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-// local
-#include "../RichRayTraceCherenkovConesSIMD.h"
-
-// All code is in general Rich reconstruction namespace
-using namespace Rich::Future::Rec;
-
-MassHypoRingsVector
-RayTraceCherenkovConesSIMD::
-run_avx2( const LHCb::RichTrackSegment::Vector& segments,
-          const CherenkovAngles::Vector& ckAngles ) const
-{
-#include "../RichRayTraceCherenkovConesSIMD.icpp"
-}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
deleted file mode 100644
index 311c28b8d8..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/generic/RichRayTraceCherenkovCones.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-// local
-#include "../RichRayTraceCherenkovConesSIMD.h"
-
-// All code is in general Rich reconstruction namespace
-using namespace Rich::Future::Rec;
-
-MassHypoRingsVector
-RayTraceCherenkovConesSIMD::
-run_generic( const LHCb::RichTrackSegment::Vector& segments,
-             const CherenkovAngles::Vector& ckAngles ) const
-{
-#include "../RichRayTraceCherenkovConesSIMD.icpp"
-}
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp
deleted file mode 100644
index 4b59308297..0000000000
--- a/Rich/RichFutureRecTrackAlgorithms/src/sse4/RichRayTraceCherenkovCones.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-// local
-#include "../RichRayTraceCherenkovConesSIMD.h"
-
-// All code is in general Rich reconstruction namespace
-using namespace Rich::Future::Rec;
-
-MassHypoRingsVector
-RayTraceCherenkovConesSIMD::
-run_sse4( const LHCb::RichTrackSegment::Vector& segments,
-          const CherenkovAngles::Vector& ckAngles ) const
-{
-#include "../RichRayTraceCherenkovConesSIMD.icpp"
-}
-- 
GitLab


From bf1637b6a1153a11b37b6c5807c26db3aaa0a98b Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 11:37:58 +0100
Subject: [PATCH 30/68] Remove test options

---
 .../python/RichFutureRecSys/ConfiguredRichReco.py   | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
index 9fc833512e..c21660c283 100644
--- a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
+++ b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
@@ -322,7 +322,6 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         from Configurables import Rich__Future__Rec__TrackEmittedCherenkovAngles as EmittedCherenkovAngles
         from Configurables import Rich__Future__Rec__TrackSignalCherenkovAngles as SignalCherenkovAngles
         from Configurables import Rich__Future__Rec__RayTraceCherenkovCones as EmittedMassCones
-        from Configurables import Rich__Future__Rec__RayTraceCherenkovConesSIMD as EmittedMassConesSIMD
         from Configurables import Rich__Future__Rec__GeomEffCKMassRings as GeomEff
         from Configurables import Rich__Future__Rec__TrackFunctionalCherenkovResolutions as TrackCKResolutions
         from Configurables import Rich__Future__Rec__SelectTrackSegments as SelectTrackSegments
@@ -387,16 +386,6 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         # Options
         emitMassCones.NRingPoints = NRingPoints
 
-        # Cherenkov mass cones using emitted spectra SIMD
-        emitMassConesSIMD = makeRichAlg( EmittedMassConesSIMD, "RichMassConesSIMD"+name, algprops )
-        # Input
-        emitMassConesSIMD.TrackSegmentsLocation   = locs["TrackSegmentsLocation"]
-        emitMassConesSIMD.CherenkovAnglesLocation = locs["EmittedCherenkovAnglesLocation"]
-        # Output
-        emitMassConesSIMD.MassHypothesisRingsLocation = locs["EmittedMassHypothesisRingsLocation"]+"SIMD"
-        # Options
-        emitMassConesSIMD.NRingPoints = NRingPoints
-
         # Detectable photon yields
         detY = makeRichAlg( DetectableYields, "RichDetectableYields"+name, algprops )
         # Inputs
@@ -465,7 +454,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
         segs = GaudiSequencer( "RichTracks" + name,
                                MeasureTime = MeasureTime,
                                Members = [ segCr, tkGloPnts, tkLocPnts, emitY, 
-                                           emitChAngles, emitMassCones, emitMassConesSIMD, detY, 
+                                           emitChAngles, emitMassCones, detY, 
                                            geomEff, tkSel, sigYields, sigChAngles, tkRes ] )
         # Add to final sequence
         tkSeq.Members += [ segs ]
-- 
GitLab


From 981435e0ac9d25e9109f58281204ee61931230af Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 11:38:34 +0100
Subject: [PATCH 31/68] Use vectorised ray tracing from
 RichRayTraceCherenkovCones

---
 .../CMakeLists.txt                            |  20 +--
 .../src/RichRayTraceCherenkovCones.cpp        | 114 +++++++++++++-----
 .../src/RichRayTraceCherenkovCones.h          |   4 +
 3 files changed, 92 insertions(+), 46 deletions(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt b/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
index 9873e24314..c4c1f41f28 100644
--- a/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
+++ b/Rich/RichFutureRecTrackAlgorithms/CMakeLists.txt
@@ -8,28 +8,16 @@ gaudi_depends_on_subdirs(Rich/RichFutureRecBase
                          Rich/RichUtils
                          Rich/RichFutureUtils
                          Tr/TrackKernel
-                         Tr/TrackInterfaces
-                         Kernel/TemplatedGenVector
-                         Kernel/Vc
-                         Kernel/VectorClass)
+                         Tr/TrackInterfaces)
 
 find_package(ROOT)
 find_package(Boost)
 find_package(GSL)
 find_package(VDT)
-find_package(Vc)
 
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS} ${Vc_INCLUDE_DIR})
 
 gaudi_add_module(RichFutureRecTrackAlgorithms
-                 src/*.cpp src/generic/*.cpp src/sse4/*.cpp src/avx/*.cpp src/avx2/*.cpp
-                 INCLUDE_DIRS Vc Boost GSL VDT Kernel/VectorClass Rich/RichFutureRecBase Rich/RichUtils Rich/RichFutureUtils Tr/TrackInterfaces Tr/TrackKernel
-                 LINK_LIBRARIES Boost GSL VDT RichFutureRecBase RichUtils RichFutureUtils TemplatedGenVectorLib )
-
-target_link_libraries( RichFutureRecTrackAlgorithms "${Vc_LIB_DIR}/libVc.a" )
-
-set_property(SOURCE src/RichRayTraceCherenkovConesSIMD.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes " )
-set_property(SOURCE src/generic/RichRayTraceCherenkovCones.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes " )
-set_property(SOURCE src/sse4/RichRayTraceCherenkovCones.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -msse4.2 " )
-set_property(SOURCE src/avx/RichRayTraceCherenkovCones.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
-set_property(SOURCE src/avx2/RichRayTraceCherenkovCones.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx2 -mfma -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+                 src/*.cpp
+                 INCLUDE_DIRS Boost GSL VDT Rich/RichFutureRecBase Rich/RichUtils Rich/RichFutureUtils Tr/TrackInterfaces Tr/TrackKernel
+                 LINK_LIBRARIES Boost GSL VDT RichFutureRecBase RichUtils RichFutureUtils )
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
index b39a6afa73..f411bee2bd 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
@@ -110,46 +110,100 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
         // reserve size in the points container
         rings[id].reserve( m_nPoints[rad] );
 
-        // loop around the ring
-        unsigned int nOK(0), nPhot(0);
-        for ( auto iP = m_cosSinPhiV[rad].begin(); iP != m_cosSinPhiV[rad].end(); ++iP, ++nPhot )
+        // Container for photon directions
+        std::vector<Gaudi::XYZVector> vects;
+        vects.reserve( m_nPoints[rad] );
+
+        // loop around the ring to create the directions
+        for ( const auto& P : m_cosSinPhiV[rad] )
         {
           // Photon direction around loop
-          const auto photDir =
-            segment.vectorAtCosSinThetaPhi( cosTheta,     sinTheta,
-                                            (*iP).cosPhi, (*iP).sinPhi );
-
-          // do the ray tracing
-          // really need to speed this up by removing virtual function call and need for photon. 
-          const auto result =
-            m_rayTrace.get()->traceToDetector( rich, emissionPoint, photDir, photon, 
+          vects.emplace_back( segment.vectorAtCosSinThetaPhi( cosTheta, sinTheta,
+                                                              P.cosPhi, P.sinPhi ) );
+        }
+
+        // Which ray tracing to run
+        if ( m_useVectorised )
+        {
+
+          // The vectorised ray tracing
+          const auto results =
+            m_rayTrace.get()->traceToDetector( emissionPoint, vects, segment, m_traceModeRad[rad] );
+
+          // loop over the results and fill
+          unsigned int nOK(0), nPhot(0);
+          for ( const auto && data : Ranges::ConstZip(results,m_cosSinPhiV[rad]) )
+          {
+            const auto & res    = std::get<0>(data);
+            const auto & cosphi = std::get<1>(data);
+
+            // count photons
+            ++nPhot;
+
+            // Add a new point
+            const auto & gP = res.detectionPoint;
+            rings[id].emplace_back ( gP,
+                                     corrector.correct(m_idTool.get()->globalToPDPanel(gP),rad),
+                                     res.smartID,
+                                     (RayTracedCKRingPoint::Acceptance)(res.result),
+                                     res.primaryMirror,
+                                     res.secondaryMirror,
+                                     cosphi.phi );
+
+            // count raytraces that are in HPD panel
+            if ( res.result >= LHCb::RichTraceMode::InHPDPanel ) { ++nOK; }
+            
+          }
+
+        }
+        else
+        {
+
+          // Loop over the directions and ray trace them using the scalar method
+          unsigned int nOK(0), nPhot(0);
+          for ( const auto && data : Ranges::ConstZip(vects,m_cosSinPhiV[rad]) )
+          {
+            const auto & photDir = std::get<0>(data);
+            const auto & cosphi  = std::get<1>(data);
+
+            // count photons
+            ++nPhot;
+
+            // do the ray tracing
+            // really need to speed this up by removing virtual function call and need for photon. 
+            const auto result =
+              m_rayTrace.get()->traceToDetector( rich, emissionPoint, photDir, photon, 
                                                segment, 
                                                m_traceModeRad[rad], Rich::top ); // Note forced side is not used..
 
-          // Add a new point
-          const auto & gP = photon.detectionPoint();
-          rings[id].emplace_back ( gP,
-                                   corrector.correct(m_idTool.get()->globalToPDPanel(gP),rad),
-                                   photon.smartID(),
-                                   (RayTracedCKRingPoint::Acceptance)(result),
-                                   photon.primaryMirror(),
-                                   photon.secondaryMirror(),
-                                   (*iP).phi );
-
-          // count raytraces that are in HPD panel
-          if ( result >= LHCb::RichTraceMode::InHPDPanel ) { ++nOK; }
-          
-          // bailout check
-          if ( 0 == nOK && nPhot >= m_nBailout[rad] ) break;
+            // Add a new point
+            const auto & gP = photon.detectionPoint();
+            rings[id].emplace_back ( gP,
+                                     corrector.correct(m_idTool.get()->globalToPDPanel(gP),rad),
+                                     photon.smartID(),
+                                     (RayTracedCKRingPoint::Acceptance)(result),
+                                     photon.primaryMirror(),
+                                     photon.secondaryMirror(),
+                                     cosphi.phi );
+            
+            // count raytraces that are in HPD panel
+            if ( result >= LHCb::RichTraceMode::InHPDPanel ) { ++nOK; }
+            
+            // bailout check
+            if ( 0 == nOK && nPhot >= m_nBailout[rad] ) break; 
+          }
+
+          // if no good hits empty the container
+          if ( 0 == nOK ) { rings[id].clear(); }
           
         }
-
+        
       }
-
+      
     }
-
+    
   }
-
+  
   return ringsV;
 }
 
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
index cb61557178..9b653e9356 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
@@ -122,6 +122,10 @@ namespace Rich
         Gaudi::Property< RadiatorArray<float> > m_bailoutFrac
         { this, "BailoutFraction", { 0.75, 0.75, 0.75 } };
 
+        /// Use the scalar or vector ray tracing
+        Gaudi::Property<bool> m_useVectorised
+        { this, "UseVectorisedRayTracing", true };
+
         /// Ray tracing tool
         ToolHandle<const IRayTracing> m_rayTrace
         { "Rich::Future::RayTracing/RayTracing", this };
-- 
GitLab


From 32cf0707fd7606f8dc31c59dbb07007545f51128 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 16:13:21 +0100
Subject: [PATCH 32/68] Add new QuarticSollver from Rainer and Christina that
 uses a Newton Rhapson approach that is much faster than the original

---
 .../src/RichQuarticPhotonReco.h               |   6 +-
 .../src/application/PhotonReco/main.cpp       |   4 +-
 .../RichPhotonRecoUsingQuarticSoln.h          |   4 +-
 .../RichRecUtils/RichRecUtils/QuarticSolver.h |   5 +-
 .../RichRecUtils/QuarticSolverNewton.h        | 344 ++++++++++++++++++
 5 files changed, 352 insertions(+), 11 deletions(-)
 create mode 100755 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 7f5d5fe2a0..8449cc5409 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -36,7 +36,7 @@
 #include "RichDet/DeRichSphMirror.h"
 
 // Quartic Solver
-#include "RichRecUtils/QuarticSolver.h"
+#include "RichRecUtils/QuarticSolverNewton.h"
 
 // interfaces
 #include "RichInterfaces/IRichMirrorSegFinderLookUpTable.h"
@@ -136,8 +136,8 @@ namespace Rich
 
       private:
 
-        /// Quartic Solver
-        Rich::Rec::QuarticSolver m_quarticSolver;
+        /// Newton Quartic Solver 
+        Rich::Rec::QuarticSolverNewton m_quarticSolver;
 
         /// Rich1 and Rich2 detector elements
         DetectorArray<const DeRich *> m_rich = {{}};
diff --git a/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp b/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp
index 20a2eb747d..462946f929 100644
--- a/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp
+++ b/Rich/RichRecPhotonTools/src/application/PhotonReco/main.cpp
@@ -1,6 +1,6 @@
 
 // Quartic Solver
-#include "RichRecUtils/QuarticSolver.h"
+#include "RichRecUtils/QuarticSolverNewton.h"
 
 // STL
 #include <random>
@@ -10,7 +10,7 @@
 #include <typeinfo>
 
 // Make an instance of the quartic solver
-Rich::Rec::QuarticSolver qSolver;
+Rich::Rec::QuarticSolverNewton qSolver;
 
 Gaudi::XYZPoint sphReflPoint;
 
diff --git a/Rich/RichRecPhotonTools/src/component/RichPhotonRecoUsingQuarticSoln.h b/Rich/RichRecPhotonTools/src/component/RichPhotonRecoUsingQuarticSoln.h
index b1618bab6d..6331185cce 100755
--- a/Rich/RichRecPhotonTools/src/component/RichPhotonRecoUsingQuarticSoln.h
+++ b/Rich/RichRecPhotonTools/src/component/RichPhotonRecoUsingQuarticSoln.h
@@ -56,7 +56,7 @@
 #include "gsl/gsl_poly.h"
 
 // Quartic Solver
-#include "RichRecUtils/QuarticSolver.h"
+#include "RichRecUtils/QuarticSolverNewton.h"
 
 namespace Rich
 {
@@ -175,7 +175,7 @@ namespace Rich
       mutable const ISnellsLawRefraction * m_snellsLaw = nullptr;
 
       /// Quartic Solver
-      QuarticSolver m_quarticSolver;
+      QuarticSolverNewton m_quarticSolver;
 
       /** @brief Flag to indicate if the unambiguous photon test should be performed
        *  for each radiator
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
index 4fbabe905e..115dd3f353 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolver.h
@@ -7,8 +7,7 @@
  */
 //----------------------------------------------------------------------
 
-#ifndef RICHRECPHOTONTOOLS_QuarticSolver_H
-#define RICHRECPHOTONTOOLS_QuarticSolver_H 1
+#pragma once
 
 // Gaudi
 #include "GaudiKernel/Kernel.h"
@@ -241,5 +240,3 @@ namespace Rich
 
   }
 }
-
-#endif // RICHRECPHOTONTOOLS_QuarticSolver_H
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
new file mode 100755
index 0000000000..147cbde568
--- /dev/null
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -0,0 +1,344 @@
+
+//----------------------------------------------------------------------
+/** @file QuarticSolverNewton.h
+ *
+ *  @author Christina Quast, Rainer Schwemmer
+ *  @date   2017-02-03
+ */
+//----------------------------------------------------------------------
+
+#pragma once
+
+// Gaudi
+#include "GaudiKernel/Kernel.h"
+#include "GaudiKernel/Transform3DTypes.h"
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+
+// VectorClass
+#include "VectorClass/vectorclass.h"
+#include "VectorClass/complexvec.h"
+
+// STL
+#include <math.h>
+#include <type_traits>
+
+// Eigen
+#include "LHCbMath/EigenTypes.h"
+#include <Eigen/Geometry>
+
+// VDT
+#include "vdt/asin.h"
+
+// LHCb Maths
+#include "LHCbMath/FastRoots.h"
+
+namespace Rich
+{
+  namespace Rec
+  {
+
+    //-----------------------------------------------------------------------------
+    /** @class QuarticSolverNewton
+     *
+     *  Utility class that implements the solving of the Quartic equation for the RICH
+     *  Based on original code by Chris Jones
+     *
+     *  @author Christina Quast, Rainer Schwemmer
+     *  @date   2017-02-03
+     */
+    //-----------------------------------------------------------------------------
+    class QuarticSolverNewton
+    {
+
+    public:
+
+      // Use eigen types
+      typedef LHCb::Math::Eigen::XYZPoint  Point;   ///< Point type
+      typedef LHCb::Math::Eigen::XYZVector Vector;  ///< vector type
+
+    public:
+
+      /** Solves the characteristic quartic equation for the RICH optical system.
+       *
+       *  See note LHCB/98-040 RICH section 3 for more details
+       *
+       *  @param emissionPoint Assumed photon emission point on track
+       *  @param CoC           Spherical mirror centre of curvature
+       *  @param virtDetPoint  Virtual detection point
+       *  @param radius        Spherical mirror radius of curvature
+       *  @param sphReflPoint  The reconstructed reflection pont on the spherical mirror
+       *
+       *  @return boolean indicating status of the quartic solution
+       *  @retval true  Calculation was successful. sphReflPoint is valid.
+       *  @retval false Calculation failed. sphReflPoint is not valid.
+       */
+      template< class TYPE >
+      inline void solve( const Gaudi::XYZPoint& emissionPoint,
+                         const Gaudi::XYZPoint& CoC,
+                         const Gaudi::XYZPoint& virtDetPoint,
+                         const TYPE radius,
+                         Gaudi::XYZPoint& sphReflPoint ) const
+      {
+
+        // typedefs vectorised types
+        typedef Eigen::Matrix< TYPE , 3 , 1 > Eigen3Vector;
+        using Vec4x = typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
+
+        // vector from mirror centre of curvature to assumed emission point
+        const Vector evec( emissionPoint - CoC );
+        const TYPE e2 = evec.dot(evec);
+
+        // vector from mirror centre of curvature to virtual detection point
+        const Vector dvec( virtDetPoint - CoC );
+        const TYPE d2 = dvec.dot(dvec);
+
+        // various quantities needed to create quartic equation
+        // see LHCB/98-040 section 3, equation 3
+        const TYPE ed2 = e2 * d2;
+        //std::pow uses internal loop and causes branch misses and other inefficiencies
+        //There might be a constant exponent pow function too, but i'm too lazy to check.
+        const TYPE cosgamma2 = ( ed2 > 0 ? std::pow(evec.dot(dvec),2)/ed2 : 1.0 );
+        //const TYPE cosgamma2 = ( ed2 > 0.0f ? evec.dot(dvec)*evec.dot(dvec)/ed2 : 1.0f );
+        // vectorise 4 square roots into 1
+        //TODO: This vectorized sqrt is questionable. There is a lot of overhead in gathering
+        //The different components via unaligned loads. It's probably not
+        //Faster than just computing the 4 square roots individually.
+        const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
+                                           cosgamma2 < 1.0f ? 1.0f-cosgamma2 : 0.0f,
+                                           cosgamma2 ) );
+        const TYPE e         = tmp_sqrt[0];
+        const TYPE d         = tmp_sqrt[1];
+        const TYPE singamma  = tmp_sqrt[2];
+        const TYPE cosgamma  = tmp_sqrt[3];
+
+        const TYPE dx        = d * cosgamma;
+        const TYPE dy        = d * singamma;
+        const TYPE r2        = radius * radius;
+        const TYPE dy2       = dy * dy;
+        const TYPE edx       = e + dx;
+
+        // Fill array for quartic equation
+        const auto a0      =     4.0f * ed2;
+        //Newton solver doesn't care about a0 being not 1.0. Remove costly division and several multiplies.
+        //This has some downsides though. The a-values are hovering around a numerical value of 10^15. single
+        //precision float max is 10^37. A single square and some multiplies will push it over the limit of what
+        //single precision float can handle. It's ok for the newton method, but Halley or higher order Housholder
+        //will fail without this normalization.
+        //const auto inv_a0  =   ( a0 > 0 ? 1.0 / a0 : std::numeric_limits<TYPE>::max() );
+        const TYPE dyrad2  =     2.0f * dy * radius;
+        const TYPE a1      = - ( 2.0f * dyrad2 * e2 );// * inv_a0;
+        const TYPE a2      =   ( (dy2 * r2) + ( edx * edx * r2 ) - a0 );// * inv_a0;
+        const TYPE a3      =   ( dyrad2 * e * (e-dx) );// * inv_a0;
+        const TYPE a4      =   ( ( e2 - r2 ) * dy2 );// * inv_a0;
+
+        // use simplified RICH version of quartic solver
+        //        const auto sinbeta = solve_quartic_RICH<TYPE>( a1, // a
+        //                                                       a2, // b
+        //                                                       a3, // c
+        //                                                       a4  // d
+        //                                                       );
+
+        //Use optimized newton solver on quartic equation.
+        const auto sinbeta = solve_quartic_newton_RICH( a0, a1, a2, a3, a4 );
+
+        //TODO: This method should be better but has problems still for some reasons
+        //const auto sinbeta = solve_quartic_housholder_RICH<TYPE, 3>(a1, a2, a3, a4);
+
+        // construct rotation transformation
+        // Set vector magnitude to radius
+        // rotate vector and update reflection point
+        //rotation matrix uses sin(beta) and cos(beta) to perform rotation
+        //even fast_asinf (which is only single precision and defeats the purpose
+        //of this class being templatable to double btw) is still too slow
+        //plus there is a cos and sin call inside AngleAxis ...
+        //We can do much better by just using the cos(beta) we already have to calculate
+        //sin(beta) and do our own rotation. On top of that we rotate non-normalized and save several
+        //Divisions by normalizing only once at the very end
+        //Again, care has to be taken since we are close to float_max here without immediate normalization.
+        //As far as we have tried with extreme values in the rich coordinate systems this is fine.
+        //const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
+        //                                        Eigen3Vector(n[0],n[1],n[2]) );
+        const TYPE nx = (evec[1]*dvec[2]) - (evec[2]*dvec[1]);
+        const TYPE ny = (evec[2]*dvec[0]) - (evec[0]*dvec[2]);
+        const TYPE nz = (evec[0]*dvec[1]) - (evec[1]*dvec[0]);
+        //const auto n = evec.cross3(dvec);
+        //const auto norm = n.dot(n);
+        const TYPE norm = nx*nx + ny*ny + nz*nz;
+        const TYPE norm_sqrt = std::sqrt(norm);
+
+        const TYPE a = sinbeta * norm_sqrt;
+        const TYPE b = ( TYPE(1.0) - std::sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
+        const TYPE enorm = radius/(e*norm);
+
+        //Perform non-normalized rotation
+        const std::array<TYPE,9> M = 
+          { norm + b*(-nz*nz-ny*ny), a*nz+b*nx*ny,         -a*ny+b*nx*nz,
+            -a*nz+b*nx*ny,           norm+b*(-nx*nx-nz*nz), a*nx+b*ny*nz,
+            a*ny+b*nx*nz,           -a*nx+b*ny*nz,         norm+b*(-ny*ny-nx*nx) };
+        
+        //re-normalize rotation and scale to radius in one step
+        const TYPE ex = enorm*(evec[0]*M[0]+evec[1]*M[3]+evec[2]*M[6]);
+        const TYPE ey = enorm*(evec[0]*M[1]+evec[1]*M[4]+evec[2]*M[7]);
+        const TYPE ez = enorm*(evec[0]*M[2]+evec[1]*M[5]+evec[2]*M[8]);
+
+        sphReflPoint = ( CoC + Gaudi::XYZVector( ex, ey, ez ) );
+      }
+
+    private:
+
+      //A newton iteration solver for the Rich quartic equation
+      //Since the polynomial that is evaluated here is extremely constrained
+      //(root is in small interval, one root guaranteed), we can use a much more
+      //efficient approximation (which still has the same precision) instead of the
+      //full blown mathematically absolute correct method and still end up with
+      //usable results
+
+      template < class TYPE >
+      inline TYPE f4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, const TYPE &a4, TYPE &x) const
+      {
+        //return (a0 * x*x*x*x + a1 * x*x*x + a2 * x*x + a3 * x + a4);
+        //A bit more FMA friendly
+        return ((((a0*x)+a1)*x+a2)*x+a3)*x+a4;
+      }
+
+      template < class TYPE >
+      inline TYPE df4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, TYPE &x) const
+      {
+        //return (4.0f*a0 * x*x*x + 3.0f*a1 * x*x + 2.0f*a2 * x + a3);
+        return (((4.0f * a0*x)+3.0f*a1)*x+2.0f*a2)*x+a3;
+      }
+
+      /** Horner's method to evaluate the polynomial and its derivatives with as little math operations as
+       *  possible. We use a template here to allow the compiler to unroll the for loops and produce code
+       *  that is free from branches and optimized for the grade of polynomial and derivatives as necessary.
+       */
+      template < class TYPE, std::size_t ORDER = 4, std::size_t DIFFGRADE = 3 >
+      inline void evalPolyHorner(const TYPE (&a)[ORDER+1], TYPE (&res)[DIFFGRADE+1], TYPE x) const
+      {
+        for(unsigned int i = 0; i <= DIFFGRADE; i++)
+        {
+          res[i] = a[0];
+        }
+
+        for(unsigned int j = 1; j <= ORDER; j++)
+        {
+          res[0] = res[0] * x + a[j];
+          int l = (ORDER - j) > DIFFGRADE ? DIFFGRADE : ORDER - j;
+          for (int i = 1; i <= l ; i++)
+          {
+            res[i] = res[i] * x + res[i-1];
+          }
+        }
+
+        //TODO: Check assembly to see if this is optimized away if DIFFGRADE is <= 2
+        float l = 1.0;
+        for(unsigned int i = 2; i <= DIFFGRADE; i++)
+        {
+          l *= i;
+          res[i] = res[i] * l;
+        }
+
+      }
+
+      /** 3rd grade Housholder's method for iteratively finding the root of a function. Tests have shown that we seem to be
+       *  already too constrained in our polynomial and input data that we are not gaining anything over newton. In fact it seems
+       *  to make performance worse.
+       *  TODO: find out why performance of this is so bad. We might be missing something. It should converge much faster than newton.
+       */
+      template < class TYPE, std::size_t ITER = 3 >
+      inline TYPE householder(const TYPE (&a)[5], TYPE x0) const
+      {
+        TYPE res[4];
+        for(unsigned int i = 0; i < ITER; i++)
+        {
+          evalPolyHorner<TYPE, 4, 3>(a, res, x0);
+          x0  =  x0 -   ((6.0 * res[0]*res[1]*res[1] - 3.0 * res[0]*res[0]*res[2])/
+                         (6.0 * res[1]*res[1]*res[1] - 6.0 * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
+          //std::cout << x0 << ": " << res[0] << ", " << res[1] << ", " << res[2] << ", "<< res[3] << ", " << std::endl;
+
+        }
+        return x0;
+      }
+
+      /** Use Housholder's method to solve the rich quartic equation. Important! If this function is used, the coefficients of the
+       *  polynomial have to be normalized. They are typically around 10^15 and floating point overflows will occur in here if these
+       *  large values are used.
+       */
+      template < class TYPE , std::size_t ITER = 3 >
+      inline TYPE solve_quartic_housholder_RICH( const TYPE& a0,
+                                                 const TYPE& a1,
+                                                 const TYPE& a2,
+                                                 const TYPE& a3) const
+      {
+        //Starting value for housholder iteration. Empirically values seem to be
+        //between 0 0and 0.4 so we chose the value in the middle as starting point
+        TYPE x0 = 0.2f;
+
+        TYPE a[5] = {1.0f, a0, a1, a2, a3};
+        //std::cout << "Polynomial: " << std::endl;
+        //std::cout << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << std::endl;
+        x0 = householder<TYPE, ITER>(a, x0);
+
+        return x0;
+      }
+
+      /** Newton-Rhapson method for calculating the root of the rich polynomial. It uses the bisection method in the beginning
+       *  to get close enough to the root to allow the second stage newton method to converge faster. After 4 iterations of newton
+       *  precision is as good as single precision floating point will get you. We have introduced a few tuning parameters like the
+       *  newton gain factor and a slightly skewed bisection division, which in this particular case help to speed things up.
+       *  TODO: Once we are happy with the number of newton and bisection iterations, this function should be templated to the number of
+       *  these iterations to allow loop unrolling and elimination of unnecessary branching
+       *  TODO: These tuning parameters have been found by low effort experimentation on random input data. A more detailed
+       *  study should be done with real data to find the best values
+       */
+      template < class TYPE >
+      inline TYPE solve_quartic_newton_RICH( const TYPE& a0,
+                                             const TYPE& a1,
+                                             const TYPE& a2,
+                                             const TYPE& a3,
+                                             const TYPE& a4 ) const
+      {
+        TYPE epsilon;
+        //Use N steps of bisection method to find starting point for newton
+        TYPE l(0);
+        TYPE u(0.5);
+        TYPE m(0.2); //We start a bit off center since the distribution of roots tends to be more to the left side
+        const TYPE a[5] = {a0, a1, a2, a3, a4};
+        TYPE res[2];
+        for ( int i = 0; i < 3; ++i )
+        {
+          auto oppositeSign = std::signbit(f4(a0,a1,a2,a3,a4,m) * f4(a0,a1,a2,a3,a4,l));
+
+          l = oppositeSign ? l : m;
+          u = oppositeSign ? m : u;
+          //std::cout << l.extract(0) << ", " << m.extract(0) << ", " << u.extract(0) << ", " << oppositeSign.extract(0) << std::endl;
+          //0.4 instead of 0.5 to speed up convergence. Most roots seem to be closer to 0 than to the extreme end
+          m = (u + l) * 0.4;
+        }
+
+        //Newton for the rest
+        TYPE x = m;
+
+        //Most of the times we are approaching the root of the polynomial from one side
+        //and fall short by a certain fraction. This fraction seems to be around 1.04 of the
+        //quotient which is subtracted from x. By scaling it up, we take bigger steps towards
+        //the root and thus converge faster.
+        //TODO: study this factor more closely it's pure guesswork right now. We might get
+        //away with 3 iterations if we can find an exact value
+        const TYPE gain = 1.04;
+
+        for ( int i = 0; i < 4; ++i )
+        {
+          evalPolyHorner<TYPE, 4, 1>(a, res, x);
+          //epsilon = f4(a0,a1,a2,a3,a4,x) / df4(a0,a1,a2,a3,x);
+          epsilon = res[0] / res[1];
+          x = x - gain * epsilon;
+        }
+        return x;
+      }
+
+    };
+
+  }
+}
-- 
GitLab


From e4fafc8f92afd5c01a2f76d4eec3f8c7ed65ff32 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 16:32:24 +0100
Subject: [PATCH 33/68] template the number if NR iterations

---
 .../RichRecUtils/QuarticSolverNewton.h        | 33 ++++++++++---------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 147cbde568..c85a472525 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -216,16 +216,16 @@ namespace Rich
       template < class TYPE, std::size_t ORDER = 4, std::size_t DIFFGRADE = 3 >
       inline void evalPolyHorner(const TYPE (&a)[ORDER+1], TYPE (&res)[DIFFGRADE+1], TYPE x) const
       {
-        for(unsigned int i = 0; i <= DIFFGRADE; i++)
+        for ( unsigned int i = 0; i <= DIFFGRADE; ++i )
         {
           res[i] = a[0];
         }
 
-        for(unsigned int j = 1; j <= ORDER; j++)
+        for ( unsigned int j = 1; j <= ORDER; ++j )
         {
           res[0] = res[0] * x + a[j];
           int l = (ORDER - j) > DIFFGRADE ? DIFFGRADE : ORDER - j;
-          for (int i = 1; i <= l ; i++)
+          for ( int i = 1; i <= l ; ++i )
           {
             res[i] = res[i] * x + res[i-1];
           }
@@ -233,7 +233,7 @@ namespace Rich
 
         //TODO: Check assembly to see if this is optimized away if DIFFGRADE is <= 2
         float l = 1.0;
-        for(unsigned int i = 2; i <= DIFFGRADE; i++)
+        for ( unsigned int i = 2; i <= DIFFGRADE; ++i )
         {
           l *= i;
           res[i] = res[i] * l;
@@ -250,11 +250,11 @@ namespace Rich
       inline TYPE householder(const TYPE (&a)[5], TYPE x0) const
       {
         TYPE res[4];
-        for(unsigned int i = 0; i < ITER; i++)
+        for ( unsigned int i = 0; i < ITER; ++i )
         {
           evalPolyHorner<TYPE, 4, 3>(a, res, x0);
-          x0  =  x0 -   ((6.0 * res[0]*res[1]*res[1] - 3.0 * res[0]*res[0]*res[2])/
-                         (6.0 * res[1]*res[1]*res[1] - 6.0 * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
+          x0 -= ((6.0 * res[0]*res[1]*res[1] - 3.0 * res[0]*res[0]*res[2])/
+                 (6.0 * res[1]*res[1]*res[1] - 6.0 * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
           //std::cout << x0 << ": " << res[0] << ", " << res[1] << ", " << res[2] << ", "<< res[3] << ", " << std::endl;
 
         }
@@ -292,21 +292,20 @@ namespace Rich
        *  TODO: These tuning parameters have been found by low effort experimentation on random input data. A more detailed
        *  study should be done with real data to find the best values
        */
-      template < class TYPE >
+      template < class TYPE, std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3 >
       inline TYPE solve_quartic_newton_RICH( const TYPE& a0,
                                              const TYPE& a1,
                                              const TYPE& a2,
                                              const TYPE& a3,
                                              const TYPE& a4 ) const
       {
-        TYPE epsilon;
         //Use N steps of bisection method to find starting point for newton
         TYPE l(0);
         TYPE u(0.5);
         TYPE m(0.2); //We start a bit off center since the distribution of roots tends to be more to the left side
         const TYPE a[5] = {a0, a1, a2, a3, a4};
         TYPE res[2];
-        for ( int i = 0; i < 3; ++i )
+        for ( std::size_t i = 0; i <= BISECTITS; ++i )
         {
           auto oppositeSign = std::signbit(f4(a0,a1,a2,a3,a4,m) * f4(a0,a1,a2,a3,a4,l));
 
@@ -318,7 +317,8 @@ namespace Rich
         }
 
         //Newton for the rest
-        TYPE x = m;
+        // CRJ : why copy the value. original value is not needed later on...
+        //TYPE x = m;
 
         //Most of the times we are approaching the root of the polynomial from one side
         //and fall short by a certain fraction. This fraction seems to be around 1.04 of the
@@ -328,14 +328,15 @@ namespace Rich
         //away with 3 iterations if we can find an exact value
         const TYPE gain = 1.04;
 
-        for ( int i = 0; i < 4; ++i )
+        for ( std::size_t i = 0; i <= NEWTONITS; ++i )
         {
-          evalPolyHorner<TYPE, 4, 1>(a, res, x);
+          evalPolyHorner<TYPE, 4, 1>(a, res, m);
           //epsilon = f4(a0,a1,a2,a3,a4,x) / df4(a0,a1,a2,a3,x);
-          epsilon = res[0] / res[1];
-          x = x - gain * epsilon;
+          TYPE epsilon = res[0] / res[1];
+          m -= gain * epsilon;
         }
-        return x;
+
+        return m;
       }
 
     };
-- 
GitLab


From 3c472c72682aef78259dfb8f2fd1a38985bbea81 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 16:48:19 +0100
Subject: [PATCH 34/68] Add templation of # iterations to public method

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index c85a472525..016d24b96c 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -17,7 +17,6 @@
 
 // VectorClass
 #include "VectorClass/vectorclass.h"
-#include "VectorClass/complexvec.h"
 
 // STL
 #include <math.h>
@@ -73,7 +72,7 @@ namespace Rich
        *  @retval true  Calculation was successful. sphReflPoint is valid.
        *  @retval false Calculation failed. sphReflPoint is not valid.
        */
-      template< class TYPE >
+      template< class TYPE, std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3  >
       inline void solve( const Gaudi::XYZPoint& emissionPoint,
                          const Gaudi::XYZPoint& CoC,
                          const Gaudi::XYZPoint& virtDetPoint,
-- 
GitLab


From 569e569adeee6ddb965cbfad9112dce181b67a3c Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 16:50:11 +0100
Subject: [PATCH 35/68] resolve conflicts

---
 Rec/GlobalReco/root/RichKaonIDCompareFiles.C | 6 +++---
 Rich/RichFutureRecSys/examples/Brunel.py     | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Rec/GlobalReco/root/RichKaonIDCompareFiles.C b/Rec/GlobalReco/root/RichKaonIDCompareFiles.C
index 0d62054025..abd6ca3a8a 100755
--- a/Rec/GlobalReco/root/RichKaonIDCompareFiles.C
+++ b/Rec/GlobalReco/root/RichKaonIDCompareFiles.C
@@ -51,14 +51,14 @@ void RichKaonIDCompareFiles()
 
   //const std::string dir = "/Users/chris/LHCb/RootFiles/Run2";
   //const std::string dir = "/usera/jonesc/LHCbCMake/lhcb-head/BrunelDevNightly/output/Run2";
-  const std::string dir = "/usera/jonesc/LHCbCMake/Brunel/output/future";
+  const std::string dir = "/home/chris/LHCb/future";
 
   typedef std::vector< std::tuple<std::string,std::string,Color_t> > PlotData;
 
   const PlotData plotdata = 
     {
-      std::make_tuple ( "rich", "RICH Current", kBlack  ),
-      std::make_tuple ( "richfuture", "RICH Future", kRed-6  )
+      std::make_tuple ( "old-quartic", "Old Quartic", kBlack  ),
+      std::make_tuple ( "new-quartic", "New NR Quartic", kRed-6  )
     };
 
   // const PlotData plotdata = 
diff --git a/Rich/RichFutureRecSys/examples/Brunel.py b/Rich/RichFutureRecSys/examples/Brunel.py
index afccb289d4..c6b69a4c32 100644
--- a/Rich/RichFutureRecSys/examples/Brunel.py
+++ b/Rich/RichFutureRecSys/examples/Brunel.py
@@ -50,10 +50,10 @@ Brunel().MCCheckSequence = richs+["PROTO"]
 Brunel().OutputType = 'None'
 importOptions("$APPCONFIGOPTS/Persistency/Compression-ZLIB-1.py")
 
-Brunel().EvtMax     = 500
-Brunel().PrintFreq  = 100
+Brunel().EvtMax     = 10000
+Brunel().PrintFreq  = 500
 
-#Brunel().Histograms = "Expert"
+Brunel().Histograms = "Expert"
 
 #ApplicationMgr().ExtSvc += [ "AuditorSvc" ]
 
-- 
GitLab


From b67808d806d0e840de4209f10f1f3c4c0a7add93 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 16:57:59 +0100
Subject: [PATCH 36/68] Adapt to changes in Eigen classes

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 016d24b96c..de00b7747c 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -50,12 +50,6 @@ namespace Rich
     class QuarticSolverNewton
     {
 
-    public:
-
-      // Use eigen types
-      typedef LHCb::Math::Eigen::XYZPoint  Point;   ///< Point type
-      typedef LHCb::Math::Eigen::XYZVector Vector;  ///< vector type
-
     public:
 
       /** Solves the characteristic quartic equation for the RICH optical system.
@@ -81,8 +75,10 @@ namespace Rich
       {
 
         // typedefs vectorised types
-        typedef Eigen::Matrix< TYPE , 3 , 1 > Eigen3Vector;
+        using Eigen3Vector = Eigen::Matrix< TYPE , 3 , 1 >;
         using Vec4x = typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
+        using Vector = LHCb::Math::Eigen::XYZVector<TYPE>;
+        using Point  = LHCb::Math::Eigen::XYZPoint<TYPE>;
 
         // vector from mirror centre of curvature to assumed emission point
         const Vector evec( emissionPoint - CoC );
-- 
GitLab


From a5ffb96d761109c325d4bd87eb5b5900b62f0585 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 18:06:10 +0100
Subject: [PATCH 37/68] Remove use of Eigen from QuarticSolverNewton.h

---
 .../RichRecUtils/QuarticSolverNewton.h        | 79 +++++++++----------
 1 file changed, 37 insertions(+), 42 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index de00b7747c..689c3d3c34 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -22,16 +22,9 @@
 #include <math.h>
 #include <type_traits>
 
-// Eigen
-#include "LHCbMath/EigenTypes.h"
-#include <Eigen/Geometry>
-
 // VDT
 #include "vdt/asin.h"
 
-// LHCb Maths
-#include "LHCbMath/FastRoots.h"
-
 namespace Rich
 {
   namespace Rec
@@ -66,46 +59,46 @@ namespace Rich
        *  @retval true  Calculation was successful. sphReflPoint is valid.
        *  @retval false Calculation failed. sphReflPoint is not valid.
        */
-      template< class TYPE, std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3  >
-      inline void solve( const Gaudi::XYZPoint& emissionPoint,
-                         const Gaudi::XYZPoint& CoC,
-                         const Gaudi::XYZPoint& virtDetPoint,
+      template< class TYPE, class POINT = Gaudi::XYZPoint, 
+                std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3  >
+      inline void solve( const POINT& emissionPoint,
+                         const POINT& CoC,
+                         const POINT& virtDetPoint,
                          const TYPE radius,
-                         Gaudi::XYZPoint& sphReflPoint ) const
+                         POINT& sphReflPoint ) const
       {
+        using namespace std;
 
         // typedefs vectorised types
-        using Eigen3Vector = Eigen::Matrix< TYPE , 3 , 1 >;
         using Vec4x = typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
-        using Vector = LHCb::Math::Eigen::XYZVector<TYPE>;
-        using Point  = LHCb::Math::Eigen::XYZPoint<TYPE>;
 
         // vector from mirror centre of curvature to assumed emission point
-        const Vector evec( emissionPoint - CoC );
-        const TYPE e2 = evec.dot(evec);
+        const auto evec( emissionPoint - CoC );
+        const TYPE e2 = evec.Dot(evec);
 
         // vector from mirror centre of curvature to virtual detection point
-        const Vector dvec( virtDetPoint - CoC );
-        const TYPE d2 = dvec.dot(dvec);
+        const auto dvec( virtDetPoint - CoC );
+        const TYPE d2 = dvec.Dot(dvec);
 
         // various quantities needed to create quartic equation
         // see LHCB/98-040 section 3, equation 3
         const TYPE ed2 = e2 * d2;
         //std::pow uses internal loop and causes branch misses and other inefficiencies
         //There might be a constant exponent pow function too, but i'm too lazy to check.
-        const TYPE cosgamma2 = ( ed2 > 0 ? std::pow(evec.dot(dvec),2)/ed2 : 1.0 );
+        const TYPE cosgamma2 = ( ed2 > 0 ? pow(evec.Dot(dvec),2)/ed2 : TYPE(1.0) );
         //const TYPE cosgamma2 = ( ed2 > 0.0f ? evec.dot(dvec)*evec.dot(dvec)/ed2 : 1.0f );
         // vectorise 4 square roots into 1
-        //TODO: This vectorized sqrt is questionable. There is a lot of overhead in gathering
-        //The different components via unaligned loads. It's probably not
-        //Faster than just computing the 4 square roots individually.
         const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
-                                           cosgamma2 < 1.0f ? 1.0f-cosgamma2 : 0.0f,
+                                           cosgamma2 < TYPE(1.0) ? TYPE(1.0)-cosgamma2 : TYPE(0.0),
                                            cosgamma2 ) );
         const TYPE e         = tmp_sqrt[0];
         const TYPE d         = tmp_sqrt[1];
         const TYPE singamma  = tmp_sqrt[2];
         const TYPE cosgamma  = tmp_sqrt[3];
+        //const TYPE e         = std::sqrt(e2);
+        //const TYPE d         = std::sqrt(d2);
+        //const TYPE singamma  = std::sqrt( cosgamma2 < TYPE(1.0) ? TYPE(1.0)-cosgamma2 : TYPE(0.0) );
+        //const TYPE cosgamma  = std::sqrt(cosgamma2);
 
         const TYPE dx        = d * cosgamma;
         const TYPE dy        = d * singamma;
@@ -114,15 +107,15 @@ namespace Rich
         const TYPE edx       = e + dx;
 
         // Fill array for quartic equation
-        const auto a0      =     4.0f * ed2;
+        const auto a0      =     TYPE(4.0) * ed2;
         //Newton solver doesn't care about a0 being not 1.0. Remove costly division and several multiplies.
         //This has some downsides though. The a-values are hovering around a numerical value of 10^15. single
         //precision float max is 10^37. A single square and some multiplies will push it over the limit of what
         //single precision float can handle. It's ok for the newton method, but Halley or higher order Housholder
         //will fail without this normalization.
         //const auto inv_a0  =   ( a0 > 0 ? 1.0 / a0 : std::numeric_limits<TYPE>::max() );
-        const TYPE dyrad2  =     2.0f * dy * radius;
-        const TYPE a1      = - ( 2.0f * dyrad2 * e2 );// * inv_a0;
+        const TYPE dyrad2  =     TYPE(2.0) * dy * radius;
+        const TYPE a1      = - ( TYPE(2.0) * dyrad2 * e2 );// * inv_a0;
         const TYPE a2      =   ( (dy2 * r2) + ( edx * edx * r2 ) - a0 );// * inv_a0;
         const TYPE a3      =   ( dyrad2 * e * (e-dx) );// * inv_a0;
         const TYPE a4      =   ( ( e2 - r2 ) * dy2 );// * inv_a0;
@@ -154,16 +147,16 @@ namespace Rich
         //As far as we have tried with extreme values in the rich coordinate systems this is fine.
         //const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
         //                                        Eigen3Vector(n[0],n[1],n[2]) );
-        const TYPE nx = (evec[1]*dvec[2]) - (evec[2]*dvec[1]);
-        const TYPE ny = (evec[2]*dvec[0]) - (evec[0]*dvec[2]);
-        const TYPE nz = (evec[0]*dvec[1]) - (evec[1]*dvec[0]);
+        const TYPE nx = (evec.y()*dvec.z()) - (evec.z()*dvec.y());
+        const TYPE ny = (evec.z()*dvec.x()) - (evec.x()*dvec.z());
+        const TYPE nz = (evec.x()*dvec.y()) - (evec.y()*dvec.x());
         //const auto n = evec.cross3(dvec);
         //const auto norm = n.dot(n);
         const TYPE norm = nx*nx + ny*ny + nz*nz;
-        const TYPE norm_sqrt = std::sqrt(norm);
+        const TYPE norm_sqrt = sqrt(norm);
 
         const TYPE a = sinbeta * norm_sqrt;
-        const TYPE b = ( TYPE(1.0) - std::sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
+        const TYPE b = ( TYPE(1.0) - sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
         const TYPE enorm = radius/(e*norm);
 
         //Perform non-normalized rotation
@@ -173,11 +166,12 @@ namespace Rich
             a*ny+b*nx*nz,           -a*nx+b*ny*nz,         norm+b*(-ny*ny-nx*nx) };
         
         //re-normalize rotation and scale to radius in one step
-        const TYPE ex = enorm*(evec[0]*M[0]+evec[1]*M[3]+evec[2]*M[6]);
-        const TYPE ey = enorm*(evec[0]*M[1]+evec[1]*M[4]+evec[2]*M[7]);
-        const TYPE ez = enorm*(evec[0]*M[2]+evec[1]*M[5]+evec[2]*M[8]);
+        const TYPE ex = enorm*(evec.x()*M[0]+evec.y()*M[3]+evec.z()*M[6]);
+        const TYPE ey = enorm*(evec.x()*M[1]+evec.y()*M[4]+evec.z()*M[7]);
+        const TYPE ez = enorm*(evec.x()*M[2]+evec.y()*M[5]+evec.z()*M[8]);
 
-        sphReflPoint = ( CoC + Gaudi::XYZVector( ex, ey, ez ) );
+        //sphReflPoint = ( CoC + Gaudi::XYZVector( ex, ey, ez ) );
+        sphReflPoint = { CoC.x() + ex, CoC.y() + ey, CoC.z() + ez };
       }
 
     private:
@@ -190,7 +184,8 @@ namespace Rich
       //usable results
 
       template < class TYPE >
-      inline TYPE f4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, const TYPE &a4, TYPE &x) const
+      inline TYPE f4(const TYPE &a0, const TYPE &a1, const TYPE &a2, 
+                     const TYPE &a3, const TYPE &a4, TYPE &x) const
       {
         //return (a0 * x*x*x*x + a1 * x*x*x + a2 * x*x + a3 * x + a4);
         //A bit more FMA friendly
@@ -201,7 +196,7 @@ namespace Rich
       inline TYPE df4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, TYPE &x) const
       {
         //return (4.0f*a0 * x*x*x + 3.0f*a1 * x*x + 2.0f*a2 * x + a3);
-        return (((4.0f * a0*x)+3.0f*a1)*x+2.0f*a2)*x+a3;
+        return ((( TYPE(4.0) * a0*x) + TYPE(3.0)*a1)*x+TYPE(2.0)*a2)*x+a3;
       }
 
       /** Horner's method to evaluate the polynomial and its derivatives with as little math operations as
@@ -227,7 +222,7 @@ namespace Rich
         }
 
         //TODO: Check assembly to see if this is optimized away if DIFFGRADE is <= 2
-        float l = 1.0;
+        TYPE l = 1.0;
         for ( unsigned int i = 2; i <= DIFFGRADE; ++i )
         {
           l *= i;
@@ -248,8 +243,8 @@ namespace Rich
         for ( unsigned int i = 0; i < ITER; ++i )
         {
           evalPolyHorner<TYPE, 4, 3>(a, res, x0);
-          x0 -= ((6.0 * res[0]*res[1]*res[1] - 3.0 * res[0]*res[0]*res[2])/
-                 (6.0 * res[1]*res[1]*res[1] - 6.0 * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
+          x0 -= ((TYPE(6.0) * res[0]*res[1]*res[1] - TYPE(3.0) * res[0]*res[0]*res[2])/
+                 (TYPE(6.0) * res[1]*res[1]*res[1] - TYPE(6.0) * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
           //std::cout << x0 << ": " << res[0] << ", " << res[1] << ", " << res[2] << ", "<< res[3] << ", " << std::endl;
 
         }
@@ -268,7 +263,7 @@ namespace Rich
       {
         //Starting value for housholder iteration. Empirically values seem to be
         //between 0 0and 0.4 so we chose the value in the middle as starting point
-        TYPE x0 = 0.2f;
+        TYPE x0 = TYPE(0.2);
 
         TYPE a[5] = {1.0f, a0, a1, a2, a3};
         //std::cout << "Polynomial: " << std::endl;
-- 
GitLab


From 59d0bb8dc714708a5a3067550e64bf8ef9f568fd Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 18:10:11 +0100
Subject: [PATCH 38/68] increase number of test photons

---
 Rich/RichRecTests/src/PhotonReco/main.icpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 07eb3eb80b..28ff543be4 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -86,7 +86,7 @@ unsigned long long int __attribute__((noinline)) solve( const Data::Vector & dat
 
 int main ( int /*argc*/, char** /*argv*/ )
 {
-  const unsigned int nPhotons = 1e4;
+  const unsigned int nPhotons = 1e5;
   
   Data::Vector dataV;
   dataV.reserve( nPhotons );
-- 
GitLab


From b2c4b91abad37df452d85877d8b1cbe5aba954bd Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 18:19:46 +0100
Subject: [PATCH 39/68] Reorder template types

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 689c3d3c34..1212d04545 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -11,9 +11,6 @@
 
 // Gaudi
 #include "GaudiKernel/Kernel.h"
-#include "GaudiKernel/Transform3DTypes.h"
-#include "GaudiKernel/Point3DTypes.h"
-#include "GaudiKernel/Vector3DTypes.h"
 
 // VectorClass
 #include "VectorClass/vectorclass.h"
@@ -59,8 +56,9 @@ namespace Rich
        *  @retval true  Calculation was successful. sphReflPoint is valid.
        *  @retval false Calculation failed. sphReflPoint is not valid.
        */
-      template< class TYPE, class POINT = Gaudi::XYZPoint, 
-                std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3  >
+      template< class TYPE,
+                std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3,
+                class POINT = Gaudi::XYZPoint >
       inline void solve( const POINT& emissionPoint,
                          const POINT& CoC,
                          const POINT& virtDetPoint,
-- 
GitLab


From 95224bb46434622ea2715722591d3d95d7b30496 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 18:20:19 +0100
Subject: [PATCH 40/68] Add headers removed from quartic solver

---
 Rich/RichRecTests/src/PhotonReco/main.icpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 28ff543be4..809b5abac8 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -1,4 +1,9 @@
 
+// Gaudi
+//#include "GaudiKernel/Transform3DTypes.h"
+#include "GaudiKernel/Point3DTypes.h"
+#include "GaudiKernel/Vector3DTypes.h"
+
 // Quartic Solver
 #include "RichRecUtils/QuarticSolverNewton.h"
 
-- 
GitLab


From 4039ee37313636bbbac5ec2daf3f50d8c744899b Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 20:11:41 +0100
Subject: [PATCH 41/68] Set ray traced photons back to 100

---
 .../python/RichFutureRecSys/ConfiguredRichReco.py               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
index c21660c283..e99f4138a7 100644
--- a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
+++ b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
@@ -137,7 +137,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
                       preloadGeometry = False,
 
                       # Number points for mass hypothesis ring ray tracing
-                      NRingPoints = ( 96, 96, 96 ),
+                      NRingPoints = ( 100, 100, 100 ),
 
                       # Track Extrapolator type
                       trackExtrapolator = "TrackRungeKuttaExtrapolator",
-- 
GitLab


From d5b40736273b886951dd4556271ad0776ccb7d60 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 21:37:25 +0100
Subject: [PATCH 42/68] Turn off bad photon check

---
 .../src/RichRayTraceCherenkovCones.cpp              | 13 ++++++++-----
 .../src/RichRayTraceCherenkovCones.h                |  2 +-
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
index f411bee2bd..98ab9292e9 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
@@ -122,6 +122,9 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
                                                               P.cosPhi, P.sinPhi ) );
         }
 
+        // Count the number of good photons
+        unsigned int nOK(0);
+
         // Which ray tracing to run
         if ( m_useVectorised )
         {
@@ -131,7 +134,7 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
             m_rayTrace.get()->traceToDetector( emissionPoint, vects, segment, m_traceModeRad[rad] );
 
           // loop over the results and fill
-          unsigned int nOK(0), nPhot(0);
+          unsigned int nPhot(0);
           for ( const auto && data : Ranges::ConstZip(results,m_cosSinPhiV[rad]) )
           {
             const auto & res    = std::get<0>(data);
@@ -160,7 +163,7 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
         {
 
           // Loop over the directions and ray trace them using the scalar method
-          unsigned int nOK(0), nPhot(0);
+          unsigned int nPhot(0);
           for ( const auto && data : Ranges::ConstZip(vects,m_cosSinPhiV[rad]) )
           {
             const auto & photDir = std::get<0>(data);
@@ -193,10 +196,10 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
             if ( 0 == nOK && nPhot >= m_nBailout[rad] ) break; 
           }
 
-          // if no good hits empty the container
-          if ( 0 == nOK ) { rings[id].clear(); }
-          
         }
+
+        // if no good hits empty the container
+        //if ( 0 == nOK ) { rings[id].clear(); } 
         
       }
       
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
index 9b653e9356..93a22334a6 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
@@ -124,7 +124,7 @@ namespace Rich
 
         /// Use the scalar or vector ray tracing
         Gaudi::Property<bool> m_useVectorised
-        { this, "UseVectorisedRayTracing", true };
+        { this, "UseVectorisedRayTracing", false };
 
         /// Ray tracing tool
         ToolHandle<const IRayTracing> m_rayTrace
-- 
GitLab


From c7c6a4dc17f44a08ef139e00cf2d510bca657f5e Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 22:19:01 +0100
Subject: [PATCH 43/68] Small clean up

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 1212d04545..6d14df6709 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -263,7 +263,7 @@ namespace Rich
         //between 0 0and 0.4 so we chose the value in the middle as starting point
         TYPE x0 = TYPE(0.2);
 
-        TYPE a[5] = {1.0f, a0, a1, a2, a3};
+        TYPE a[5] = { TYPE(1.0), a0, a1, a2, a3};
         //std::cout << "Polynomial: " << std::endl;
         //std::cout << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << std::endl;
         x0 = householder<TYPE, ITER>(a, x0);
@@ -301,7 +301,7 @@ namespace Rich
           u = oppositeSign ? m : u;
           //std::cout << l.extract(0) << ", " << m.extract(0) << ", " << u.extract(0) << ", " << oppositeSign.extract(0) << std::endl;
           //0.4 instead of 0.5 to speed up convergence. Most roots seem to be closer to 0 than to the extreme end
-          m = (u + l) * 0.4;
+          m = (u + l) * TYPE(0.4);
         }
 
         //Newton for the rest
@@ -320,8 +320,7 @@ namespace Rich
         {
           evalPolyHorner<TYPE, 4, 1>(a, res, m);
           //epsilon = f4(a0,a1,a2,a3,a4,x) / df4(a0,a1,a2,a3,x);
-          TYPE epsilon = res[0] / res[1];
-          m -= gain * epsilon;
+          m -= gain * ( res[0] / res[1] );
         }
 
         return m;
-- 
GitLab


From e72174a3d354ddd325f9a76ff6fa82334859a98b Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 23:33:49 +0100
Subject: [PATCH 44/68] Small improvements

---
 .../src/RichRayTraceCherenkovCones.cpp        |  3 ++
 .../src/RichRayTraceCherenkovCones.h          |  2 +-
 .../RichRecUtils/QuarticSolverNewton.h        | 33 ++++++++++---------
 3 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
index 98ab9292e9..64cc4a39e0 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.cpp
@@ -155,6 +155,9 @@ RayTraceCherenkovCones::operator()( const LHCb::RichTrackSegment::Vector& segmen
 
             // count raytraces that are in HPD panel
             if ( res.result >= LHCb::RichTraceMode::InHPDPanel ) { ++nOK; }
+
+            // bailout check
+            if ( 0 == nOK && nPhot >= m_nBailout[rad] ) break; 
             
           }
 
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
index 93a22334a6..9b653e9356 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
@@ -124,7 +124,7 @@ namespace Rich
 
         /// Use the scalar or vector ray tracing
         Gaudi::Property<bool> m_useVectorised
-        { this, "UseVectorisedRayTracing", false };
+        { this, "UseVectorisedRayTracing", true };
 
         /// Ray tracing tool
         ToolHandle<const IRayTracing> m_rayTrace
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 6d14df6709..79fa0ffbec 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -105,7 +105,7 @@ namespace Rich
         const TYPE edx       = e + dx;
 
         // Fill array for quartic equation
-        const auto a0      =     TYPE(4.0) * ed2;
+        const TYPE a0        =     TYPE(4.0) * ed2;
         //Newton solver doesn't care about a0 being not 1.0. Remove costly division and several multiplies.
         //This has some downsides though. The a-values are hovering around a numerical value of 10^15. single
         //precision float max is 10^37. A single square and some multiplies will push it over the limit of what
@@ -145,23 +145,26 @@ namespace Rich
         //As far as we have tried with extreme values in the rich coordinate systems this is fine.
         //const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
         //                                        Eigen3Vector(n[0],n[1],n[2]) );
-        const TYPE nx = (evec.y()*dvec.z()) - (evec.z()*dvec.y());
-        const TYPE ny = (evec.z()*dvec.x()) - (evec.x()*dvec.z());
-        const TYPE nz = (evec.x()*dvec.y()) - (evec.y()*dvec.x());
+        const TYPE nx  = (evec.y()*dvec.z()) - (evec.z()*dvec.y());
+        const TYPE ny  = (evec.z()*dvec.x()) - (evec.x()*dvec.z());
+        const TYPE nz  = (evec.x()*dvec.y()) - (evec.y()*dvec.x());
+        const TYPE nx2 = nx*nx; 
+        const TYPE ny2 = ny*ny; 
+        const TYPE nz2 = nz*nz; 
         //const auto n = evec.cross3(dvec);
         //const auto norm = n.dot(n);
-        const TYPE norm = nx*nx + ny*ny + nz*nz;
+        const TYPE norm      = nx2 + ny2 + nz2;
         const TYPE norm_sqrt = sqrt(norm);
 
-        const TYPE a = sinbeta * norm_sqrt;
-        const TYPE b = ( TYPE(1.0) - sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
+        const TYPE     a = sinbeta * norm_sqrt;
+        const TYPE     b = ( TYPE(1.0) - sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
         const TYPE enorm = radius/(e*norm);
 
         //Perform non-normalized rotation
         const std::array<TYPE,9> M = 
-          { norm + b*(-nz*nz-ny*ny), a*nz+b*nx*ny,         -a*ny+b*nx*nz,
-            -a*nz+b*nx*ny,           norm+b*(-nx*nx-nz*nz), a*nx+b*ny*nz,
-            a*ny+b*nx*nz,           -a*nx+b*ny*nz,         norm+b*(-ny*ny-nx*nx) };
+          { norm + b*(-nz2-ny2), a*nz+b*nx*ny,         -a*ny+b*nx*nz,
+            -a*nz+b*nx*ny,       norm+b*(-nx2-nz2), a*nx+b*ny*nz,
+            a*ny+b*nx*nz,       -a*nx+b*ny*nz,         norm+b*(-ny2-nx2) };
         
         //re-normalize rotation and scale to radius in one step
         const TYPE ex = enorm*(evec.x()*M[0]+evec.y()*M[3]+evec.z()*M[6]);
@@ -194,7 +197,7 @@ namespace Rich
       inline TYPE df4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, TYPE &x) const
       {
         //return (4.0f*a0 * x*x*x + 3.0f*a1 * x*x + 2.0f*a2 * x + a3);
-        return ((( TYPE(4.0) * a0*x) + TYPE(3.0)*a1)*x+TYPE(2.0)*a2)*x+a3;
+        return ( ( ( ( TYPE(4.0) * a0*x ) + TYPE(3.0) * a1 ) * x + ( TYPE(2.0) * a2 ) ) * x ) + a3;
       }
 
       /** Horner's method to evaluate the polynomial and its derivatives with as little math operations as
@@ -204,12 +207,12 @@ namespace Rich
       template < class TYPE, std::size_t ORDER = 4, std::size_t DIFFGRADE = 3 >
       inline void evalPolyHorner(const TYPE (&a)[ORDER+1], TYPE (&res)[DIFFGRADE+1], TYPE x) const
       {
-        for ( unsigned int i = 0; i <= DIFFGRADE; ++i )
+        for ( std::size_t i = 0; i <= DIFFGRADE; ++i )
         {
           res[i] = a[0];
         }
 
-        for ( unsigned int j = 1; j <= ORDER; ++j )
+        for ( std::size_t j = 1; j <= ORDER; ++j )
         {
           res[0] = res[0] * x + a[j];
           int l = (ORDER - j) > DIFFGRADE ? DIFFGRADE : ORDER - j;
@@ -221,7 +224,7 @@ namespace Rich
 
         //TODO: Check assembly to see if this is optimized away if DIFFGRADE is <= 2
         TYPE l = 1.0;
-        for ( unsigned int i = 2; i <= DIFFGRADE; ++i )
+        for ( std::size_t i = 2; i <= DIFFGRADE; ++i )
         {
           l *= i;
           res[i] = res[i] * l;
@@ -238,7 +241,7 @@ namespace Rich
       inline TYPE householder(const TYPE (&a)[5], TYPE x0) const
       {
         TYPE res[4];
-        for ( unsigned int i = 0; i < ITER; ++i )
+        for ( std::size_t i = 0; i < ITER; ++i )
         {
           evalPolyHorner<TYPE, 4, 3>(a, res, x0);
           x0 -= ((TYPE(6.0) * res[0]*res[1]*res[1] - TYPE(3.0) * res[0]*res[0]*res[2])/
-- 
GitLab


From 2206e3c40789ec575f7f88b3f6c92c61fa2fb992 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sat, 4 Mar 2017 23:55:35 +0100
Subject: [PATCH 45/68] cache a few computations

---
 .../RichRecUtils/QuarticSolverNewton.h        | 27 +++++++++++--------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 79fa0ffbec..663fce6572 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -83,7 +83,7 @@ namespace Rich
         const TYPE ed2 = e2 * d2;
         //std::pow uses internal loop and causes branch misses and other inefficiencies
         //There might be a constant exponent pow function too, but i'm too lazy to check.
-        const TYPE cosgamma2 = ( ed2 > 0 ? pow(evec.Dot(dvec),2)/ed2 : TYPE(1.0) );
+        const TYPE cosgamma2 = ( ed2 > TYPE(0.0) ? pow(evec.Dot(dvec),2)/ed2 : TYPE(1.0) );
         //const TYPE cosgamma2 = ( ed2 > 0.0f ? evec.dot(dvec)*evec.dot(dvec)/ed2 : 1.0f );
         // vectorise 4 square roots into 1
         const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
@@ -148,24 +148,29 @@ namespace Rich
         const TYPE nx  = (evec.y()*dvec.z()) - (evec.z()*dvec.y());
         const TYPE ny  = (evec.z()*dvec.x()) - (evec.x()*dvec.z());
         const TYPE nz  = (evec.x()*dvec.y()) - (evec.y()*dvec.x());
+
         const TYPE nx2 = nx*nx; 
         const TYPE ny2 = ny*ny; 
         const TYPE nz2 = nz*nz; 
-        //const auto n = evec.cross3(dvec);
-        //const auto norm = n.dot(n);
+
+        const TYPE nxny = nx*ny;
+        const TYPE nxnz = nx*nz;
+        const TYPE nynz = ny*nz;
+
         const TYPE norm      = nx2 + ny2 + nz2;
         const TYPE norm_sqrt = sqrt(norm);
 
-        const TYPE     a = sinbeta * norm_sqrt;
-        const TYPE     b = ( TYPE(1.0) - sqrt( TYPE(1.0) - (sinbeta*sinbeta) ) ); // <--(1-cos(beta))
-        const TYPE enorm = radius/(e*norm);
+        const TYPE        a = sinbeta * norm_sqrt;
+        const TYPE sinbeta2 = sinbeta * sinbeta;
+        const TYPE        b = ( sinbeta2 < TYPE(1.0) ? ( TYPE(1.0) - sqrt( TYPE(1.0) - sinbeta2 ) ) : TYPE(1.0) );
+        const TYPE    enorm = radius/(e*norm);
 
         //Perform non-normalized rotation
         const std::array<TYPE,9> M = 
-          { norm + b*(-nz2-ny2), a*nz+b*nx*ny,         -a*ny+b*nx*nz,
-            -a*nz+b*nx*ny,       norm+b*(-nx2-nz2), a*nx+b*ny*nz,
-            a*ny+b*nx*nz,       -a*nx+b*ny*nz,         norm+b*(-ny2-nx2) };
-        
+          { norm - b*(nz2+ny2), a*nz+b*nxny,         -a*ny+b*nxnz,
+            -a*nz+b*nxny,       norm - b*(nx2+nz2),  a*nx+b*nynz,
+            a*ny+b*nxnz,       -a*nx+b*nynz,         norm-b*(ny2+nx2) };
+ 
         //re-normalize rotation and scale to radius in one step
         const TYPE ex = enorm*(evec.x()*M[0]+evec.y()*M[3]+evec.z()*M[6]);
         const TYPE ey = enorm*(evec.x()*M[1]+evec.y()*M[4]+evec.z()*M[7]);
@@ -190,7 +195,7 @@ namespace Rich
       {
         //return (a0 * x*x*x*x + a1 * x*x*x + a2 * x*x + a3 * x + a4);
         //A bit more FMA friendly
-        return ((((a0*x)+a1)*x+a2)*x+a3)*x+a4;
+        return ( ( ( (a0*x) + a1 ) *x + a2 ) *x + a3 ) *x + a4;
       }
 
       template < class TYPE >
-- 
GitLab


From cfa96a2e046968a9b24f508adb660c9a0914bf47 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 00:01:29 +0100
Subject: [PATCH 46/68] cache a few computations

---
 .../RichRecUtils/QuarticSolverNewton.h         | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 663fce6572..e86da121e7 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -143,8 +143,6 @@ namespace Rich
         //Divisions by normalizing only once at the very end
         //Again, care has to be taken since we are close to float_max here without immediate normalization.
         //As far as we have tried with extreme values in the rich coordinate systems this is fine.
-        //const Eigen::AngleAxis<TYPE> angleaxis( vdt::fast_asinf(sinbeta),
-        //                                        Eigen3Vector(n[0],n[1],n[2]) );
         const TYPE nx  = (evec.y()*dvec.z()) - (evec.z()*dvec.y());
         const TYPE ny  = (evec.z()*dvec.x()) - (evec.x()*dvec.z());
         const TYPE nz  = (evec.x()*dvec.y()) - (evec.y()*dvec.x());
@@ -153,10 +151,6 @@ namespace Rich
         const TYPE ny2 = ny*ny; 
         const TYPE nz2 = nz*nz; 
 
-        const TYPE nxny = nx*ny;
-        const TYPE nxnz = nx*nz;
-        const TYPE nynz = ny*nz;
-
         const TYPE norm      = nx2 + ny2 + nz2;
         const TYPE norm_sqrt = sqrt(norm);
 
@@ -165,11 +159,15 @@ namespace Rich
         const TYPE        b = ( sinbeta2 < TYPE(1.0) ? ( TYPE(1.0) - sqrt( TYPE(1.0) - sinbeta2 ) ) : TYPE(1.0) );
         const TYPE    enorm = radius/(e*norm);
 
+        const TYPE bnxny = b*nx*ny;
+        const TYPE bnxnz = b*nx*nz;
+        const TYPE bnynz = b*ny*nz;
+
         //Perform non-normalized rotation
         const std::array<TYPE,9> M = 
-          { norm - b*(nz2+ny2), a*nz+b*nxny,         -a*ny+b*nxnz,
-            -a*nz+b*nxny,       norm - b*(nx2+nz2),  a*nx+b*nynz,
-            a*ny+b*nxnz,       -a*nx+b*nynz,         norm-b*(ny2+nx2) };
+          { norm - b*(nz2+ny2), a*nz+bnxny,         -a*ny+bnxnz,
+            -a*nz+bnxny,       norm - b*(nx2+nz2),  a*nx+bnynz,
+            a*ny+bnxnz,       -a*nx+bnynz,         norm-b*(ny2+nx2) };
  
         //re-normalize rotation and scale to radius in one step
         const TYPE ex = enorm*(evec.x()*M[0]+evec.y()*M[3]+evec.z()*M[6]);
@@ -195,7 +193,7 @@ namespace Rich
       {
         //return (a0 * x*x*x*x + a1 * x*x*x + a2 * x*x + a3 * x + a4);
         //A bit more FMA friendly
-        return ( ( ( (a0*x) + a1 ) *x + a2 ) *x + a3 ) *x + a4;
+        return ( ( ( ( ( ( (a0*x) + a1 ) * x ) + a2 ) * x ) + a3 ) * x ) + a4;
       }
 
       template < class TYPE >
-- 
GitLab


From fd5fc1138eaee7db0363ed1be9836feb032f9140 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 00:05:44 +0100
Subject: [PATCH 47/68] cache a few computations

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index e86da121e7..39e5420262 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -301,7 +301,7 @@ namespace Rich
         TYPE res[2];
         for ( std::size_t i = 0; i <= BISECTITS; ++i )
         {
-          auto oppositeSign = std::signbit(f4(a0,a1,a2,a3,a4,m) * f4(a0,a1,a2,a3,a4,l));
+          const auto oppositeSign = std::signbit(f4(a0,a1,a2,a3,a4,m) * f4(a0,a1,a2,a3,a4,l));
 
           l = oppositeSign ? l : m;
           u = oppositeSign ? m : u;
-- 
GitLab


From de148cfe3399dd75512b42aa8961bb637d69144f Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 00:43:53 +0100
Subject: [PATCH 48/68] clean up a little

---
 .../RichRecUtils/QuarticSolverNewton.h        | 36 +++++++------------
 1 file changed, 13 insertions(+), 23 deletions(-)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 39e5420262..fff91e926c 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -80,11 +80,8 @@ namespace Rich
 
         // various quantities needed to create quartic equation
         // see LHCB/98-040 section 3, equation 3
-        const TYPE ed2 = e2 * d2;
-        //std::pow uses internal loop and causes branch misses and other inefficiencies
-        //There might be a constant exponent pow function too, but i'm too lazy to check.
+        const TYPE       ed2 = e2 * d2;
         const TYPE cosgamma2 = ( ed2 > TYPE(0.0) ? pow(evec.Dot(dvec),2)/ed2 : TYPE(1.0) );
-        //const TYPE cosgamma2 = ( ed2 > 0.0f ? evec.dot(dvec)*evec.dot(dvec)/ed2 : 1.0f );
         // vectorise 4 square roots into 1
         const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
                                            cosgamma2 < TYPE(1.0) ? TYPE(1.0)-cosgamma2 : TYPE(0.0),
@@ -93,6 +90,7 @@ namespace Rich
         const TYPE d         = tmp_sqrt[1];
         const TYPE singamma  = tmp_sqrt[2];
         const TYPE cosgamma  = tmp_sqrt[3];
+        // scalar versions
         //const TYPE e         = std::sqrt(e2);
         //const TYPE d         = std::sqrt(d2);
         //const TYPE singamma  = std::sqrt( cosgamma2 < TYPE(1.0) ? TYPE(1.0)-cosgamma2 : TYPE(0.0) );
@@ -188,16 +186,16 @@ namespace Rich
       //usable results
 
       template < class TYPE >
-      inline TYPE f4(const TYPE &a0, const TYPE &a1, const TYPE &a2, 
-                     const TYPE &a3, const TYPE &a4, TYPE &x) const
+      inline TYPE f4( const TYPE &a0, const TYPE &a1, const TYPE &a2, 
+                      const TYPE &a3, const TYPE &a4, TYPE &x ) const
       {
         //return (a0 * x*x*x*x + a1 * x*x*x + a2 * x*x + a3 * x + a4);
         //A bit more FMA friendly
-        return ( ( ( ( ( ( (a0*x) + a1 ) * x ) + a2 ) * x ) + a3 ) * x ) + a4;
+        return ( ( ( ( ( ( ( a0 * x ) + a1 ) * x ) + a2 ) * x ) + a3 ) * x ) + a4;
       }
 
       template < class TYPE >
-      inline TYPE df4(const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, TYPE &x) const
+      inline TYPE df4( const TYPE &a0, const TYPE &a1, const TYPE &a2, const TYPE &a3, TYPE &x ) const
       {
         //return (4.0f*a0 * x*x*x + 3.0f*a1 * x*x + 2.0f*a2 * x + a3);
         return ( ( ( ( TYPE(4.0) * a0*x ) + TYPE(3.0) * a1 ) * x + ( TYPE(2.0) * a2 ) ) * x ) + a3;
@@ -208,7 +206,7 @@ namespace Rich
        *  that is free from branches and optimized for the grade of polynomial and derivatives as necessary.
        */
       template < class TYPE, std::size_t ORDER = 4, std::size_t DIFFGRADE = 3 >
-      inline void evalPolyHorner(const TYPE (&a)[ORDER+1], TYPE (&res)[DIFFGRADE+1], TYPE x) const
+      inline void evalPolyHorner( const TYPE (&a)[ORDER+1], TYPE (&res)[DIFFGRADE+1], const TYPE x ) const
       {
         for ( std::size_t i = 0; i <= DIFFGRADE; ++i )
         {
@@ -218,7 +216,7 @@ namespace Rich
         for ( std::size_t j = 1; j <= ORDER; ++j )
         {
           res[0] = res[0] * x + a[j];
-          int l = (ORDER - j) > DIFFGRADE ? DIFFGRADE : ORDER - j;
+          const int l = (ORDER - j) > DIFFGRADE ? DIFFGRADE : ORDER - j;
           for ( int i = 1; i <= l ; ++i )
           {
             res[i] = res[i] * x + res[i-1];
@@ -249,8 +247,6 @@ namespace Rich
           evalPolyHorner<TYPE, 4, 3>(a, res, x0);
           x0 -= ((TYPE(6.0) * res[0]*res[1]*res[1] - TYPE(3.0) * res[0]*res[0]*res[2])/
                  (TYPE(6.0) * res[1]*res[1]*res[1] - TYPE(6.0) * res[0]*res[1]*res[2] + res[0]*res[0]*res[3]));
-          //std::cout << x0 << ": " << res[0] << ", " << res[1] << ", " << res[2] << ", "<< res[3] << ", " << std::endl;
-
         }
         return x0;
       }
@@ -268,13 +264,8 @@ namespace Rich
         //Starting value for housholder iteration. Empirically values seem to be
         //between 0 0and 0.4 so we chose the value in the middle as starting point
         TYPE x0 = TYPE(0.2);
-
-        TYPE a[5] = { TYPE(1.0), a0, a1, a2, a3};
-        //std::cout << "Polynomial: " << std::endl;
-        //std::cout << a[0] << ", " << a[1] << ", " << a[2] << ", " << a[3] << ", " << a[4] << std::endl;
-        x0 = householder<TYPE, ITER>(a, x0);
-
-        return x0;
+        TYPE a[5] = { TYPE(1.0), a0, a1, a2, a3 };
+        return householder<TYPE, ITER>( a, x0 );
       }
 
       /** Newton-Rhapson method for calculating the root of the rich polynomial. It uses the bisection method in the beginning
@@ -294,7 +285,7 @@ namespace Rich
                                              const TYPE& a4 ) const
       {
         //Use N steps of bisection method to find starting point for newton
-        TYPE l(0);
+        TYPE l(0.0);
         TYPE u(0.5);
         TYPE m(0.2); //We start a bit off center since the distribution of roots tends to be more to the left side
         const TYPE a[5] = {a0, a1, a2, a3, a4};
@@ -305,9 +296,8 @@ namespace Rich
 
           l = oppositeSign ? l : m;
           u = oppositeSign ? m : u;
-          //std::cout << l.extract(0) << ", " << m.extract(0) << ", " << u.extract(0) << ", " << oppositeSign.extract(0) << std::endl;
           //0.4 instead of 0.5 to speed up convergence. Most roots seem to be closer to 0 than to the extreme end
-          m = (u + l) * TYPE(0.4);
+          m = ( u + l ) * TYPE(0.4);
         }
 
         //Newton for the rest
@@ -324,7 +314,7 @@ namespace Rich
 
         for ( std::size_t i = 0; i <= NEWTONITS; ++i )
         {
-          evalPolyHorner<TYPE, 4, 1>(a, res, m);
+          evalPolyHorner<TYPE, 4, 1>( a, res, m );
           //epsilon = f4(a0,a1,a2,a3,a4,x) / df4(a0,a1,a2,a3,x);
           m -= gain * ( res[0] / res[1] );
         }
-- 
GitLab


From 23c8ac0f9dbc0fc71e2dd20dc6699caab0264055 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 13:30:22 +0100
Subject: [PATCH 49/68] Reduce number of ray traced photons from 100 to 96 so
 as to fit perfectly into a SIMD vector

---
 .../python/RichFutureRecSys/ConfiguredRichReco.py               | 2 +-
 .../src/RichRayTraceCherenkovCones.h                            | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
index e99f4138a7..c21660c283 100644
--- a/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
+++ b/Rich/RichFutureRecSys/python/RichFutureRecSys/ConfiguredRichReco.py
@@ -137,7 +137,7 @@ def RichRecoSequence( GroupName = "", # Optional name given to this group.
                       preloadGeometry = False,
 
                       # Number points for mass hypothesis ring ray tracing
-                      NRingPoints = ( 100, 100, 100 ),
+                      NRingPoints = ( 96, 96, 96 ),
 
                       # Track Extrapolator type
                       trackExtrapolator = "TrackRungeKuttaExtrapolator",
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
index 9b653e9356..26dd924732 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichRayTraceCherenkovCones.h
@@ -100,7 +100,7 @@ namespace Rich
 
         /// Number of points to ray trace on each ring, for each radiator
         Gaudi::Property< RadiatorArray<unsigned int> > m_nPoints
-        { this, "NRingPoints", { 100u, 100u, 100u } };
+        { this, "NRingPoints", { 96u, 96u, 96u } };
 
         /// Bailout number
         RadiatorArray<unsigned int> m_nBailout = {{}};
-- 
GitLab


From 6eaef4e27238ef08fe2fe9d701d6d2837db03d66 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 13:31:03 +0100
Subject: [PATCH 50/68] Reduce number of NR iterations for first stage of
 photon reco where best precision is not required

---
 .../src/RichQuarticPhotonReco.cpp             | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
index 5959114866..6616869b50 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
@@ -456,11 +456,11 @@ QuarticPhotonReco::operator()( const LHCb::RichTrackSegment::Vector& segments,
             virtDetPoint = gloPos - 2.0 * distance * secSegment->centreNormal();
           
             // solve the quartic using the new data
-            m_quarticSolver.solve<double>( emissionPoint,
-                                           sphSegment->centreOfCurvature(),
-                                           virtDetPoint,
-                                           sphSegment->radius(),
-                                           sphReflPoint );
+            m_quarticSolver.solve<double,2,3>( emissionPoint,
+                                               sphSegment->centreOfCurvature(),
+                                               virtDetPoint,
+                                               sphSegment->radius(),
+                                               sphReflPoint );
           
             // (re)find the spherical mirror segment
             // CRJ - Is this needed ?
@@ -507,11 +507,11 @@ QuarticPhotonReco::operator()( const LHCb::RichTrackSegment::Vector& segments,
               virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
             
               // solve the quartic using the new data
-              m_quarticSolver.solve<double>( emissionPoint,
-                                             sphSegment->centreOfCurvature(),
-                                             virtDetPoint,
-                                             sphSegment->radius(),
-                                             sphReflPoint );
+              m_quarticSolver.solve<double,2,3>( emissionPoint,
+                                                 sphSegment->centreOfCurvature(),
+                                                 virtDetPoint,
+                                                 sphSegment->radius(),
+                                                 sphReflPoint );
 
               // (re)find the spherical mirror segment
               sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
@@ -663,11 +663,11 @@ findMirrorData( const Rich::DetectorType rich,
                 Gaudi::XYZPoint& secReflPoint ) const
 {
   // solve quartic equation with nominal values and find spherical mirror reflection point
-  m_quarticSolver.solve<double>( emissionPoint,
-                                 m_rich[rich]->nominalCentreOfCurvature(side),
-                                 virtDetPoint,
-                                 m_rich[rich]->sphMirrorRadius(),
-                                 sphReflPoint );
+  m_quarticSolver.solve<double,2,2>( emissionPoint,
+                                     m_rich[rich]->nominalCentreOfCurvature(side),
+                                     virtDetPoint,
+                                     m_rich[rich]->sphMirrorRadius(),
+                                     sphReflPoint );
   // find the spherical mirror segment
   sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
   // Search for the secondary segment
-- 
GitLab


From c8dd66e31a7784800c3fa525371e7d2fe340e46d Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Sun, 5 Mar 2017 17:05:11 +0100
Subject: [PATCH 51/68] Propagate template parameters to NR method

---
 Rich/RichRecTests/src/PhotonReco/main.icpp           | 10 +++++-----
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 809b5abac8..91a02a4784 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -61,11 +61,11 @@ public:
 template< class TYPE >
 inline void solve( const Data& data )
 {
-  qSolver.solve<TYPE>( data.emissPnt, 
-                       data.centOfCurv, 
-                       data.virtDetPoint,
-                       data.radius, 
-                       sphReflPoint );
+  qSolver.solve<TYPE,2,2>( data.emissPnt, 
+                           data.centOfCurv, 
+                           data.virtDetPoint,
+                           data.radius, 
+                           sphReflPoint );
 }
 
 template< class TYPE >
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index fff91e926c..097bfeec93 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -124,7 +124,7 @@ namespace Rich
         //                                                       );
 
         //Use optimized newton solver on quartic equation.
-        const auto sinbeta = solve_quartic_newton_RICH( a0, a1, a2, a3, a4 );
+        const auto sinbeta = solve_quartic_newton_RICH<TYPE,BISECTITS,NEWTONITS>( a0, a1, a2, a3, a4 );
 
         //TODO: This method should be better but has problems still for some reasons
         //const auto sinbeta = solve_quartic_housholder_RICH<TYPE, 3>(a1, a2, a3, a4);
@@ -255,7 +255,7 @@ namespace Rich
        *  polynomial have to be normalized. They are typically around 10^15 and floating point overflows will occur in here if these
        *  large values are used.
        */
-      template < class TYPE , std::size_t ITER = 3 >
+      template < class TYPE, std::size_t ITER = 3 >
       inline TYPE solve_quartic_housholder_RICH( const TYPE& a0,
                                                  const TYPE& a1,
                                                  const TYPE& a2,
-- 
GitLab


From 0b27591e9aabf9e3dbb131b1acbd06901681cb33 Mon Sep 17 00:00:00 2001
From: Jeroen van Tilburg <Jeroen.van.Tilburg@cern.ch>
Date: Mon, 6 Mar 2017 16:33:44 +0100
Subject: [PATCH 52/68] Changed location of linker tables with spillover for
 extended digi output

---
 Pr/PrMCTools/src/PrClustersResidual.cpp | 8 ++++++--
 Pr/PrMCTools/src/PrClustersResidual.h   | 2 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index 520ceab16d..de6a202d10 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -39,6 +39,10 @@ PrClustersResidual::PrClustersResidual( const std::string& name,
   m_ftHitManager(nullptr),
   m_zone(24){
   declareProperty("MCHitsLocation",m_mcHitLocation = "/Event/MC/FT/Hits");
+  declareProperty("FTClusterToParticleLinkerLocation",
+      m_ftClusterToParticleLinkerLocation = LHCb::FTLiteClusterLocation::Default + "WithSpillover");
+  declareProperty("FTClusterToHitLinkerLocation",
+      m_ftClusterToHitLinkerLocation = LHCb::FTLiteClusterLocation::Default + "2MCHitsWithSpillover");
   declareProperty("HitManagerName",m_hitManagerName = "PrFTHitManager");
   declareProperty("DebugTracking",m_debugTracking = false);
   declareProperty("DoClusterResidual",m_doClusterResidual = false); //Cluster residual tuple
@@ -124,8 +128,8 @@ void PrClustersResidual::Occupancy(){
   //"/Event/Prev/MC/FT/Hits"
 
   LinkedFrom<LHCb::MCHit,LHCb::MCParticle> myMCHitLink( evtSvc(), msgSvc(), LHCb::MCParticleLocation::Default + "2MC" + "FT" + "Hits" );
-  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), LHCb::FTLiteClusterLocation::Default );
-  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), LHCb::FTLiteClusterLocation::Default + "2MCHits");
+  LinkedTo<LHCb::MCParticle> myClusterLink ( evtSvc(), msgSvc(), m_ftClusterToParticleLinkerLocation );
+  LinkedTo<LHCb::MCHit> myFTCluster2MCHitLink ( evtSvc(),msgSvc(), m_ftClusterToHitLinkerLocation);
   char layerName[100];
   char Title[100];
   std::vector<int> nHits(12,0);
diff --git a/Pr/PrMCTools/src/PrClustersResidual.h b/Pr/PrMCTools/src/PrClustersResidual.h
index 0c6c12778d..4ab37712b6 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.h
+++ b/Pr/PrMCTools/src/PrClustersResidual.h
@@ -104,6 +104,8 @@ private:
   LHCb::FTLiteCluster getLiteCluster(const LHCb::LHCbID id);
   
   std::string m_mcHitLocation;
+  std::string m_ftClusterToParticleLinkerLocation;
+  std::string m_ftClusterToHitLinkerLocation;
   
   //  unsigned int m_zone;
   bool m_debugTracking;
-- 
GitLab


From d8fdd3066a3fb22755856ef960555d31e3bb7ac4 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Mon, 6 Mar 2017 18:02:33 +0000
Subject: [PATCH 53/68] Add CPU capabilities selection for Quartic algorithm

---
 .../CMakeLists.txt                            |  24 +-
 .../src/RichQuarticPhotonReco.cpp             | 681 +-----------------
 .../src/RichQuarticPhotonReco.h               | 201 +++++-
 .../src/RichQuarticPhotonReco.icpp            | 526 ++++++++++++++
 .../src/avx/RichQuarticPhotonReco.cpp         |  30 +
 .../src/avx2/RichQuarticPhotonReco.cpp        |  30 +
 .../src/generic/RichQuarticPhotonReco.cpp     |  21 +
 .../src/sse4/RichQuarticPhotonReco.cpp        |  21 +
 8 files changed, 846 insertions(+), 688 deletions(-)
 create mode 100644 Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
 create mode 100644 Rich/RichFutureRecPhotonAlgorithms/src/avx/RichQuarticPhotonReco.cpp
 create mode 100644 Rich/RichFutureRecPhotonAlgorithms/src/avx2/RichQuarticPhotonReco.cpp
 create mode 100644 Rich/RichFutureRecPhotonAlgorithms/src/generic/RichQuarticPhotonReco.cpp
 create mode 100644 Rich/RichFutureRecPhotonAlgorithms/src/sse4/RichQuarticPhotonReco.cpp

diff --git a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
index a3c59f6df2..a226a88b4c 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
+++ b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
@@ -5,7 +5,8 @@ gaudi_subdir(RichFutureRecPhotonAlgorithms v1r0)
 
 gaudi_depends_on_subdirs(Rich/RichFutureRecBase
                          Rich/RichFutureRecEvent
-                         Rich/RichUtils)
+                         Rich/RichUtils
+                         Kernel/VectorClass)
 
 find_package(Boost)
 find_package(GSL)
@@ -16,10 +17,21 @@ find_package(ROOT)
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
                                                  ${EIGEN_INCLUDE_DIRS})
 
-# For testing high vectorisation and optimisation levels
-#set_property(SOURCE src/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -O3 -mavx2 -mfma -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
-
 gaudi_add_module(RichFutureRecPhotonAlgorithms
-                 src/*.cpp
-                 INCLUDE_DIRS Boost GSL VDT Eigen Rich/RichFutureRecBase Rich/RichFutureRecEvent Rich/RichUtils
+                 src/*.cpp src/generic/*.cpp src/sse4/*.cpp src/avx/*.cpp src/avx2/*.cpp
+                 INCLUDE_DIRS Boost GSL VDT Eigen Kernel/VectorClass Rich/RichFutureRecBase Rich/RichFutureRecEvent Rich/RichUtils
                  LINK_LIBRARIES Boost GSL VDT RichFutureRecBase RichFutureRecEvent RichUtils)
+
+set_property(SOURCE src/generic/RichQuarticPhotonReco.cpp  APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes " )
+
+set_property(SOURCE src/sse4/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -msse4.2 " )
+
+set_property(SOURCE src/avx/RichQuarticPhotonReco.cpp      APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx " )
+
+set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx2 -mfma " )
+
+if(LCG_COMP STREQUAL "gcc" OR
+    (BINARY_TAG_COMP_NAME STREQUAL "gcc" AND BINARY_TAG_COMP_VERSION VERSION_LESS "5"))
+  set_property(SOURCE src/avx/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+  set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fabi-version=0 " )
+endif()
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
index 6616869b50..9ca2553298 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
@@ -47,6 +47,15 @@ StatusCode QuarticPhotonReco::initialize()
   auto sc = MultiTransformer::initialize();
   if ( !sc ) return sc;
 
+  // Get the CPU capabilities and set dispatch method
+  //enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
+  //const auto cpuLevel = instrset_detect();
+  //_ri_debug << "Instruction set level = " << cpuLevel << endmsg;
+  //if      ( cpuLevel >= AVX2 ) { m_run = &QuarticPhotonReco::run_avx2; }
+  //else if ( cpuLevel >= AVX  ) { m_run = &QuarticPhotonReco::run_avx; }
+  //else if ( cpuLevel >= SSE4 ) { m_run = &QuarticPhotonReco::run_sse4; }
+  //else                         { m_run = &QuarticPhotonReco::run_generic; }
+
   // get the detector elements
   m_rich[Rich::Rich1] = getDet<DeRich>( DeRichLocations::Rich1 );
   m_rich[Rich::Rich2] = getDet<DeRich>( DeRichLocations::Rich2 );
@@ -112,678 +121,6 @@ StatusCode QuarticPhotonReco::initialize()
 
 //=============================================================================
 
-OutData
-QuarticPhotonReco::operator()( const LHCb::RichTrackSegment::Vector& segments,
-                               const CherenkovAngles::Vector& ckAngles,
-                               const CherenkovResolutions::Vector& ckResolutions,
-                               const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
-                               const SegmentPhotonFlags::Vector& segPhotFlags,
-                               const Rich::PDPixelCluster::Vector& clusters,
-                               const SpacePointVector& globalPoints,
-                               const SpacePointVector& localPoints,
-                               const Relations::TrackToSegments::Vector& tkToSegRels ) const
-{
-  // use ranges v3 library
-  using namespace ranges::v3;
-
-  // make the output data
-  OutData outData;
-
-  // Shortcut to the photons and relations
-  auto & photons   = std::get<0>(outData);
-  auto & relations = std::get<1>(outData);
-  // guess at reserve size
-  const auto resSize = segments.size() * globalPoints.size() / 20;
-  photons.reserve( resSize );
-  relations.reserve( resSize );
-
-  // View range for pixel data
-  const auto allPixels = Ranges::ConstZip( clusters, globalPoints, localPoints );
-
-  // Make 'ranges' for RICH pixels
-  const auto RPixs = richRanges( allPixels );
-  const auto & RichRanges  = RPixs[0];   // Complete RICH ranges
-  const auto & Rich1Ranges = RPixs[1];   // ranges for RICH1 [top,bottom]
-  const auto & Rich2Ranges = RPixs[2];   // ranges for RICH2 [left,right]
-  
-  // local position corrector
-  // longer term need to remove this
-  const Rich::Rec::RadPositionCorrector corrector;
-
-  // global photon index
-  int photonIndex(-1);
-  
-  // Loop over the track->segment relations
-  for ( const auto & inTkRel : tkToSegRels )
-  {
-    // loop over segments for this track
-    for ( const auto & segIndex : inTkRel.segmentIndices )
-    {
-      // Get the data from the segment containers
-      const auto & segment     = segments[segIndex];
-      const auto & tkCkAngles  = ckAngles[segIndex];
-      const auto & tkCkRes     = ckResolutions[segIndex];
-      const auto & tkLocPtn    = trHitPntsLoc[segIndex];
-      const auto & segFlags    = segPhotFlags[segIndex];
-
-      // Is this segment above threshold. Should be implicit due to above segment loop
-      //if ( ! ( tkCkAngles[lightestActiveHypo()] > 0 ) ) continue;
-
-      // which RICH and radiator
-      const auto rich = segment.rich();
-      const auto rad  = segment.radiator();
-
-      // This implementiation does not support Aerogel
-      if ( UNLIKELY( Rich::Aerogel == rad ) ) { Exception("Aerogel not supported"); }
-
-      // get the best pixel range for this segment, based on where hits are expected
-      const auto& pixR = ( segFlags.inBothPanels() ? RichRanges[rich] :
-                           Rich::Rich1 == rich ? 
-                           ( segFlags.inPanel(Rich::top) ? 
-                             Rich1Ranges[Rich::top]  : Rich1Ranges[Rich::bottom] ) :
-                           ( segFlags.inPanel(Rich::left) ? 
-                             Rich2Ranges[Rich::left] : Rich2Ranges[Rich::right] ) );
-
-      // Loop over pixel information
-      int pixIndex = pixR.first - allPixels.begin() - 1; // (start index - 1) for this range
-      for ( auto pix_it = pixR.first; pix_it != pixR.second; ++pix_it )
-      {
-        // load the data from the tuple
-        const auto & cluster = std::get<0>(*pix_it);
-        const auto & gloPos  = std::get<1>(*pix_it);
-        const auto & locPos  = std::get<2>(*pix_it);
-        // increment the pixel index
-        ++pixIndex;
-
-        //_ri_verbo << "Trying Segment P=" << segment.bestMomentum() << " Pixel " 
-        //          << cluster << endmsg;
-
-        // Apply pre-selection
-      
-        // Pixel position, in local HPD coords corrected for average radiator distortion
-        // Might need to pre-compute and cache this as we repeat it here each segment...
-        const auto pixP = corrector.correct(locPos,rad);
-
-        //  Track local hit point on the same panel as the hit
-        /// @todo CRJ Need to figure out why I was not correcting this in the current stack...
-        ///           Probably correct but should check. 
-        //const auto segPanelPnt = corrector.correct(tkLocPtn.point(cluster.panel()),rad);
-        const auto& segPanelPnt = tkLocPtn.point(cluster.panel());
-
-        // compute the seperation squared
-        const auto sep2 = ( std::pow( (pixP.x()-segPanelPnt.x()), 2 ) +
-                            std::pow( (pixP.y()-segPanelPnt.y()), 2 ) );
-
-        // presel. default to rejected
-        bool SelOK = false;
-
-        // Check overall boundaries
-        //_ri_verbo << " -> sep2 = " << sep2 << " " << m_maxROI2PreSel[rad]
-        //          << " " << m_minROI2PreSel[rad] << endmsg;
-        if ( sep2 < m_maxROI2PreSel[rad] && sep2 > m_minROI2PreSel[rad] )
-        {
-        
-          // estimated CK theta
-          const auto ckThetaEsti = std::sqrt(sep2)*m_scalePreSel[rad];
-          //_ri_verbo << " -> CK theta Esti " << ckThetaEsti << endmsg;
-
-          // Is the hit close to any mass hypo in local coordinate space
-          SelOK = any_of( activeParticles(),
-                         [sigma=m_nSigmaPreSel[rad],&ckThetaEsti,&tkCkAngles,&tkCkRes]
-                         ( const auto hypo )
-                         { return fabs(tkCkAngles[hypo]-ckThetaEsti) < sigma*tkCkRes[hypo]; } );
-          
-        } // boundary check
-
-        // Did we pass the pre-sel
-        if ( !SelOK )
-        {
-          //_ri_verbo << "   -> FAILED pre-selection -> reject" << endmsg;
-          continue;
-        }
-
-        // Move on to the full Quartic reconstruction
-
-        //std::cout << "Starting photon reco" << std::endl;
-
-        // make a photon object to work on
-        photons.emplace_back();
-        auto & gPhoton = photons.back();
-        DataGuard<decltype(photons)> photGuard(photons);
-
-        // pixel side
-        const auto side = cluster.panel();
-
-        // Emission point to use for photon reconstruction
-        // operate directly on photon data member for efficiency
-        //auto & emissionPoint = gPhoton.emissionPoint();
-        //emissionPoint = segment.bestPoint();
-        auto emissionPoint = segment.bestPoint();
-
-        // Photon direction at emission point
-        // Again, operator directly on data member
-        //auto & photonDirection = gPhoton.emissionDir();
-        Gaudi::XYZVector photonDirection;
-
-        // Final reflection points on sec and spherical mirrors
-        // operate directly on photon data
-        //auto & sphReflPoint = gPhoton.sphMirReflectionPoint();
-        //auto & secReflPoint = gPhoton.flatMirReflectionPoint();
-        Gaudi::XYZPoint sphReflPoint, secReflPoint;
-
-        // fraction of segment path length accessible to the photon
-        float fraction(1);
-
-        // Pointers to best sec and spherical mirror segments
-        const DeRichSphMirror * sphSegment = nullptr;
-        const DeRichSphMirror * secSegment = nullptr;
-
-        // flag to say if this photon candidate is un-ambiguous - default to false
-        bool unambigPhoton = false;
-
-        // find the reflection of the detection point in the sec mirror
-        // (virtual detection point) starting with nominal values
-        // At this we are assuming a flat nominal mirror common to all segments
-        auto distance = m_rich[rich]->nominalPlane(side).Distance(gloPos);
-        auto virtDetPoint = gloPos - 2.0 * distance * m_rich[rich]->nominalNormal(side);
-
-        // --------------------------------------------------------------------------------------
-        // For gas radiators, try start and end points to see if photon is unambiguous
-        // NOTE : For this we are using the virtual detection point determined using
-        // the noimnal flat secondary mirror plane. Now the secondary mirrors are actually
-        // spherical this may be introducing some additional uncertainties.
-        // --------------------------------------------------------------------------------------
-        if ( m_testForUnambigPhots[rad] )
-        {
-          if ( UNLIKELY( rad == Rich::Aerogel ) )
-          {
-            // use default emission point and assume unambiguous since path length is so short..
-            unambigPhoton = true;
-          }
-          else  // gas radiators
-          {
-          
-            // flag for beam pipe check. Default is OK
-            bool beamTestOK(true);
-          
-            // -------------------------------------------------------------------------------
-            // First emission point, at start of track segment
-            const auto emissionPoint1 = segment.bestPoint(0.01);
-            // Find mirror segments for this emission point
-            const DeRichSphMirror* sphSegment1 = nullptr;
-            const DeRichSphMirror* secSegment1 = nullptr;
-            Gaudi::XYZPoint sphReflPoint1, secReflPoint1;
-            if ( !findMirrorData( rich, side, virtDetPoint, emissionPoint1,
-                                  sphSegment1, secSegment1, sphReflPoint1, secReflPoint1 ) )
-            {
-              //_ri_debug << rad << " : Failed to reconstruct photon for start of segment" << endmsg;
-              continue;
-            }
-            if ( m_checkBeamPipe[rad] )
-            {
-              beamTestOK = !deBeam(rich)->testForIntersection( emissionPoint1, sphReflPoint1 );
-            }
-            // -------------------------------------------------------------------------------
-          
-            // -------------------------------------------------------------------------------
-            // now do it again for emission point #2, at end of segment
-            const auto emissionPoint2 = segment.bestPoint(0.99);
-            // Find mirror segments for this emission point
-            const DeRichSphMirror* sphSegment2 = nullptr;
-            const DeRichSphMirror* secSegment2 = nullptr;
-            Gaudi::XYZPoint sphReflPoint2, secReflPoint2;
-            if ( !findMirrorData( rich, side, virtDetPoint, emissionPoint2,
-                                  sphSegment2, secSegment2, sphReflPoint2, secReflPoint2 ) )
-            {
-              //_ri_debug << rad << " : Failed to reconstruct photon for end of segment" << endmsg;
-              continue;
-            }
-            if ( !beamTestOK && m_checkBeamPipe[rad] )
-            {
-              beamTestOK = !deBeam(rich)->testForIntersection( emissionPoint2, sphReflPoint2 );
-            }
-            // -------------------------------------------------------------------------------
-          
-            // -------------------------------------------------------------------------------
-            if ( !beamTestOK )
-            {
-              // both start and end points failed beam pipe test -> reject
-              //_ri_debug << rad << " : Failed ambiguous photon beampipe intersection checks" << endmsg;
-              continue;
-            }
-            // -------------------------------------------------------------------------------
-          
-            // -------------------------------------------------------------------------------
-            // Test to see if photon direction hits the real physical mirror segments
-            // -------------------------------------------------------------------------------
-            if ( UNLIKELY(m_checkPrimMirrSegs[rad]) )
-            {
-              // primary mirrors
-              const auto ok = ( sphSegment1->intersects( emissionPoint1,
-                                                         sphReflPoint1-emissionPoint1 ) ||
-                                sphSegment2->intersects( emissionPoint2,
-                                                         sphReflPoint2-emissionPoint2 ) );
-              if ( !ok )
-              {
-                //_ri_debug << rad << " : Failed mirror segment intersection checks" << endmsg;
-                continue;
-              }
-            }
-            // -------------------------------------------------------------------------------
-          
-            // -------------------------------------------------------------------------------
-            // Get the best gas emission point
-            if ( !getBestGasEmissionPoint( rad,
-                                           sphReflPoint1,
-                                           sphReflPoint2,
-                                           gloPos,
-                                           segment,
-                                           emissionPoint,
-                                           fraction ) )
-            {
-              //_ri_debug << rad << " : Failed to compute best gas emission point" << endmsg;
-              continue;
-            }
-            // -------------------------------------------------------------------------------
-          
-            // -------------------------------------------------------------------------------
-            // Is this an unambiguous photon - I.e. only one possible mirror combination
-            if ( ( sphSegment1 == sphSegment2 ) && ( secSegment1 == secSegment2 ) )
-            {
-              // Set pointers to the mirror detector objects
-              sphSegment = sphSegment1;
-              secSegment = secSegment1;
-              // rough guesses at reflection points (improved later on)
-              sphReflPoint = sphReflPoint1 + 0.5*(sphReflPoint2-sphReflPoint1);
-              secReflPoint = secReflPoint1 + 0.5*(secReflPoint2-secReflPoint1);
-              // photon is not unambiguous
-              unambigPhoton = true;
-            }
-            // -------------------------------------------------------------------------------
-          
-          } // end radiator type if
-        
-          // if configured to do so reject ambiguous photons
-          if ( UNLIKELY( m_rejectAmbigPhots[rad] && !unambigPhoton ) )
-          {
-            //_ri_debug << rad << " : Failed ambiguous photon test" << endmsg;
-            continue;
-          }
-        
-        } // end unambiguous photon check
-        // --------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // Active segment fraction cut
-        // --------------------------------------------------------------------------------------
-        if ( UNLIKELY( fraction < m_minActiveFrac[rad] ) )
-        {
-          //_ri_debug << rad << " : Failed active segment fraction cut" << endmsg;
-          continue;
-        }
-        // --------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // if ambiguous gas photon or if ambiguous photon check above has been skipped, try again
-        // using best emission point and nominal mirror geometries to get the spherical and sec
-        // mirrors. Also, force this reconstruction if the above unambiguous test was skipped
-        // --------------------------------------------------------------------------------------
-        if ( UNLIKELY( !m_testForUnambigPhots[rad] || !unambigPhoton ) )
-        {
-          if ( !findMirrorData(rich,side,
-                               virtDetPoint,emissionPoint,
-                               sphSegment,secSegment,sphReflPoint,secReflPoint ) )
-          {
-            //_ri_debug << rad << " : Failed backup photon reconstruction" << endmsg;
-            continue;
-          }
-        }
-        // --------------------------------------------------------------------------------------
-      
-        // --------------------------------------------------------------------------------------
-        // Finally reconstruct the photon using best emission point and the best mirror segments
-        // --------------------------------------------------------------------------------------
-        if ( m_useAlignedMirrSegs[rad] )
-        {
-        
-          // If iterations are disabled for this radiator, update the virtual detection point
-          // using the selected mirror segment
-          if ( UNLIKELY( 0 == m_nMaxQits[rad] ) )
-          {
-          
-            // Form the virtual detection point
-            distance     = secSegment->centreNormalPlane().Distance(gloPos);
-            virtDetPoint = gloPos - 2.0 * distance * secSegment->centreNormal();
-          
-            // solve the quartic using the new data
-            m_quarticSolver.solve<double,2,3>( emissionPoint,
-                                               sphSegment->centreOfCurvature(),
-                                               virtDetPoint,
-                                               sphSegment->radius(),
-                                               sphReflPoint );
-          
-            // (re)find the spherical mirror segment
-            // CRJ - Is this needed ?
-            sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
-          
-          }
-          else
-          {
-          
-            // Iterate to final solution, improving the secondary mirror info
-            int iIt(0);
-            Gaudi::XYZPoint last_mirror_point(0,0,0);
-            bool loopOK = true;
-            while ( iIt < m_nMaxQits[rad] )
-            {
-            
-              // Get secondary mirror reflection point,
-              // using the best actual secondary mirror segment at this point
-              const auto dir = virtDetPoint - sphReflPoint;
-              const auto sc = ( m_treatSecMirrsFlat[rich] ? 
-                                intersectPlane( sphReflPoint, dir,
-                                                secSegment->centreNormalPlane(),
-                                                secReflPoint ) :
-                                intersectSpherical( sphReflPoint, dir,
-                                                    secSegment->centreOfCurvature(),
-                                                    secSegment->radius(),
-                                                    secReflPoint ) );
-              if ( UNLIKELY(!sc) )
-              {
-                //_ri_debug << rad << " : Failed to intersect nominal secondary mirror plane" << endmsg;
-                loopOK = false;
-                break;
-              }
-
-              // (re)find the secondary mirror
-              secSegment = m_mirrorSegFinder.get()->findSecMirror( rich, side, secReflPoint );
-            
-              // Construct plane tangential to secondary mirror passing through reflection point
-              const Gaudi::Plane3D plane( secSegment->centreOfCurvature()-secReflPoint, secReflPoint );
-            
-              // re-find the reflection of the detection point in the sec mirror
-              // (virtual detection point) with this mirror plane
-              distance     = plane.Distance(gloPos);
-              virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
-            
-              // solve the quartic using the new data
-              m_quarticSolver.solve<double,2,3>( emissionPoint,
-                                                 sphSegment->centreOfCurvature(),
-                                                 virtDetPoint,
-                                                 sphSegment->radius(),
-                                                 sphReflPoint );
-
-              // (re)find the spherical mirror segment
-              sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
-
-              // for iterations after the first, see if we are still moving
-              // If not, abort iterations early
-              if ( iIt > m_nMinQits[rad] &&
-                   (last_mirror_point-secReflPoint).Mag2() < m_minSphMirrTolIt[rad] ) { break; }
-
-              // store last sec mirror point
-              last_mirror_point = secReflPoint;
-
-              // increment iteration counter
-              ++iIt;
-            }
-            // if above while loop failed, abort this photon
-            if ( UNLIKELY(!loopOK) ) { continue; }
-          
-          }
-        
-        }
-        // --------------------------------------------------------------------------------------
-      
-        // --------------------------------------------------------------------------------------
-        // check that spherical mirror reflection point is on the same side as detection point
-        // and (if configured to do so) photon does not cross between detector sides
-        // --------------------------------------------------------------------------------------
-        if ( UNLIKELY( !sameSide(rad,sphReflPoint,virtDetPoint) ) )
-        {
-          //_ri_debug << rad << " : Reflection point on wrong side" << endmsg;
-          continue;
-        }
-        if ( UNLIKELY( m_checkPhotCrossSides[rad] &&
-                       !sameSide(rad,sphReflPoint,emissionPoint) ) )
-        {
-          //_ri_debug << rad << " : Photon crosses between detector sides" << endmsg;
-          continue;
-        }
-        //else { continue; } // uncomment to select ONLY crossing photons
-        // --------------------------------------------------------------------------------------
-      
-        // --------------------------------------------------------------------------------------
-        // For as radiators if ambiguous photon checks are disabled (since this is
-        // already done for these photons during those checks), check if the photon would have
-        // intersected with the beampipe
-        // --------------------------------------------------------------------------------------
-        if ( UNLIKELY( m_checkBeamPipe[rad] && !m_testForUnambigPhots[rad] ) )
-        {
-          if ( UNLIKELY( deBeam(rich)->testForIntersection( emissionPoint, sphReflPoint ) ) )
-          {
-            //_ri_debug << rad << " : Failed final beampipe intersection checks" << endmsg;
-            continue;
-          }
-        }
-        // --------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // If using aligned mirror segments, get the final sec mirror reflection
-        // point using the best mirror segments available at this point
-        // For RICH2, use the spherical nature of the scondary mirrors
-        // For RICH1, where they are much flatter, assume complete flatness
-        // --------------------------------------------------------------------------------------
-        if ( m_useAlignedMirrSegs[rad] )
-        {
-          const auto dir = virtDetPoint - sphReflPoint;
-          const auto sc = ( m_treatSecMirrsFlat[rich] ? 
-                            intersectPlane( sphReflPoint, dir,
-                                            secSegment->centreNormalPlane(),
-                                            secReflPoint ) :
-                            intersectSpherical( sphReflPoint, dir,
-                                                secSegment->centreOfCurvature(),
-                                                secSegment->radius(),
-                                                secReflPoint ) );
-          if ( !sc )
-          {
-            //_ri_debug << rad << " : Failed final secondary mirror plane intersection" << endmsg;
-            continue;
-          }
-        }
-        // --------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // calculate the cherenkov angles using the photon and track vectors
-        // --------------------------------------------------------------------------------------
-        photonDirection = (sphReflPoint-emissionPoint).Unit();
-        float thetaCerenkov(0), phiCerenkov(0);
-        segment.angleToDirection( photonDirection, thetaCerenkov, phiCerenkov );
-        // --------------------------------------------------------------------------------------
-
-        //---------------------------------------------------------------------------------------
-        // Apply fudge factor correction for small biases in CK theta
-        //---------------------------------------------------------------------------------------
-        thetaCerenkov += ckThetaCorrection(rad);
-        //---------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // Final checks on the Cherenkov angles
-        // --------------------------------------------------------------------------------------
-        if ( UNLIKELY( !checkAngles( rad, tkCkAngles, tkCkRes,
-                                     thetaCerenkov, phiCerenkov ) ) )
-        {
-          //_ri_verbo << "    -> photon FAILED checkAngleInRange test" << endmsg;
-          continue;
-        }
-        // --------------------------------------------------------------------------------------
-
-        // --------------------------------------------------------------------------------------
-        // Set (remaining) photon parameters
-        // --------------------------------------------------------------------------------------
-        gPhoton.setCherenkovTheta         ( thetaCerenkov       );
-        gPhoton.setCherenkovPhi           ( phiCerenkov         );
-        gPhoton.setActiveSegmentFraction  ( fraction            );
-        //gPhoton.setDetectionPoint         ( gloPos              );
-        gPhoton.setSmartID                ( cluster.primaryID() );
-        gPhoton.setUnambiguousPhoton      ( unambigPhoton       );
-        //gPhoton.setPrimaryMirror          ( sphSegment          );
-        //gPhoton.setSecondaryMirror        ( secSegment          );
-        //_ri_verbo << "Created photon " << gPhoton << endmsg;
-        // --------------------------------------------------------------------------------------
-     
-        // If we get here, keep the just made photon
-        photGuard.setOK();
-        // Save relations
-        relations.emplace_back( ++photonIndex, pixIndex, segIndex, inTkRel.tkIndex );
-        //info() << relations.back() << endmsg;
-
-      }
-
-    }
-    
-  }
-  
-  //_ri_debug << "Created " << photons.size() << " photons" << endmsg;
-  return outData;
-}
-
-//=========================================================================
-// Find mirror segments and reflection points for given data
-//=========================================================================
-bool
-QuarticPhotonReco::
-findMirrorData( const Rich::DetectorType rich,
-                const Rich::Side side,
-                const Gaudi::XYZPoint& virtDetPoint,
-                const Gaudi::XYZPoint& emissionPoint,
-                const DeRichSphMirror*& sphSegment,
-                const DeRichSphMirror*& secSegment,
-                Gaudi::XYZPoint& sphReflPoint,
-                Gaudi::XYZPoint& secReflPoint ) const
-{
-  // solve quartic equation with nominal values and find spherical mirror reflection point
-  m_quarticSolver.solve<double,2,2>( emissionPoint,
-                                     m_rich[rich]->nominalCentreOfCurvature(side),
-                                     virtDetPoint,
-                                     m_rich[rich]->sphMirrorRadius(),
-                                     sphReflPoint );
-  // find the spherical mirror segment
-  sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
-  // Search for the secondary segment
-  // Direction vector from primary mirror point to virtual detection point
-  const auto dir ( virtDetPoint - sphReflPoint );
-  // find the sec mirror intersction point and secondary mirror segment
-  const bool OK = intersectPlane( sphReflPoint, dir,
-                                  m_rich[rich]->nominalPlane(side),
-                                  secReflPoint );
-  if ( OK )
-  {
-    // find the secondary mirror
-    secSegment = m_mirrorSegFinder.get()->findSecMirror( rich, side, secReflPoint );
-    // Re-find the secondary mirror reflection point using the new mirror info
-    // OK = ( !m_treatSecMirrsFlat[rich] ? 
-    //        intersectSpherical( sphReflPoint, dir,
-    //                            secSegment->centreOfCurvature(),
-    //                            secSegment->radius(),
-    //                            secReflPoint ) :
-    //        intersectPlane( sphReflPoint, dir,
-    //                        secSegment->centreNormalPlane(),
-    //                        secReflPoint ) );
-  }
-  // return
-  return OK;
-}
-
-//=========================================================================
-// Compute the best emission point for the gas radiators using
-// the given spherical mirror reflection points
-//=========================================================================
-bool
-QuarticPhotonReco::
-getBestGasEmissionPoint( const Rich::RadiatorType radiator,
-                         const Gaudi::XYZPoint& sphReflPoint1,
-                         const Gaudi::XYZPoint& sphReflPoint2,
-                         const Gaudi::XYZPoint& detectionPoint,
-                         const LHCb::RichTrackSegment & segment,
-                         Gaudi::XYZPoint & emissionPoint,
-                         float & fraction ) const
-{
-  double alongTkFrac = 0.5;
-
-  if ( radiator == Rich::Rich1Gas )
-  {
-    // First reflection and hit point on same y side ?
-    const bool sameSide1 = ( sphReflPoint1.y() * detectionPoint.y() > 0 );
-    const bool sameSide2 = ( sphReflPoint2.y() * detectionPoint.y() > 0 );
-    if ( sameSide1 && sameSide2 )
-    {
-      emissionPoint = segment.bestPoint();
-    }
-    else if ( sameSide1 )
-    {
-      fraction = (float)(std::fabs(sphReflPoint1.y()/(sphReflPoint1.y()-sphReflPoint2.y())));
-      alongTkFrac = fraction/2.0;
-      emissionPoint = segment.bestPoint(alongTkFrac);
-    }
-    else if ( sameSide2 )
-    {
-      fraction = (float)(std::fabs(sphReflPoint2.y()/(sphReflPoint1.y()-sphReflPoint2.y())));
-      alongTkFrac = 1.0-fraction/2.0;
-      emissionPoint = segment.bestPoint(alongTkFrac);
-    }
-    else
-    {
-      //Warning( "Rich1Gas : Both RICH spherical mirror hits opposite side to detection point" );
-      return false;
-    }
-
-  }
-  else if ( radiator == Rich::Rich2Gas )
-  {
-    // First sphReflPoint and hit point on same x side ?
-    const bool sameSide1 = ( sphReflPoint1.x() * detectionPoint.x() > 0 );
-    const bool sameSide2 = ( sphReflPoint2.x() * detectionPoint.x() > 0 );
-    if ( sameSide1 && sameSide2 )
-    {
-      emissionPoint = segment.bestPoint();
-    }
-    else if ( sameSide1 )
-    {
-      fraction = (float)(std::fabs(sphReflPoint1.x()/(sphReflPoint1.x()-sphReflPoint2.x())));
-      alongTkFrac = fraction/2.0;
-      emissionPoint = segment.bestPoint(alongTkFrac);
-    }
-    else if ( sameSide2 )
-    {
-      fraction = (float)(std::fabs(sphReflPoint2.x()/(sphReflPoint1.x()-sphReflPoint2.x())));
-      alongTkFrac = 1.0-fraction/2.0;
-      emissionPoint = segment.bestPoint(alongTkFrac);
-    }
-    else
-    {
-      //Warning( "Rich2Gas : Both RICH spherical mirror hits opposite side to detection point" );
-      return false;
-    }
-  }
-  else { Error( "::getBestGasEmissionPoint() called for Aerogel segment !!" ); }
-
-  // if ( msgLevel(MSG::VERBOSE) )
-  // {
-  //   verbose() << radiator << " best emission point correction :- " << endmsg
-  //             << " -> Photon detection point = " << detectionPoint << endmsg
-  //             << " -> Sph. Mirror ptns       = " << sphReflPoint1 << " " << sphReflPoint2 << endmsg
-  //             << " -> Segment entry/exit     = " << trSeg.entryPoint() << " " << trSeg.exitPoint() << endmsg
-  //             << " -> Segment fraction       = " << fraction << endmsg
-  //             << " -> Emm. Ptn. Along traj   = " << alongTkFrac << endmsg
-  //             << " -> Best Emission point    = " << emissionPoint << endmsg;
-  // }
-
-  return true;
-}
-
-//=============================================================================
-
 // Declaration of the Algorithm Factory
 DECLARE_ALGORITHM_FACTORY( QuarticPhotonReco )
 
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 8449cc5409..83b1baead2 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -41,6 +41,9 @@
 // interfaces
 #include "RichInterfaces/IRichMirrorSegFinderLookUpTable.h"
 
+// Vector Class
+#include "VectorClass/instrset.h"
+
 namespace Rich
 {
   namespace Future
@@ -51,6 +54,9 @@ namespace Rich
       // Use the functional framework
       using namespace Gaudi::Functional;
 
+      // pull in methods from Rich::RayTracingUtils
+      using namespace Rich::RayTracingUtils;
+
       namespace
       {
         /// Shortcut to the output data type
@@ -98,8 +104,72 @@ namespace Rich
                             const Rich::PDPixelCluster::Vector& clusters,
                             const SpacePointVector& globalPoints,
                             const SpacePointVector& localPoints,
-                            const Relations::TrackToSegments::Vector& tkToSegRels ) const override;
+                            const Relations::TrackToSegments::Vector& tkToSegRels ) const override
+        {
+          return (this->*m_run)( segments, ckAngles, ckResolutions, trHitPntsLoc,
+                                 segPhotFlags, clusters, globalPoints, localPoints, tkToSegRels );
+        }
 
+      private: // dispatch methods
+
+        /** Pointer to dispatch function for the operator call
+         *  Default to lowest common denominator. 
+         *  Reset in initialize() according to runtime support */
+        OutData (QuarticPhotonReco::*m_run)
+          ( const LHCb::RichTrackSegment::Vector& segments,
+            const CherenkovAngles::Vector& ckAngles,
+            const CherenkovResolutions::Vector& ckResolutions,
+            const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+            const SegmentPhotonFlags::Vector& segPhotFlags,
+            const Rich::PDPixelCluster::Vector& clusters,
+            const SpacePointVector& globalPoints,
+            const SpacePointVector& localPoints,
+            const Relations::TrackToSegments::Vector& tkToSegRels  ) const 
+          = &QuarticPhotonReco::run_generic;
+        
+        /// Generic method
+        OutData run_generic( const LHCb::RichTrackSegment::Vector& segments,
+                             const CherenkovAngles::Vector& ckAngles,
+                             const CherenkovResolutions::Vector& ckResolutions,
+                             const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                             const SegmentPhotonFlags::Vector& segPhotFlags,
+                             const Rich::PDPixelCluster::Vector& clusters,
+                             const SpacePointVector& globalPoints,
+                             const SpacePointVector& localPoints,
+                             const Relations::TrackToSegments::Vector& tkToSegRels ) const;
+
+        /// SSE4 method
+        OutData run_sse4( const LHCb::RichTrackSegment::Vector& segments,
+                          const CherenkovAngles::Vector& ckAngles,
+                          const CherenkovResolutions::Vector& ckResolutions,
+                          const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                          const SegmentPhotonFlags::Vector& segPhotFlags,
+                          const Rich::PDPixelCluster::Vector& clusters,
+                          const SpacePointVector& globalPoints,
+                          const SpacePointVector& localPoints,
+                          const Relations::TrackToSegments::Vector& tkToSegRels ) const;
+         
+        /// AVX method
+        OutData run_avx( const LHCb::RichTrackSegment::Vector& segments,
+                         const CherenkovAngles::Vector& ckAngles,
+                         const CherenkovResolutions::Vector& ckResolutions,
+                         const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                         const SegmentPhotonFlags::Vector& segPhotFlags,
+                         const Rich::PDPixelCluster::Vector& clusters,
+                         const SpacePointVector& globalPoints,
+                         const SpacePointVector& localPoints,
+                         const Relations::TrackToSegments::Vector& tkToSegRels ) const;
+        /// AVX2 method
+        OutData run_avx2( const LHCb::RichTrackSegment::Vector& segments,
+                          const CherenkovAngles::Vector& ckAngles,
+                          const CherenkovResolutions::Vector& ckResolutions,
+                          const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                          const SegmentPhotonFlags::Vector& segPhotFlags,
+                          const Rich::PDPixelCluster::Vector& clusters,
+                          const SpacePointVector& globalPoints,
+                          const SpacePointVector& localPoints,
+                          const Relations::TrackToSegments::Vector& tkToSegRels ) const;
+        
       private: // methods
 
         /// Access the DeRich beam pipe objects
@@ -115,15 +185,39 @@ namespace Rich
         inline float  myacos( const float  x ) const noexcept { return vdt::fast_acosf(x); }
 
         /// Find mirror segments and reflection points for given data
-        bool findMirrorData( const Rich::DetectorType rich,
-                             const Rich::Side side,
-                             const Gaudi::XYZPoint & virtDetPoint,
-                             const Gaudi::XYZPoint & emissionPoint,
-                             const DeRichSphMirror *& sphSegment,
-                             const DeRichSphMirror *& secSegment,
-                             Gaudi::XYZPoint & sphReflPoint,
-                             Gaudi::XYZPoint & secReflPoint ) const;
-
+        inline bool findMirrorData( const Rich::DetectorType rich,
+                                    const Rich::Side side,
+                                    const Gaudi::XYZPoint & virtDetPoint,
+                                    const Gaudi::XYZPoint & emissionPoint,
+                                    const DeRichSphMirror *& sphSegment,
+                                    const DeRichSphMirror *& secSegment,
+                                    Gaudi::XYZPoint & sphReflPoint,
+                                    Gaudi::XYZPoint & secReflPoint ) const
+        {
+          // solve quartic equation with nominal values and find spherical mirror reflection point
+          m_quarticSolver.solve<double,2,2>( emissionPoint,
+                                             m_rich[rich]->nominalCentreOfCurvature(side),
+                                             virtDetPoint,
+                                             m_rich[rich]->sphMirrorRadius(),
+                                             sphReflPoint );
+          // find the spherical mirror segment
+          sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
+          // Search for the secondary segment
+          // Direction vector from primary mirror point to virtual detection point
+          const auto dir ( virtDetPoint - sphReflPoint );
+          // find the sec mirror intersction point and secondary mirror segment
+          const bool OK = intersectPlane( sphReflPoint, dir,
+                                          m_rich[rich]->nominalPlane(side),
+                                          secReflPoint );
+          if ( OK )
+          {
+            // find the secondary mirror
+            secSegment = m_mirrorSegFinder.get()->findSecMirror( rich, side, secReflPoint );
+          }
+          // return
+          return OK;
+        }
+        
         /// Compute the best emission point for the gas radiators using
         /// the given spherical mirror reflection points
         bool getBestGasEmissionPoint( const Rich::RadiatorType radiator,
@@ -226,6 +320,93 @@ namespace Rich
 
       };
 
+      //=========================================================================
+      // Compute the best emission point for the gas radiators using
+      // the given spherical mirror reflection points
+      //=========================================================================
+      inline bool
+      QuarticPhotonReco::
+      getBestGasEmissionPoint( const Rich::RadiatorType radiator,
+                               const Gaudi::XYZPoint& sphReflPoint1,
+                               const Gaudi::XYZPoint& sphReflPoint2,
+                               const Gaudi::XYZPoint& detectionPoint,
+                               const LHCb::RichTrackSegment & segment,
+                               Gaudi::XYZPoint & emissionPoint,
+                               float & fraction ) const
+      {
+        double alongTkFrac = 0.5;
+        
+        if ( radiator == Rich::Rich1Gas )
+        {
+          // First reflection and hit point on same y side ?
+          const bool sameSide1 = ( sphReflPoint1.y() * detectionPoint.y() > 0 );
+          const bool sameSide2 = ( sphReflPoint2.y() * detectionPoint.y() > 0 );
+          if ( sameSide1 && sameSide2 )
+          {
+            emissionPoint = segment.bestPoint();
+          }
+          else if ( sameSide1 )
+          {
+            fraction = (float)(std::fabs(sphReflPoint1.y()/(sphReflPoint1.y()-sphReflPoint2.y())));
+            alongTkFrac = fraction/2.0;
+            emissionPoint = segment.bestPoint(alongTkFrac);
+          }
+          else if ( sameSide2 )
+          {
+            fraction = (float)(std::fabs(sphReflPoint2.y()/(sphReflPoint1.y()-sphReflPoint2.y())));
+            alongTkFrac = 1.0-fraction/2.0;
+            emissionPoint = segment.bestPoint(alongTkFrac);
+          }
+          else
+          {
+            //Warning( "Rich1Gas : Both RICH spherical mirror hits opposite side to detection point" );
+            return false;
+          }
+          
+        }
+        else if ( radiator == Rich::Rich2Gas )
+        {
+          // First sphReflPoint and hit point on same x side ?
+          const bool sameSide1 = ( sphReflPoint1.x() * detectionPoint.x() > 0 );
+          const bool sameSide2 = ( sphReflPoint2.x() * detectionPoint.x() > 0 );
+          if ( sameSide1 && sameSide2 )
+          {
+            emissionPoint = segment.bestPoint();
+          }
+          else if ( sameSide1 )
+          {
+            fraction = (float)(std::fabs(sphReflPoint1.x()/(sphReflPoint1.x()-sphReflPoint2.x())));
+            alongTkFrac = fraction/2.0;
+            emissionPoint = segment.bestPoint(alongTkFrac);
+          }
+          else if ( sameSide2 )
+          {
+            fraction = (float)(std::fabs(sphReflPoint2.x()/(sphReflPoint1.x()-sphReflPoint2.x())));
+            alongTkFrac = 1.0-fraction/2.0;
+            emissionPoint = segment.bestPoint(alongTkFrac);
+          }
+          else
+          {
+            //Warning( "Rich2Gas : Both RICH spherical mirror hits opposite side to detection point" );
+            return false;
+          }
+        }
+        else { Error( "::getBestGasEmissionPoint() called for Aerogel segment !!" ); }
+        
+        // if ( msgLevel(MSG::VERBOSE) )
+        // {
+        //   verbose() << radiator << " best emission point correction :- " << endmsg
+        //             << " -> Photon detection point = " << detectionPoint << endmsg
+        //             << " -> Sph. Mirror ptns       = " << sphReflPoint1 << " " << sphReflPoint2 << endmsg
+        //             << " -> Segment entry/exit     = " << trSeg.entryPoint() << " " << trSeg.exitPoint() << endmsg
+        //             << " -> Segment fraction       = " << fraction << endmsg
+        //             << " -> Emm. Ptn. Along traj   = " << alongTkFrac << endmsg
+        //             << " -> Best Emission point    = " << emissionPoint << endmsg;
+        // }
+        
+        return true;
+      }
+
     }
   }
 }
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
new file mode 100644
index 0000000000..dd4cb6f94b
--- /dev/null
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
@@ -0,0 +1,526 @@
+
+{
+  // use ranges v3 library
+  using namespace ranges::v3;
+
+  // make the output data
+  OutData outData;
+
+  // Shortcut to the photons and relations
+  auto & photons   = std::get<0>(outData);
+  auto & relations = std::get<1>(outData);
+  // guess at reserve size
+  const auto resSize = segments.size() * globalPoints.size() / 20;
+  photons.reserve( resSize );
+  relations.reserve( resSize );
+
+  // View range for pixel data
+  const auto allPixels = Ranges::ConstZip( clusters, globalPoints, localPoints );
+
+  // Make 'ranges' for RICH pixels
+  const auto RPixs = richRanges( allPixels );
+  const auto & RichRanges  = RPixs[0];   // Complete RICH ranges
+  const auto & Rich1Ranges = RPixs[1];   // ranges for RICH1 [top,bottom]
+  const auto & Rich2Ranges = RPixs[2];   // ranges for RICH2 [left,right]
+  
+  // local position corrector
+  // longer term need to remove this
+  const Rich::Rec::RadPositionCorrector corrector;
+
+  // global photon index
+  int photonIndex(-1);
+  
+  // Loop over the track->segment relations
+  for ( const auto & inTkRel : tkToSegRels )
+  {
+    // loop over segments for this track
+    for ( const auto & segIndex : inTkRel.segmentIndices )
+    {
+      // Get the data from the segment containers
+      const auto & segment     = segments[segIndex];
+      const auto & tkCkAngles  = ckAngles[segIndex];
+      const auto & tkCkRes     = ckResolutions[segIndex];
+      const auto & tkLocPtn    = trHitPntsLoc[segIndex];
+      const auto & segFlags    = segPhotFlags[segIndex];
+
+      // Is this segment above threshold. Should be implicit due to above segment loop
+      //if ( ! ( tkCkAngles[lightestActiveHypo()] > 0 ) ) continue;
+
+      // which RICH and radiator
+      const auto rich = segment.rich();
+      const auto rad  = segment.radiator();
+
+      // This implementiation does not support Aerogel
+      if ( UNLIKELY( Rich::Aerogel == rad ) ) { Exception("Aerogel not supported"); }
+
+      // get the best pixel range for this segment, based on where hits are expected
+      const auto& pixR = ( segFlags.inBothPanels() ? RichRanges[rich] :
+                           Rich::Rich1 == rich ? 
+                           ( segFlags.inPanel(Rich::top) ? 
+                             Rich1Ranges[Rich::top]  : Rich1Ranges[Rich::bottom] ) :
+                           ( segFlags.inPanel(Rich::left) ? 
+                             Rich2Ranges[Rich::left] : Rich2Ranges[Rich::right] ) );
+
+      // Loop over pixel information
+      int pixIndex = pixR.first - allPixels.begin() - 1; // (start index - 1) for this range
+      for ( auto pix_it = pixR.first; pix_it != pixR.second; ++pix_it )
+      {
+        // load the data from the tuple
+        const auto & cluster = std::get<0>(*pix_it);
+        const auto & gloPos  = std::get<1>(*pix_it);
+        const auto & locPos  = std::get<2>(*pix_it);
+        // increment the pixel index
+        ++pixIndex;
+
+        //_ri_verbo << "Trying Segment P=" << segment.bestMomentum() << " Pixel " 
+        //          << cluster << endmsg;
+
+        // Apply pre-selection
+      
+        // Pixel position, in local HPD coords corrected for average radiator distortion
+        // Might need to pre-compute and cache this as we repeat it here each segment...
+        const auto pixP = corrector.correct(locPos,rad);
+
+        //  Track local hit point on the same panel as the hit
+        /// @todo CRJ Need to figure out why I was not correcting this in the current stack...
+        ///           Probably correct but should check. 
+        //const auto segPanelPnt = corrector.correct(tkLocPtn.point(cluster.panel()),rad);
+        const auto& segPanelPnt = tkLocPtn.point(cluster.panel());
+
+        // compute the seperation squared
+        const auto sep2 = ( std::pow( (pixP.x()-segPanelPnt.x()), 2 ) +
+                            std::pow( (pixP.y()-segPanelPnt.y()), 2 ) );
+
+        // presel. default to rejected
+        bool SelOK = false;
+
+        // Check overall boundaries
+        //_ri_verbo << " -> sep2 = " << sep2 << " " << m_maxROI2PreSel[rad]
+        //          << " " << m_minROI2PreSel[rad] << endmsg;
+        if ( sep2 < m_maxROI2PreSel[rad] && sep2 > m_minROI2PreSel[rad] )
+        {
+        
+          // estimated CK theta
+          const auto ckThetaEsti = std::sqrt(sep2)*m_scalePreSel[rad];
+          //_ri_verbo << " -> CK theta Esti " << ckThetaEsti << endmsg;
+
+          // Is the hit close to any mass hypo in local coordinate space
+          SelOK = any_of( activeParticles(),
+                         [sigma=m_nSigmaPreSel[rad],&ckThetaEsti,&tkCkAngles,&tkCkRes]
+                         ( const auto hypo )
+                         { return fabs(tkCkAngles[hypo]-ckThetaEsti) < sigma*tkCkRes[hypo]; } );
+          
+        } // boundary check
+
+        // Did we pass the pre-sel
+        if ( !SelOK )
+        {
+          //_ri_verbo << "   -> FAILED pre-selection -> reject" << endmsg;
+          continue;
+        }
+
+        // Move on to the full Quartic reconstruction
+
+        //std::cout << "Starting photon reco" << std::endl;
+
+        // make a photon object to work on
+        photons.emplace_back();
+        auto & gPhoton = photons.back();
+        DataGuard<decltype(photons)> photGuard(photons);
+
+        // pixel side
+        const auto side = cluster.panel();
+
+        // Emission point to use for photon reconstruction
+        // operate directly on photon data member for efficiency
+        //auto & emissionPoint = gPhoton.emissionPoint();
+        //emissionPoint = segment.bestPoint();
+        auto emissionPoint = segment.bestPoint();
+
+        // Photon direction at emission point
+        // Again, operator directly on data member
+        //auto & photonDirection = gPhoton.emissionDir();
+        Gaudi::XYZVector photonDirection;
+
+        // Final reflection points on sec and spherical mirrors
+        // operate directly on photon data
+        //auto & sphReflPoint = gPhoton.sphMirReflectionPoint();
+        //auto & secReflPoint = gPhoton.flatMirReflectionPoint();
+        Gaudi::XYZPoint sphReflPoint, secReflPoint;
+
+        // fraction of segment path length accessible to the photon
+        float fraction(1);
+
+        // Pointers to best sec and spherical mirror segments
+        const DeRichSphMirror * sphSegment = nullptr;
+        const DeRichSphMirror * secSegment = nullptr;
+
+        // flag to say if this photon candidate is un-ambiguous - default to false
+        bool unambigPhoton = false;
+
+        // find the reflection of the detection point in the sec mirror
+        // (virtual detection point) starting with nominal values
+        // At this we are assuming a flat nominal mirror common to all segments
+        auto distance = m_rich[rich]->nominalPlane(side).Distance(gloPos);
+        auto virtDetPoint = gloPos - 2.0 * distance * m_rich[rich]->nominalNormal(side);
+
+        // --------------------------------------------------------------------------------------
+        // For gas radiators, try start and end points to see if photon is unambiguous
+        // NOTE : For this we are using the virtual detection point determined using
+        // the noimnal flat secondary mirror plane. Now the secondary mirrors are actually
+        // spherical this may be introducing some additional uncertainties.
+        // --------------------------------------------------------------------------------------
+        if ( m_testForUnambigPhots[rad] )
+        {
+          if ( UNLIKELY( rad == Rich::Aerogel ) )
+          {
+            // use default emission point and assume unambiguous since path length is so short..
+            unambigPhoton = true;
+          }
+          else  // gas radiators
+          {
+          
+            // flag for beam pipe check. Default is OK
+            bool beamTestOK(true);
+          
+            // -------------------------------------------------------------------------------
+            // First emission point, at start of track segment
+            const auto emissionPoint1 = segment.bestPoint(0.01);
+            // Find mirror segments for this emission point
+            const DeRichSphMirror* sphSegment1 = nullptr;
+            const DeRichSphMirror* secSegment1 = nullptr;
+            Gaudi::XYZPoint sphReflPoint1, secReflPoint1;
+            if ( !findMirrorData( rich, side, virtDetPoint, emissionPoint1,
+                                  sphSegment1, secSegment1, sphReflPoint1, secReflPoint1 ) )
+            {
+              //_ri_debug << rad << " : Failed to reconstruct photon for start of segment" << endmsg;
+              continue;
+            }
+            if ( m_checkBeamPipe[rad] )
+            {
+              beamTestOK = !deBeam(rich)->testForIntersection( emissionPoint1, sphReflPoint1 );
+            }
+            // -------------------------------------------------------------------------------
+          
+            // -------------------------------------------------------------------------------
+            // now do it again for emission point #2, at end of segment
+            const auto emissionPoint2 = segment.bestPoint(0.99);
+            // Find mirror segments for this emission point
+            const DeRichSphMirror* sphSegment2 = nullptr;
+            const DeRichSphMirror* secSegment2 = nullptr;
+            Gaudi::XYZPoint sphReflPoint2, secReflPoint2;
+            if ( !findMirrorData( rich, side, virtDetPoint, emissionPoint2,
+                                  sphSegment2, secSegment2, sphReflPoint2, secReflPoint2 ) )
+            {
+              //_ri_debug << rad << " : Failed to reconstruct photon for end of segment" << endmsg;
+              continue;
+            }
+            if ( !beamTestOK && m_checkBeamPipe[rad] )
+            {
+              beamTestOK = !deBeam(rich)->testForIntersection( emissionPoint2, sphReflPoint2 );
+            }
+            // -------------------------------------------------------------------------------
+          
+            // -------------------------------------------------------------------------------
+            if ( !beamTestOK )
+            {
+              // both start and end points failed beam pipe test -> reject
+              //_ri_debug << rad << " : Failed ambiguous photon beampipe intersection checks" << endmsg;
+              continue;
+            }
+            // -------------------------------------------------------------------------------
+          
+            // -------------------------------------------------------------------------------
+            // Test to see if photon direction hits the real physical mirror segments
+            // -------------------------------------------------------------------------------
+            if ( UNLIKELY(m_checkPrimMirrSegs[rad]) )
+            {
+              // primary mirrors
+              const auto ok = ( sphSegment1->intersects( emissionPoint1,
+                                                         sphReflPoint1-emissionPoint1 ) ||
+                                sphSegment2->intersects( emissionPoint2,
+                                                         sphReflPoint2-emissionPoint2 ) );
+              if ( !ok )
+              {
+                //_ri_debug << rad << " : Failed mirror segment intersection checks" << endmsg;
+                continue;
+              }
+            }
+            // -------------------------------------------------------------------------------
+          
+            // -------------------------------------------------------------------------------
+            // Get the best gas emission point
+            if ( !getBestGasEmissionPoint( rad,
+                                           sphReflPoint1,
+                                           sphReflPoint2,
+                                           gloPos,
+                                           segment,
+                                           emissionPoint,
+                                           fraction ) )
+            {
+              //_ri_debug << rad << " : Failed to compute best gas emission point" << endmsg;
+              continue;
+            }
+            // -------------------------------------------------------------------------------
+          
+            // -------------------------------------------------------------------------------
+            // Is this an unambiguous photon - I.e. only one possible mirror combination
+            if ( ( sphSegment1 == sphSegment2 ) && ( secSegment1 == secSegment2 ) )
+            {
+              // Set pointers to the mirror detector objects
+              sphSegment = sphSegment1;
+              secSegment = secSegment1;
+              // rough guesses at reflection points (improved later on)
+              sphReflPoint = sphReflPoint1 + 0.5*(sphReflPoint2-sphReflPoint1);
+              secReflPoint = secReflPoint1 + 0.5*(secReflPoint2-secReflPoint1);
+              // photon is not unambiguous
+              unambigPhoton = true;
+            }
+            // -------------------------------------------------------------------------------
+          
+          } // end radiator type if
+        
+          // if configured to do so reject ambiguous photons
+          if ( UNLIKELY( m_rejectAmbigPhots[rad] && !unambigPhoton ) )
+          {
+            //_ri_debug << rad << " : Failed ambiguous photon test" << endmsg;
+            continue;
+          }
+        
+        } // end unambiguous photon check
+        // --------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // Active segment fraction cut
+        // --------------------------------------------------------------------------------------
+        if ( UNLIKELY( fraction < m_minActiveFrac[rad] ) )
+        {
+          //_ri_debug << rad << " : Failed active segment fraction cut" << endmsg;
+          continue;
+        }
+        // --------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // if ambiguous gas photon or if ambiguous photon check above has been skipped, try again
+        // using best emission point and nominal mirror geometries to get the spherical and sec
+        // mirrors. Also, force this reconstruction if the above unambiguous test was skipped
+        // --------------------------------------------------------------------------------------
+        if ( UNLIKELY( !m_testForUnambigPhots[rad] || !unambigPhoton ) )
+        {
+          if ( !findMirrorData(rich,side,
+                               virtDetPoint,emissionPoint,
+                               sphSegment,secSegment,sphReflPoint,secReflPoint ) )
+          {
+            //_ri_debug << rad << " : Failed backup photon reconstruction" << endmsg;
+            continue;
+          }
+        }
+        // --------------------------------------------------------------------------------------
+      
+        // --------------------------------------------------------------------------------------
+        // Finally reconstruct the photon using best emission point and the best mirror segments
+        // --------------------------------------------------------------------------------------
+        if ( m_useAlignedMirrSegs[rad] )
+        {
+        
+          // If iterations are disabled for this radiator, update the virtual detection point
+          // using the selected mirror segment
+          if ( UNLIKELY( 0 == m_nMaxQits[rad] ) )
+          {
+          
+            // Form the virtual detection point
+            distance     = secSegment->centreNormalPlane().Distance(gloPos);
+            virtDetPoint = gloPos - 2.0 * distance * secSegment->centreNormal();
+          
+            // solve the quartic using the new data
+            m_quarticSolver.solve<double,2,3>( emissionPoint,
+                                               sphSegment->centreOfCurvature(),
+                                               virtDetPoint,
+                                               sphSegment->radius(),
+                                               sphReflPoint );
+          
+            // (re)find the spherical mirror segment
+            // CRJ - Is this needed ?
+            sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
+          
+          }
+          else
+          {
+          
+            // Iterate to final solution, improving the secondary mirror info
+            int iIt(0);
+            Gaudi::XYZPoint last_mirror_point(0,0,0);
+            bool loopOK = true;
+            while ( iIt < m_nMaxQits[rad] )
+            {
+            
+              // Get secondary mirror reflection point,
+              // using the best actual secondary mirror segment at this point
+              const auto dir = virtDetPoint - sphReflPoint;
+              const auto sc = ( m_treatSecMirrsFlat[rich] ? 
+                                intersectPlane( sphReflPoint, dir,
+                                                secSegment->centreNormalPlane(),
+                                                secReflPoint ) :
+                                intersectSpherical( sphReflPoint, dir,
+                                                    secSegment->centreOfCurvature(),
+                                                    secSegment->radius(),
+                                                    secReflPoint ) );
+              if ( UNLIKELY(!sc) )
+              {
+                //_ri_debug << rad << " : Failed to intersect nominal secondary mirror plane" << endmsg;
+                loopOK = false;
+                break;
+              }
+
+              // (re)find the secondary mirror
+              secSegment = m_mirrorSegFinder.get()->findSecMirror( rich, side, secReflPoint );
+            
+              // Construct plane tangential to secondary mirror passing through reflection point
+              const Gaudi::Plane3D plane( secSegment->centreOfCurvature()-secReflPoint, secReflPoint );
+            
+              // re-find the reflection of the detection point in the sec mirror
+              // (virtual detection point) with this mirror plane
+              distance     = plane.Distance(gloPos);
+              virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
+            
+              // solve the quartic using the new data
+              m_quarticSolver.solve<double,2,3>( emissionPoint,
+                                                 sphSegment->centreOfCurvature(),
+                                                 virtDetPoint,
+                                                 sphSegment->radius(),
+                                                 sphReflPoint );
+
+              // (re)find the spherical mirror segment
+              sphSegment = m_mirrorSegFinder.get()->findSphMirror( rich, side, sphReflPoint );
+
+              // for iterations after the first, see if we are still moving
+              // If not, abort iterations early
+              if ( iIt > m_nMinQits[rad] &&
+                   (last_mirror_point-secReflPoint).Mag2() < m_minSphMirrTolIt[rad] ) { break; }
+
+              // store last sec mirror point
+              last_mirror_point = secReflPoint;
+
+              // increment iteration counter
+              ++iIt;
+            }
+            // if above while loop failed, abort this photon
+            if ( UNLIKELY(!loopOK) ) { continue; }
+          
+          }
+        
+        }
+        // --------------------------------------------------------------------------------------
+      
+        // --------------------------------------------------------------------------------------
+        // check that spherical mirror reflection point is on the same side as detection point
+        // and (if configured to do so) photon does not cross between detector sides
+        // --------------------------------------------------------------------------------------
+        if ( UNLIKELY( !sameSide(rad,sphReflPoint,virtDetPoint) ) )
+        {
+          //_ri_debug << rad << " : Reflection point on wrong side" << endmsg;
+          continue;
+        }
+        if ( UNLIKELY( m_checkPhotCrossSides[rad] &&
+                       !sameSide(rad,sphReflPoint,emissionPoint) ) )
+        {
+          //_ri_debug << rad << " : Photon crosses between detector sides" << endmsg;
+          continue;
+        }
+        //else { continue; } // uncomment to select ONLY crossing photons
+        // --------------------------------------------------------------------------------------
+      
+        // --------------------------------------------------------------------------------------
+        // For as radiators if ambiguous photon checks are disabled (since this is
+        // already done for these photons during those checks), check if the photon would have
+        // intersected with the beampipe
+        // --------------------------------------------------------------------------------------
+        if ( UNLIKELY( m_checkBeamPipe[rad] && !m_testForUnambigPhots[rad] ) )
+        {
+          if ( UNLIKELY( deBeam(rich)->testForIntersection( emissionPoint, sphReflPoint ) ) )
+          {
+            //_ri_debug << rad << " : Failed final beampipe intersection checks" << endmsg;
+            continue;
+          }
+        }
+        // --------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // If using aligned mirror segments, get the final sec mirror reflection
+        // point using the best mirror segments available at this point
+        // For RICH2, use the spherical nature of the scondary mirrors
+        // For RICH1, where they are much flatter, assume complete flatness
+        // --------------------------------------------------------------------------------------
+        if ( m_useAlignedMirrSegs[rad] )
+        {
+          const auto dir = virtDetPoint - sphReflPoint;
+          const auto sc = ( m_treatSecMirrsFlat[rich] ? 
+                            intersectPlane( sphReflPoint, dir,
+                                            secSegment->centreNormalPlane(),
+                                            secReflPoint ) :
+                            intersectSpherical( sphReflPoint, dir,
+                                                secSegment->centreOfCurvature(),
+                                                secSegment->radius(),
+                                                secReflPoint ) );
+          if ( !sc )
+          {
+            //_ri_debug << rad << " : Failed final secondary mirror plane intersection" << endmsg;
+            continue;
+          }
+        }
+        // --------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // calculate the cherenkov angles using the photon and track vectors
+        // --------------------------------------------------------------------------------------
+        photonDirection = (sphReflPoint-emissionPoint).Unit();
+        float thetaCerenkov(0), phiCerenkov(0);
+        segment.angleToDirection( photonDirection, thetaCerenkov, phiCerenkov );
+        // --------------------------------------------------------------------------------------
+
+        //---------------------------------------------------------------------------------------
+        // Apply fudge factor correction for small biases in CK theta
+        //---------------------------------------------------------------------------------------
+        thetaCerenkov += ckThetaCorrection(rad);
+        //---------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // Final checks on the Cherenkov angles
+        // --------------------------------------------------------------------------------------
+        if ( UNLIKELY( !checkAngles( rad, tkCkAngles, tkCkRes,
+                                     thetaCerenkov, phiCerenkov ) ) )
+        {
+          //_ri_verbo << "    -> photon FAILED checkAngleInRange test" << endmsg;
+          continue;
+        }
+        // --------------------------------------------------------------------------------------
+
+        // --------------------------------------------------------------------------------------
+        // Set (remaining) photon parameters
+        // --------------------------------------------------------------------------------------
+        gPhoton.setCherenkovTheta         ( thetaCerenkov       );
+        gPhoton.setCherenkovPhi           ( phiCerenkov         );
+        gPhoton.setActiveSegmentFraction  ( fraction            );
+        //gPhoton.setDetectionPoint         ( gloPos              );
+        gPhoton.setSmartID                ( cluster.primaryID() );
+        gPhoton.setUnambiguousPhoton      ( unambigPhoton       );
+        //gPhoton.setPrimaryMirror          ( sphSegment          );
+        //gPhoton.setSecondaryMirror        ( secSegment          );
+        //_ri_verbo << "Created photon " << gPhoton << endmsg;
+        // --------------------------------------------------------------------------------------
+     
+        // If we get here, keep the just made photon
+        photGuard.setOK();
+        // Save relations
+        relations.emplace_back( ++photonIndex, pixIndex, segIndex, inTkRel.tkIndex );
+        //info() << relations.back() << endmsg;
+
+      }
+
+    }
+    
+  }
+  
+  //_ri_debug << "Created " << photons.size() << " photons" << endmsg;
+  return outData;
+}
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/avx/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/avx/RichQuarticPhotonReco.cpp
new file mode 100644
index 0000000000..1840557ea2
--- /dev/null
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/avx/RichQuarticPhotonReco.cpp
@@ -0,0 +1,30 @@
+
+// local
+#include "../RichQuarticPhotonReco.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future;
+using namespace Rich::Future::Rec;
+
+struct avx_guard {
+  // see Agner Fog's optimization guide, 12.1 about mixing AVX and non-AVX code,
+  // (http://www.agner.org/optimize/optimizing_cpp.pdf)
+  // and preserving the YMM register state.
+  // Invoking __mm256_zeroupper seems to reduce the overhead when switching.
+  ~avx_guard() { _mm256_zeroupper(); }
+};
+
+OutData 
+QuarticPhotonReco::run_avx( const LHCb::RichTrackSegment::Vector& segments,
+                            const CherenkovAngles::Vector& ckAngles,
+                            const CherenkovResolutions::Vector& ckResolutions,
+                            const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                            const SegmentPhotonFlags::Vector& segPhotFlags,
+                            const Rich::PDPixelCluster::Vector& clusters,
+                            const SpacePointVector& globalPoints,
+                            const SpacePointVector& localPoints,
+                            const Relations::TrackToSegments::Vector& tkToSegRels ) const
+{
+  avx_guard guard{};
+#include "../RichQuarticPhotonReco.icpp"
+}
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/avx2/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/avx2/RichQuarticPhotonReco.cpp
new file mode 100644
index 0000000000..672aa63991
--- /dev/null
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/avx2/RichQuarticPhotonReco.cpp
@@ -0,0 +1,30 @@
+
+// local
+#include "../RichQuarticPhotonReco.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future;
+using namespace Rich::Future::Rec;
+
+struct avx_guard {
+  // see Agner Fog's optimization guide, 12.1 about mixing AVX and non-AVX code,
+  // (http://www.agner.org/optimize/optimizing_cpp.pdf)
+  // and preserving the YMM register state.
+  // Invoking __mm256_zeroupper seems to reduce the overhead when switching.
+  ~avx_guard() { _mm256_zeroupper(); }
+};
+
+OutData 
+QuarticPhotonReco::run_avx2( const LHCb::RichTrackSegment::Vector& segments,
+                             const CherenkovAngles::Vector& ckAngles,
+                             const CherenkovResolutions::Vector& ckResolutions,
+                             const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                             const SegmentPhotonFlags::Vector& segPhotFlags,
+                             const Rich::PDPixelCluster::Vector& clusters,
+                             const SpacePointVector& globalPoints,
+                             const SpacePointVector& localPoints,
+                             const Relations::TrackToSegments::Vector& tkToSegRels ) const
+{
+  avx_guard guard{};
+#include "../RichQuarticPhotonReco.icpp"
+}
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/generic/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/generic/RichQuarticPhotonReco.cpp
new file mode 100644
index 0000000000..d5db58c914
--- /dev/null
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/generic/RichQuarticPhotonReco.cpp
@@ -0,0 +1,21 @@
+
+// local
+#include "../RichQuarticPhotonReco.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future;
+using namespace Rich::Future::Rec;
+
+OutData 
+QuarticPhotonReco::run_generic( const LHCb::RichTrackSegment::Vector& segments,
+                                const CherenkovAngles::Vector& ckAngles,
+                                const CherenkovResolutions::Vector& ckResolutions,
+                                const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                                const SegmentPhotonFlags::Vector& segPhotFlags,
+                                const Rich::PDPixelCluster::Vector& clusters,
+                                const SpacePointVector& globalPoints,
+                                const SpacePointVector& localPoints,
+                                const Relations::TrackToSegments::Vector& tkToSegRels ) const
+{
+#include "../RichQuarticPhotonReco.icpp"
+}
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/sse4/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/sse4/RichQuarticPhotonReco.cpp
new file mode 100644
index 0000000000..82131fc133
--- /dev/null
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/sse4/RichQuarticPhotonReco.cpp
@@ -0,0 +1,21 @@
+
+// local
+#include "../RichQuarticPhotonReco.h"
+
+// All code is in general Rich reconstruction namespace
+using namespace Rich::Future;
+using namespace Rich::Future::Rec;
+
+OutData 
+QuarticPhotonReco::run_sse4( const LHCb::RichTrackSegment::Vector& segments,
+                             const CherenkovAngles::Vector& ckAngles,
+                             const CherenkovResolutions::Vector& ckResolutions,
+                             const SegmentPanelSpacePoints::Vector& trHitPntsLoc,
+                             const SegmentPhotonFlags::Vector& segPhotFlags,
+                             const Rich::PDPixelCluster::Vector& clusters,
+                             const SpacePointVector& globalPoints,
+                             const SpacePointVector& localPoints,
+                             const Relations::TrackToSegments::Vector& tkToSegRels ) const
+{
+#include "../RichQuarticPhotonReco.icpp"
+}
-- 
GitLab


From 2e830441ceb22af09b91747e484e5fb5c621ffde Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Mon, 6 Mar 2017 18:02:57 +0000
Subject: [PATCH 54/68] Update test package build options

---
 Rich/RichRecTests/CMakeLists.txt           | 32 +++++++++++++++-------
 Rich/RichRecTests/src/RayTracing/main.icpp | 10 +++----
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
index a227c20223..8ac0bf8ba3 100644
--- a/Rich/RichRecTests/CMakeLists.txt
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -20,9 +20,9 @@ find_package(Vc)
 find_package(ROOT COMPONENTS MathCore GenVector )
 
 message(STATUS "Using Vc ${Vc_INCLUDE_DIR} ${Vc_LIB_DIR}")
-message(STATUS "Vc DEFINITIONS ${Vc_DEFINITIONS}")
-message(STATUS "Vc COMPILE flags ${Vc_COMPILE_FLAGS}")
-message(STATUS "Vc ARCHITECTURE flags ${Vc_ARCHITECTURE_FLAGS}")
+#message(STATUS "Vc DEFINITIONS ${Vc_DEFINITIONS}")
+#message(STATUS "Vc COMPILE flags ${Vc_COMPILE_FLAGS}")
+#message(STATUS "Vc ARCHITECTURE flags ${Vc_ARCHITECTURE_FLAGS}")
 
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
                            ${EIGEN_INCLUDE_DIRS} ${Vc_INCLUDE_DIR})
@@ -34,28 +34,28 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestSSE4 -lrt )
-  set_property(SOURCE src/RayTracing/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4.2 " )  
+  set_property(SOURCE src/PhotonReco/main_sse4.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -msse4.2 " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX
                        src/PhotonReco/main_avx.cpp
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX -lrt )
-  set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+  set_property(SOURCE src/PhotonReco/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX2
                        src/PhotonReco/main_avx2.cpp
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2 -lrt )
-  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+  set_property(SOURCE src/PhotonReco/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 " )  
 
   gaudi_add_executable(RichPhotonRecoTestAVX2FMA
                        src/PhotonReco/main_avx2fma.cpp
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2FMA -lrt )
-  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )  
+  set_property(SOURCE src/PhotonReco/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 " )  
 
 
 
@@ -71,20 +71,32 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX "-lrt ${Vc_LIB_DIR}/libVc.a" )
-  set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+  set_property(SOURCE src/RayTracing/main_avx.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx " )
 
   gaudi_add_executable(RichRayTracingTestAVX2
                        src/RayTracing/main_avx2.cpp
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2 "-lrt ${Vc_LIB_DIR}/libVc.a" )
-  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 " )
 
   gaudi_add_executable(RichRayTracingTestAVX2FMA
                        src/RayTracing/main_avx2fma.cpp
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2FMA "-lrt ${Vc_LIB_DIR}/libVc.a" )
-  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 -fabi-version=0 -fabi-compat-version=0 -ffp-contract=fast " )
+  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 " )
+
+
+  if(LCG_COMP STREQUAL "gcc" OR
+      (BINARY_TAG_COMP_NAME STREQUAL "gcc" AND BINARY_TAG_COMP_VERSION VERSION_LESS "5"))
+    set_property(SOURCE src/PhotonReco/main_avx.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+    set_property(SOURCE src/PhotonReco/main_avx2.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+    set_property(SOURCE src/PhotonReco/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+    set_property(SOURCE src/RayTracing/main_avx.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+    set_property(SOURCE src/RayTracing/main_avx2.cpp    APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+    set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+  endif()
+
 
 endif()
diff --git a/Rich/RichRecTests/src/RayTracing/main.icpp b/Rich/RichRecTests/src/RayTracing/main.icpp
index 802a83b2b7..8fb4bbf692 100644
--- a/Rich/RichRecTests/src/RayTracing/main.icpp
+++ b/Rich/RichRecTests/src/RayTracing/main.icpp
@@ -77,7 +77,7 @@ inline void trace( DATA & dataV )
   {
     reflectSpherical( data.position, data.direction, data.CoC, data.radius );
     reflectPlane    ( data.position, data.direction, data.plane );
-    std::cout << data.position << std::endl;
+    //std::cout << data.position << std::endl;
   }
 }
 
@@ -89,8 +89,8 @@ unsigned long long int __attribute__((noinline)) rayTrace( const DATA & in_dataV
 
   unsigned long long int best_dur{ 99999999999999999 };
 
-  const unsigned int nTests = 1;
-  std::cout << "Running " << nTests << " tests on " << in_dataV.size() << " data objects" << std::endl;
+  const unsigned int nTests = 10000;
+  //std::cout << "Running " << nTests << " tests on " << in_dataV.size() << " data objects" << std::endl;
   DATA dataV; // working data copy;
   for ( unsigned int i = 0; i < nTests; ++i )
   {
@@ -108,8 +108,8 @@ unsigned long long int __attribute__((noinline)) rayTrace( const DATA & in_dataV
 int main ( int /*argc*/, char** /*argv*/ )
 {
 
-  //const unsigned int nPhotons = 96 * 1e2;
-  const unsigned int nPhotons = 8;
+  const unsigned int nPhotons = 96 * 1e2;
+  //const unsigned int nPhotons = 8;
   std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
 
   // Templated GenVector
-- 
GitLab


From 67bbd664526adce3f83fdd9a0e737f084abf82a6 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Mon, 6 Mar 2017 18:03:22 +0000
Subject: [PATCH 55/68] Add missing array include to QuarticSolverNewton.h

---
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 097bfeec93..8a83c1c857 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -18,6 +18,7 @@
 // STL
 #include <math.h>
 #include <type_traits>
+#include <array>
 
 // VDT
 #include "vdt/asin.h"
-- 
GitLab


From cbac48207bc08477b481314a59afa712c9d10965 Mon Sep 17 00:00:00 2001
From: Renato <rquaglia@lxplus.cern.ch>
Date: Mon, 6 Mar 2017 19:42:57 +0100
Subject: [PATCH 56/68]  update Cluster Residual tool using new v61 convention
 and adding entry/exit point position of MCHit in ntuples

---
 Pr/PrMCTools/CMakeLists.txt             |   5 +-
 Pr/PrMCTools/src/PrClustersResidual.cpp | 121 ++++++++++++++++++------
 Pr/PrMCTools/src/PrClustersResidual.h   |  41 +++-----
 3 files changed, 112 insertions(+), 55 deletions(-)

diff --git a/Pr/PrMCTools/CMakeLists.txt b/Pr/PrMCTools/CMakeLists.txt
index 82046778da..a682e63eee 100644
--- a/Pr/PrMCTools/CMakeLists.txt
+++ b/Pr/PrMCTools/CMakeLists.txt
@@ -3,7 +3,8 @@
 ################################################################################
 gaudi_subdir(PrMCTools v2r12)
 
-gaudi_depends_on_subdirs(Det/VPDet
+gaudi_depends_on_subdirs(Det/FTDet       
+                         Det/VPDet
                          Det/STDet
                          Event/FTEvent
                          Event/LinkerEvent
@@ -19,5 +20,5 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS})
 gaudi_add_module(PrMCTools
                  src/*.cpp
                  INCLUDE_DIRS Event/FTEvent Pr/PrPixel
-                 LINK_LIBRARIES LinkerEvent MCEvent GaudiAlgLib PrKernel VPDetLib STDetLib LoKiMCLib)
+                 LINK_LIBRARIES LinkerEvent MCEvent GaudiAlgLib PrKernel VPDetLib STDetLib FTDetLib LoKiMCLib)
 
diff --git a/Pr/PrMCTools/src/PrClustersResidual.cpp b/Pr/PrMCTools/src/PrClustersResidual.cpp
index de6a202d10..a1b5fc54bc 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.cpp
+++ b/Pr/PrMCTools/src/PrClustersResidual.cpp
@@ -38,20 +38,6 @@ PrClustersResidual::PrClustersResidual( const std::string& name,
 : GaudiTupleAlg ( name , pSvcLocator ),
   m_ftHitManager(nullptr),
   m_zone(24){
-  declareProperty("MCHitsLocation",m_mcHitLocation = "/Event/MC/FT/Hits");
-  declareProperty("FTClusterToParticleLinkerLocation",
-      m_ftClusterToParticleLinkerLocation = LHCb::FTLiteClusterLocation::Default + "WithSpillover");
-  declareProperty("FTClusterToHitLinkerLocation",
-      m_ftClusterToHitLinkerLocation = LHCb::FTLiteClusterLocation::Default + "2MCHitsWithSpillover");
-  declareProperty("HitManagerName",m_hitManagerName = "PrFTHitManager");
-  declareProperty("DebugTracking",m_debugTracking = false);
-  declareProperty("DoClusterResidual",m_doClusterResidual = false); //Cluster residual tuple
-  declareProperty("DoTrackStudy",m_doTrackStudy = false); // Produce tuple for track studies
-  declareProperty("DecodeData",m_decodeData = false); //ask to decode data ( is False if other algorithms are runned
-  declareProperty("OnlyHasT",m_onlyHasT=false); //(keep only MCParticles with hasT = true
-  declareProperty("RemoveClones",m_removeClones = true); //Observed clones MCHits when processed ( not understood )
-  declareProperty("DumpAllHits",m_dumpAllHits = false);
-  declareProperty("Occupancy",m_Occupancy = true);
 }
 //=============================================================================
 // Destructor
@@ -87,8 +73,17 @@ StatusCode PrClustersResidual::initialize() {
 //=============================================================================
 // Main execution
 //=============================================================================
-StatusCode PrClustersResidual::execute() {
-
+StatusCode PrClustersResidual::execute() {  
+  m_ftDet = getDet<DeFTDetector>(DeFTDetectorLocation::Default);
+  if( UNLIKELY( !m_ftDet) ){
+    error() << " Cannot load the FTDetector from default location" << endmsg;
+    return StatusCode::FAILURE;
+  }else if( m_ftDet->version() < 61){
+    error()<< "This code requires FTDet v6.1 or higher "<<endmsg;
+    return StatusCode::FAILURE;
+  }
+  
+  
   if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
   m_nEvents++;
   if(m_doClusterResidual){
@@ -153,7 +148,7 @@ void PrClustersResidual::Occupancy(){
   int recoblewanted = 0;
   LHCb::MCParticles* mcParts = getIfExists<LHCb::MCParticles> ( LHCb::MCParticleLocation::Default );
   LHCb::MCParticle* mcPart = nullptr;
-  for( LHCb::MCParticles::const_iterator iPart = mcParts->begin(); iPart != mcParts->end(); ++iPart){
+  for( auto iPart = mcParts->begin(); iPart != mcParts->end(); ++iPart){
     mcPart = (*iPart);
     bool isRecoble = trackInfo.hasT(mcPart);
     bool recobleWanted = isRecoble && (mcPart->originVertex()->isPrimary() || mcPart->originVertex()->isDecay());
@@ -178,8 +173,30 @@ void PrClustersResidual::Occupancy(){
     for(auto itH = m_ftHitManager->getIterator_Begin(zoneI); m_ftHitManager->getIterator_End(zoneI) != itH;++itH){
       hit = &(*itH);
       nHits[layer]++;
-      LHCb::FTLiteCluster liteCluster = getLiteCluster(hit->id());
-      int index = liteCluster.channelID().uniqueSiPM() & 511;
+      auto liteCluster = getLiteCluster(hit->id());
+      
+      //---- new numbering scheme (v61 sci-fi) plots for occupancy! pseudochannel conversion needed!
+      /*
+        It requires to have the m_ftDet as private member of the algorithm and also modify the CMakeLists to compile
+        PrMCTools linking the Det/FTDet package.
+      */
+      int quarter = liteCluster.channelID().quarter();
+      const auto chanID = liteCluster.channelID();
+      const DeFTModule* module = m_ftDet->findModule( chanID );
+      if( module == nullptr){
+        error()<<"Cannot find Module associated to FTChannelID : "<<chanID<<endmsg;
+        error()<<"Abort Occupancy plot checking"<<endmsg;
+        return;
+        }
+      int pseudochannel = module->pseudoChannel( chanID );
+      //--- runs from [0 to 12,287] (96 SiPm *128 channels/SiPm)
+      //--- 4 quartes [0,1,2,3] , 128 channels squeezed to 1 value. (Occupancy in terms of Hits/SiPM array [128 channels]
+      //--- ToDo : make it depenent on xml geometry information through m_ftDet 
+      int sipm = std::floor( pseudochannel/128);
+      int index = quarter * 128  +  sipm ;
+      // old way [ < v61 ] : int index = liteCluster.channelID().uniqueSiPM() & 511;
+      
+      
       sprintf(layerName,"Layer%i/AllContributions",layer);
       sprintf(Title,"Sipm Index Layer %i;SiPm Id;Clusters/Sipm/Event",layer);
       plot1D(index,layerName,Title,-0.5,511.5,512);
@@ -423,6 +440,8 @@ void PrClustersResidual::TrackStudy(){
       debug()<<"For the processed MCParticle i found  "<<track.size()<<"PrHits   associated to "<<assoc_MCHit.size()<<"   MCHits"<<endmsg;
       tuple->farray("FiredLayers_Counter",firedLayers,"FiredLayers",24);
       tuple->column("CheatedSeeding_NHits",totHits);
+      std::vector<double> MCHit_EntryX,MCHit_EntryY,MCHit_EntryZ;      
+      std::vector<double> MCHit_ExitX,MCHit_ExitY,MCHit_ExitZ;
       std::vector<double> MCHit_X,MCHit_Y,MCHit_Z;
       std::vector<double> MCHit_tx,MCHit_ty,MCHit_p;
       std::vector<double> MCHit_pathlength;
@@ -470,6 +489,13 @@ void PrClustersResidual::TrackStudy(){
           MCHit_ty.push_back(mcHit->dydz());
           MCHit_p.push_back(mcHit->p());
           MCHit_pathlength.push_back(mcHit->pathLength());
+          
+          MCHit_EntryX.push_back(mcHit->entry().X());
+          MCHit_EntryY.push_back(mcHit->entry().Y());
+          MCHit_EntryZ.push_back(mcHit->entry().Z());
+          MCHit_ExitX.push_back(mcHit->exit().X());
+          MCHit_ExitY.push_back(mcHit->exit().Y());
+          MCHit_ExitZ.push_back(mcHit->exit().Z());
           MCHit_X.push_back(mcHit->midPoint().X());
           MCHit_Y.push_back(mcHit->midPoint().Y());
           MCHit_Z.push_back(mcHit->midPoint().Z());
@@ -523,6 +549,12 @@ void PrClustersResidual::TrackStudy(){
         MCHit_time.push_back(-999999.);
         MCHit_Particle_key.push_back(-999999.);
         MCHit_pathlength.push_back(-999999.);
+        MCHit_EntryX.push_back(-999999.);
+        MCHit_EntryY.push_back(-999999.);
+        MCHit_EntryZ.push_back(-999999.);
+        MCHit_ExitX.push_back(-999999.);
+        MCHit_ExitY.push_back(-999999.);
+        MCHit_ExitZ.push_back(-999999.);
         MCHit_X.push_back(-999999.);
         MCHit_Y.push_back(-999999.);
         MCHit_Z.push_back(-999999.);
@@ -545,6 +577,13 @@ void PrClustersResidual::TrackStudy(){
       tuple->farray("MCHit_tx",MCHit_tx,"MC_ass",100);
       tuple->farray("MCHit_p",MCHit_p,"MC_ass",100);
       tuple->farray("MCHit_pathlength",MCHit_pathlength,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_EntryX",MCHit_EntryX ,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_EntryY",MCHit_EntryY ,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_EntryZ",MCHit_EntryZ ,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_ExitX",MCHit_ExitX ,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_ExitY",MCHit_ExitY ,"MC_ass",100);
+      tuple->farray("MCHit_Assoc_ExitZ",MCHit_ExitZ ,"MC_ass",100);
+
       tuple->farray("MCHit_Assoc_X",MCHit_X ,"MC_ass",100);
       tuple->farray("MCHit_Assoc_Y",MCHit_Y ,"MC_ass",100);
       tuple->farray("MCHit_Assoc_Z",MCHit_Z ,"MC_ass",100);
@@ -1025,6 +1064,8 @@ void  PrClustersResidual::ClusterResidual(){
       if(msgLevel(MSG::DEBUG)) debug()<<"Loaded"<<endmsg;
       //took first MCHit associated to Hit channelID
       std::vector<double>  MCHit_X,MCHit_Y,MCHit_Z;
+      std::vector<double>  MCHit_EntryX,  MCHit_EntryY, MCHit_EntryZ;
+      std::vector<double>  MCHit_ExitX,   MCHit_ExitY,  MCHit_ExitZ;
       std::vector<double>  Residual_X,Residual_Z;
       std::vector<double>  SlopeX;
       std::vector<double>  SlopeY;
@@ -1040,15 +1081,25 @@ void  PrClustersResidual::ClusterResidual(){
         MCHit_X.push_back(-9999.);
         MCHit_Y.push_back(-9999.);
         MCHit_Z.push_back(-9999.);
-        SlopeX.push_back(-999.);
-        SlopeY.push_back(-999.);
-        pathlength.push_back(-999.);
-        energy.push_back( -999.);
+        MCHit_EntryX.push_back(-9999.);
+        MCHit_EntryY.push_back(-9999.);
+        MCHit_EntryZ.push_back(-9999.);
+        
+        MCHit_ExitX.push_back(-9999.);
+        MCHit_ExitY.push_back(-9999.);
+        MCHit_ExitZ.push_back(-9999.);
+
+        SlopeX.push_back(-9999.);
+        SlopeY.push_back(-9999.);
+        pathlength.push_back(-9999.);
+        energy.push_back( -9999.);
         hit_Physics.push_back(false);
       }
       while(mcHit != nullptr){
         nMCHitToCluster++;
-        Gaudi::XYZPoint pMid = mcHit->midPoint();
+        auto pMid = mcHit->midPoint();
+        auto pEntry = mcHit->entry();
+        auto pExit  = mcHit->exit();
         Residual_X.push_back( (*iHit).x(pMid.y()) - pMid.x()); //x at y - y at z
         Residual_Z.push_back( (*iHit).z(pMid.y()) - pMid.z());
         SlopeX.push_back( mcHit->dxdz());
@@ -1058,6 +1109,13 @@ void  PrClustersResidual::ClusterResidual(){
         MCHit_X.push_back( pMid.x());
         MCHit_Y.push_back( pMid.y());
         MCHit_Z.push_back( pMid.z());
+        
+        MCHit_ExitX.push_back( pExit.x());
+        MCHit_ExitY.push_back( pExit.y());
+        MCHit_ExitZ.push_back( pExit.z());
+        MCHit_EntryX.push_back( pEntry.x());
+        MCHit_EntryY.push_back( pEntry.y());
+        MCHit_EntryZ.push_back( pEntry.z());
         //mcHit = myFTCluster2MCHitLink.next();
         // const LHCb::MCParticle *mcPart = mcHit->mcParticle();
         const LHCb::MCParticle *mcPart = mcHit->mcParticle();
@@ -1067,6 +1125,7 @@ void  PrClustersResidual::ClusterResidual(){
         if(mcPart!= nullptr){
           if(msgLevel(MSG::DEBUG)) debug() <<"Getting Vertex"<<endmsg;
           const LHCb::MCVertex* vertex = mcPart->originVertex();
+          //track of physical interest if the associated vertex is a Primary one or from Decay ( i.e. veto the interaction one )
           if( vertex!=nullptr && (vertex->isPrimary() || vertex->isDecay())){
             hit_Physics.push_back( true );
           }else{
@@ -1077,7 +1136,6 @@ void  PrClustersResidual::ClusterResidual(){
       }
       if(msgLevel(MSG::DEBUG)) debug()<<"Storing vectors"<<endmsg;
       tuple->column("isNoiseCluster",isNoise);
-
       tuple->farray("MCHit_Physics", hit_Physics.begin(),hit_Physics.end(),"N_MC",100);
       tuple->farray("CosSlopeX",SlopeX.begin(),SlopeX.end(),"N_MC",100);
       tuple->farray("CosSlopeY",SlopeY.begin(),SlopeY.end(),"N_MC",100);
@@ -1088,6 +1146,15 @@ void  PrClustersResidual::ClusterResidual(){
       tuple->farray("MCHit_X",MCHit_X.begin(),MCHit_X.end(),"N_MC",100);
       tuple->farray("MCHit_Z",MCHit_Z.begin(),MCHit_Z.end(),"N_MC",100);
       tuple->farray("MCHit_Y",MCHit_Y.begin(),MCHit_Y.end(),"N_MC",100);
+      
+      tuple->farray("MCHit_EntryX",MCHit_EntryX.begin(),MCHit_EntryX.end(),"N_MC",100);
+      tuple->farray("MCHit_EntryZ",MCHit_EntryZ.begin(),MCHit_EntryZ.end(),"N_MC",100);
+      tuple->farray("MCHit_EntryY",MCHit_EntryY.begin(),MCHit_EntryY.end(),"N_MC",100);
+      tuple->farray("MCHit_ExitX",MCHit_ExitX.begin(),MCHit_ExitX.end(),"N_MC",100);
+      tuple->farray("MCHit_ExitZ",MCHit_ExitZ.begin(),MCHit_ExitZ.end(),"N_MC",100);
+      tuple->farray("MCHit_ExitY",MCHit_ExitY.begin(),MCHit_ExitY.end(),"N_MC",100);
+
+
       //here fill the tuple with watever you want
       //get Cluster associated to the Hit
       if(msgLevel(MSG::DEBUG)) debug()<<"Getting LiteCluster from PrHit"<<endmsg;
@@ -1145,8 +1212,8 @@ void  PrClustersResidual::ClusterResidual(){
       tuple->column("Hit_Zone",(*iHit).zone());
       tuple->column("Hit_dzDy_manually",((*iHit).z(1000.)-(*iHit).z(0.))/1000);
       //Get the list of tracks generated by the Hit i am lookign to
-      if(m_debugTracking)
-      {
+      if(m_debugTracking){
+        //get linker Forward tracks and Seeding ones to see hit content!
         LinkedTo<LHCb::MCParticle, LHCb::Track> myForwardLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Forward);
         LinkedTo<LHCb::MCParticle, LHCb::Track> mySeedLink ( evtSvc(), msgSvc(),LHCb::TrackLocation::Seed);
 
diff --git a/Pr/PrMCTools/src/PrClustersResidual.h b/Pr/PrMCTools/src/PrClustersResidual.h
index 4ab37712b6..6c48866a67 100644
--- a/Pr/PrMCTools/src/PrClustersResidual.h
+++ b/Pr/PrMCTools/src/PrClustersResidual.h
@@ -23,7 +23,7 @@
 #include "Event/Track.h"
 #include "Linker/LinkerTool.h"
 #include "PrKernel/IPrCounter.h"
-
+#include "FTDet/DeFTDetector.h"
 /** @class PrClustersResidual PrClustersResidual.h
  *  Make nTuples of Cluster vs MCHits and Hit content on track + Occupancy study possible ( also in PrPlotFTHits )
  *  -MCHitsLocation : Where to find the MCHits ( /Event/MC/FT/FTHits by default )
@@ -103,39 +103,28 @@ private:
   std::vector<const LHCb::Track*> getTrack(const LHCb::LHCbID id, const std::string location);
   LHCb::FTLiteCluster getLiteCluster(const LHCb::LHCbID id);
   
-  std::string m_mcHitLocation;
-  std::string m_ftClusterToParticleLinkerLocation;
-  std::string m_ftClusterToHitLinkerLocation;
   
-  //  unsigned int m_zone;
-  bool m_debugTracking;
+  Gaudi::Property<std::string> m_mcHitLocation                     {this, "MCHitsLocation", "/Event/MC/FT/Hits"};
+  Gaudi::Property<std::string> m_ftClusterToParticleLinkerLocation { this, "FTClusterToParticleLinkerLocation", LHCb::FTLiteClusterLocation::Default + "WithSpillover"};
+  Gaudi::Property<std::string> m_ftClusterToHitLinkerLocation      { this, "FTClusterToHitLinkerLocation", LHCb::FTLiteClusterLocation::Default + "2MCHitsWithSpillover"};
+  Gaudi::Property<std::string> m_hitManagerName                     { this, "HitManagerName", "PrFTHitManager"};
   
+  Gaudi::Property<bool> m_debugTracking                             { this, "DebugTracking", false};
+  Gaudi::Property<bool> m_doClusterResidual                         { this, "DoClusterResidual", false}; //Cluster residual tuple
+  Gaudi::Property<bool> m_doTrackStudy                              { this, "DoTrackStudy", false}; // Produce tuple for track studies
+  Gaudi::Property<bool> m_decodeData                                { this, "DecodeData", false}; //ask to decode data ( is False if other algorithms are runned
+  Gaudi::Property<bool> m_onlyHasT                                  { this, "OnlyHasT",false}; //(keep only MCParticles with hasT = true
+  Gaudi::Property<bool> m_removeClones                              { this, "RemoveClones", true}; //Observed clones MCHits when processed ( not understood )
+  Gaudi::Property<bool> m_dumpAllHits                               { this, "DumpAllHits", false }; //Dump in tuple for a given event all the hits
+  Gaudi::Property<bool> m_Occupancy                                 { this, "Occupancy",   true };// Produce Occupancy plot
   int m_nEvents;
-  
   double m_NClusters ;
   double m_NMCHit ;
   double m_NMCHit_inClusters;
-  bool m_onlyHasT;
   PrHitManager* m_ftHitManager;
   unsigned int m_zone;
   
-  bool m_decodeData;
-  bool m_removeClones;
-  bool m_dumpAllHits;
-  bool m_Occupancy;
-  std::string m_hitManagerName;
-  bool m_doClusterResidual;
-  bool m_doTrackStudy;
-  
-  //from PrCounter
-  // typedef LinkerTool<LHCb::Track, LHCb::MCParticle> MyAsct;  
-  // typedef MyAsct::DirectType            Table;  
-  // typedef MyAsct::DirectType::Range     Range;
-  // typedef Table::iterator               iterator;                     
-  // typedef MyAsct::InverseType           InvTable;
-  // typedef InvTable::Range               InvRange;
-  // typedef InvTable::iterator            InvIterator;
-  // MyAsct*         m_link;
-  // const InvTable* m_invTable;                                  
+  //need the ftDet to produce the pseudochannel conversion numbering in occupancy plot for v61
+  DeFTDetector * m_ftDet = nullptr;
 };
 #endif // PRCLUSTERSRESIDUAL_H
-- 
GitLab


From b051f41d4e90dcae4fa8582ed9088027b699c2c7 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 10:10:11 +0000
Subject: [PATCH 57/68] Add CPU capabilities detector to Quartic reconstruction
 algorithm. Does not change much yet, but is in preparation for other future
 improvements

---
 .../CMakeLists.txt                              |  6 ++++--
 .../src/RichQuarticPhotonReco.cpp               | 17 ++++++++++-------
 .../src/RichQuarticPhotonReco.h                 |  3 +++
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
index a226a88b4c..85678715d1 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
+++ b/Rich/RichFutureRecPhotonAlgorithms/CMakeLists.txt
@@ -28,10 +28,12 @@ set_property(SOURCE src/sse4/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERT
 
 set_property(SOURCE src/avx/RichQuarticPhotonReco.cpp      APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx " )
 
-set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx2 -mfma " )
+# Until such a time that all build targets support AVX2+FMA, fallback to just AVX here
+#set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx2 -mfma " )
+set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp     APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -O3 -mavx " )
 
 if(LCG_COMP STREQUAL "gcc" OR
     (BINARY_TAG_COMP_NAME STREQUAL "gcc" AND BINARY_TAG_COMP_VERSION VERSION_LESS "5"))
-  set_property(SOURCE src/avx/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS  " -fabi-version=0 " )
+  set_property(SOURCE src/avx/RichQuarticPhotonReco.cpp  APPEND_STRING PROPERTY COMPILE_FLAGS " -fabi-version=0 " )
   set_property(SOURCE src/avx2/RichQuarticPhotonReco.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fabi-version=0 " )
 endif()
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
index 9ca2553298..14f6b40195 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.cpp
@@ -48,13 +48,16 @@ StatusCode QuarticPhotonReco::initialize()
   if ( !sc ) return sc;
 
   // Get the CPU capabilities and set dispatch method
-  //enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
-  //const auto cpuLevel = instrset_detect();
-  //_ri_debug << "Instruction set level = " << cpuLevel << endmsg;
-  //if      ( cpuLevel >= AVX2 ) { m_run = &QuarticPhotonReco::run_avx2; }
-  //else if ( cpuLevel >= AVX  ) { m_run = &QuarticPhotonReco::run_avx; }
-  //else if ( cpuLevel >= SSE4 ) { m_run = &QuarticPhotonReco::run_sse4; }
-  //else                         { m_run = &QuarticPhotonReco::run_generic; }
+  if ( m_detectCPU )
+  {
+    enum CPUID { GENERIC = 0, SSE4 = 6, AVX = 7, AVX2 = 8 };
+    const auto cpuLevel = instrset_detect();
+    _ri_debug << "Instruction set level = " << cpuLevel << endmsg;
+    if      ( cpuLevel >= AVX2 ) { m_run = &QuarticPhotonReco::run_avx2; }
+    else if ( cpuLevel >= AVX  ) { m_run = &QuarticPhotonReco::run_avx; }
+    else if ( cpuLevel >= SSE4 ) { m_run = &QuarticPhotonReco::run_sse4; }
+    else                         { m_run = &QuarticPhotonReco::run_generic; }
+  }
 
   // get the detector elements
   m_rich[Rich::Rich1] = getDet<DeRich>( DeRichLocations::Rich1 );
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 83b1baead2..565496df0e 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -318,6 +318,9 @@ namespace Rich
         ToolHandle<const IMirrorSegFinderLookUpTable> m_mirrorSegFinder
         { "Rich::Future::MirrorSegFinderLookUpTable/MirrorFinder:PUBLIC", this };
 
+        /// Flag to control if CPU detection should be performed or not
+        Gaudi::Property<bool> m_detectCPU { this, "DetectCPUCapabilites", true };
+
       };
 
       //=========================================================================
-- 
GitLab


From 608a6e80d4389386d7d97e81f4008903590aff2f Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 10:10:33 +0000
Subject: [PATCH 58/68] Disable AVX2+FMA until such a time as all build
 platforms can support it

---
 Rich/RichRecTests/CMakeLists.txt | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
index 8ac0bf8ba3..2e13a4845a 100644
--- a/Rich/RichRecTests/CMakeLists.txt
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -55,7 +55,9 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2FMA -lrt )
-  set_property(SOURCE src/PhotonReco/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 " )  
+  # Until such a time that all build targets support AVX2+FMA, fallback to just AVX here
+  #set_property(SOURCE src/PhotonReco/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mfma -mavx2 " )  
+  set_property(SOURCE src/PhotonReco/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx " )  
 
 
 
@@ -85,8 +87,9 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2FMA "-lrt ${Vc_LIB_DIR}/libVc.a" )
-  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 " )
-
+  # Until such a time that all build targets support AVX2+FMA, fallback to just AVX here
+  #set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mfma -mavx2 " )
+  set_property(SOURCE src/RayTracing/main_avx2fma.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx " )
 
   if(LCG_COMP STREQUAL "gcc" OR
       (BINARY_TAG_COMP_NAME STREQUAL "gcc" AND BINARY_TAG_COMP_VERSION VERSION_LESS "5"))
-- 
GitLab


From df06ae2fd9e5368033e17fb6c3187229b1c5515e Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 14:55:13 +0000
Subject: [PATCH 59/68] Fix doxygen comments

---
 .../src/RichGlobalPIDNamespaces.h             | 20 +++++++++++++++++++
 .../RichFutureRecBase/RichRecNamespaces.h     | 14 +++++++++++--
 .../RichRecPhotonPredictedPixelSignals.h      |  1 +
 .../RichFutureRecEvent/RichSummaryEventData.h | 18 ++++++++++++++++-
 .../src/RichQuarticPhotonReco.h               |  1 +
 .../examples/Col16RawDataFiles.py             |  3 +++
 .../src/RichBaseTrSegMaker.h                  |  2 +-
 .../src/RichGeomEffCKMassRings.h              |  2 +-
 .../RichTrackFunctionalCherenkovResolutions.h |  2 +-
 9 files changed, 57 insertions(+), 6 deletions(-)
 create mode 100755 Rich/RichFutureGlobalPID/src/RichGlobalPIDNamespaces.h

diff --git a/Rich/RichFutureGlobalPID/src/RichGlobalPIDNamespaces.h b/Rich/RichFutureGlobalPID/src/RichGlobalPIDNamespaces.h
new file mode 100755
index 0000000000..d28f230cf0
--- /dev/null
+++ b/Rich/RichFutureGlobalPID/src/RichGlobalPIDNamespaces.h
@@ -0,0 +1,20 @@
+
+//-----------------------------------------------------------------------------
+/** @namespace Rich::Future::Rec::GlobalPID
+ *
+ *  Namespace for RICH Global PID software
+ *
+ *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
+ *  @date   04/12/2006
+ */
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/** @namespace Rich::Future::Rec::GlobalPID::MC
+ *
+ *  Namespace for RICH Global PID MC related software
+ *
+ *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
+ *  @date   05/12/2006
+ */
+//-----------------------------------------------------------------------------
diff --git a/Rich/RichFutureRecBase/RichFutureRecBase/RichRecNamespaces.h b/Rich/RichFutureRecBase/RichFutureRecBase/RichRecNamespaces.h
index c7472cd147..8443cac3c5 100644
--- a/Rich/RichFutureRecBase/RichFutureRecBase/RichRecNamespaces.h
+++ b/Rich/RichFutureRecBase/RichFutureRecBase/RichRecNamespaces.h
@@ -5,7 +5,7 @@
  *  General namespace for all RICH reconstruction software
  *
  *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
- *  @date   08/07/2004
+ *  @date   01/02/2017
  */
 //-----------------------------------------------------------------------------
 
@@ -15,6 +15,16 @@
  *  General namespace for RICH reconstruction MC related software
  *
  *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
- *  @date   05/12/2006
+ *  @date   01/02/2017
+ */
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/** @namespace Rich::Future::Rec::Moni
+ *
+ *  General namespace for RICH reconstruction monitoring utilities
+ *
+ *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
+ *  @date   01/02/2017
  */
 //-----------------------------------------------------------------------------
diff --git a/Rich/RichFutureRecEvent/RichFutureRecEvent/RichRecPhotonPredictedPixelSignals.h b/Rich/RichFutureRecEvent/RichFutureRecEvent/RichRecPhotonPredictedPixelSignals.h
index 45351b5eed..d7391683b5 100644
--- a/Rich/RichFutureRecEvent/RichFutureRecEvent/RichRecPhotonPredictedPixelSignals.h
+++ b/Rich/RichFutureRecEvent/RichFutureRecEvent/RichRecPhotonPredictedPixelSignals.h
@@ -24,6 +24,7 @@ namespace Rich
       /// Type for flags to say if a photon is active or not. i.e. has any signal.
       using PhotonFlags = LHCb::STL::Vector<bool>;
 
+      /// photon active flags TES locations
       namespace PhotonActiveFlagsLocation
       {
         /// Location in TES for the active photon flags
diff --git a/Rich/RichFutureRecEvent/RichFutureRecEvent/RichSummaryEventData.h b/Rich/RichFutureRecEvent/RichFutureRecEvent/RichSummaryEventData.h
index 0c5854a240..2c322afa97 100644
--- a/Rich/RichFutureRecEvent/RichFutureRecEvent/RichSummaryEventData.h
+++ b/Rich/RichFutureRecEvent/RichFutureRecEvent/RichSummaryEventData.h
@@ -24,6 +24,14 @@ namespace Rich
     { 
       // ===========================================================================
       
+      /** @namespace Summary
+       *
+       *  General namespace for RICH reconstruction summary information
+       *
+       *  @author Chris Jones  Christopher.Rob.Jones@cern.ch
+       *  @date   01/02/2017
+       */
+
       namespace Summary
       {
         
@@ -125,6 +133,14 @@ namespace Rich
         
         // ===========================================================================
         
+        /** @class Pixel RichSummaryEventData.h
+         *
+         *  Summary of the immutable pixell data.
+         *
+         *  @author Chris Jones
+         *  @date   2016-09-30
+         */
+
         class Pixel final
         {
           
@@ -155,7 +171,7 @@ namespace Rich
         
         // ===========================================================================
         
-        /// TES locations
+        /// Summary information TES locations
         namespace TESLocations
         {
           /// Tracks
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 565496df0e..5eff019747 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -159,6 +159,7 @@ namespace Rich
                          const SpacePointVector& globalPoints,
                          const SpacePointVector& localPoints,
                          const Relations::TrackToSegments::Vector& tkToSegRels ) const;
+
         /// AVX2 method
         OutData run_avx2( const LHCb::RichTrackSegment::Vector& segments,
                           const CherenkovAngles::Vector& ckAngles,
diff --git a/Rich/RichFutureRecSys/examples/Col16RawDataFiles.py b/Rich/RichFutureRecSys/examples/Col16RawDataFiles.py
index 93f5018ebe..c56359d4d3 100644
--- a/Rich/RichFutureRecSys/examples/Col16RawDataFiles.py
+++ b/Rich/RichFutureRecSys/examples/Col16RawDataFiles.py
@@ -21,3 +21,6 @@ from Configurables import Brunel, LHCbApp
 Brunel().DataType  = "2016"
 Brunel().Simulation = False
 Brunel().WithMC     = False
+
+#Brunel().DDDBtag   = "dddb-20150724"
+#Brunel().CondDBtag = "cond-20161011"
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.h b/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.h
index 2aa35f224f..f4dc7eaec5 100755
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichBaseTrSegMaker.h
@@ -49,7 +49,7 @@ namespace Rich
     {
 
       //---------------------------------------------------------------------------------
-      /** @class BaseTrSegMakerFromRecoTracks RichBaseTrSegMakerFromRecoTracks.h
+      /** @class BaseTrSegMaker RichBaseTrSegMaker.h
        *
        *  Base class to tools that create RichTrackSegments from Tracks.
        *
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichGeomEffCKMassRings.h b/Rich/RichFutureRecTrackAlgorithms/src/RichGeomEffCKMassRings.h
index 66423a3cf4..67e050fba0 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichGeomEffCKMassRings.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichGeomEffCKMassRings.h
@@ -42,7 +42,7 @@ namespace Rich
                                     SegmentPhotonFlags::Vector >;
       }
 
-      /** @class RichGeomEffCKMassRings RichRichGeomEffCKMassRings.h
+      /** @class GeomEffCKMassRings RichRichGeomEffCKMassRings.h
        *
        *  Computes the geometrical efficiencies for a set of track segments.
        *
diff --git a/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h b/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
index c5f3e88bef..3072c9e114 100644
--- a/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
+++ b/Rich/RichFutureRecTrackAlgorithms/src/RichTrackFunctionalCherenkovResolutions.h
@@ -53,7 +53,7 @@ namespace Rich
     namespace Rec
     {
 
-      /** @class FunctionalCherenkovResolutions RichRichTrackFunctionalCherenkovResolutions.h
+      /** @class TrackFunctionalCherenkovResolutions RichTrackFunctionalCherenkovResolutions.h
        *
        *  Computes the expected Cherenkov resolutions for the given track segments
        *
-- 
GitLab


From c5bd3a6a2ff92758afa0b0722d3ceaa62147aadb Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 16:09:55 +0000
Subject: [PATCH 60/68] cleanup

---
 Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 5eff019747..41125b129d 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -124,7 +124,7 @@ namespace Rich
             const Rich::PDPixelCluster::Vector& clusters,
             const SpacePointVector& globalPoints,
             const SpacePointVector& localPoints,
-            const Relations::TrackToSegments::Vector& tkToSegRels  ) const 
+            const Relations::TrackToSegments::Vector& tkToSegRels ) const 
           = &QuarticPhotonReco::run_generic;
         
         /// Generic method
-- 
GitLab


From 4e36eddc85d034dbc8d9e624a5aa0c6e8fc463b6 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 16:10:52 +0000
Subject: [PATCH 61/68] Add simple ROOT macro script for RICH correlation
 studies

---
 Rec/GlobalReco/root/RichCorrelations.C | 66 ++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Rec/GlobalReco/root/RichCorrelations.C

diff --git a/Rec/GlobalReco/root/RichCorrelations.C b/Rec/GlobalReco/root/RichCorrelations.C
new file mode 100644
index 0000000000..96d0e67575
--- /dev/null
+++ b/Rec/GlobalReco/root/RichCorrelations.C
@@ -0,0 +1,66 @@
+
+#include <memory>
+
+void RichCorrelations()
+{
+
+  auto c = std::make_unique<TCanvas>( "RichCor", "RichCor", 1400, 1000 );
+
+  TTree tree;
+  
+  tree.AddFriend("hlt2 = ChargedProtoTuple/protoPtuple",
+                 "/usera/jonesc/LHCbCMake/Brunel/output/future/Quartic100R1R2-AllHypos/protoparticles.tuples.root");
+
+  //tree.AddFriend("hlt1 = ChargedProtoTuple/protoPtuple", "/usera/jonesc/LHCbCMake/Brunel/output/future/FastQuartic50R1R2-AllHypos-NoUnAmBigPhot-NoBeamPipeCheck-1It/protoparticles.tuples.root");
+  //tree.AddFriend("hlt1 = ChargedProtoTuple/protoPtuple", "/usera/jonesc/LHCbCMake/Brunel/output/future/CKEsti50R1R2-KaPi/protoparticles.tuples.root");
+  tree.AddFriend("hlt1 = ChargedProtoTuple/protoPtuple", "/usera/jonesc/LHCbCMake/Brunel/output/future/CKEsti50R1R2-AllHypos/protoparticles.tuples.root");
+
+  tree.Draw("hlt2.TrackP:hlt1.TrackP","hlt2.TrackP<100000","zcol");
+  c->SaveAs( "P-Correlations.pdf" );
+
+  auto sel = TCut("hlt2.RichAbovePiThres>0 && hlt1.RichAbovePiThres>0 && hlt2.TrackP<100000 && hlt2.TrackP>3000");
+
+  auto trueK = TCut("abs(hlt2.MCParticleType) == 321");
+
+  auto truePi = TCut("abs(hlt2.MCParticleType) == 211");
+
+  tree.Draw( "hlt2.RichDLLk:hlt1.RichDLLk",sel && trueK,"zcol");
+  c->SaveAs( "TrueK-RichDLLk-2dCorrelations.pdf" );
+
+  tree.Draw( "hlt2.RichDLLk-hlt1.RichDLLk",sel && trueK );
+  c->SaveAs( "TrueK-RichDLLk-1dCorrelations.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel );
+  c->SaveAs( "All-RichDLLk-HLT1.pdf" );
+
+  tree.Draw( "hlt2.RichDLLk", sel );
+  c->SaveAs( "All-RichDLLk-HLT2.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK );
+  c->SaveAs( "TrueK-RichDLLk-HLT1.pdf" );
+
+  tree.Draw( "hlt2.RichDLLk", sel && trueK );
+  c->SaveAs( "TrueK-RichDLLk-HLT2.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && truePi );
+  c->SaveAs( "TruePi-RichDLLk-HLT1.pdf" );
+
+  tree.Draw( "hlt2.RichDLLk", sel && truePi );
+  c->SaveAs( "TruePi-RichDLLk-HLT2.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK && TCut("hlt2.RichDLLk>-2") );
+  c->SaveAs( "TrueK-RichDLLk-HLT1-HLT2gt-2.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK && TCut("hlt2.RichDLLk>0") );
+  c->SaveAs( "TrueK-RichDLLk-HLT1-HLT2gt0.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK && TCut("hlt2.RichDLLk>2") );
+  c->SaveAs( "TrueK-RichDLLk-HLT1-HLT2gt2.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK && TCut("hlt2.RichDLLk>4") );
+  c->SaveAs( "TrueK-RichDLLk-HLT1-HLT2gt4.pdf" );
+
+  tree.Draw( "hlt1.RichDLLk", sel && trueK && TCut("hlt2.RichDLLk>10") );
+  c->SaveAs( "TrueK-RichDLLk-HLT1-HLT2gt10.pdf" );
+
+}
-- 
GitLab


From 7d8defd5ff03b8535cdc499965fd5c4ead4318c1 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 19:05:59 +0000
Subject: [PATCH 62/68] update photon reco test code to make seperate float and
 double containers

---
 Rich/RichRecTests/src/PhotonReco/main.icpp | 53 +++++++++++++---------
 1 file changed, 31 insertions(+), 22 deletions(-)

diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 91a02a4784..0888834dbf 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -17,7 +17,8 @@
 // Make an instance of the quartic solver
 Rich::Rec::QuarticSolverNewton qSolver;
 
-Gaudi::XYZPoint sphReflPoint;
+ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<float>  > sphReflPointF;
+ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<double> > sphReflPointD;
 
 unsigned long long int time_diff( struct timespec *start, 
                                   struct timespec *stop ) 
@@ -31,25 +32,26 @@ unsigned long long int time_diff( struct timespec *start,
   }
 }
 
+template< typename TYPE >
 class Data
 {
 public:
   typedef std::vector<Data> Vector;
 public:
-  Gaudi::XYZPoint emissPnt;
-  Gaudi::XYZPoint centOfCurv;
-  Gaudi::XYZPoint virtDetPoint;
-  double           radius;
+  ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<TYPE> > emissPnt;
+  ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<TYPE> > centOfCurv;
+  ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D<TYPE> > virtDetPoint;
+  TYPE radius;
 public:
   Data() 
   {
     // randomn generator
     static std::default_random_engine gen;
     // Distributions for each member
-    static std::uniform_real_distribution<double> r_emiss_x(-800,800), r_emiss_y(-600,600), r_emiss_z(10000,10500);
-    static std::uniform_real_distribution<double> r_coc_x(-3000,3000), r_coc_y(-20,20),     r_coc_z(3300,3400);
-    static std::uniform_real_distribution<double> r_vdp_x(-3000,3000), r_vdp_y(-200,200),   r_vdp_z(8100,8200);
-    static std::uniform_real_distribution<float>  r_rad(8500,8600);
+    static std::uniform_real_distribution<TYPE> r_emiss_x(-800,800), r_emiss_y(-600,600), r_emiss_z(10000,10500);
+    static std::uniform_real_distribution<TYPE> r_coc_x(-3000,3000), r_coc_y(-20,20),     r_coc_z(3300,3400);
+    static std::uniform_real_distribution<TYPE> r_vdp_x(-3000,3000), r_vdp_y(-200,200),   r_vdp_z(8100,8200);
+    static std::uniform_real_distribution<TYPE> r_rad(8500,8600);
     // setup data
     emissPnt     = Gaudi::XYZPoint( r_emiss_x(gen), r_emiss_y(gen), r_emiss_z(gen) );
     centOfCurv   = Gaudi::XYZPoint( r_coc_x(gen),   r_coc_y(gen),   r_coc_z(gen)   );
@@ -58,8 +60,8 @@ public:
   }
 };
 
-template< class TYPE >
-inline void solve( const Data& data )
+template< class TYPE, class POINT >
+inline void solve( const Data<TYPE>& data, POINT & sphReflPoint )
 {
   qSolver.solve<TYPE,2,2>( data.emissPnt, 
                            data.centOfCurv, 
@@ -68,8 +70,9 @@ inline void solve( const Data& data )
                            sphReflPoint );
 }
 
-template< class TYPE >
-unsigned long long int __attribute__((noinline)) solve( const Data::Vector & dataV )
+template< class TYPE, class POINT  >
+unsigned long long int __attribute__((noinline)) 
+solve( const typename Data<TYPE>::Vector & dataV, POINT & sphReflPoint )
 {
   unsigned long long int best_dur{ 99999999999999999 };
 
@@ -80,7 +83,7 @@ unsigned long long int __attribute__((noinline)) solve( const Data::Vector & dat
   {
     clock_gettime(CLOCK_MONOTONIC_RAW,&start);
     // iterate over the data and solve it...
-    for ( const auto& data : dataV ) { solve<TYPE>(data); }
+    for ( const auto& data : dataV ) { solve<TYPE>(data,sphReflPoint); }
     clock_gettime(CLOCK_MONOTONIC_RAW,&end);
     const auto duration = time_diff(&start,&end);
     if ( duration < best_dur ) { best_dur = duration; }
@@ -93,20 +96,26 @@ int main ( int /*argc*/, char** /*argv*/ )
 {
   const unsigned int nPhotons = 1e5;
   
-  Data::Vector dataV;
-  dataV.reserve( nPhotons );
+  Data<double>::Vector dataVD;
+  Data<float>::Vector dataVF;
+  dataVD.reserve( nPhotons );
+  dataVF.reserve( nPhotons );
   // Construct the data to work on
   std::cout << "Creating " << nPhotons << " random photons ..." << std::endl;
-  for ( unsigned int i = 0; i < nPhotons; ++i ) { dataV.push_back( Data() ); }
-
-  // run the solver for floats
-  auto fTime = solve<float>( dataV );
-  std::cout << "Float  " << fTime << std::endl;
+  for ( unsigned int i = 0; i < nPhotons; ++i ) 
+  { 
+    dataVD.emplace_back( );
+    dataVF.emplace_back( ); 
+  }
 
   // run the solver for doubles
-  auto dTime = solve<double>( dataV );
+  auto dTime = solve<double>( dataVD, sphReflPointD );
   std::cout << "Double " << dTime << std::endl;
 
+  // run the solver for floats
+  auto fTime = solve<float>( dataVF, sphReflPointF );
+  std::cout << "Float  " << fTime << std::endl;
+
   // make sure we are not optimized away
   asm volatile ("" : "+x"(fTime));
   asm volatile ("" : "+x"(dTime));
-- 
GitLab


From 0228508d170e0c04e0b2c277e133b27c48cce10f Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Tue, 7 Mar 2017 19:47:26 +0000
Subject: [PATCH 63/68] Update template ranges

---
 .../src/RichQuarticPhotonReco.h                       |  5 ++++-
 .../src/RichQuarticPhotonReco.icpp                    |  4 ++--
 Rich/RichRecTests/src/PhotonReco/main.icpp            |  2 +-
 Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h  | 11 ++++-------
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
index 41125b129d..a5a3b1e54d 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.h
@@ -44,6 +44,9 @@
 // Vector Class
 #include "VectorClass/instrset.h"
 
+// VDT
+#include "vdt/asin.h"
+
 namespace Rich
 {
   namespace Future
@@ -196,7 +199,7 @@ namespace Rich
                                     Gaudi::XYZPoint & secReflPoint ) const
         {
           // solve quartic equation with nominal values and find spherical mirror reflection point
-          m_quarticSolver.solve<double,2,2>( emissionPoint,
+          m_quarticSolver.solve<double,3,3>( emissionPoint,
                                              m_rich[rich]->nominalCentreOfCurvature(side),
                                              virtDetPoint,
                                              m_rich[rich]->sphMirrorRadius(),
diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
index dd4cb6f94b..2da9b16e53 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
@@ -333,7 +333,7 @@
             virtDetPoint = gloPos - 2.0 * distance * secSegment->centreNormal();
           
             // solve the quartic using the new data
-            m_quarticSolver.solve<double,2,3>( emissionPoint,
+            m_quarticSolver.solve<double,3,4>( emissionPoint,
                                                sphSegment->centreOfCurvature(),
                                                virtDetPoint,
                                                sphSegment->radius(),
@@ -384,7 +384,7 @@
               virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
             
               // solve the quartic using the new data
-              m_quarticSolver.solve<double,2,3>( emissionPoint,
+              m_quarticSolver.solve<double,3,4>( emissionPoint,
                                                  sphSegment->centreOfCurvature(),
                                                  virtDetPoint,
                                                  sphSegment->radius(),
diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 0888834dbf..9373a35608 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -63,7 +63,7 @@ public:
 template< class TYPE, class POINT >
 inline void solve( const Data<TYPE>& data, POINT & sphReflPoint )
 {
-  qSolver.solve<TYPE,2,2>( data.emissPnt, 
+  qSolver.solve<TYPE,3,2>( data.emissPnt, 
                            data.centOfCurv, 
                            data.virtDetPoint,
                            data.radius, 
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 8a83c1c857..00b5d47c42 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -20,9 +20,6 @@
 #include <type_traits>
 #include <array>
 
-// VDT
-#include "vdt/asin.h"
-
 namespace Rich
 {
   namespace Rec
@@ -58,7 +55,7 @@ namespace Rich
        *  @retval false Calculation failed. sphReflPoint is not valid.
        */
       template< class TYPE,
-                std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3,
+                std::size_t BISECTITS = 3, std::size_t NEWTONITS = 4,
                 class POINT = Gaudi::XYZPoint >
       inline void solve( const POINT& emissionPoint,
                          const POINT& CoC,
@@ -278,7 +275,7 @@ namespace Rich
        *  TODO: These tuning parameters have been found by low effort experimentation on random input data. A more detailed
        *  study should be done with real data to find the best values
        */
-      template < class TYPE, std::size_t BISECTITS = 2, std::size_t NEWTONITS = 3 >
+      template < class TYPE, std::size_t BISECTITS = 3, std::size_t NEWTONITS = 4 >
       inline TYPE solve_quartic_newton_RICH( const TYPE& a0,
                                              const TYPE& a1,
                                              const TYPE& a2,
@@ -291,7 +288,7 @@ namespace Rich
         TYPE m(0.2); //We start a bit off center since the distribution of roots tends to be more to the left side
         const TYPE a[5] = {a0, a1, a2, a3, a4};
         TYPE res[2];
-        for ( std::size_t i = 0; i <= BISECTITS; ++i )
+        for ( std::size_t i = 0; i < BISECTITS; ++i )
         {
           const auto oppositeSign = std::signbit(f4(a0,a1,a2,a3,a4,m) * f4(a0,a1,a2,a3,a4,l));
 
@@ -313,7 +310,7 @@ namespace Rich
         //away with 3 iterations if we can find an exact value
         const TYPE gain = 1.04;
 
-        for ( std::size_t i = 0; i <= NEWTONITS; ++i )
+        for ( std::size_t i = 0; i < NEWTONITS; ++i )
         {
           evalPolyHorner<TYPE, 4, 1>( a, res, m );
           //epsilon = f4(a0,a1,a2,a3,a4,x) / df4(a0,a1,a2,a3,x);
-- 
GitLab


From 9db641492d78062e15fe0f21c8d0c59e10cf7065 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 8 Mar 2017 10:05:38 +0000
Subject: [PATCH 64/68] Disable AVX2 in AVX2 only test builds as well as
 AVX2+FMA

---
 Rich/RichRecTests/CMakeLists.txt | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Rich/RichRecTests/CMakeLists.txt b/Rich/RichRecTests/CMakeLists.txt
index 2e13a4845a..5a43b8ec44 100644
--- a/Rich/RichRecTests/CMakeLists.txt
+++ b/Rich/RichRecTests/CMakeLists.txt
@@ -48,7 +48,9 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichPhotonRecoTestAVX2 -lrt )
-  set_property(SOURCE src/PhotonReco/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 " )  
+  # Until such a time that all build targets support AVX2+FMA, fallback to just AVX here
+  #set_property(SOURCE src/PhotonReco/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx2 " ) 
+  set_property(SOURCE src/PhotonReco/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -mavx " ) 
 
   gaudi_add_executable(RichPhotonRecoTestAVX2FMA
                        src/PhotonReco/main_avx2fma.cpp
@@ -80,7 +82,9 @@ if(GAUDI_BUILD_TESTS)
                        INCLUDE_DIRS Kernel/TemplatedGenVector ROOT Vc Eigen GSL VectorClass src
                        LINK_LIBRARIES LHCbMathLib GSL GaudiKernel TemplatedGenVectorLib )
   target_link_libraries( RichRayTracingTestAVX2 "-lrt ${Vc_LIB_DIR}/libVc.a" )
-  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 " )
+  # Until such a time that all build targets support AVX2+FMA, fallback to just AVX here
+  #set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx2 " )
+  set_property(SOURCE src/RayTracing/main_avx2.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-ignored-attributes -mavx " )
 
   gaudi_add_executable(RichRayTracingTestAVX2FMA
                        src/RayTracing/main_avx2fma.cpp
-- 
GitLab


From 57cd213801e93a218b8a5820971fc4cdabc5c890 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 8 Mar 2017 14:46:16 +0000
Subject: [PATCH 65/68] Optimise the reflection of the detection point in the
 virtual secondary plane

---
 .../src/RichQuarticPhotonReco.icpp            | 24 ++++++++++++-------
 .../RichRecUtils/QuarticSolverNewton.h        |  4 +---
 2 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
index 2da9b16e53..a634b24086 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
@@ -161,8 +161,8 @@
         // find the reflection of the detection point in the sec mirror
         // (virtual detection point) starting with nominal values
         // At this we are assuming a flat nominal mirror common to all segments
-        auto distance = m_rich[rich]->nominalPlane(side).Distance(gloPos);
-        auto virtDetPoint = gloPos - 2.0 * distance * m_rich[rich]->nominalNormal(side);
+        const auto nom_dist = m_rich[rich]->nominalPlane(side).Distance(gloPos);
+        auto virtDetPoint = gloPos - 2.0 * nom_dist * m_rich[rich]->nominalNormal(side);
 
         // --------------------------------------------------------------------------------------
         // For gas radiators, try start and end points to see if photon is unambiguous
@@ -329,7 +329,7 @@
           {
           
             // Form the virtual detection point
-            distance     = secSegment->centreNormalPlane().Distance(gloPos);
+            const auto distance = secSegment->centreNormalPlane().Distance(gloPos);
             virtDetPoint = gloPos - 2.0 * distance * secSegment->centreNormal();
           
             // solve the quartic using the new data
@@ -375,14 +375,22 @@
               // (re)find the secondary mirror
               secSegment = m_mirrorSegFinder.get()->findSecMirror( rich, side, secReflPoint );
             
+              // Compute the virtual reflection point
+ 
               // Construct plane tangential to secondary mirror passing through reflection point
-              const Gaudi::Plane3D plane( secSegment->centreOfCurvature()-secReflPoint, secReflPoint );
-            
+              //const Gaudi::Plane3D plane( secSegment->centreOfCurvature()-secReflPoint, secReflPoint );
               // re-find the reflection of the detection point in the sec mirror
               // (virtual detection point) with this mirror plane
-              distance     = plane.Distance(gloPos);
-              virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
-            
+              //const auto distance     = plane.Distance(gloPos);
+              //virtDetPoint = gloPos - 2.0 * distance * plane.Normal();
+
+              // Same as above, just written out by hand and simplified a bit
+              const auto normV = secSegment->centreOfCurvature() - secReflPoint;
+              const auto distance = ( ( normV.X() * ( gloPos.X() - secReflPoint.X() ) ) + 
+                                      ( normV.Y() * ( gloPos.Y() - secReflPoint.Y() ) ) + 
+                                      ( normV.Z() * ( gloPos.Z() - secReflPoint.Z() ) ) );
+              virtDetPoint = gloPos - 2.0 * distance * normV / normV.Mag2();
+
               // solve the quartic using the new data
               m_quarticSolver.solve<double,3,4>( emissionPoint,
                                                  sphSegment->centreOfCurvature(),
diff --git a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
index 00b5d47c42..dfc5da3a9f 100755
--- a/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
+++ b/Rich/RichRecUtils/RichRecUtils/QuarticSolverNewton.h
@@ -65,9 +65,6 @@ namespace Rich
       {
         using namespace std;
 
-        // typedefs vectorised types
-        using Vec4x = typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
-
         // vector from mirror centre of curvature to assumed emission point
         const auto evec( emissionPoint - CoC );
         const TYPE e2 = evec.Dot(evec);
@@ -81,6 +78,7 @@ namespace Rich
         const TYPE       ed2 = e2 * d2;
         const TYPE cosgamma2 = ( ed2 > TYPE(0.0) ? pow(evec.Dot(dvec),2)/ed2 : TYPE(1.0) );
         // vectorise 4 square roots into 1
+        using Vec4x = typename std::conditional<std::is_same<TYPE,float>::value,Vec4f,Vec4d>::type;
         const auto tmp_sqrt = sqrt( Vec4x( e2, d2,
                                            cosgamma2 < TYPE(1.0) ? TYPE(1.0)-cosgamma2 : TYPE(0.0),
                                            cosgamma2 ) );
-- 
GitLab


From 9c01bf5e5b5c4383a666d257bdd6a39e94cbfc75 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 8 Mar 2017 14:47:13 +0000
Subject: [PATCH 66/68] Remove Gaudi::XYZPoint construction

---
 Rich/RichRecTests/src/PhotonReco/main.icpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Rich/RichRecTests/src/PhotonReco/main.icpp b/Rich/RichRecTests/src/PhotonReco/main.icpp
index 9373a35608..dbc074555b 100644
--- a/Rich/RichRecTests/src/PhotonReco/main.icpp
+++ b/Rich/RichRecTests/src/PhotonReco/main.icpp
@@ -53,9 +53,9 @@ public:
     static std::uniform_real_distribution<TYPE> r_vdp_x(-3000,3000), r_vdp_y(-200,200),   r_vdp_z(8100,8200);
     static std::uniform_real_distribution<TYPE> r_rad(8500,8600);
     // setup data
-    emissPnt     = Gaudi::XYZPoint( r_emiss_x(gen), r_emiss_y(gen), r_emiss_z(gen) );
-    centOfCurv   = Gaudi::XYZPoint( r_coc_x(gen),   r_coc_y(gen),   r_coc_z(gen)   );
-    virtDetPoint = Gaudi::XYZPoint( r_vdp_x(gen),   r_vdp_y(gen),   r_vdp_z(gen)   );
+    emissPnt     = { r_emiss_x(gen), r_emiss_y(gen), r_emiss_z(gen) };
+    centOfCurv   = { r_coc_x(gen),   r_coc_y(gen),   r_coc_z(gen)   };
+    virtDetPoint = { r_vdp_x(gen),   r_vdp_y(gen),   r_vdp_z(gen)   };
     radius       = r_rad(gen);
   }
 };
-- 
GitLab


From c580bf1e9296f7f9d7f98648f62520e0e7bca210 Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 8 Mar 2017 14:52:41 +0000
Subject: [PATCH 67/68] reorder the calculation to make sure the vector is
 scaled only once

---
 .../src/RichQuarticPhotonReco.icpp                              | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
index a634b24086..63eb84b8e5 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichQuarticPhotonReco.icpp
@@ -389,7 +389,7 @@
               const auto distance = ( ( normV.X() * ( gloPos.X() - secReflPoint.X() ) ) + 
                                       ( normV.Y() * ( gloPos.Y() - secReflPoint.Y() ) ) + 
                                       ( normV.Z() * ( gloPos.Z() - secReflPoint.Z() ) ) );
-              virtDetPoint = gloPos - 2.0 * distance * normV / normV.Mag2();
+              virtDetPoint = gloPos - ( normV * ( 2.0 * distance / normV.Mag2() ) );
 
               // solve the quartic using the new data
               m_quarticSolver.solve<double,3,4>( emissionPoint,
-- 
GitLab


From e884189fd705d30d2c1ac43a3f2987b8aa90f49b Mon Sep 17 00:00:00 2001
From: Chris Jones <jonesc@hep.phy.cam.ac.uk>
Date: Wed, 8 Mar 2017 16:37:00 +0000
Subject: [PATCH 68/68] template floating point type in checkAngles and reorder
 cuts to place most likely to reject first

---
 .../src/RichBasePhotonReco.h                           | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Rich/RichFutureRecPhotonAlgorithms/src/RichBasePhotonReco.h b/Rich/RichFutureRecPhotonAlgorithms/src/RichBasePhotonReco.h
index ff0522a364..09fadbbfe2 100644
--- a/Rich/RichFutureRecPhotonAlgorithms/src/RichBasePhotonReco.h
+++ b/Rich/RichFutureRecPhotonAlgorithms/src/RichBasePhotonReco.h
@@ -166,18 +166,18 @@ namespace Rich
         }
         
         /// Check the final Cherenkov angles
-        template < typename HYPODATA >
+        template < typename HYPODATA, typename FTYPE >
         inline bool checkAngles( const Rich::RadiatorType rad,
                                  const HYPODATA& tkCkAngles,
                                  const HYPODATA& tkCkRes,
-                                 const float ckTheta,
-                                 const float ckPhi ) const noexcept
+                                 const FTYPE ckTheta,
+                                 const FTYPE ckPhi ) const noexcept
         {
           return (
             // First the basic checks
-            ckPhi   > 0 &&
-            ckTheta > absMinCKTheta(rad) &&
             ckTheta < absMaxCKTheta(rad) &&
+            ckTheta > absMinCKTheta(rad) &&
+            ckPhi   > 0                  &&
             // Now check each hypo
             std::any_of( activeParticles().begin(),
                          activeParticles().end(),
-- 
GitLab