From 5237836396f4c84396204b6780a17cf4b8baa10d Mon Sep 17 00:00:00 2001
From: "P.-A. Loizeau" <p.-a.loizeau@gsi.de>
Date: Wed, 1 Dec 2021 17:47:50 +0100
Subject: [PATCH] [MQ] Make Parameter server the only source of CbmSetup

- In sim/steer, add CbmSetupStorable class in CbmSetup to convert back and forth from memory Instance to streamable object
- Add support for CbmSetup in MQ parameter server device, with CbmSetupStorable output upon request
- Change CbmSetup usage in MQ Unpack device from Disk access to parameter server request
- Add printout of the received tag in MQ unpack for each detector system
---
 MQ/mcbm/CbmDeviceUnpack.cxx               |  35 ++++++-
 MQ/mcbm/CbmDeviceUnpack.h                 |   4 +-
 MQ/mcbm/UnpBuildSink_missing_features.txt |   5 +-
 MQ/mcbm/startBuildRawEvents2021.sh.in     |   3 +
 MQ/parmq/CMakeLists.txt                   |  11 ++-
 MQ/parmq/ParameterMQServer.cxx            | 115 ++++++++++++++--------
 MQ/parmq/ParameterMQServer.h              |  24 +++--
 MQ/parmq/runParameterMQServer.cxx         |  28 ++++--
 sim/transport/steer/CbmSetup.cxx          |  19 ++++
 sim/transport/steer/CbmSetup.h            |  56 ++++++++++-
 sim/transport/steer/CbmSimSteerLinkDef.h  |   1 +
 11 files changed, 229 insertions(+), 72 deletions(-)

diff --git a/MQ/mcbm/CbmDeviceUnpack.cxx b/MQ/mcbm/CbmDeviceUnpack.cxx
index eebb7eb279..3932fca43a 100644
--- a/MQ/mcbm/CbmDeviceUnpack.cxx
+++ b/MQ/mcbm/CbmDeviceUnpack.cxx
@@ -87,8 +87,34 @@ Bool_t CbmDeviceUnpack::InitContainers()
   //  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
 
   // -----   CbmSetup   -----------------------------------------------------
-  auto cbmsetup = CbmSetup::Instance();
-  cbmsetup->LoadSetup(fsSetupName.data());  //nh - accesses file system! FIXME
+  // TODO: support for multiple setups on Par Server? with request containing setup name?
+  CbmSetup* cbmsetup = CbmSetup::Instance();
+  FairMQMessagePtr req(NewSimpleMessage("setup"));
+  FairMQMessagePtr rep(NewMessage());
+
+  if (Send(req, "parameters") > 0) {
+    if (Receive(rep, "parameters") >= 0) {
+      if (0 != rep->GetSize()) {
+        CbmSetupStorable* exchangableSetup;
+
+        CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
+        exchangableSetup = dynamic_cast<CbmSetupStorable*>(tmsg.ReadObject(tmsg.GetClass()));
+
+        if (nullptr != exchangableSetup) {
+          /// Prevent clang format single line if
+          cbmsetup->LoadStoredSetup(exchangableSetup);
+        }
+        else {
+          LOG(error) << "Received corrupt reply. Setup not available";
+          throw InitTaskError("Setup not received from par-server.");
+        }
+      }  // if( 0 !=  rep->GetSize() )
+      else {
+        LOG(error) << "Received empty reply. Setup not available";
+        throw InitTaskError("Setup not received from par-server.");
+      }  // else of if( 0 !=  rep->GetSize() )
+    }    // if( Receive( rep, "parameters" ) >= 0)
+  }      // if( Send(req, "parameters") > 0 )
   // ------------------------------------------------------------------------
 
   /// Initialize the UnpackerConfigs objects and their "user options"
@@ -97,6 +123,7 @@ Bool_t CbmDeviceUnpack::InitContainers()
   TString stsSetupTag                           = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kSts, stsSetupTag);
   if ("" != stsSetupTag) {
+    LOG(info) << "From received setup, using STS tag: " << stsSetupTag;
     stsconfig = std::make_shared<CbmStsUnpackConfig>(std::string(fsSetupName), fuRunId);
     if (stsconfig) {
       // stsconfig->SetDebugState();
@@ -136,6 +163,7 @@ Bool_t CbmDeviceUnpack::InitContainers()
   TString trdsetuptag                             = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
   if ("" != trdsetuptag) {
+    LOG(info) << "From received setup, using TRD tag: " << trdsetuptag;
     // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), fuRunId);
     trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), 3);
     if (trd1Dconfig) {
@@ -174,6 +202,7 @@ Bool_t CbmDeviceUnpack::InitContainers()
   TString tofSetupTag                           = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kTof, tofSetupTag);
   if ("" != tofSetupTag) {
+    LOG(info) << "From received setup, using TOF tag: " << tofSetupTag;
     tofconfig = std::make_shared<CbmTofUnpackConfig>("", fuRunId);
     if (tofconfig) {
       // tofconfig->SetDebugState();
@@ -190,6 +219,7 @@ Bool_t CbmDeviceUnpack::InitContainers()
   TString richSetupTag                            = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kRich, richSetupTag);
   if ("" != richSetupTag) {
+    LOG(info) << "From received setup, using RICH tag: " << richSetupTag;
     richconfig = std::make_shared<CbmRichUnpackConfig>("", fuRunId);
     if (richconfig) {
       richconfig->SetDebugState();
@@ -206,6 +236,7 @@ Bool_t CbmDeviceUnpack::InitContainers()
   TString psdSetupTag                           = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kPsd, psdSetupTag);
   if ("" != psdSetupTag) {
+    LOG(info) << "From received setup, using PSD tag: " << psdSetupTag;
     psdconfig = std::make_shared<CbmPsdUnpackConfig>("", fuRunId);
     if (psdconfig) {
       // psdconfig->SetDebugState();
diff --git a/MQ/mcbm/CbmDeviceUnpack.h b/MQ/mcbm/CbmDeviceUnpack.h
index b53bdd7d7e..24a17c916b 100644
--- a/MQ/mcbm/CbmDeviceUnpack.h
+++ b/MQ/mcbm/CbmDeviceUnpack.h
@@ -99,8 +99,8 @@ private:
   bool fbOutputFullTimeSorting = false;
 
   /// User settings parameters
-  std::string fsSetupName             = "mcbm_beam_2021_07";
-  uint32_t fuRunId                    = 1588;
+  std::string fsSetupName = "mcbm_beam_2021_07_surveyed";
+  uint32_t fuRunId        = 1588;
   /// message queues
   std::string fsChannelNameDataInput   = "ts-request";
   std::string fsChannelNameDataOutput  = "unpts_0";
diff --git a/MQ/mcbm/UnpBuildSink_missing_features.txt b/MQ/mcbm/UnpBuildSink_missing_features.txt
index fd500ae3f1..a948c0e68e 100644
--- a/MQ/mcbm/UnpBuildSink_missing_features.txt
+++ b/MQ/mcbm/UnpBuildSink_missing_features.txt
@@ -1,7 +1,4 @@
-High priority
-- Make the parameter server the single source for the CbmSetup object (remove all disk accesses in Unpacker device!)
-
 Low priority
-- Pub-Sub Queue from Sink to intermediate devices (unpackers, Event builders, ?calibrators?, ...) to signal that last TS was received and dumped and Transition 
+- Pub-Sub Queue from Sink to intermediate devices (unpackers, Event builders, ?calibrators?, ...) to signal that last TS was received and dumped and Transition
   `Active -> Ready -> Stop -> End` can be done (e.g. through a Finish method)
 - Empty/custom TsEventHeader and event vector when dumping missing TS in Sink (vector maybe already OK)
diff --git a/MQ/mcbm/startBuildRawEvents2021.sh.in b/MQ/mcbm/startBuildRawEvents2021.sh.in
index 1da57926ad..d24b68e452 100755
--- a/MQ/mcbm/startBuildRawEvents2021.sh.in
+++ b/MQ/mcbm/startBuildRawEvents2021.sh.in
@@ -77,6 +77,7 @@ _parfileTrdGain=$VMCWORKDIR/parameters/trd/trd_v21b_mcbm.gain.par
 _parfileTof=$VMCWORKDIR/macro/beamtime/mcbm2021/mTofCriPar.par
 _parfileRich=$VMCWORKDIR/macro/beamtime/mcbm2021/mRichPar_70.par
 _parfilePsd=$VMCWORKDIR/macro/beamtime/mcbm2021/mPsdPar.par
+_setup_name=mcbm_beam_2021_07_surveyed
 
 LOGFILETAG=`hostname`
 LOGFILETAG+="_"
@@ -135,6 +136,7 @@ while (( _iMoni < _nbmoni )); do
   UNPACKER+=" --id unp$_iMoni"
   UNPACKER+=" --severity info"
   #UNPACKER+=" --severity debug"
+  UNPACKER+=" --Setup $_setup_name"
   UNPACKER+=" --IgnOverMs 1"
   UNPACKER+=" --SetTimeOffs kSTS,-2221"
   UNPACKER+=" --SetTimeOffs kMUCH,-885"
@@ -240,6 +242,7 @@ PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transpo
 PARAMETERSERVER+=" --first-input-name $_parfileSts;$_parfileMuch;$_parfileTrdAsic;$_parfileTrdDigi;$_parfileTrdGas;$_parfileTrdGain;$_parfileTof;$_parfileRich;$_parfilePsd"
 PARAMETERSERVER+=" --first-input-type ASCII"
 PARAMETERSERVER+=" --libs-to-load=libCbmFlibMcbm2018" # doesn't work due to runtime problem
+PARAMETERSERVER+=" --setup $_setup_name"
 # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
 # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
 PARAMSRV_LOG="parmq_$LOGFILETAG"
diff --git a/MQ/parmq/CMakeLists.txt b/MQ/parmq/CMakeLists.txt
index c1de1a42c6..3f6c9f8988 100644
--- a/MQ/parmq/CMakeLists.txt
+++ b/MQ/parmq/CMakeLists.txt
@@ -1,6 +1,9 @@
 Set(INCLUDE_DIRECTORIES
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_SOURCE_DIR}/MQ/base
+    ${CBMDATA_DIR} # For CbmDefs, needed by CbmSetup
+    ${CBMROOT_SOURCE_DIR}/sim/transport/steer # For CbmSetup.h!
+    ${CBMROOT_SOURCE_DIR}/sim/transport/geosetup # For CbmGeoSetupDbProvider.h, needed by CbmSetup
 )
 
 Set(SYSTEM_INCLUDE_DIRECTORIES
@@ -10,6 +13,7 @@ Set(SYSTEM_INCLUDE_DIRECTORIES
   ${FAIRMQ_INCLUDE_DIR}/options
   ${Boost_INCLUDE_DIR}
   ${ZeroMQ_INCLUDE_DIR}
+  ${FAIRLOGGER_INCLUDE_DIR} # For CbmSetup.h!
 )
 
 Include_Directories(${INCLUDE_DIRECTORIES})
@@ -51,8 +55,8 @@ If(FAIRLOGGER_FOUND)
 EndIf()
 
 Set(EXE_NAME parmq-server)
-Set(SRCS 
-  ParameterMQServer.cxx 
+Set(SRCS
+  ParameterMQServer.cxx
   runParameterMQServer.cxx
 #  CbmMQTestContFact.cxx
 )
@@ -64,11 +68,14 @@ Set(DEPENDENCIES
   Core
   Net
   Geom
+  CbmBase
+  CbmData
   CbmField
   CbmTofBase
   CbmStsBase
   CbmStsSim
   CbmSimBase
+  CbmSimSteer # for CbmSetup!
   CbmFlibMcbm2018
 )
 GENERATE_EXECUTABLE()
diff --git a/MQ/parmq/ParameterMQServer.cxx b/MQ/parmq/ParameterMQServer.cxx
index b0587fa434..58275549db 100644
--- a/MQ/parmq/ParameterMQServer.cxx
+++ b/MQ/parmq/ParameterMQServer.cxx
@@ -1,8 +1,8 @@
 /********************************************************************************
  *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
  *                                                                              *
- *              This software is distributed under the terms of the             * 
- *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *  
+ *              This software is distributed under the terms of the             *
+ *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *
  *                  copied verbatim in the file "LICENSE"                       *
  ********************************************************************************/
 /**
@@ -15,6 +15,7 @@
 #include "ParameterMQServer.h"
 
 #include "CbmMQDefs.h"
+#include "CbmSetup.h"
 
 #include "FairMQLogger.h"
 #include "FairMQProgOptions.h"
@@ -34,13 +35,6 @@ using namespace std;
 
 ParameterMQServer::ParameterMQServer()
   : fRtdb(FairRuntimeDb::instance())
-  , fFirstInputName("first_input.root")
-  , fFirstInputType("ROOT")
-  , fSecondInputName("")
-  , fSecondInputType("ROOT")
-  , fOutputName("")
-  , fOutputType("ROOT")
-  , fChannelName("data")
 {
 }
 
@@ -75,6 +69,8 @@ void ParameterMQServer::InitTask()
   fOutputType      = fConfig->GetValue<string>("output-type");
   fChannelName     = fConfig->GetValue<string>("channel-name");
 
+  fsSetupName = fConfig->GetValue<std::string>("setup");
+
   if (fRtdb != 0) {
     // Set first input
     if (fFirstInputType == "ROOT") {
@@ -146,6 +142,13 @@ void ParameterMQServer::InitTask()
     }
   }
   fRtdb->print();
+
+  // -----   CbmSetup   -----------------------------------------------------
+  if ("" != fsSetupName) {
+    fSetup = CbmSetup::Instance();
+    fSetup->LoadSetup(fsSetupName.data());
+  }
+  // ------------------------------------------------------------------------
 }
 
 void ParameterMQServer::Run()
@@ -160,45 +163,75 @@ void ParameterMQServer::Run()
       string reqStr(static_cast<char*>(req->GetData()), req->GetSize());
       LOG(info) << "Received parameter request from client: \"" << reqStr << "\"";
 
-      size_t pos              = reqStr.rfind(",");
-      string newParameterName = reqStr.substr(0, pos);
-      int runId               = stoi(reqStr.substr(pos + 1));
-      LOG(info) << "Parameter name: " << newParameterName;
-      LOG(info) << "Run ID: " << runId;
-
-      LOG(info) << "Retrieving parameter...";
-      // Check if the parameter name has changed to avoid getting same container repeatedly
-      if (newParameterName != parameterName) {
-        parameterName = newParameterName;
-        par           = static_cast<FairParGenericSet*>(fRtdb->getContainer(parameterName.c_str()));
+      if ("setup" == reqStr) {
+        // TODO: support for multiple setups on Par Server? with request containing setup name?
+        if ("" != fsSetupName && fSetup) {
+          /// Prepare serialized versions of the CbmSetup
+          CbmSetupStorable exchangableSetup(fSetup);
+
+          TMessage* tmsg = new TMessage(kMESS_OBJECT);
+          tmsg->WriteObject(&exchangableSetup);
+
+          FairMQMessagePtr rep(NewMessage(
+            tmsg->Buffer(), tmsg->BufferSize(),
+            [](void* /*data*/, void* object) { delete static_cast<TMessage*>(object); }, tmsg));
+
+          if (Send(rep, fChannelName, 0) < 0) {
+            LOG(error) << "failed sending reply to Setup request";
+            break;
+          }
+        }
+        else {
+          LOG(error) << "CbmSetup uninitialized!";
+          // Send an empty message back to keep the REQ/REP cycle
+          FairMQMessagePtr rep(NewMessage());
+          if (Send(rep, fChannelName, 0) < 0) {
+            LOG(error) << "failed sending reply to Setup request";
+            break;
+          }
+        }
       }
-      LOG(info) << "Retrieving parameter...Done";
+      else {
+        size_t pos              = reqStr.rfind(",");
+        string newParameterName = reqStr.substr(0, pos);
+        int runId               = stoi(reqStr.substr(pos + 1));
+        LOG(info) << "Parameter name: " << newParameterName;
+        LOG(info) << "Run ID: " << runId;
+
+        LOG(info) << "Retrieving parameter...";
+        // Check if the parameter name has changed to avoid getting same container repeatedly
+        if (newParameterName != parameterName) {
+          parameterName = newParameterName;
+          par           = static_cast<FairParGenericSet*>(fRtdb->getContainer(parameterName.c_str()));
+        }
+        LOG(info) << "Retrieving parameter...Done";
 
-      if (-1 != runId) { fRtdb->initContainers(runId); }
+        if (-1 != runId) { fRtdb->initContainers(runId); }
 
-      LOG(info) << "Sending following parameter to the client:";
-      if (par) {
-        par->print();
+        LOG(info) << "Sending following parameter to the client:";
+        if (par) {
+          par->print();
 
-        TMessage* tmsg = new TMessage(kMESS_OBJECT);
-        tmsg->WriteObject(par);
+          TMessage* tmsg = new TMessage(kMESS_OBJECT);
+          tmsg->WriteObject(par);
 
-        FairMQMessagePtr rep(NewMessage(
-          tmsg->Buffer(), tmsg->BufferSize(),
-          [](void* /*data*/, void* object) { delete static_cast<TMessage*>(object); }, tmsg));
+          FairMQMessagePtr rep(NewMessage(
+            tmsg->Buffer(), tmsg->BufferSize(),
+            [](void* /*data*/, void* object) { delete static_cast<TMessage*>(object); }, tmsg));
 
-        if (Send(rep, fChannelName, 0) < 0) {
-          LOG(error) << "failed sending reply";
-          break;
+          if (Send(rep, fChannelName, 0) < 0) {
+            LOG(error) << "failed sending reply";
+            break;
+          }
         }
-      }
-      else {
-        LOG(error) << "Parameter uninitialized!";
-        // Send an empty message back to keep the REQ/REP cycle
-        FairMQMessagePtr rep(NewMessage());
-        if (Send(rep, fChannelName, 0) < 0) {
-          LOG(error) << "failed sending reply";
-          break;
+        else {
+          LOG(error) << "Parameter uninitialized!";
+          // Send an empty message back to keep the REQ/REP cycle
+          FairMQMessagePtr rep(NewMessage());
+          if (Send(rep, fChannelName, 0) < 0) {
+            LOG(error) << "failed sending reply";
+            break;
+          }
         }
       }
     }
diff --git a/MQ/parmq/ParameterMQServer.h b/MQ/parmq/ParameterMQServer.h
index 1994099536..949b293e08 100644
--- a/MQ/parmq/ParameterMQServer.h
+++ b/MQ/parmq/ParameterMQServer.h
@@ -1,8 +1,8 @@
 /********************************************************************************
  *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
  *                                                                              *
- *              This software is distributed under the terms of the             * 
- *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *  
+ *              This software is distributed under the terms of the             *
+ *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *
  *                  copied verbatim in the file "LICENSE"                       *
  ********************************************************************************/
 /**
@@ -20,6 +20,7 @@
 #include <string>
 
 class FairRuntimeDb;
+class CbmSetup;
 
 class ParameterMQServer : public FairMQDevice {
 public:
@@ -50,16 +51,19 @@ public:
   std::string GetChannelName() { return fChannelName; }
 
 private:
-  FairRuntimeDb* fRtdb;
+  FairRuntimeDb* fRtdb = nullptr;
+  CbmSetup* fSetup     = nullptr;
 
-  std::string fFirstInputName;
-  std::string fFirstInputType;
-  std::string fSecondInputName;
-  std::string fSecondInputType;
-  std::string fOutputName;
-  std::string fOutputType;
+  std::string fFirstInputName  = "first_input.root";
+  std::string fFirstInputType  = "ROOT";
+  std::string fSecondInputName = "";
+  std::string fSecondInputType = "ROOT";
+  std::string fOutputName      = "";
+  std::string fOutputType      = "ROOT";
 
-  std::string fChannelName;
+  std::string fChannelName = "data";
+
+  std::string fsSetupName = "";
 };
 
 #endif /* PARAMETERMQSERVER_H_ */
diff --git a/MQ/parmq/runParameterMQServer.cxx b/MQ/parmq/runParameterMQServer.cxx
index efa757200c..e9d58b2a60 100644
--- a/MQ/parmq/runParameterMQServer.cxx
+++ b/MQ/parmq/runParameterMQServer.cxx
@@ -1,8 +1,8 @@
 /********************************************************************************
  *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
  *                                                                              *
- *              This software is distributed under the terms of the             * 
- *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *  
+ *              This software is distributed under the terms of the             *
+ *         GNU Lesser General Public Licence version 3 (LGPL) version 3,        *
  *                  copied verbatim in the file "LICENSE"                       *
  ********************************************************************************/
 /**
@@ -20,14 +20,22 @@ namespace bpo = boost::program_options;
 void addCustomOptions(bpo::options_description& options)
 {
   options.add_options()("first-input-name", bpo::value<std::string>()->default_value("first_input.root"),
-                        "First input file name")("first-input-type", bpo::value<std::string>()->default_value("ROOT"),
-                                                 "First input file type (ROOT/ASCII)")(
-    "second-input-name", bpo::value<std::string>()->default_value(""), "Second input file name")(
-    "second-input-type", bpo::value<std::string>()->default_value("ROOT"), "Second input file type (ROOT/ASCII)")(
-    "libs-to-load", bpo::value<std::string>()->default_value(""),
-    "List of libraries to load")("output-name", bpo::value<std::string>()->default_value(""), "Output file name")(
-    "output-type", bpo::value<std::string>()->default_value("ROOT"),
-    "Output file type")("channel-name", bpo::value<std::string>()->default_value("data"), "Output channel name");
+                        "First input file name");
+  options.add_options()("first-input-type", bpo::value<std::string>()->default_value("ROOT"),
+                        "First input file type (ROOT/ASCII)");
+
+  options.add_options()("second-input-name", bpo::value<std::string>()->default_value(""), "Second input file name");
+  options.add_options()("second-input-type", bpo::value<std::string>()->default_value("ROOT"),
+                        "Second input file type (ROOT/ASCII)");
+
+  options.add_options()("libs-to-load", bpo::value<std::string>()->default_value(""), "List of libraries to load");
+
+  options.add_options()("output-name", bpo::value<std::string>()->default_value(""), "Output file name");
+  options.add_options()("output-type", bpo::value<std::string>()->default_value("ROOT"), "Output file type");
+
+  options.add_options()("channel-name", bpo::value<std::string>()->default_value("data"), "Output channel name");
+
+  options.add_options()("setup", bpo::value<std::string>()->default_value(""), "Name/tag of the geomatry setup");
 }
 
 FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new ParameterMQServer(); }
diff --git a/sim/transport/steer/CbmSetup.cxx b/sim/transport/steer/CbmSetup.cxx
index 6b0a7b17f7..88ed27f365 100644
--- a/sim/transport/steer/CbmSetup.cxx
+++ b/sim/transport/steer/CbmSetup.cxx
@@ -42,6 +42,25 @@ CbmSetup* CbmSetup::fgInstance = NULL;
 void CbmSetup::Clear(Option_t*) { fProvider->Reset(); }
 // -------------------------------------------------------------------------
 
+// -----   Load a stored/exchanged copy of the setup   ---------------------
+void CbmSetup::LoadStoredSetup(CbmSetupStorable* setupIn)
+{
+  CbmGeoSetupRepoProvider* ptrRepoProv = setupIn->GetRepoProvPtr();
+  if (nullptr == ptrRepoProv) {
+    CbmGeoSetupDbProvider* ptrDbProv = setupIn->GetDbProvPtr();
+    if (nullptr == ptrDbProv) {
+      /// To avoid clang format one-lining
+      LOG(error) << "Could not  leod event as storable even does not contain any provider";
+    }
+    else {
+      SetProvider(ptrDbProv);
+    }
+  }
+  else {
+    SetProvider(ptrRepoProv);
+  }
+}
+// -------------------------------------------------------------------------
 
 // -----   Get field map type   --------------------------------------------
 CbmFieldMap* CbmSetup::CreateFieldMap()
diff --git a/sim/transport/steer/CbmSetup.h b/sim/transport/steer/CbmSetup.h
index 4ded7e0b3b..8ff24d4d00 100644
--- a/sim/transport/steer/CbmSetup.h
+++ b/sim/transport/steer/CbmSetup.h
@@ -28,6 +28,7 @@
 class FairModule;
 class FairRunSim;
 class CbmFieldMap;
+class CbmSetupStorable;
 
 enum ECbmSetupSource
 {
@@ -51,6 +52,10 @@ public:
      **/
   virtual void Clear(Option_t* opt = "");
 
+  /** Load a stored/exchanged copy of the setup
+     **/
+  void LoadStoredSetup(CbmSetupStorable* setupIn);
+
   /** Load setup modules, field and media.
      ** Afterward the parameters can be overriden over the provider
      ** See CbmGeoSetupProvider::GetSetup() for details
@@ -184,7 +189,7 @@ public:
 
 
   /** @brief Set the geo setup provider
-     ** @param value provider 
+     ** @param value provider
      ** This class takes the ownership of the provider
      **/
   void SetProvider(CbmGeoSetupProvider* value)
@@ -210,4 +215,53 @@ private:
   ClassDef(CbmSetup, 3);
 };
 
+
+class CbmSetupStorable : public TNamed {
+public:
+  /** Default constructor **/
+  CbmSetupStorable() : TNamed("CBM Setup", "") {};
+
+  /** Destructor **/
+  ~CbmSetupStorable() {};
+
+  /** Copy constructor and assignment operator (not implemented ) **/
+  CbmSetupStorable(const CbmSetupStorable& rhs) : TNamed(rhs)
+  {
+    if (nullptr != rhs.fProviderRepo) {
+      /// To avoid clang format one-lining
+      fProviderRepo = new CbmGeoSetupRepoProvider(*(rhs.fProviderRepo));
+    }
+    else if (nullptr != fProviderDb) {
+      /// To avoid clang format one-lining
+      fProviderDb = new CbmGeoSetupDbProvider(*(rhs.fProviderDb));
+    }
+  }
+
+  /** Constructor from CbmSetup object **/
+  CbmSetupStorable(CbmSetup* rawSetup)
+  {
+    CbmGeoSetupProvider* ptrGenProv      = rawSetup->GetProvider();
+    CbmGeoSetupRepoProvider* ptrRepoProv = dynamic_cast<CbmGeoSetupRepoProvider*>(ptrGenProv);
+    if (nullptr == ptrRepoProv) {
+      /// To avoid clang format one-lining
+      CbmGeoSetupDbProvider* ptrDbProv = dynamic_cast<CbmGeoSetupDbProvider*>(ptrGenProv);
+      if (nullptr != ptrDbProv) {
+        /// To avoid clang format one-lining
+        fProviderDb = new CbmGeoSetupDbProvider(*ptrDbProv);
+      }
+    }
+    else {
+      fProviderRepo = new CbmGeoSetupRepoProvider(*ptrRepoProv);
+    }
+  }
+
+  CbmGeoSetupRepoProvider* GetRepoProvPtr() { return fProviderRepo; }
+  CbmGeoSetupDbProvider* GetDbProvPtr() { return fProviderDb; }
+
+private:
+  CbmGeoSetupRepoProvider* fProviderRepo = nullptr;
+  CbmGeoSetupDbProvider* fProviderDb     = nullptr;
+
+  ClassDef(CbmSetupStorable, 1);
+};
 #endif /* CBMSETUP_H */
diff --git a/sim/transport/steer/CbmSimSteerLinkDef.h b/sim/transport/steer/CbmSimSteerLinkDef.h
index 2708f8b177..c3a36c2f40 100644
--- a/sim/transport/steer/CbmSimSteerLinkDef.h
+++ b/sim/transport/steer/CbmSimSteerLinkDef.h
@@ -10,6 +10,7 @@
 
 // --- transport/base
 #pragma link C++ class CbmSetup + ;
+#pragma link C++ class CbmSetupStorable + ;
 #pragma link C++ class CbmTransport + ;
 #pragma link C++ class CbmVMCSettings + ;
 #pragma link C++ class CbmGeant3Settings + ;
-- 
GitLab