From d60e0386cb3685ca29a66e9a2f3103b8ef47376d Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Wed, 30 Oct 2024 19:39:52 +0100
Subject: [PATCH] Addinga hash getter for a CbmSetup; storing and testing a
 reference hash in the KF-setup builder initialization

---
 algo/kf/core/geo/KfSetupBuilder.cxx      | 11 +++++++++++
 algo/kf/core/geo/KfSetupBuilder.h        | 11 +++++++++--
 reco/kfnew/CbmKfTrackingSetupBuilder.cxx | 18 ++++++++++++++----
 reco/kfnew/CbmKfTrackingSetupBuilder.h   | 21 +++++++++++++--------
 sim/transport/steer/CbmSetup.cxx         | 24 +++++++++++++++++++++---
 sim/transport/steer/CbmSetup.h           |  9 +++++++++
 6 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/algo/kf/core/geo/KfSetupBuilder.cxx b/algo/kf/core/geo/KfSetupBuilder.cxx
index 0d88a20b1c..6c300eb53b 100644
--- a/algo/kf/core/geo/KfSetupBuilder.cxx
+++ b/algo/kf/core/geo/KfSetupBuilder.cxx
@@ -67,6 +67,7 @@ void SetupBuilder::Init()
     }
 
     if (!bMaterialLoaded) {
+      fvMaterial.clear();
       fvMaterial.reserve(fGeoLayers.size());
     }
     double zLast{fTarget.GetZ() + fTarget.GetDz() * kTargetMaterialOffset};
@@ -124,6 +125,15 @@ bool SetupBuilder::LoadMaterial()
   try {
     boost::archive::binary_iarchive ia(ifs);
     MaterialMap targetMat;
+    size_t refHash;
+    ia >> refHash;
+    if (refHash != fGeoHash) {
+      LOG(warn) << "kf::SetupBuilder::LoadMaterial: reference hash from input file \"" << fsMaterialCacheFile
+                << "\" "
+                   "diverges from one, obtained from the actual detector setup geometry. Material budget will be "
+                   "re-generated, and a new file will be created";
+      return false;
+    }
     ia >> targetMat;
     ia >> fvMaterial;
     fTarget.SetMaterial(targetMat);
@@ -195,6 +205,7 @@ void SetupBuilder::StoreMaterial() const
     throw std::runtime_error(msg.str());
   }
   boost::archive::binary_oarchive oa(ofs);
+  oa << fGeoHash;
   oa << fTarget.GetMaterial();
   oa << fvMaterial;
 }
diff --git a/algo/kf/core/geo/KfSetupBuilder.h b/algo/kf/core/geo/KfSetupBuilder.h
index 649f64e279..bebd43ad57 100644
--- a/algo/kf/core/geo/KfSetupBuilder.h
+++ b/algo/kf/core/geo/KfSetupBuilder.h
@@ -122,11 +122,17 @@ namespace cbm::algo::kf
 
     /// \brief Sets the material budget cache file name
     /// \param filename  Material budget cache file name
+    /// \param refHash   Reference hash of the geometry
     ///
     /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
     /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
-    /// and stored to the file.
-    void SetMaterialCacheFile(const std::string& filename) { fsMaterialCacheFile = filename; }
+    /// and stored to the file. If the reference hash differs from one, read from the file, a warning will be produced,
+    /// and the new cache file will be generated.
+    void SetMaterialCacheFile(const std::string& filename, size_t refHash)
+    {
+      fsMaterialCacheFile = filename;
+      fGeoHash            = refHash;
+    }
 
     /// \brief Sets target initialization properties
     /// \param x  Target x-coordinate [cm]
@@ -187,6 +193,7 @@ namespace cbm::algo::kf
     ModuleIndexMapFactory fModuleIndexFactory;                           ///< Module index factory
     FieldFactory fFieldFactory;                                          ///< Instance of field factory
     Target<double> fTarget;                                              ///< Target properties
+    size_t fGeoHash{0};                                                  ///< A hash of the geometry
     int fMatMapNofBins{100};                                             ///< Number of bins in material maps
 
     bool fbIfTargetSet{false};         ///< Target initialized
diff --git a/reco/kfnew/CbmKfTrackingSetupBuilder.cxx b/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
index 347f7c6931..338a86b63d 100644
--- a/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
+++ b/reco/kfnew/CbmKfTrackingSetupBuilder.cxx
@@ -25,6 +25,8 @@
 #include "KfMaterialMapFactory.h"
 #include "Logger.h"
 
+#include <boost/filesystem.hpp>
+
 #include <functional>
 
 using cbm::algo::ca::EDetectorID;
@@ -134,20 +136,28 @@ catch (const std::exception& err) {
 //
 TrackingSetupBuilder* TrackingSetupBuilder::Instance()
 {
+  namespace fs = boost::filesystem;
   if (fpInstance == nullptr) {
     std::lock_guard<std::mutex> lock(fMutex);
     fpInstance = new TrackingSetupBuilder{};
     fpInstance->CheckDetectorPresence();
 
+    // Retrieve the geometry tag
     auto setupTag = CbmSetup::Instance()->GetProvider()->GetSetup().GetTag();
     if (setupTag.empty()) {
       throw std::logic_error("The setup tag in CbmSetup is not defined");
     }
-    //TString sinkName = FairRootManager::Instance()->GetSink()->GetFileName();
 
-    // Creating the cache file in "./", so the macros from different directories could use the same file
-    std::string sCacheFile = Form("./%s.mat.kf.bin", setupTag.c_str());
-    fpInstance->SetMaterialCacheFile(sCacheFile);
+    // Retrieve the data directory (the same as for the sink file)
+    TString sinkName     = FairRootManager::Instance()->GetSink()->GetFileName();
+    auto sinkPath        = fs::path{sinkName.Data()};
+    std::string sDataDir = sinkPath.parent_path().string();
+    if (sDataDir.empty()) {
+      sDataDir = ".";
+    }
+
+    std::string sCacheFile = Form("%s/%s.mat.kf.bin", sDataDir.c_str(), setupTag.c_str());
+    fpInstance->SetMaterialCacheFile(sCacheFile, CbmSetup::Instance()->GetHash());
   }
   return fpInstance;
 }
diff --git a/reco/kfnew/CbmKfTrackingSetupBuilder.h b/reco/kfnew/CbmKfTrackingSetupBuilder.h
index a4754c4efe..1263cd9e33 100644
--- a/reco/kfnew/CbmKfTrackingSetupBuilder.h
+++ b/reco/kfnew/CbmKfTrackingSetupBuilder.h
@@ -54,14 +54,6 @@ namespace cbm::kf
     TrackingSetupBuilder& operator=(const TrackingSetupBuilder&) = delete;
     TrackingSetupBuilder& operator=(TrackingSetupBuilder&&) = delete;
 
-    /// \brief  Sets a name for the material budget cache-file
-    /// \param  filename  A name of the file
-    ///
-    /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
-    /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
-    /// and stored to the file.
-    void SetMaterialCacheFile(const TString& filename) { fBuilder.SetMaterialCacheFile(filename.Data()); }
-
    private:
     template<typename T>
     using DetectorIDArray_t = cbm::core::EnumArray<cbm::algo::ca::EDetectorID, T>;
@@ -79,6 +71,19 @@ namespace cbm::kf
     /// \brief  Check detector presence
     void CheckDetectorPresence();
 
+    /// \brief Sets the material budget cache file name
+    /// \param filename  Material budget cache file name
+    /// \param geoHash   A hash of the geometry
+    ///
+    /// If provided, the instance will try to read the material budget maps from the file. If the file does not exist,
+    /// or the geometry hash was changed since the last time, the material budget maps will be recreated on the flight
+    /// and stored to the file. If the reference hash differs from one, read from the file, a warning will be produced,
+    /// and the new cache file will be generated.
+    void SetMaterialCacheFile(const TString& filename, size_t geoHash)
+    {
+      fBuilder.SetMaterialCacheFile(filename.Data(), geoHash);
+    }
+
     /// \brief  Initializes the instance
     /// \note   Is executed on the first call of MakeSetup function
     void Init();
diff --git a/sim/transport/steer/CbmSetup.cxx b/sim/transport/steer/CbmSetup.cxx
index 88ed27f365..d8a3480f1d 100644
--- a/sim/transport/steer/CbmSetup.cxx
+++ b/sim/transport/steer/CbmSetup.cxx
@@ -15,11 +15,8 @@
 #include "CbmFieldMapData.h"
 #include "CbmFieldMapSym2.h"
 #include "CbmFieldMapSym3.h"
-
 #include "FairModule.h"
 #include "FairRunSim.h"
-#include <Logger.h>
-
 #include "TFile.h"
 #include "TGeoMatrix.h"
 #include "TGeoNode.h"
@@ -27,8 +24,11 @@
 #include "TKey.h"
 #include "TSystem.h"
 
+#include <Logger.h>
+
 #include <iomanip>
 #include <sstream>
+#include <string>  // for std::hash<string_view>
 
 using std::string;
 using std::stringstream;
@@ -138,6 +138,24 @@ Bool_t CbmSetup::GetGeoTag(ECbmModuleId moduleId, TString& tag)
 // -------------------------------------------------------------------------
 
 
+// -----  Get a hash of the setup  -----------------------------------------
+size_t CbmSetup::GetHash()
+{
+  // TODO: make all getters constant (up to the CbmGeoSetupModule and co. classes)
+  std::string hashString{""};
+  auto& moduleMap = fProvider->GetSetup().GetModuleMap();
+  for (auto& entry : moduleMap) {
+    if (!hashString.empty()) {
+      hashString += ";";
+    }
+    hashString += entry.second.GetName() + ":" + entry.second.GetTag();
+  }
+  //LOG(info) << "CbmSetup::GetHash(): " << hashString;
+  return std::hash<std::string>{}(hashString);
+}
+// -------------------------------------------------------------------------
+
+
 // -----   Instance   ------------------------------------------------------
 CbmSetup* CbmSetup::Instance()
 {
diff --git a/sim/transport/steer/CbmSetup.h b/sim/transport/steer/CbmSetup.h
index 8ff24d4d00..c31338c5a1 100644
--- a/sim/transport/steer/CbmSetup.h
+++ b/sim/transport/steer/CbmSetup.h
@@ -96,6 +96,15 @@ public:
   Bool_t GetGeoFileName(ECbmModuleId moduleId, TString& fileName);
 
 
+  /** Get a hash of the setup
+     ** @return  A 64-bit integer, representing the hash value
+     **
+     ** The hash is formed from a string of pairs "module name -- module tag", separated by semicolon. Only
+     ** active modules are considered.
+     **/
+  size_t GetHash();
+
+
   /** Get number of modules in the setup
      ** @value  Number of modules in setup
      **/
-- 
GitLab