From 0be1fa93a68c90f52150c07c9b6aa1921fb2be3e Mon Sep 17 00:00:00 2001 From: Dominik Smith <d.smith@gsi.de> Date: Tue, 5 Jul 2022 15:16:26 +0200 Subject: [PATCH] Started to implement new Much unpacker in algo namespace. --- algo/CMakeLists.txt | 2 + algo/detectors/much/MuchReadoutConfig.cxx | 323 ++++++++++++++++++++++ algo/detectors/much/MuchReadoutConfig.h | 129 +++++++++ algo/detectors/much/UnpackMuch.cxx | 163 +++++++++++ algo/detectors/much/UnpackMuch.h | 146 ++++++++++ 5 files changed, 763 insertions(+) create mode 100644 algo/detectors/much/MuchReadoutConfig.cxx create mode 100644 algo/detectors/much/MuchReadoutConfig.h create mode 100644 algo/detectors/much/UnpackMuch.cxx create mode 100644 algo/detectors/much/UnpackMuch.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 623ce77119..965746fe0d 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -8,6 +8,8 @@ set(SRCS trigger/TimeClusterTrigger.cxx detectors/sts/StsReadoutConfig.cxx detectors/sts/UnpackSts.cxx + detectors/much/MuchReadoutConfig.cxx + detectors/much/UnpackMuch.cxx ) add_library(Algo SHARED ${SRCS}) diff --git a/algo/detectors/much/MuchReadoutConfig.cxx b/algo/detectors/much/MuchReadoutConfig.cxx new file mode 100644 index 0000000000..e96079548c --- /dev/null +++ b/algo/detectors/much/MuchReadoutConfig.cxx @@ -0,0 +1,323 @@ +/* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Ajit Kumar, Florian Uhlig [committer] */ + +#include "MuchReadoutConfig.h" + +//#include "FairDetParIo.h" +//#include "FairParIo.h" +//#include "FairParamList.h" +#include <Logger.h> + +//#include "TMath.h" +//#include "TString.h" + +using namespace std; + +namespace cbm::algo +{ + + /* +// ----- Public method clear ------------------------------------------- +void MuchReadoutConfig::clear() +{ + status = false; + resetInputVersions(); +} +// ------------------------------------------------------------------------- + +// ------------------------------------------------------------------------- + +void MuchReadoutConfig::putParams(FairParamList* l) +{ + if (!l) return; + + l->add("NrOfDpbs", fuNrOfDpbs); + l->add("DbpIdArray", fiDbpIdArray); + l->add("CrobActiveFlag", fiCrobActiveFlag); + l->add("NrOfFebsInGemA", fuFebsInGemA); + l->add("nFebsIdsArrayA", fnFebsIdsArrayGemA); + l->add("NrOfFebsInGemB", fuFebsInGemB); + l->add("nFebsIdsArrayB", fnFebsIdsArrayGemB); + l->add("NrOfFebsInRpc", fuFebsInRpc); + l->add("nFebsIdsArrayRpc", fnFebsIdsArrayRpc); + l->add("ChannelsToPadXA", fChannelsToPadXA); + l->add("ChannelsToPadYA", fChannelsToPadYA); + l->add("ChannelsToPadXB", fChannelsToPadXB); + l->add("ChannelsToPadYB", fChannelsToPadYB); + l->add("ChannelsToPadXRpc", fChannelsToPadXRpc); + l->add("ChannelsToPadYRpc", fChannelsToPadYRpc); + l->add("RealX", fRealX); + l->add("PadSize", fRealPadSize); +} + +// ------------------------------------------------------------------------- + +bool MuchReadoutConfig::getParams(FairParamList* l) +{ + + if (!l) return false; + + if (!l->fill("NrOfDpbs", &fuNrOfDpbs)) return false; + + fiDbpIdArray.Set(fuNrOfDpbs); + if (!l->fill("DbpIdArray", &fiDbpIdArray)) return false; + + fiCrobActiveFlag.Set(fuNrOfDpbs * kuNbCrobsPerDpb); + if (!l->fill("CrobActiveFlag", &fiCrobActiveFlag)) return false; + + if (!l->fill("NrOfFebsInGemA", &fuFebsInGemA)) return false; + + fnFebsIdsArrayGemA.Set(GetNrOfFebsInGemA()); + if (!l->fill("nFebsIdsArrayA", &fnFebsIdsArrayGemA)) return false; + + if (!l->fill("NrOfFebsInGemB", &fuFebsInGemB)) return false; + + fnFebsIdsArrayGemB.Set(GetNrOfFebsInGemB()); + if (!l->fill("nFebsIdsArrayB", &fnFebsIdsArrayGemB)) return false; + + if (!l->fill("NrOfFebsInRpc", &fuFebsInRpc)) return false; + + fnFebsIdsArrayRpc.Set(GetNrOfFebsInRpc()); + if (!l->fill("nFebsIdsArrayRpc", &fnFebsIdsArrayRpc)) return false; + + fChannelsToPadXA.Set(GetNrOfFebs() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadXA", &fChannelsToPadXA)) return false; + + fChannelsToPadYA.Set(GetNrOfFebs() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadYA", &fChannelsToPadYA)) return false; + + fChannelsToPadXB.Set(GetNrOfFebs() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadXB", &fChannelsToPadXB)) return false; + + fChannelsToPadYB.Set(GetNrOfFebs() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadYB", &fChannelsToPadYB)) return false; + + fChannelsToPadXRpc.Set(GetNrOfFebsInRpc() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadXRpc", &fChannelsToPadXRpc)) return false; + + fChannelsToPadYRpc.Set(GetNrOfFebsInRpc() * kuNbChanPerAsic); + if (!l->fill("ChannelsToPadYRpc", &fChannelsToPadYRpc)) return false; + + fRealX.Set(2232); // Number of Sectors in one GEM Module + if (!l->fill("RealX", &fRealX)) return false; + + fRealPadSize.Set(2232); // Number of Sectors in one GEM Module + if (!l->fill("PadSize", &fRealPadSize)) return false; + + return true; +} +*/ + + // ------------------------------------------------------------------------- + int16_t MuchReadoutConfig::ElinkIdxToFebIdx(uint16_t uElink) + { + if (uElink < kuNbElinksPerCrob) return kiCrobMapElinkFebIdx[uElink]; + else { + LOG(warning) << "MuchReadoutConfig::ElinkIdxToFebIdx => Index out of bound, " + << "Elink is " << uElink << " returning crazy value!"; + return -1; + } + } + + // ------------------------------------------------------------------------- + uint16_t MuchReadoutConfig::GetDpbId(uint16_t uDpbIdx) + { + if (uDpbIdx < fuNrOfDpbs) return fiDbpIdArray[uDpbIdx]; + else { + LOG(warning) << "MuchReadoutConfig::GetDpbId => Index out of bound, " + << "DPB Id is " << std::hex << uDpbIdx << " returning crazy value!"; + return 0xFFFFFFFF; + } + } + + bool MuchReadoutConfig::IsCrobActive(uint16_t uDpbIdx, uint16_t uCrobIdx) + { + if (uDpbIdx < fuNrOfDpbs) { + if (uCrobIdx < kuNbCrobsPerDpb) return 0 < fiCrobActiveFlag[uDpbIdx * kuNbCrobsPerDpb + uCrobIdx] ? true : false; + else { + LOG(warning) << "MuchReadoutConfig::IsCrobActive => Crob Index out of bound, " + << "returning default inactive!"; + return false; + } + } + else { + LOG(warning) << "MuchReadoutConfig::IsCrobActive => Dpb Index out of bound, " + << "returning default inactive!"; + return false; + } + } + + bool MuchReadoutConfig::IsFebActive(uint16_t uFebInSystIdx) + { + + if (uFebInSystIdx < GetNrOfFebs()) { + /// Always return true for now + return true; + } + else { + LOG(warning) << "MuchReadoutConfig::IsFebActive => Feb Index out of bound, " + << "returning default inactive!"; + return false; + } + } + + bool MuchReadoutConfig::IsFebActive(uint16_t uDpbIdx, uint16_t uCrobIdx, uint16_t uFebIdx) + { + if (uDpbIdx < fuNrOfDpbs) { + if (uCrobIdx < kuNbCrobsPerDpb) { + if (uFebIdx < kuNbFebsPerCrob) { + uint16_t uIdx = (uDpbIdx * kuNbCrobsPerDpb + uCrobIdx) * kuNbFebsPerCrob + uFebIdx; + return IsFebActive(uIdx); + } + else { + LOG(warning) << "MuchReadoutConfig::IsFebActive => Feb Index out of bound, " + << "returning default inactive!"; + return false; + } + } + else { + LOG(warning) << "MuchReadoutConfig::IsFebActive => Crob Index out of bound, " + << "returning default inactive!"; + return false; + } + } + else { + LOG(warning) << "MuchReadoutConfig::IsFebActive => Dpb Index out of bound, " + << "returning default inactive!"; + return false; + } + } + + int8_t MuchReadoutConfig::GetPadXA(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadXA.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "MuchReadoutConfig::GetPadXA => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadXA.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadXA[(febid * kuNbChanPerAsic) + channelid]; + } + + int8_t MuchReadoutConfig::GetPadYA(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadYA.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "MuchReadoutConfig::GetPadYA => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadYA.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadYA[(febid * kuNbChanPerAsic) + channelid]; + } + + int8_t MuchReadoutConfig::GetPadXB(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadXB.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "MuchReadoutConfig::GetPadXB => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadXB.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadXB[(febid * kuNbChanPerAsic) + channelid]; + } + + int8_t MuchReadoutConfig::GetPadYB(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadYB.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "MuchReadoutConfig::GetPadYB => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadYB.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadYB[(febid * kuNbChanPerAsic) + channelid]; + } + + int8_t MuchReadoutConfig::GetPadXRpc(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadXRpc.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "CbmMcbm2018MuchPar::GetPadXRpc => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadXRpc.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadXRpc[(febid * kuNbChanPerAsic) + channelid]; + } + + int8_t MuchReadoutConfig::GetPadYRpc(uint8_t febid, uint8_t channelid) + { + if (fChannelsToPadYRpc.size() <= static_cast<int16_t>((febid * kuNbChanPerAsic) + channelid)) { + LOG(debug) << "CbmMcbm2018MuchPar::GetPadYRpc => Index out of bounds: " << ((febid * kuNbChanPerAsic) + channelid) + << " VS " << fChannelsToPadYRpc.size() << " (" << febid << " and " << channelid << ")"; + return -2; + } + return fChannelsToPadYRpc[(febid * kuNbChanPerAsic) + channelid]; + } + + int32_t MuchReadoutConfig::GetFebId(uint16_t uAsicIdx) + { + if (uAsicIdx >= GetNrOfFebsInGemA() && uAsicIdx < (GetNrOfFebsInGemA() + GetNrOfFebsInRpc())) //Check + return fnFebsIdsArrayRpc[uAsicIdx - GetNrOfFebsInGemA()]; //Check Vikas + else if (uAsicIdx >= (GetNrOfFebsInGemA() + GetNrOfFebsInRpc()) + && uAsicIdx < (GetNrOfFebsInGemA() + GetNrOfFebsInRpc() + GetNrOfFebsInGemB())) //Check + return fnFebsIdsArrayGemB[uAsicIdx - (GetNrOfFebsInGemA() + GetNrOfFebsInRpc())]; + else if (uAsicIdx < GetNrOfFebsInGemA()) + return fnFebsIdsArrayGemA[uAsicIdx]; + else { + LOG(warning) << "MuchReadoutConfig::GetFebId => provided uAsicIdx : " << uAsicIdx + << " not in the range of :" << (GetNrOfFebsInGemA() + GetNrOfFebsInRpc() + GetNrOfFebsInGemB()) + << "Returning large value -2"; + return -2; + } + } + + //GetModule() is not used in unpacker + uint16_t MuchReadoutConfig::GetModule(uint16_t uAsicIdx) + { + if (uAsicIdx >= GetNrOfFebsInGemA()) { + if ((uAsicIdx % GetNrOfFebsInGemA()) < GetNrOfFebsInRpc()) return 1; + else + return 2; + } + else + return 0; + } + + double MuchReadoutConfig::GetRealX(int16_t SectorIndex) + { + if (SectorIndex < 0 || SectorIndex <= 97) { + LOG(debug) << "MuchReadoutConfig::GetRealX => Index out of bounds: "; + return -2; + } + return fRealX[SectorIndex]; + } + + double MuchReadoutConfig::GetRealPadSize(int16_t SectorIndex) + { + if (SectorIndex < 0 || SectorIndex <= 97) { + LOG(debug) << "MuchReadoutConfig::GetRealX => Index out of bounds: "; + return -2; + } + return fRealPadSize[SectorIndex]; + } + + double MuchReadoutConfig::GetRealX(int16_t Channel, int16_t Sector) + { + int16_t PadIndex = Channel + 97 * Sector; + if (Channel < 0 || Sector < 0) return -2; + if (fRealX.size() <= PadIndex) { + LOG(info) << "MuchReadoutConfig::GetRealX => Index out of bounds: " << Channel << " " << Sector << " " + << PadIndex; + return -1; + } + return fRealX[PadIndex]; + } + + double MuchReadoutConfig::GetRealPadSize(int16_t Channel, int16_t Sector) + { + int16_t PadIndex = Channel + 97 * Sector; + if (Channel < 0 || Sector < 0) return -2; + if (fRealPadSize.size() <= PadIndex) { + LOG(info) << "MuchReadoutConfig::GetRealPadSize => Index out of bounds: " << Channel << " " << Sector << " " + << PadIndex; + return -1; + } + return fRealPadSize[PadIndex]; + } + +} /* namespace cbm::algo */ diff --git a/algo/detectors/much/MuchReadoutConfig.h b/algo/detectors/much/MuchReadoutConfig.h new file mode 100644 index 0000000000..3302932515 --- /dev/null +++ b/algo/detectors/much/MuchReadoutConfig.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Florian Uhlig [committer] */ + +// ------------------------------------------------------------------------- +// ----- MuchReadoutConfig header file ----- +// ----- Created 22/02/22 by P.-A. Loizeau ----- +// ----- Modified 07/12/18 by A Kumar ----- +// ------------------------------------------------------------------------- + +#ifndef ALGO_DETECTORS_MUCH_MUCHREADOUTCONFIG_H +#define ALGO_DETECTORS_MUCH_MUCHREADOUTCONFIG_H + +//#include "FairParGenericSet.h" + +#include <cstdint> +#include <vector> + +//#include "TArrayD.h" +//#include "TArrayI.h" + +//class FairParIo; +//class FairParamList; + +namespace cbm::algo +{ + + //class MuchReadoutConfig : public FairParGenericSet { + class MuchReadoutConfig { + + public: + /** Standard constructor **/ + MuchReadoutConfig() {}; + + /** Destructor **/ + ~MuchReadoutConfig() {}; + + /** Reset all parameters **/ + virtual void clear(); + + /* + void putParams(FairParamList*); + bool getParams(FairParamList*); +*/ + static constexpr uint16_t GetNbCrobsPerDpb() { return kuNbCrobsPerDpb; } + static constexpr uint16_t GetNbElinkPerCrob() { return kuNbElinksPerCrob; } + static constexpr uint16_t GetNbElinkPerDpb() { return kuNbCrobsPerDpb * kuNbElinksPerCrob; } + static constexpr uint16_t GetNbFebsPerCrob() { return kuNbFebsPerCrob; } + static constexpr uint16_t GetNbFebsPerDpb() { return kuNbCrobsPerDpb * kuNbFebsPerCrob; } + static constexpr uint16_t GetNbAsicsPerFeb() { return kuNbAsicsPerFeb; } + static constexpr uint16_t GetNbAsicsPerCrob() { return kuNbFebsPerCrob * kuNbAsicsPerFeb; } + static constexpr uint16_t GetNbAsicsPerDpb() { return kuNbCrobsPerDpb * GetNbAsicsPerCrob(); } + static constexpr uint16_t GetNbChanPerAsic() { return kuNbChanPerAsic; } + static constexpr uint16_t GetNbChanPerFeb() { return kuNbAsicsPerFeb * kuNbChanPerAsic; } + + //! Convert from eLink index to FEB Connection ( 0 to kuNbFebsPerCrob) + int16_t ElinkIdxToFebIdx(uint16_t uElink); + + uint16_t GetNrOfDpbs() { return fuNrOfDpbs; } + uint16_t GetDpbId(uint16_t uDpbIdx); + uint16_t GetNrOfCrobs() { return fuNrOfDpbs * kuNbCrobsPerDpb; } + uint16_t GetNrOfFebs() { return GetNrOfCrobs() * kuNbFebsPerCrob; } + uint16_t GetNrOfAsics() { return GetNrOfFebs() * kuNbAsicsPerFeb; } + uint16_t GetNrOfFebsInGemA() { return fuFebsInGemA; } + uint16_t GetNrOfFebsInGemB() { return fuFebsInGemB; } + int16_t GetNrOfChannels() { return kuNbChanPerAsic; } + + int32_t GetFebId(uint16_t); + uint16_t GetModule(uint16_t); + + int8_t GetPadXA(uint8_t febid, uint8_t channelid); + int8_t GetPadYA(uint8_t febid, uint8_t channelid); + int8_t GetPadXB(uint8_t febid, uint8_t channelid); + int8_t GetPadYB(uint8_t febid, uint8_t channelid); + double GetRealX(int16_t); + double GetRealPadSize(int16_t); + + double GetRealX(int16_t Channel, int16_t Sector); + double GetRealPadSize(int16_t Channel, int16_t Sector); + + //RPC Module Related Functions + uint16_t GetNrOfFebsInRpc() { return fuFebsInRpc; } + int8_t GetPadXRpc(uint8_t febid, uint8_t channelid); + int8_t GetPadYRpc(uint8_t febid, uint8_t channelid); + + bool IsCrobActive(uint16_t uDpbIdx, uint16_t uCrobIdx); + bool IsFebActive(uint16_t uFebInSystIdx); + bool IsFebActive(uint16_t uDpbIdx, uint16_t uCrobIdx, uint16_t uFebIdx); + bool IsFebPulser(uint16_t uFebInSystIdx); + bool IsFebPulser(uint16_t uDpbIdx, uint16_t uCrobIdx, uint16_t uFebIdx); + double GetFebAdcGain(uint16_t uDpbIdx, uint16_t uCrobIdx, uint16_t uFebIdx); + double GetFebAdcOffset(uint16_t uDpbIdx, uint16_t uCrobIdx, uint16_t uFebIdx); + + private: + /// Constants + static const uint16_t kuNbCrobsPerDpb = 1; // Number of CROBs possible per DPB + static const uint16_t kuNbElinksPerCrob = 42; // Number of elinks in each CROB ? + static const uint16_t kuNbFebsPerCrob = 9; // Number of FEBs connected to each CROB for mMuch 2019 + static const uint16_t kuNbAsicsPerFeb = 1; // Number of ASICs connected in each FEB for MUCH + static const uint16_t kuNbChanPerAsic = 128; // Number of channels in each ASIC + // static constexpr uint16_t kuCrobMapElinkFebIdx[ kuNbElinksPerCrob ] = { + const int16_t kiCrobMapElinkFebIdx[kuNbElinksPerCrob] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8}; + //! Map from eLink index to ASIC index within CROB ( 0 to kuNbFebsPerCrob * kuNbAsicPerFeb ) + + /// Variables + uint16_t fuNrOfDpbs = 0; // Total number of MUCH DPBs in system + std::vector<int16_t> fiDbpIdArray; // Array to hold the unique IDs (equipment ID) for all MUCH DPBs + std::vector<int16_t> fiCrobActiveFlag; // Array to hold the active flag for all CROBs, [ NbDpb * kuNbCrobPerDpb ] + uint16_t fuFebsInGemA = 0; // Number of FEBs connected in GEM Module A + uint16_t fuFebsInGemB = 0; // Number of FEBs connected in GEM Module B + uint16_t fuFebsInRpc = 0; // Number of FEBs connected in RPC Module + std::vector<int16_t> fnFebsIdsArrayGemA; // Array to hold FEB IDs connected to GEM Module A + std::vector<int16_t> fnFebsIdsArrayGemB; // Array to hold FEB IDs connected to GEM Module B + std::vector<int16_t> fnFebsIdsArrayRpc; // Array to hold FEB IDs connected to RPC Module + std::vector<int16_t> fChannelsToPadXA; // Array which stores the corresponding x position of PAD of entire module A + std::vector<int16_t> fChannelsToPadYA; // Array which stores the corresponding y position of PAD of entire module A + std::vector<int16_t> fChannelsToPadXB; // Array which stores the corresponding x position of PAD of entire module B + std::vector<int16_t> fChannelsToPadYB; // Array which stores the corresponding y position of PAD of entire module B + std::vector<int16_t> fChannelsToPadXRpc; // Array which stores the corresponding x position of PAD of RPC module + std::vector<int16_t> fChannelsToPadYRpc; // Array which stores the corresponding y position of PAD of RPC module + std::vector<double> fRealX; // Array which stores the Real X (starting 18.733 cm) position of PAD + std::vector<double> fRealPadSize; // Array which stores the Real Progressive size of each padX (starting .327 cm ) + }; + +} /* namespace cbm::algo */ + +#endif // ALGO_DETECTORS_MUCH_MUCHREADOUTCONFIG_H diff --git a/algo/detectors/much/UnpackMuch.cxx b/algo/detectors/much/UnpackMuch.cxx new file mode 100644 index 0000000000..c7daa77b09 --- /dev/null +++ b/algo/detectors/much/UnpackMuch.cxx @@ -0,0 +1,163 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Volker Friese [committer] */ + +#include "UnpackMuch.h" + +#include <cassert> +#include <utility> +#include <vector> + +#include <cmath> + +#include "StsXyterMessage.h" + +using std::unique_ptr; +using std::vector; + +namespace cbm::algo +{ + + // ---- Algorithm execution --------------------------------------------- + UnpackMuch::resultType UnpackMuch::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) + { + + // --- Output data + resultType result = {}; + + // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs + // --- and the epoch is a multiple of ns. + const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen; + fCurrentTsTime = tTimeslice / epochLengthInNs; + + // --- Current TS_MSB epoch cycle + auto const msTime = msDescr.idx; // Unix time of MS in ns + fCurrentCycle = std::ldiv(msTime, fkCycleLength).quot; + + // ---Â Number of messages in microslice + auto msSize = msDescr.size; + if (msSize % sizeof(stsxyter::Message) != 0) { + result.second.fNumErrInvalidMsSize++; + return result; + } + const uint32_t numMessages = msSize / sizeof(stsxyter::Message); + if (numMessages < 2) { + result.second.fNumErrInvalidMsSize++; + return result; + } + + // --- Interpret MS content as sequence of SMX messages + auto message = reinterpret_cast<const stsxyter::Message*>(msContent); + + // --- The first message in the MS is expected to be of type EPOCH and can be ignored. + if (message[0].GetMessType() != stsxyter::MessType::Epoch) { + result.second.fNumErrInvalidFirstMessage++; + return result; + } + + // --- The second message must be of type ts_msb. + if (message[1].GetMessType() != stsxyter::MessType::TsMsb) { + result.second.fNumErrInvalidFirstMessage++; + return result; + } + ProcessTsmsbMessage(message[1]); + + // --- Message loop + for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) { + + // --- Action depending on message type + switch (message[messageNr].GetMessType()) { + + case stsxyter::MessType::Hit: { + ProcessHitMessage(message[messageNr], result.first, result.second); + break; + } + case stsxyter::MessType::TsMsb: { + ProcessTsmsbMessage(message[messageNr]); + break; + } + default: { + result.second.fNumNonHitOrTsbMessage++; + break; + } + + } //? Message type + + } //# Messages + + return result; + } + // -------------------------------------------------------------------------- + + + // ----- Process hit message -------------------------------------------- + inline void UnpackMuch::ProcessHitMessage(const stsxyter::Message& message, vector<CbmMuchDigi>& digiVec, + UnpackMuchMonitorData& monitor) const + { + + // --- Check eLink and get parameters + uint16_t elink = message.GetLinkIndexHitBinning(); + if (elink >= fParams.fElinkParams.size()) { + monitor.fNumErrElinkOutOfRange++; + return; + } + const UnpackMuchElinkPar& elinkPar = fParams.fElinkParams.at(elink); + uint32_t asicNr = elinkPar.fAsicNr; + + // --- Hardware-to-software address + uint32_t numChansPerModule = fParams.fNumAsicsPerModule * fParams.fNumChansPerAsic; + uint32_t address = elinkPar.fAddress; + uint32_t channel = 0; + if (asicNr < fParams.fNumAsicsPerModule / 2) { // front side (n side) + channel = message.GetHitChannel() + fParams.fNumChansPerAsic * asicNr; + } + else { // back side (p side) + channel = numChansPerModule - message.GetHitChannel() + 1; + } + + // --- Expand time stamp to time within timeslice (in clock cycle) + uint64_t messageTime = message.GetHitTimeBinning() + fCurrentEpochTime; + + // --- Convert time stamp from clock cycles to ns. Round to nearest full ns. + messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen; + + // --- Correct ASIC-wise offsets + messageTime -= elinkPar.fTimeOffset; + // --- TODO: Add walk correction (depends on ADC) + + // --- Charge + double charge = elinkPar.fAdcOffset + (message.GetHitAdc() - 1) * elinkPar.fAdcGain; + + // --- Create output digi + // digiVec.emplace_back(address, channel, messageTime, charge); + } + // -------------------------------------------------------------------------- + + + // ----- Process an epoch (TS_MSB) message ------------------------------ + inline void UnpackMuch::ProcessTsmsbMessage(const stsxyter::Message& message) + { + // The compression of time is based on the hierarchy epoch cycle - epoch - message time. + // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb). + // The epoch number is counted within each cycle. The time in the hit message is expressed + // in units of the readout clock cycle relative to the current epoch. + // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch + // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is + // indicated by the epoch number being smaller than the previous one (epoch messages are + // seemingly not consecutively in the data stream, but only if there are hit messages in between). + auto epoch = message.GetTsMsbValBinning(); + + // --- Cycle wrap + if (epoch < fCurrentEpoch) fCurrentCycle++; + + // --- Update current epoch counter + fCurrentEpoch = epoch; + + // --- Calculate epoch time in clocks cycles relative to timeslice start time + fCurrentEpochTime = (fCurrentCycle * fkEpochsPerCycle + epoch - fCurrentTsTime) * fkEpochLength; + } + // -------------------------------------------------------------------------- + + +} /* namespace cbm::algo */ diff --git a/algo/detectors/much/UnpackMuch.h b/algo/detectors/much/UnpackMuch.h new file mode 100644 index 0000000000..22bc306fdd --- /dev/null +++ b/algo/detectors/much/UnpackMuch.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Volker Friese [committer] */ + +#ifndef CBM_ALGO_UNPACKMUCH_H +#define CBM_ALGO_UNPACKMUCH_H 1 + + +#include "CbmMuchDigi.h" + +#include "MicrosliceDescriptor.hpp" +#include "Timeslice.hpp" + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <vector> + +#include "StsXyterMessage.h" + +namespace cbm::algo +{ + + + /** @struct UnpackMuchElinkPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief STS Unpacking parameters for one eLink / ASIC + **/ + struct UnpackMuchElinkPar { + int32_t fAddress = 0; ///< CbmMuchAddress for the connected module + uint32_t fAsicNr = 0; ///< Number of connected ASIC within the module + uint64_t fTimeOffset = 0.; ///< Time calibration parameter + double fAdcOffset = 0.; ///< Charge calibration parameter + double fAdcGain = 0.; ///< Charge calibration parameter + }; + + + /** @struct UnpackMuchPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief Parameters required for the STS unpacking (specific to one component) + **/ + struct UnpackMuchPar { + uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC + uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module + std::vector<UnpackMuchElinkPar> fElinkParams = {}; ///< Parameters for each eLink + }; + + + /** @struct UnpackMuchMoni + ** @author Volker Friese <v.friese@gsi.de> + ** @since 2 December 2021 + ** @brief Monitoring data for STS unpacking + **/ + struct UnpackMuchMonitorData { + uint32_t fNumNonHitOrTsbMessage = 0; + uint32_t fNumErrElinkOutOfRange = 0; ///< Elink not contained in parameters + uint32_t fNumErrInvalidFirstMessage = 0; ///< First message is not TS_MSB or second is not EPOCH + uint32_t fNumErrInvalidMsSize = 0; ///< Microslice size is not multiple of message size + uint32_t fNumErrTimestampOverflow = 0; ///< Overflow in 64 bit time stamp + bool HasErrors() + { + uint32_t numErrors = fNumNonHitOrTsbMessage + fNumErrElinkOutOfRange + fNumErrInvalidFirstMessage + + fNumErrInvalidMsSize + fNumErrTimestampOverflow; + return (numErrors > 0 ? true : false); + } + }; + + + /** @class UnpackMuch + ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de> + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief Unpack algorithm for STS + **/ + class UnpackMuch { + + public: + typedef std::pair<std::vector<CbmMuchDigi>, UnpackMuchMonitorData> resultType; + + + /** @brief Default constructor **/ + UnpackMuch() {}; + + + /** @brief Destructor **/ + ~UnpackMuch() {}; + + + /** @brief Algorithm execution + ** @param msContent Microslice payload + ** @param msDescr Microslice descriptor + ** @param tTimeslice Unix start time of timeslice [ns] + ** @return STS digi data + **/ + resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice); + + /** @brief Set the parameter container + ** @param params Pointer to parameter container + **/ + void SetParams(std::unique_ptr<UnpackMuchPar> params) { fParams = *(std::move(params)); } + + + private: // methods + /** @brief Process a hit message + ** @param message SMX message (32-bit word) + ** @param digiVec Vector to append the created digi to + ** @param monitor Reference to monitor object + **/ + void ProcessHitMessage(const stsxyter::Message& message, std::vector<CbmMuchDigi>& digiVec, + UnpackMuchMonitorData& monitor) const; + + /** @brief Process an epoch message (TS_MSB) + ** @param message SMX message (32-bit word) + **/ + void ProcessTsmsbMessage(const stsxyter::Message& message); + + + private: // members + uint64_t fCurrentTsTime = 0; ///< Unix time of timeslice in units of epoch length + uint64_t fCurrentCycle = 0; ///< Current epoch cycle + uint32_t fCurrentEpoch = 0; ///< Current epoch number within epoch cycle + uint64_t fCurrentEpochTime = 0; ///< Current epoch time relative to timeslice in clock cycles + UnpackMuchPar fParams = {}; ///< Parameter container + + /** Number of TS_MSB epochs per cycle **/ + static constexpr uint64_t fkEpochsPerCycle = stsxyter::kuTsMsbNbTsBinsBinning; + + /** Length of TS_MSB epoch in clock cycles **/ + static constexpr uint64_t fkEpochLength = stsxyter::kuHitNbTsBinsBinning; + + /** Clock cycle nominator [ns] and denominator. The clock cycle in ns is nominator / denominator. **/ + static constexpr uint32_t fkClockCycleNom = stsxyter::kulClockCycleNom; + static constexpr uint32_t fkClockCycleDen = stsxyter::kulClockCycleDen; + + /** Epoch cycle length in ns **/ + static constexpr uint64_t fkCycleLength = (fkEpochsPerCycle * fkEpochLength * fkClockCycleNom) / fkClockCycleDen; + }; + + +} /* namespace cbm::algo */ + +#endif /* CBM_ALGO_UNPACKSTS_H */ -- GitLab