diff --git a/algo/detectors/rich/UnpackMS.cxx b/algo/detectors/rich/UnpackMS.cxx index 7460c6bfb915dd983819a7242529ec0c0fec274c..07c826e6d023c9f1f0dd3e11850bc302aeb8e37e 100644 --- a/algo/detectors/rich/UnpackMS.cxx +++ b/algo/detectors/rich/UnpackMS.cxx @@ -166,6 +166,11 @@ namespace cbm::algo::rich void UnpackMS::ProcessSubSubEvent(rich::MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId, MSContext& ctx) const { + bool wasHeader = false; + bool wasEpoch = false; + bool wasTime = false; + bool wasTrailer = false; + uint32_t epoch = 0; // store last epoch obtained in sub-sub-event // Store last raising edge time for each channel or -1. if no time @@ -179,19 +184,67 @@ namespace cbm::algo::rich } return; } + // Skip SubSubEvent for CTS and unknown DiRICH addresses + // TODO: properly handle/skip CTS subsubevents + if (fParams.fElinkParams.end() == fParams.fElinkParams.find(subSubEventId)) { + if (0x8000 != (subSubEventId & 0xF000)) { + // No log for CTS subsubevents + L_(debug) << "Unknown DiRICH ID 0x" << std::hex << subSubEventId << std::dec + << ": Stopping processing of this subsubevent!!!"; + } + ctx.monitor.fNumCtsAndUnmappedDirich++; + ctx.monitor.fNumSkippedSubsubevent++; + for (int i = 0; i < nofTimeWords; i++) { + reader.NextWord(); + } + return; + } + + // Catch Subsubevents where some of the 3 "mandatory words" is missing + // but this lack was properly accounted/detected by the TRBnet/CTS + // => Otherwise the final readout of the Trailer word offsets the next + // subsubevent + if (nofTimeWords < 3) { + ctx.monitor.fNumSkippedSubsubevent++; + for (int i = 0; i < nofTimeWords; i++) { + reader.NextWord(); + } + return; + } + // First word is expected to be of type "header" if (GetTdcWordType(reader.NextWord()) != TdcWordType::Header) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": 1st message is not a TDC Header, skipping subsubevent"; ctx.monitor.fNumErrInvalidFirstMessage++; + ctx.monitor.fNumSkippedSubsubevent++; + for (int i = 1; i < nofTimeWords; i++) { + reader.NextWord(); + } + return; + } + else { + wasHeader = true; } // Second word is expected to be of type "epoch" uint32_t word = reader.NextWord(); if (GetTdcWordType(word) != TdcWordType::Epoch) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": 2nd message is not an epoch, skipping subsubevent"; ctx.monitor.fNumErrInvalidSecondMessage++; + ctx.monitor.fNumSkippedSubsubevent++; + // Currently skip the subsubevent + // TODO: Check if possible to only skip to next Epoch and continue from there + for (int i = 2; i < nofTimeWords; i++) { + reader.NextWord(); + } + return; } else { epoch = ProcessEpoch(word); + wasEpoch = true; } // Loop over words @@ -199,23 +252,69 @@ namespace cbm::algo::rich word = reader.NextWord(); switch (GetTdcWordType(word)) { case TdcWordType::TimeData: { + if (!wasHeader || !wasEpoch || wasTrailer) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": illegal position of TDC Time (before header/epoch or after trailer)"; + ctx.monitor.fNumErrWildTdcTime++; + ctx.monitor.fNumSkippedSubsubevent++; + // Currently skip the subsubevent + // TODO: Check if possible to only skip to next Epoch and continue from there + for (; i < nofTimeWords - 1; i++) { + reader.NextWord(); + } + return; + } + wasTime = true; ProcessTimeDataWord(epoch, word, subSubEventId, raisingTime, ctx); break; } case TdcWordType::Epoch: { + if (!wasHeader || wasTrailer) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": illegal position of TDC Epoch (before header or after trailer)"; + ctx.monitor.fNumErrWildEpoch++; + ctx.monitor.fNumSkippedSubsubevent++; + for (; i < nofTimeWords - 1; i++) { + reader.NextWord(); + } + return; + } + wasEpoch = true; epoch = ProcessEpoch(word); break; } case TdcWordType::Header: { + if (wasEpoch || wasTime || wasTrailer) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": illegal position of TDC Header (after time/epoch/trailer)"; + ctx.monitor.fNumErrWildHeaderMessage++; + ctx.monitor.fNumSkippedSubsubevent++; + for (; i < nofTimeWords - 1; i++) { + reader.NextWord(); + } + return; + } ctx.monitor.fNumErrWildHeaderMessage++; break; } case TdcWordType::Trailer: { + if (!wasEpoch || !wasTime || !wasHeader) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": illegal position of TDC Trailer (before time/epoch/header)"; + ctx.monitor.fNumErrWildTrailerMessage++; + ctx.monitor.fNumSkippedSubsubevent++; + for (; i < nofTimeWords - 1; i++) { + reader.NextWord(); + } + return; + } + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec << ": TDC Trailer too early, " + << (nofTimeWords - 1 - i) << " word(s) before last"; ctx.monitor.fNumErrWildTrailerMessage++; + wasTrailer = true; break; } case TdcWordType::Debug: { - break; // for the moment do nothing ctx.monitor.fNumDebugMessage++; break; @@ -228,18 +327,33 @@ namespace cbm::algo::rich } // Last word is expected to be of type "trailer" - if (GetTdcWordType(reader.NextWord()) != TdcWordType::Trailer) { + word = reader.NextWord(); + if (GetTdcWordType(word) != TdcWordType::Trailer) { + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec << ": Last word not a TDC trailer"; ctx.monitor.fNumErrInvalidLastMessage++; + if (GetTdcWordType(word) == TdcWordType::TimeData && !wasTrailer) { + if (ProcessTimeDataWord(epoch, word, subSubEventId, raisingTime, ctx)) { + ctx.monitor.fNumWarnRecoveredLastDigi++; + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": Rescuing TimeData in subsubevent with missing Trailer leading to saved Digi"; + } + else { + ctx.monitor.fNumErrOrphanRecovTimeData++; + L_(debug) << "DiRICH 0x" << std::hex << subSubEventId << std::dec + << ": Rescuing TimeData in subsubevent with missing Trailer w/o extra digi"; + } + } } } // ---- ProcessTimeDataWord ---- - void UnpackMS::ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, + bool UnpackMS::ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, std::vector<double>& raisingTime, MSContext& ctx) const { const TdcTimeData td = ProcessTimeData(tdcWord); const double fullTime = CalculateTime(epoch, td.fCoarse, td.fFine); + bool madeDigi = false; if (td.fChannel != 0) { const double dT = fullTime - ctx.prevLastCh0ReTime[ctx.currentSubSubEvent]; const double subtrigOffset = @@ -248,6 +362,7 @@ namespace cbm::algo::rich if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) { ctx.monitor.fNumErrChannelOutOfBounds++; + return false; } if (td.fIsRisingEdge) { // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched. @@ -260,6 +375,7 @@ namespace cbm::algo::rich if (ToT >= fToTMin && ToT <= fToTMax) { if (fullTimeCorr >= 0.0) { WriteOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT, ctx); + madeDigi = true; } } // pair was created, set raising edge to -1. @@ -267,6 +383,10 @@ namespace cbm::algo::rich } } } + else { + ctx.monitor.fNumErrChannelOutOfBounds++; + } + return madeDigi; } double UnpackMS::CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine) const diff --git a/algo/detectors/rich/UnpackMS.h b/algo/detectors/rich/UnpackMS.h index f89b2f58cf8a07000fe2a9b6cd67562ce6e99fa7..0dd092c3019de79a5f8627679b5b7ad4b86ee728 100644 --- a/algo/detectors/rich/UnpackMS.h +++ b/algo/detectors/rich/UnpackMS.h @@ -66,32 +66,41 @@ namespace cbm::algo::rich **/ struct UnpackMonitorData { uint32_t fNumDebugMessage = 0; ///< Received debug messages + uint32_t fNumCtsAndUnmappedDirich = 0; ///< Dirich address is unknown (or is of a CTS) uint32_t fNumErrInvalidFirstMessage = 0; ///< First message is not HEADER uint32_t fNumErrInvalidSecondMessage = 0; ///< Second message is not EPOCH uint32_t fNumErrInvalidLastMessage = 0; ///< Last message is not TRAILER uint32_t fNumErrWildHeaderMessage = 0; ///< TDC header in invalid position uint32_t fNumErrWildTrailerMessage = 0; ///< TDC trailer in invalid position + uint32_t fNumErrWildEpoch = 0; ///< TDC epoch in invalid position + uint32_t fNumErrWildTdcTime = 0; ///< TDC time (digi) in invalid position uint32_t fNumErrTdcErrorWord = 0; ///< TDC word of error type uint32_t fNumErrChannelOutOfBounds = 0; ///< TDC channel out of bounds + uint32_t fNumErrOrphanRecovTimeData = 0; ///< TimeData in last position (not TRAILER) but not creating a Digi + uint32_t fNumWarnRecoveredLastDigi = 0; ///< TimeData in last position (not TRAILER) led to recovered Digi uint32_t fNumErrInvalidHubId = 0; ///< "SubSubEvent" has invalid ID uint32_t fNumErrInvalidHubSize = 0; ///< Premature end of hub block - uint32_t fNumErrExcessLastWords = 0; ///< More than exprected trailing words + uint32_t fNumErrExcessLastWords = 0; ///< More than expected trailing words + uint32_t fNumSkippedSubsubevent = 0; ///< Whenever subsubevent skipped due to error (but not mask) - bool HasErrors() + bool HasErrors() const { uint32_t numErrors = fNumDebugMessage + fNumErrInvalidFirstMessage + fNumErrInvalidSecondMessage + fNumErrInvalidLastMessage + fNumErrWildHeaderMessage + fNumErrWildTrailerMessage - + fNumErrTdcErrorWord + fNumErrChannelOutOfBounds + fNumErrInvalidHubId - + fNumErrInvalidHubSize + fNumErrExcessLastWords; + + fNumErrWildEpoch + fNumErrWildTdcTime + fNumErrTdcErrorWord + fNumErrChannelOutOfBounds + + fNumErrOrphanRecovTimeData + fNumErrInvalidHubId + fNumErrInvalidHubSize + + fNumErrExcessLastWords; return (numErrors > 0 ? true : false); } - std::string print() + std::string print() const { std::stringstream ss; - ss << "errors " << fNumDebugMessage << " | " << fNumErrInvalidFirstMessage << " | " << fNumErrInvalidSecondMessage - << " | " << fNumErrInvalidLastMessage << " | " << fNumErrWildHeaderMessage << " | " - << fNumErrWildTrailerMessage << " | " << fNumErrTdcErrorWord << " | " << fNumErrChannelOutOfBounds << " | " - << fNumErrInvalidHubId << " | " << fNumErrInvalidHubSize << " | " << fNumErrExcessLastWords << " | "; + ss << "errors " << fNumDebugMessage << " | " << fNumCtsAndUnmappedDirich << " | " << fNumErrInvalidFirstMessage + << " | " << fNumErrInvalidSecondMessage << " | " << fNumErrInvalidLastMessage << " | " + << fNumErrWildHeaderMessage << " | " << fNumErrWildTrailerMessage << " | " << fNumErrWildEpoch << " | " + << fNumErrWildTdcTime << " | " << fNumErrTdcErrorWord << " | " << fNumErrChannelOutOfBounds << " | " + << fNumErrOrphanRecovTimeData << " | " << fNumWarnRecoveredLastDigi << " | " << fNumErrInvalidHubId << " | " + << fNumErrInvalidHubSize << " | " << fNumErrExcessLastWords << " | " << fNumSkippedSubsubevent; return ss.str(); } }; @@ -153,7 +162,7 @@ namespace cbm::algo::rich void ProcessSubSubEvent(MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId, MSContext& ctx) const; - void ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, std::vector<double>& raisingTime, + bool ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, std::vector<double>& raisingTime, MSContext& ctx) const; TdcWordType GetTdcWordType(uint32_t tdcWord) const; diff --git a/macro/beamtime/mcbm2024/data/.gitignore b/macro/beamtime/mcbm2024/data/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4ea40f8315d27f24d50e2c0f6ac12ea00b5542f6 --- /dev/null +++ b/macro/beamtime/mcbm2024/data/.gitignore @@ -0,0 +1 @@ +*.root diff --git a/macro/beamtime/mcbm2024/run_unpack_tsa_rich_only.C b/macro/beamtime/mcbm2024/run_unpack_tsa_rich_only.C new file mode 100644 index 0000000000000000000000000000000000000000..651bfa2ff7fa0e6488a94f204f68e8f6b3df4c5e --- /dev/null +++ b/macro/beamtime/mcbm2024/run_unpack_tsa_rich_only.C @@ -0,0 +1,808 @@ +/* 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.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 + +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, bool fasp = false); +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline = false); +std::shared_ptr<CbmStsUnpackMonitor> GetStsMonitor(std::string treefilename, bool bDebugMode = false); +std::shared_ptr<CbmMuchUnpackMonitor> GetMuchMonitor(std::string treefilename, bool bDebugMode = false); +std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, bool bDebugMode = false); +std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false); +std::string defaultSetupName = "mcbm_beam_2021_07_surveyed"; + +void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid = 0, + std::string setupName = defaultSetupName, std::int32_t nevents = -1, bool bBmoninTof = false, + std::string outpath = "data/") +{ + + // ======================================================================== + // Adjust this part according to your requirements + + // --- Logger settings ---------------------------------------------------- + TString logLevel = "INFO"; + TString logVerbosity = "LOW"; + // ------------------------------------------------------------------------ + + // ----- Environment -------------------------------------------------- + TString myName = "run_unpack_tsa"; // this macro's name for screen output + TString srcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + + // ----- Potentially hardcode the infile ------------------------------ + + // std::string infile = srcDir + "/input/mcbm_run399_first20Ts.tsa"; + + // ------------------------------------------------------------------------ + + + // ----- Output filename ---------------------------------------------- + std::string outfilename = infile[0]; + auto filenamepos = infile[0].find_last_of("/"); + filenamepos++; + std::string filename = infile[0].substr(filenamepos); + if (filename.find("*") != infile[0].npos) filename = std::to_string(runid) + ".tsa"; + if (filename.find(";") != infile[0].npos) filename = std::to_string(runid) + "_merged" + ".tsa"; + if (outpath.empty()) { + outpath = infile[0].substr(0, filenamepos); + } + outfilename = outpath + filename; + if (bBmoninTof) { // + outfilename.replace(outfilename.find(".tsa"), 4, "_bmonintof.digi.root"); + } + else { + outfilename.replace(outfilename.find(".tsa"), 4, ".digi.root"); + } + std::cout << "-I- " << myName << ": Output file will be " << outfilename << std::endl; + // ------------------------------------------------------------------------ + + + // ----- Performance profiling ---------------------------------------- + // Set to true if you want some minimal performance profiling output + bool doPerfProfiling = true; + // Define if you want a special path and name for the performance profiling output file + std::string perfProfFileName = outpath + filename; + perfProfFileName.replace(perfProfFileName.find(".tsa"), 4, ".perf.root"); + // ------------------------------------------------------------------------ + + + // ----- CbmSetup ----------------------------------------------------- + /// Do automatic mapping only if not overridden by user or empty + if (defaultSetupName == setupName || "" == setupName) { + cbm::mcbm::ToForceLibLoad dummy; /// Needed to trigger loading of the library as no fct dict in ROOT6 and CLING + try { + setupName = cbm::mcbm::GetSetupFromRunId(runid); + } + catch (const std::invalid_argument& e) { + std::cout << "Error in mapping from runID to setup name: " << e.what() << std::endl; + return; + } + if (defaultSetupName != setupName) { + std::cout << "Automatic setup choice for run " << runid << ": " << setupName << std::endl; + } + } + auto cbmsetup = CbmSetup::Instance(); + cbmsetup->LoadSetup(setupName.c_str()); + + // ------------------------------------------------------------------------ + + // ----- UnpackerConfigs ---------------------------------------------- + + // ---- BMON ---- + std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr; + + if (!bBmoninTof) { + bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", runid); + if (bmonconfig) { + // bmonconfig->SetDebugState(); + bmonconfig->SetDoWriteOutput(); + // bmonconfig->SetDoWriteOptOutA("CbmBmonErrors"); + std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data()); + if (2610 < runid) { + parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2023/", srcDir.Data()); + } + if (2724 <= runid) { + parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2024/", srcDir.Data()); + } + bmonconfig->SetParFilesBasePath(parfilesbasepathBmon); + bmonconfig->SetParFileName("mBmonCriPar.par"); + bmonconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated + if (2160 <= runid) { + bmonconfig->SetSystemTimeOffset(-80); // [ns] value to be updated + } + if (2350 <= runid) { + bmonconfig->SetSystemTimeOffset(0); // [ns] value to be updated + } + /// Enable Monitor plots + // bmonconfig->SetMonitor(GetTofMonitor(outfilename, true)); + // if (2337 <= runid) { + // bmonconfig->GetMonitor()->SetSpillThreshold(250); + // bmonconfig->GetMonitor()->SetSpillThresholdNonPulser(100); + // } + } + } + // ------------- + + // ---- STS ---- + std::shared_ptr<CbmStsUnpackConfig> stsconfig = nullptr; + + stsconfig = std::make_shared<CbmStsUnpackConfig>(std::string(setupName), runid); + if (stsconfig) { + // stsconfig->SetDebugState(); + stsconfig->SetDoWriteOutput(); + stsconfig->SetDoWriteOptOutA("StsDigiPulser"); + std::string parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data()); + if (2060 <= runid) { + /// Starting to readout the U3 since 10/03/2022 Carbon run + parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data()); + } + stsconfig->SetParFilesBasePath(parfilesbasepathSts); + /// Enable duplicates rejection, Ignores the ADC for duplicates check + stsconfig->SetDuplicatesRejection(true, true); + /// Enable Monitor plots + //stsconfig->SetMonitor(GetStsMonitor(outfilename, true)); + stsconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated + if (2160 <= runid) { + stsconfig->SetSystemTimeOffset(-1075); // [ns] value to be updated + } + if (2350 <= runid) { + stsconfig->SetSystemTimeOffset(-970); // [ns] value to be updated + } + + // Noise removal + stsconfig->SetMinAdcCut(1, 1); // ADC cut to Station 0 Ladder 0 Module 0 + stsconfig->SetMinAdcCut(2, 1); // ADC cut to Station 0 Ladder 0 Module 0 + stsconfig->SetMinAdcCut(3, 1); // ADC cut to Station 0 Ladder 0 Module 1 + stsconfig->SetMinAdcCut(4, 1); // ADC cut to Station 0 Ladder 0 Module 1 + + // Masking noisy channels + std::ifstream mask_channels(Form("%s/sts_mask_channels.par", parfilesbasepathSts.data())); + int feb_idx, feb_chn; + while (mask_channels >> feb_idx >> feb_chn) { + stsconfig->MaskNoisyChannel(feb_idx, feb_chn); + } + + // Time Walk correction + std::map<uint32_t, CbmStsParModule> moduleWalkMap; + auto parAsic = new CbmStsParAsic(128, 31, 31., 1., 5., 800., 1000., 3.9789e-3); // Default ASIC parameters + auto parMod = new CbmStsParModule(2048, 128); // Generic STS module parameter object + + std::array<double, 31> tw_map = {}; // Default time walk map + parAsic->SetWalkCoef(tw_map); // Set generic ASIC par with no time walk correction + parMod->SetAllAsics(*parAsic); // Set generic module ASIC as default ASIC parameter configuration + + moduleWalkMap[0x10107C02] = CbmStsParModule(*parMod); // Make a copy for storage + moduleWalkMap[0x101FFC02] = CbmStsParModule(*parMod); // Make a copy for storage + + /// To be replaced by a storage in a new parameter class later + int sensor, asic; + std::ifstream asicTimeWalk_par(Form("%s/mStsAsicTimeWalk.par", parfilesbasepathSts.data())); + while (asicTimeWalk_par >> std::hex >> sensor >> std::dec >> asic) { // Read module and ASIC + LOG(debug) << Form("[STS] Reading %x %u", sensor, asic); + for (int adc = 0; adc < 31; adc++) { // Read time offset by ADC + asicTimeWalk_par >> tw_map[adc]; // Set time walk map offset value for given ADC + if (std::fabs(tw_map[adc]) > 100) { + LOG(warning) + << "[STS] Very large time walk parameter"; // Large offset values could indicate par file malformation + } + } // end ASIC idx loop + parAsic->SetWalkCoef(tw_map); // Set time walk map for the ASIC par obj + + if (!moduleWalkMap.count(sensor)) { // No parameters obj for given module + moduleWalkMap[sensor] = CbmStsParModule(*parMod); // Create CbmStsParModule obj for the loaded module + } + moduleWalkMap[sensor].SetAsic(asic, *parAsic); // Set ASIC parameter + + LOG(debug) << Form("\n[STS] Time Walk parameters loaded for: module %x, ASIC %u\n", sensor, asic); + } + + stsconfig->SetWalkMap(moduleWalkMap); + moduleWalkMap.clear(); + delete parMod; + delete parAsic; + } + // ------------- + + // ---- MUCH ---- + std::shared_ptr<CbmMuchUnpackConfig> muchconfig = nullptr; + + muchconfig = std::make_shared<CbmMuchUnpackConfig>(std::string(setupName), runid); + if (muchconfig) { + // muchconfig->SetDebugState(); + muchconfig->SetDoWriteOutput(); + muchconfig->SetDoWriteOptOutA("MuchDigiPulser"); + std::string parfilesbasepathMuch = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data()); + muchconfig->SetParFilesBasePath(parfilesbasepathMuch); + if (2060 <= runid && runid <= 2162) { + /// Starting to use CRI Based MUCH setup with 2GEM and 1 RPC since 09/03/2022 Carbon run + muchconfig->SetParFileName("mMuchParUpto26032022.par"); + } + else if (2163 <= runid && runid <= 2291) { + /// + muchconfig->SetParFileName("mMuchParUpto03042022.par"); + } + else if (2311 <= runid && runid <= 2315) { + /// + muchconfig->SetParFileName("mMuchParUpto10042022.par"); + } + else if (2316 <= runid && runid <= 2366) { + /// + muchconfig->SetParFileName("mMuchParUpto23052022.par"); + } + else if (2367 <= runid && runid <= 2397) { + /// Starting to use GEM 2 moved to CRI 0 on 24/05/2022 + muchconfig->SetParFileName("mMuchParUpto26052022.par"); + } + else { + /// Default file for all other runs (including 06/2022 Gold runs) + muchconfig->SetParFileName("mMuchPar.par"); + } + + + /// Enable duplicates rejection, Ignores the ADC for duplicates check + muchconfig->SetDuplicatesRejection(true, true); + /// Enable Monitor plots + //muchconfig->SetMonitor(GetMuchMonitor(outfilename, true)); + muchconfig->SetSystemTimeOffset(-2221); // [ns] value to be updated + if (2160 <= runid) { + muchconfig->SetSystemTimeOffset(-1020); // [ns] value to be updated + } + if (2350 <= runid) { + muchconfig->SetSystemTimeOffset(-980); // [ns] value to be updated + } + + // muchconfig->SetMinAdcCut(1, 1); + + // muchconfig->MaskNoisyChannel(3, 56); + //List of noisy channels *.txt file based on CbmMuchAddress is placed at the same location as par files + // + std::string NoisyChannelFilePath = parfilesbasepathMuch + "mMuChNoisyChannelMarch2022.txt"; + muchconfig->SetNoisyChannelFile(NoisyChannelFilePath); + } + // ------------- + + // ---- TRD ---- + std::shared_ptr<CbmTrdUnpackConfig> trd1Dconfig = nullptr; + + TString trdsetuptag = ""; + cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag); + // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid); + trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data()); + if (2724 <= runid) { + /// mCBM 2024 + trdsetuptag = "v24b_mcbm"; + } + if (trd1Dconfig) { + trd1Dconfig->SetDoWriteOutput(); + // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis + // trd1Dconfig->SetOutputBranchName("TrdSpadicDigi"); + // trd1Dconfig->SetDoWriteOptOutA(CbmTrdRawMessageSpadic::GetBranchName()); + // trd1Dconfig->SetDoWriteOptOutB("SpadicInfoMessages"); // SpadicInfoMessages + + std::string parfilesbasepathTrd = Form("%s/parameters/trd", srcDir.Data()); + trd1Dconfig->SetParFilesBasePath(parfilesbasepathTrd); + // trd1Dconfig->SetMonitor(GetTrdMonitor(outfilename)); + // Get the spadic configuration true = avg baseline active / false plain sample 0 + trd1Dconfig->SetSpadicObject(GetTrdSpadic(true)); + trd1Dconfig->SetSystemTimeOffset(0); // [ns] value to be updated + if (2160 <= runid) { + trd1Dconfig->SetSystemTimeOffset(1140); // [ns] value to be updated + } + if (2350 <= runid) { + trd1Dconfig->SetSystemTimeOffset(1300); // [ns] value to be updated + } + } + // ------------- + + // ---- TRDFASP2D ---- + std::shared_ptr<CbmTrdUnpackFaspConfig> trdfasp2dconfig = nullptr; + + trdfasp2dconfig = std::make_shared<CbmTrdUnpackFaspConfig>(trdsetuptag.Data()); + if (trdfasp2dconfig) { + // trdfasp2dconfig->SetDebugState(); + trdfasp2dconfig->SetDoWriteOutput(); + // Activate the line below to write Trd1D digis to a separate "TrdFaspDigi" branch. Can be used to separate between Fasp and Spadic digis + // trdfasp2dconfig->SetOutputBranchName("TrdFaspDigi"); + // uint8_t map[NFASPMOD]; + // uint16_t crob_map[NCROBMOD]; + // for (uint32_t i(0); i < NFASPMOD; i++) + // map[i] = i; + // if (runid <= 1588) { + // const size_t nfasps = 12; + // uint8_t map21[] = {9, 2, 3, 11, 10, 7, 8, 0, 1, 4, 6, 5}; + // for (uint32_t i(0); i < nfasps; i++) + // map[i] = map21[i]; + // uint16_t crob_map21[] = {0x00f0, 0, 0, 0, 0}; + // for (uint32_t i(0); i < NCROBMOD; i++) + // crob_map[i] = crob_map21[i]; + // } + // else if (runid >= 2335) { + // uint16_t crob_map22[] = {0xffc2, 0xffc5, 0xffc1, 0, 0}; + // for (uint32_t i(0); i < NCROBMOD; i++) + // crob_map[i] = crob_map22[i]; + // } + // trdfasp2dconfig->SetCrobMapping(5, crob_map); + std::string parfilesbasepathTrdfasp2d = Form("%s/parameters/trd", srcDir.Data()); + trdfasp2dconfig->SetParFilesBasePath(parfilesbasepathTrdfasp2d); + trdfasp2dconfig->SetSystemTimeOffset(-1800); // [ns] value to be updated + if (2160 <= runid) { + trdfasp2dconfig->SetSystemTimeOffset(-570); // [ns] value to be updated + } + if (2350 <= runid) { + trdfasp2dconfig->SetSystemTimeOffset(-510); // [ns] value to be updated + } + trdfasp2dconfig->SetMonitor(dynamic_pointer_cast<CbmTrdUnpackFaspMonitor>(GetTrdMonitor(outfilename, 1))); + } + // ------------- + + // ---- TOF ---- + std::shared_ptr<CbmTofUnpackConfig> tofconfig = nullptr; + + tofconfig = std::make_shared<CbmTofUnpackConfig>("", runid); + if (tofconfig) { + // tofconfig->SetDebugState(); + tofconfig->SetDoWriteOutput(); + // tofconfig->SetDoWriteOptOutA("CbmTofErrors"); + std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data()); + std::string parFileNameTof = "mTofCriPar.par"; + if (2060 <= runid) { + /// Additional modules added just before the 10/03/2022 Carbon run + parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data()); + /// Setup changed multiple times between the 2022 carbon and uranium runs + if (runid <= 2065) { + /// Carbon runs: 2060 - 2065 + parFileNameTof = "mTofCriParCarbon.par"; + } + else if (2150 <= runid && runid <= 2160) { + /// Iron runs: 2150 - 2160 + parFileNameTof = "mTofCriParIron.par"; + if (bBmoninTof) { + /// Map the BMon components in the TOF par file + parFileNameTof = "mTofCriParIron_withBmon.par"; + } + } + else if (2176 <= runid && runid <= 2310) { + /// Uranium runs: 2176 - 2310 + parFileNameTof = "mTofCriParUranium.par"; + } + else if (2335 <= runid && runid <= 2497) { + /// Nickel runs: 2335 - 2397 + /// Gold runs: 2400 - 2497 + parFileNameTof = "mTofCriParNickel.par"; + if (bBmoninTof) { + /// Map the BMon components in the TOF par file + parFileNameTof = "mTofCriParNickel_withBmon.par"; + } + } + else { + parFileNameTof = "mTofCriPar.par"; + } + } + if (2724 <= runid) { + /// mCBM 2024 + parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2024/", srcDir.Data()); + } + + tofconfig->SetParFilesBasePath(parfilesbasepathTof); + tofconfig->SetParFileName(parFileNameTof); + tofconfig->SetSystemTimeOffset(-1220); // [ns] value to be updated + if (2160 <= runid) { + tofconfig->SetSystemTimeOffset(0); // [ns] value to be updated + } + if (2350 <= runid) { + tofconfig->SetSystemTimeOffset(40); // [ns] value to be updated + } + if (runid <= 1659) { + /// Switch ON the -4 offset in epoch count (hack for Spring-Summer 2021) + tofconfig->SetFlagEpochCountHack2021(); + } + /// Enable Monitor plots + // tofconfig->SetMonitor(GetTofMonitor(outfilename, false)); + } + // ------------- + + // ---- RICH ---- + std::shared_ptr<CbmRichUnpackConfig> richconfig = nullptr; + + richconfig = std::make_shared<CbmRichUnpackConfig>("", runid); + if (richconfig) { + if (1904 < runid) { + /// Switch to new unpacking algo starting from first combined cosmics run in 2022 + richconfig->SetUnpackerVersion(CbmRichUnpackerVersion::v03); + richconfig->SetMonitor(GetRichMonitor(outfilename, true)); + } + + richconfig->DoTotOffsetCorrection(); // correct ToT offset + richconfig->SetDebugState(); + richconfig->SetDoWriteOutput(); + std::string parfilesbasepathRich = Form("%s/macro/beamtime/mcbm2024/", srcDir.Data()); + richconfig->SetParFilesBasePath(parfilesbasepathRich); + richconfig->SetSystemTimeOffset(256000 - 1200); // [ns] 1 MS and additional correction + if (1904 < runid) richconfig->SetSystemTimeOffset(-1200); + if (2160 <= runid) { + richconfig->SetSystemTimeOffset(50); // [ns] value to be updated + } + if (2350 <= runid) { + richconfig->SetSystemTimeOffset(100); // [ns] value to be updated + } + if (runid == 1588) richconfig->MaskDiRICH(0x7150); + } + // ------------- + + // ---- PSD ---- + std::shared_ptr<CbmPsdUnpackConfig> psdconfig = nullptr; + + psdconfig = std::make_shared<CbmPsdUnpackConfig>("", runid); + if (psdconfig) { + // psdconfig->SetDebugState(); + psdconfig->SetDoWriteOutput(); + // psdconfig->SetDoWriteOptOutA("CbmPsdDsp"); + std::string parfilesbasepathPsd = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data()); + psdconfig->SetParFilesBasePath(parfilesbasepathPsd); + psdconfig->SetSystemTimeOffset(0); // [ns] value to be updated + } + // ------------- + + + // ------------------------------------------------------------------------ + + // In general, the following parts need not be touched + // ======================================================================== + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + // ----- CbmSourceTsArchive ------------------------------------------- + std::unique_ptr<CbmSourceTsArchive> source = std::unique_ptr<CbmSourceTsArchive>(new CbmSourceTsArchive(infile)); + auto unpack = source->GetRecoUnpack(); + unpack->SetDoPerfProfiling(doPerfProfiling); + /// Uncomment following line to enable extra hists about unpacker and detectors performances (I/O, I/O shares, expan.) + // unpack->SetDoPerfProfilingPerTs(doPerfProfiling); + /// Uncomment following two line to enable the InfluxDb+Grafana based publication of unpacker performances + // unpack->SetPublishProfMoni(); + unpack->SetOutputFilename(perfProfFileName); + // Enable full time sorting instead sorting per FLIM link + unpack->SetTimeSorting(true); + + // if (bmonconfig) unpack->SetUnpackConfig(bmonconfig); + // if (stsconfig) unpack->SetUnpackConfig(stsconfig); + // if (muchconfig) unpack->SetUnpackConfig(muchconfig); + // if (trd1Dconfig) unpack->SetUnpackConfig(trd1Dconfig); + // if (trdfasp2dconfig) unpack->SetUnpackConfig(trdfasp2dconfig); + // if (tofconfig) unpack->SetUnpackConfig(tofconfig); + if (richconfig) unpack->SetUnpackConfig(richconfig); + // if (psdconfig) unpack->SetUnpackConfig(psdconfig); + // ------------------------------------------------------------------------ + + + // ----- FairRunAna --------------------------------------------------- + auto run = new FairRunOnline(source.release()); + auto sink = new FairRootFileSink(outfilename.data()); + 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 (through 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; + + bmonconfig.reset(); + stsconfig.reset(); + muchconfig.reset(); + trd1Dconfig.reset(); + trdfasp2dconfig.reset(); + tofconfig.reset(); + richconfig.reset(); + psdconfig.reset(); + // ------------------------------------------------------------------------ + +} // End of main macro function + + +/** + * @brief Get the Trd Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmTrdUnpackMonitor> +*/ +std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, bool fasp = false) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + std::string mydir = "/qa"; + outpath += mydir; + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) + gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) + outfilename.replace(filetypepos, 10, ".mon.trd.root"); + else + outfilename += ".mon.trd.root"; + // ------------------------------------------------------------------------ + + std::vector<CbmTrdUnpackMonitor::eDigiHistos> digihistovec = { + CbmTrdUnpackMonitor::eDigiHistos::kMap, CbmTrdUnpackMonitor::eDigiHistos::kMap_St, + CbmTrdUnpackMonitor::eDigiHistos::kMap_Nt, CbmTrdUnpackMonitor::eDigiHistos::kCharge, + CbmTrdUnpackMonitor::eDigiHistos::kCharge_St, CbmTrdUnpackMonitor::eDigiHistos::kCharge_Nt, + CbmTrdUnpackMonitor::eDigiHistos::kChannel, CbmTrdUnpackMonitor::eDigiHistos::kChannel_St, + CbmTrdUnpackMonitor::eDigiHistos::kChannel_Nt, CbmTrdUnpackMonitor::eDigiHistos::kTriggerType, + CbmTrdUnpackMonitor::eDigiHistos::kDigiDeltaT}; + + std::vector<CbmTrdUnpackMonitor::eRawHistos> rawhistovec = { + CbmTrdUnpackMonitor::eRawHistos::kSignalshape, CbmTrdUnpackMonitor::eRawHistos::kSignalshape_St, + CbmTrdUnpackMonitor::eRawHistos::kSignalshape_Nt, CbmTrdUnpackMonitor::eRawHistos::kElinkId, + CbmTrdUnpackMonitor::eRawHistos::kSampleDistStdDev, CbmTrdUnpackMonitor::eRawHistos::kSample0perChannel, + CbmTrdUnpackMonitor::eRawHistos::kHitType}; + + std::vector<CbmTrdUnpackMonitor::eOtherHistos> otherhistovec = {CbmTrdUnpackMonitor::eOtherHistos::kSpadic_Info_Types, + CbmTrdUnpackMonitor::eOtherHistos::kMs_Flags}; + std::shared_ptr<CbmTrdUnpackMonitor> monitor(nullptr); + if (!fasp) { // SPADIC monitor + monitor = std::make_shared<CbmTrdUnpackMonitor>(); + monitor->SetActiveHistos(digihistovec); + monitor->SetActiveHistos(rawhistovec); + monitor->SetActiveHistos(otherhistovec); + monitor->SetWriteToFile(outfilename.data()); + } + else { // FASP monitoring settings + monitor = std::make_shared<CbmTrdUnpackFaspMonitor>(); + monitor->SetActiveHistos(digihistovec); + monitor->SetWriteToFile(outfilename.data()); + } + return monitor; +} + + +/** + * @brief Get the Trd Spadic + * @return std::shared_ptr<CbmTrdSpadic> +*/ +std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline) +{ + auto spadic = std::make_shared<CbmTrdSpadic>(); + spadic->SetUseBaselineAverage(useAvgBaseline); + spadic->SetMaxAdcToEnergyCal(1.0); + + return spadic; +} + +/** + * @brief Get the Sts Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmStsUnpackMonitor> +*/ +std::shared_ptr<CbmStsUnpackMonitor> GetStsMonitor(std::string treefilename, bool bDebugMode = false) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + //std::string mydir = "/qa"; + //outpath += mydir; + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) + gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) + outfilename.replace(filetypepos, 10, ".mon.sts.root"); + else + outfilename += ".mon.sts.root"; + // ------------------------------------------------------------------------ + + auto monitor = std::make_shared<CbmStsUnpackMonitor>(); + monitor->SetHistoFileName(outfilename); + monitor->SetDebugMode(bDebugMode); + return monitor; +} + +/** + * @brief Get the Much Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmMuchUnpackMonitor> +*/ +std::shared_ptr<CbmMuchUnpackMonitor> GetMuchMonitor(std::string treefilename, bool bDebugMode = false) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) + gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) + outfilename.replace(filetypepos, 10, ".mon.much.root"); + else + outfilename += ".mon.much.root"; + // ------------------------------------------------------------------------ + + auto monitor = std::make_shared<CbmMuchUnpackMonitor>(); + monitor->SetHistoFileName(outfilename); + monitor->SetDebugMode(bDebugMode); + return monitor; +} + +/** + * @brief Get the Rich Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmRichUnpackMonitor> +*/ +std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, bool bDebugMode = false) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) + gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) + outfilename.replace(filetypepos, 10, ".mon.rich.root"); + else + outfilename += ".mon.rich.root"; + // ------------------------------------------------------------------------ + + auto monitor = std::make_shared<CbmRichUnpackMonitor>(); + monitor->SetHistoFileName(outfilename); + monitor->SetDebugMode(bDebugMode); + + return monitor; +} + +/** + * @brief Get the Tof Monitor. Extra function to keep default macro part more silent. + * @return std::shared_ptr<CbmTofUnpackMonitor> +*/ +std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false) +{ + // ----- Output filename and path ------------------------------------- + std::string outpath = ""; + std::string filename = ""; + auto filenamepos = treefilename.find_last_of("/"); + if (filenamepos != treefilename.npos) { + outpath = treefilename.substr(0, filenamepos); + filename = treefilename.substr(filenamepos++); + } + if (outpath.empty()) outpath = gSystem->GetWorkingDirectory(); + //std::string mydir = "/qa"; + //outpath += mydir; + + auto currentdir = gSystem->GetWorkingDirectory(); + + if (!gSystem->cd(outpath.data())) + gSystem->MakeDirectory(outpath.data()); + else + gSystem->cd(currentdir.data()); + + std::string sSystemType = ".mon.tof.root"; + if (bBmonMode) { + // + sSystemType = ".mon.bmon.root"; + } + + std::string outfilename = outpath + filename; + auto filetypepos = outfilename.find(".digi.root"); + if (filetypepos != outfilename.npos) + outfilename.replace(filetypepos, 10, sSystemType); + else + outfilename += sSystemType; + // ------------------------------------------------------------------------ + + auto monitor = std::make_shared<CbmTofUnpackMonitor>(); + monitor->SetHistoFileName(outfilename); + monitor->SetBmonMode(bBmonMode); + return monitor; +} + +void run_unpack_tsa_rich_only(std::string infile = "test.tsa", UInt_t runid = 0, + std::string setupName = defaultSetupName, std::int32_t nevents = -1, + bool bBmoninTof = false, std::string outpath = "data/") +{ + std::vector<std::string> vInFile = {infile}; + return run_unpack_tsa(vInFile, runid, setupName, nevents, bBmoninTof, outpath); +}