From 3e83afefbf3968f638dee0e1ff478d8eec9822f8 Mon Sep 17 00:00:00 2001
From: Dominik Smith <d.smith@gsi.de>
Date: Wed, 3 Jul 2024 17:22:56 +0200
Subject: [PATCH] Updated CbmTaskUnpack to reflect the current state of the
 online binary. Added macro run_unpack_tsa_algo.C with exemplary execution.

---
 macro/run/run_unpack_tsa_algo.C | 120 +++++++++++++++++
 reco/tasks/CbmReco.cxx          |   4 +-
 reco/tasks/CbmTaskUnpack.cxx    | 225 +++++++-------------------------
 reco/tasks/CbmTaskUnpack.h      |  28 ++--
 4 files changed, 180 insertions(+), 197 deletions(-)
 create mode 100644 macro/run/run_unpack_tsa_algo.C

diff --git a/macro/run/run_unpack_tsa_algo.C b/macro/run/run_unpack_tsa_algo.C
new file mode 100644
index 0000000000..2fd9dcd58a
--- /dev/null
+++ b/macro/run/run_unpack_tsa_algo.C
@@ -0,0 +1,120 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Jan de Cuveland, Volker Friese, Pierre-Alain Loizeau, Pascal Raisig [committer], Dominik Smith, Adrian A. Weber  */
+
+/** @file run_unpack_tsa_algo.C
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since May 2021
+ **/
+
+
+// --- Includes needed for IDE
+#include <RtypesCore.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+#if !defined(__CLING__)
+#include "CbmTrdRawMessageSpadic.h"
+#include "CbmTrdSpadic.h"
+
+#include <FairLogger.h>
+#include <FairRootFileSink.h>
+#include <FairRunOnline.h>
+#include <Logger.h>
+
+#include <TStopwatch.h>
+#include <TSystem.h>
+#endif
+
+void run_unpack_tsa_algo(std::string infile, std::string outpath, std::string paramsdir, UInt_t runid,
+                         std::int32_t nevents = -1)
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "INFO";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_unpack_tsa_algo";          // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+
+  // -----   Output filename   ----------------------------------------------
+  std::string outfilename = infile;
+  auto filenamepos        = infile.find_last_of("/");
+  filenamepos++;
+  std::string filename = infile.substr(filenamepos);
+  if (filename.find("*") != infile.npos) filename = std::to_string(runid) + ".tsa";
+  if (filename.find(";") != infile.npos) filename = std::to_string(runid) + "_merged" + ".tsa";
+  if (outpath.empty()) {
+    outpath = infile.substr(0, filenamepos);
+  }
+  outfilename = outpath + filename;
+  outfilename.replace(outfilename.find(".tsa"), 4, "_algo.digi.root");
+  std::cout << "-I- " << myName << ": Output file will be " << outfilename << std::endl;
+  // ------------------------------------------------------------------------
+
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  auto source = new CbmSourceTs(infile.c_str());
+
+  // -----   FairRunAna   ---------------------------------------------------
+  auto run  = new FairRunOnline(source);
+  auto sink = new FairRootFileSink(outfilename.data());
+
+  // -----    Algo Unpacker -------------------------------------------------
+  //run->AddTask(new CbmTaskUnpack());
+  run->AddTask(new CbmTaskUnpack(paramsdir, runid));
+
+  run->SetSink(sink);
+  auto eventheader = new CbmTsEventHeader();
+  run->SetRunId(runid);
+  run->SetEventHeader(eventheader);
+  // ------------------------------------------------------------------------
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  // ------------------------------------------------------------------------
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  if (nevents < 0)
+    run->Run(-1, 0);
+  else
+    run->Run(0, nevents);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "After CpuTime = " << timer.CpuTime() << " s RealTime = " << timer.RealTime() << " s." << std::endl;
+  // ------------------------------------------------------------------------
+
+  // --   Release all shared pointers to config before ROOT destroys things -
+  // => We need to destroy things by hand because run->Finish calls (trhought the FairRootManager) Source->Close which
+  //    does call the Source destructor, so due to share pointer things stay alive until out of macro scope...
+  run->SetSource(nullptr);
+  delete run;
+  // ------------------------------------------------------------------------
+
+}  // End of main macro function
diff --git a/reco/tasks/CbmReco.cxx b/reco/tasks/CbmReco.cxx
index 8d198b7c6e..84e865f39c 100644
--- a/reco/tasks/CbmReco.cxx
+++ b/reco/tasks/CbmReco.cxx
@@ -128,7 +128,9 @@ int32_t CbmReco::Run()
   if (!isRootInput) {
     CbmTaskUnpack::Config unpackConfig;
     unpackConfig.dumpSetup = fConfig.dumpSetup;
-    auto unpack            = make_unique<CbmTaskUnpack>(unpackConfig);
+    //auto unpack            = make_unique<CbmTaskUnpack>(unpackConfig);
+    // TO DO: This call no longer works. Parameters directory and run ID is needed!
+    auto unpack = make_unique<CbmTaskUnpack>();
     unpack->SetMonitor(fMonitor);
     unpack->SetOutputBranchPersistent("DigiTimeslice.", false);
     run.AddTask(unpack.release());
diff --git a/reco/tasks/CbmTaskUnpack.cxx b/reco/tasks/CbmTaskUnpack.cxx
index b7bcae797a..9fa2a88fda 100644
--- a/reco/tasks/CbmTaskUnpack.cxx
+++ b/reco/tasks/CbmTaskUnpack.cxx
@@ -18,6 +18,7 @@
 #include "CbmTrdParSetDigi.h"
 #include "CbmTrdParSpadic.h"
 #include "MicrosliceDescriptor.hpp"
+#include "ParFiles.h"
 #include "System.hpp"
 #include "bmon/ReadoutConfig.h"
 #include "sts/ChannelMaskSet.h"
@@ -42,8 +43,46 @@
 using namespace std;
 using namespace cbm::algo;
 
+
+// -----   Constructor   -----------------------------------------------------
+CbmTaskUnpack::CbmTaskUnpack() : FairTask("Unpack")
+{
+  L_(fatal) << "Instantiated CbmTaskUnpack() without arguments (needs path to parameters and run ID).";
+}
+
 // -----   Constructor   -----------------------------------------------------
-CbmTaskUnpack::CbmTaskUnpack(Config config) : FairTask("Unpack"), fConfig(config) {}
+CbmTaskUnpack::CbmTaskUnpack(fs::path paramsDir, uint32_t runId) : FairTask("Unpack")
+{
+  ParFiles parFiles(runId);
+  L_(info) << "Using parameter files for setup " << parFiles.setup;
+
+  sts::ReadoutSetup stsSetup = yaml::ReadFromFile<sts::ReadoutSetup>(paramsDir / parFiles.sts.readout);
+  auto chanMask              = yaml::ReadFromFile<sts::ChannelMaskSet>(paramsDir / parFiles.sts.chanMask);
+  auto walkMap               = yaml::ReadFromFile<sts::WalkMap>(paramsDir / parFiles.sts.walkMap);
+  sts::ReadoutConfig readout{stsSetup, chanMask};
+  sts::Unpack::Config stsCfg{.readout = readout, .walkMap = walkMap, .bCollectAuxData = false};
+  fStsUnpack = std::make_unique<sts::Unpack>(stsCfg);
+
+  tof::ReadoutSetup tofSetup = yaml::ReadFromFile<tof::ReadoutSetup>(paramsDir / parFiles.tof.readout);
+  tof::ReadoutConfig tofCfg{tofSetup};
+  fTofUnpack = std::make_unique<tof::Unpack>(tofCfg);
+
+  bmon::ReadoutSetup bmonSetup = yaml::ReadFromFile<bmon::ReadoutSetup>(paramsDir / parFiles.bmon.readout);
+  bmon::ReadoutConfig bmonCfg{bmonSetup};
+  fBmonUnpack = std::make_unique<bmon::Unpack>(bmonCfg);
+
+  auto trdCfg = yaml::ReadFromFile<trd::ReadoutConfig>(paramsDir / parFiles.trd.readout);
+  fTrdUnpack  = std::make_unique<trd::Unpack>(trdCfg);
+
+  auto trd2dCfg = yaml::ReadFromFile<trd2d::ReadoutConfig>(paramsDir / parFiles.trd.readout2d);
+  fTrd2dUnpack  = std::make_unique<trd2d::Unpack>(trd2dCfg);
+
+  much::ReadoutConfig muchCfg{};
+  fMuchUnpack = std::make_unique<much::Unpack>(muchCfg);
+
+  rich::ReadoutConfig richCfg{};
+  fRichUnpack = std::make_unique<rich::Unpack>(richCfg);
+}
 // ---------------------------------------------------------------------------
 
 
@@ -83,6 +122,11 @@ void CbmTaskUnpack::Exec(Option_t*)
   digis.fTrd   = RunUnpacker(fTrdUnpack, *timeslice, monitor);
   digis.fTrd2d = RunUnpacker(fTrd2dUnpack, *timeslice, monitor);
 
+  // Use lines below to combine TRD 1D and 2D
+  //auto& digis1d = digis.fTrd;
+  //auto& digis2d = digis.fTrd2d;
+  //std::copy(digis2d.begin(), digis2d.end(), std::back_inserter(digis1d));
+
   fTimeslice->fData = digis.ToStorable();
 
   // --- Timeslice log
@@ -165,189 +209,10 @@ InitStatus CbmTaskUnpack::Init()
   ioman->RegisterAny("DigiTimeslice.", fTimeslice, IsOutputBranchPersistent("DigiTimeslice."));
   LOG(info) << "--- Registered branch DigiTimeslice.";
 
-  // ---- Initialize unpacker
-
-  std::string bmonReadoutFile = Form("%s/parameters/online/BmonReadout_mcbm2022.yaml", std::getenv("VMCWORKDIR"));
-  auto bmonReadoutPars        = yaml::ReadFromFile<bmon::ReadoutSetup>(bmonReadoutFile);
-  fBmonUnpack                 = std::make_unique<bmon::Unpack>(bmon::ReadoutConfig{bmonReadoutPars});
-
-  fMuchUnpack = std::make_unique<much::Unpack>(much::ReadoutConfig{});
-  fRichUnpack = std::make_unique<rich::Unpack>(rich::ReadoutConfig{});
-
-  std::string stsReadoutFile     = Form("%s/parameters/online/StsReadout_mcbm2022.yaml", std::getenv("VMCWORKDIR"));
-  sts::ReadoutSetup readoutSetup = yaml::ReadFromFile<sts::ReadoutSetup>(stsReadoutFile);
-
-  std::string stsWalkMapFile = Form("%s/parameters/online/StsWalkMap_mcbm2022.yaml", std::getenv("VMCWORKDIR"));
-  auto walkMap               = yaml::ReadFromFile<sts::WalkMap>(stsWalkMapFile);
-
-  sts::ReadoutConfig readout{readoutSetup, sts::ChannelMaskSet()};
-  sts::Unpack::Config cfg{.readout = readout, .walkMap = walkMap};
-  fStsUnpack = std::make_unique<sts::Unpack>(cfg);
-
-  std::string tofReadoutFile = Form("%s/parameters/online/TofReadout_mcbm2022.yaml", std::getenv("VMCWORKDIR"));
-  auto tofReadoutPars        = yaml::ReadFromFile<tof::ReadoutSetup>(tofReadoutFile);
-  fTofUnpack                 = std::make_unique<tof::Unpack>(tof::ReadoutConfig{tofReadoutPars});
-  fTrdUnpack                 = std::make_unique<trd::Unpack>(InitTrdReadoutConfig());
-  fTrd2dUnpack               = std::make_unique<trd2d::Unpack>(InitTrd2dReadoutConfig());
-
-  if (fConfig.dumpSetup) {
-    DumpUnpackSetup();
-  }
-
   return kSUCCESS;
 }
 // ----------------------------------------------------------------------------
 
-// -----   Initialisation   ---------------------------------------------------
-cbm::algo::trd2d::ReadoutConfig CbmTaskUnpack::InitTrd2dReadoutConfig()
-{
-  // Output object
-  cbm::algo::trd2d::ReadoutConfig Trd2dConfig;
-
-  // Initialize input files
-  FairParAsciiFileIo asciiInput;
-  std::string digiparfile = Form("%s/parameters/trd/trd_v22h_mcbm.digi.par", std::getenv("VMCWORKDIR"));
-  std::string asicparfile = Form("%s/parameters/trd/trd_v22h_mcbm.asic.par", std::getenv("VMCWORKDIR"));
-
-  // Read the .digi file and store result
-  CbmTrdParSetDigi digiparset;
-  if (asciiInput.open(digiparfile.data())) {
-    digiparset.init(&asciiInput);
-  }
-  asciiInput.close();
-
-  // Read the .asic file and store result
-  CbmTrdParSetAsic asicparset;
-  if (asciiInput.open(asicparfile.data())) {
-    asicparset.init(&asciiInput);
-  }
-  asciiInput.close();
-
-  // Map (moduleId) -> (array of crobId)
-  std::map<uint32_t, uint16_t[NCROBMOD]> crobMap;
-  // Map (equipId, asicId, chanId) -> (pad address, mask flag, daq offset [FASP clk])
-  std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint64_t>>>> channelMap;
-
-  // Loop through a list of module IDs from the .digi file (can in principle contradict crob_map).
-  for (auto entry : digiparset.GetModuleMap()) {
-
-    const auto moduleId = entry.first;
-
-    // Get ASIC parameters for this module
-    CbmTrdParModAsic* setDet = static_cast<CbmTrdParModAsic*>(asicparset.GetModulePar(moduleId));
-    if (!setDet) continue;
-    if (setDet->GetAsicType() != CbmTrdDigi::eCbmTrdAsicType::kFASP) continue;
-    auto digipar = entry.second;
-
-    const int* crobs = setDet->GetCrobAddresses();
-    for (int icrob(0); icrob < NCROBMOD; icrob++)
-      crobMap[moduleId][icrob] = crobs[icrob];
-
-    // Loop through ASICs for this module
-    std::vector<int32_t> addresses;
-    setDet->GetAsicAddresses(&addresses);
-    for (auto add : addresses) {
-      //Get local IDs for this component / equipment.
-      const int32_t fasp_in_mod = add - 1000 * moduleId;
-      const int32_t fasp_in_eq  = fasp_in_mod % (NFASPCROB);
-      const int32_t crob_in_mod = fasp_in_mod / (NFASPCROB);
-      const uint16_t eq_id      = crobMap[moduleId][crob_in_mod];
-
-      // ASIC parameter set
-      CbmTrdParFasp* fasppar = (CbmTrdParFasp*) setDet->GetAsicPar(add);
-
-      // Loop through channels for this ASIC and fill map
-      for (int chan = 0; chan < fasppar->GetNchannels(); chan++) {
-        const CbmTrdParFaspChannel* faspch = fasppar->GetChannel(chan);
-        const int32_t pad                  = fasppar->GetPadAddress(chan) * (faspch->HasPairingR() ? 1 : -1);
-        const bool isMasked                = faspch->IsMasked();
-        uint64_t daq_offset                = 0;
-        if (((CbmTrdParModDigi*) digipar)->GetPadRow(pad) % 2 == 0) daq_offset = 3;
-        channelMap[eq_id][fasp_in_eq][chan] = std::make_tuple(pad, isMasked, daq_offset);
-      }
-    }
-  }
-
-  Trd2dConfig.InitComponentMap(crobMap);
-  Trd2dConfig.InitChannelMap(channelMap);
-  return Trd2dConfig;
-}
-
-// -----   Initialisation   ---------------------------------------------------
-cbm::algo::trd::ReadoutConfig CbmTaskUnpack::InitTrdReadoutConfig()
-{
-  // Output object
-  cbm::algo::trd::ReadoutConfig TrdConfig;
-
-  std::string trdparfile = Form("%s/parameters/trd/trd_v22h_mcbm.asic.par", std::getenv("VMCWORKDIR"));
-
-  CbmTrdParSetAsic trdpar;
-
-  FairParAsciiFileIo asciiInput;
-  if (asciiInput.open(trdparfile.data())) {
-    trdpar.init(&asciiInput);
-  }
-
-  FairParamList parlist;
-  trdpar.putParams(&parlist);
-
-  std::vector<int> moduleIds(trdpar.GetNrOfModules());
-  parlist.fill("ModuleId", moduleIds.data(), moduleIds.size());
-
-  std::map<size_t, std::map<size_t, std::map<size_t, size_t>>> addressMap;  //[criId][crobId][elinkId] -> asicAddress
-  std::map<size_t, std::map<size_t, std::map<size_t, std::map<size_t, size_t>>>>
-    channelMap;  //[criId][crobId][elinkId][chanId] -> chanAddress
-
-  for (auto module : moduleIds) {
-    CbmTrdParModAsic* moduleSet = (CbmTrdParModAsic*) trdpar.GetModulePar(module);
-
-    // Skip entries for "Fasp" modules in .asic.par file
-    if (moduleSet->GetAsicType() != CbmTrdDigi::eCbmTrdAsicType::kSPADIC) continue;
-
-    std::vector<int> asicAddresses;
-    moduleSet->GetAsicAddresses(&asicAddresses);
-
-    for (auto address : asicAddresses) {
-      CbmTrdParSpadic* asicPar = (CbmTrdParSpadic*) moduleSet->GetAsicPar(address);
-      const uint16_t criId     = asicPar->GetCriId();
-      const uint8_t crobId     = asicPar->GetCrobId();
-      const uint8_t elinkId    = asicPar->GetElinkId(0);
-      if (elinkId >= 98) {
-        continue;
-      }  // Don't add not connected asics to the map
-      addressMap[criId][crobId][elinkId]     = address;
-      addressMap[criId][crobId][elinkId + 1] = address;
-
-      const uint8_t numChans = 16;
-      for (uint8_t chan = 0; chan < numChans; chan++) {
-        auto asicChannelId                       = (elinkId % 2) == 0 ? chan : chan + numChans;
-        auto chanAddr                            = asicPar->GetChannelAddresses().at(asicChannelId);
-        channelMap[criId][crobId][elinkId][chan] = chanAddr;
-      }
-      for (uint8_t chan = 0; chan < numChans; chan++) {
-        auto asicChannelId                           = (elinkId + 1 % 2) == 0 ? chan : chan + numChans;
-        auto chanAddr                                = asicPar->GetChannelAddresses().at(asicChannelId);
-        channelMap[criId][crobId][elinkId + 1][chan] = chanAddr;
-      }
-      LOG(debug) << "componentID " << asicPar->GetComponentId() << " "
-                 << "address " << address << " key " << criId << " " << unsigned(crobId) << " " << unsigned(elinkId);
-    }
-  }
-  TrdConfig.Init(addressMap, channelMap);
-  LOG(debug) << TrdConfig.PrintReadoutMap();
-  return TrdConfig;
-}
-
-void CbmTaskUnpack::DumpUnpackSetup()
-{
-  LOG(info) << "--- Dumping readout setup to yaml file ---";
-
-  auto yaml = yaml::Dump{}(fTrdUnpack->Readout());
-  std::ofstream("TrdReadoutSetup.yaml") << yaml;
-
-  yaml = yaml::Dump{}(fTrd2dUnpack->Readout());
-  std::ofstream("Trd2dReadoutSetup.yaml") << yaml;
-}
 
 template<class Unpacker>
 auto CbmTaskUnpack::RunUnpacker(const std::unique_ptr<Unpacker>& unpacker, const fles::Timeslice& timeslice,
diff --git a/reco/tasks/CbmTaskUnpack.h b/reco/tasks/CbmTaskUnpack.h
index ccb50f7a87..69cec6e193 100644
--- a/reco/tasks/CbmTaskUnpack.h
+++ b/reco/tasks/CbmTaskUnpack.h
@@ -21,6 +21,7 @@ namespace cbm
 
 #include "AlgoTraits.h"
 #include "EventBuilder.h"
+#include "ParFiles.h"
 #include "bmon/Unpack.h"
 #include "much/Unpack.h"
 #include "rich/Unpack.h"
@@ -31,12 +32,15 @@ namespace cbm
 
 #include <FairTask.h>
 
+#include <boost/filesystem.hpp>
+
 #include <sstream>
 #include <vector>
 
 class CbmDigiManager;
 class CbmSourceTs;
 
+namespace fs = boost::filesystem;
 
 /** @class CbmTaskUnpack
  ** @brief Task class for associating digis to events
@@ -51,8 +55,7 @@ class CbmSourceTs;
  **/
 class CbmTaskUnpack : public FairTask {
 
-
-public:
+ public:
   struct Config {
     bool dumpSetup = false;
   };
@@ -65,7 +68,11 @@ public:
   };
 
   /** @brief Constructor **/
-  CbmTaskUnpack(Config config);
+  CbmTaskUnpack();
+
+
+  /** @brief Constructor **/
+  CbmTaskUnpack(fs::path paramsDir, uint32_t runId);
 
 
   /** @brief Copy constructor (disabled) **/
@@ -92,22 +99,11 @@ public:
   void SetMonitor(cbm::Monitor* monitor) { fMonitor = monitor; }
 
 
-private:  // methods
+ private:  // methods
   /** @brief Task initialisation **/
   virtual InitStatus Init();
 
-  /** @brief Initialisation of address maps for Trd **/
-  cbm::algo::trd::ReadoutConfig InitTrdReadoutConfig();
-
-
-  /** @brief Initialisation of address maps for Trd2d **/
-  cbm::algo::trd2d::ReadoutConfig InitTrd2dReadoutConfig();
-
-  void DumpUnpackSetup();
-
-private:  // members
-  Config fConfig = {};  ///< Configuration
-
+ private:  // members
   CbmSourceTs* fSource   = nullptr;
   cbm::Monitor* fMonitor = nullptr;
   std::string fHostname;
-- 
GitLab