diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index eabd850ac8d6239138405068a08ce7106a6a535f..bcaa1a9ecd426e022d4b0ec02606fb9cad2dd070 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -14,6 +14,7 @@ set(SRCS base/Options.cxx base/util/TimingsFormat.cxx data/sts/LandauTable.cxx + data/sts/ReadoutSetup.cxx evbuild/EventBuilder.cxx trigger/TimeClusterTrigger.cxx evselector/DigiEventSelector.cxx @@ -105,6 +106,7 @@ install( ca/simd/CaSimdPseudo.h detectors/sts/StsHitfinder.h detectors/sts/StsHitfinderChain.h + global/Reco.h DESTINATION include/ ) diff --git a/algo/data/sts/ReadoutSetup.cxx b/algo/data/sts/ReadoutSetup.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a436569489f94cd865b39927338e2972cfc5b182 --- /dev/null +++ b/algo/data/sts/ReadoutSetup.cxx @@ -0,0 +1,140 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer], Felix Weiglhofer */ +#include "ReadoutSetup.h" + +#include "CbmStsAddress.h" + +#include <cassert> +#include <iomanip> + +using std::pair; +using std::setw; + +using namespace cbm::algo; + +// --- Constructor ------------------------------------------------------------------ +sts::ReadoutMapping::ReadoutMapping(const ReadoutSetup& config) { Init(config); } +// ------------------------------------------------------------------------------------ + +// --- Equipment IDs -------------------------------------------------------------- +std::vector<u16> sts::ReadoutMapping::GetEquipmentIds() +{ + std::vector<uint16_t> result; + for (auto& entry : fReadoutMapping) + result.push_back(entry.first); + return result; +} +// ------------------------------------------------------------------------------------ + +// --- Number of elinks for a component / equipment ------------------------------- +size_t sts::ReadoutMapping::GetNumElinks(u16 equipmentId) +{ + size_t result = 0; + auto it = fReadoutMapping.find(equipmentId); + if (it != fReadoutMapping.end()) result = fReadoutMapping[equipmentId].size(); + return result; +} +// ------------------------------------------------------------------------------------ + +size_t sts::ReadoutMapping::GetNumElinks() +{ + size_t result = 0; + for (auto& entry : fReadoutMapping) { + result += entry.second.size(); + } + return result; +} + +// --- Initialise the mapping structure -------------------------------------------- +void sts::ReadoutMapping::Init(const ReadoutSetup& config) +{ + // The readout hierarchy is: component - CROB - FEB - ASIC (elink). Each elink + // connects one ASIC. One FEB comprises 8 ASICs and reads out one side of a module (sensor). + // In this setup, there is only one CROB per component. The code below is formulate such + // as to support also multiple CROBs per component. In that case, the elinks are numbered + // consecutively within one component. + + // Constants + const uint16_t numModules = config.modules.size(); // Number of modules in the setup + const uint16_t numComp = config.components.size(); // Number of components + const uint16_t numCrobPerComp = config.components.at(0).feb2module.size(); // Number of CROBs per component + // const uint16_t numFebsPerCrob = config.components.at(0).feb2module.at(0).size(); // Number of FEBs per CROB + const uint16_t numAsicsPerFeb = config.numAsicsPerFeb; // Number of ASICs per FEB + const uint16_t numElinksPerCrob = config.elinks.size(); // Number of elinks per CROB + + // Constructing the map (equipmentId, eLink) -> (module, ASIC within module) + uint16_t numElinksPerComp = numCrobPerComp * numElinksPerCrob; + for (uint16_t comp = 0; comp < numComp; comp++) { + uint16_t equipment = config.components.at(comp).equipmentId; + fReadoutMapping[equipment].resize(numElinksPerComp); + for (uint16_t crob = 0; crob < numCrobPerComp; crob++) { + for (uint16_t elink = 0; elink < numElinksPerCrob; elink++) { + + int32_t moduleAddress = -1; + uint16_t asicInModule = 0; + bool isPulser = false; + + uint16_t elinkId = numElinksPerCrob * crob + elink; // elink within component + int16_t feb = config.elinks.at(elinkId).toFeb; // FEB within CROB + if (feb != -1) { + int16_t module = config.components[comp].feb2module[crob][feb]; // Module index + isPulser = config.components[comp].febIsPulser.at(crob).at(feb); // Pulser flag + + if (module != -1) { + assert(module < numModules); + moduleAddress = config.modules.at(module).address; // Module address + bool moduleType = config.modules.at(module).type; // 0 or 1 + int16_t moduleSide = config.components.at(comp).feb2moduleSide[crob][feb]; // 0 or 1, -1 is inactive + int16_t febType = (moduleType == 0 ? moduleSide : !moduleSide); // 0 = FEB A, 1 = FEB B + uint32_t asicIndex = (febType == 0 ? config.elinks[elinkId].toAsicFebA : config.elinks[elinkId].toAsicFebB); + uint32_t asicInFeb = asicIndex % numAsicsPerFeb; // ASIC number within FEB + + asicInModule = (moduleSide == 1 ? asicInFeb : asicInFeb + numAsicsPerFeb); + } + } + fReadoutMapping[equipment][elink] = {moduleAddress, asicInModule, isPulser}; + + } //# elink + } //# CROB + } //# component +} +// ------------------------------------------------------------------------------------ + +// --- Mapping (equimentId, elink) -> (address, ASIC) -------------------------------- +sts::ReadoutMapping::Entry sts::ReadoutMapping::Map(uint16_t equipmentId, uint16_t elinkId) +{ + Entry result {-1, 0, false}; + auto equipIter = fReadoutMapping.find(equipmentId); + if (equipIter != fReadoutMapping.end()) { + if (elinkId < equipIter->second.size()) { result = equipIter->second.at(elinkId); } + } + return result; +} +// ------------------------------------------------------------------------------------ + +// ----- Print readout map ------------------------------------------------ +std::string sts::ReadoutMapping::PrintReadoutMap() +{ + + std::stringstream ss; + for (auto& equipment : fReadoutMapping) { + auto eqId = equipment.first; + for (size_t elink = 0; elink < equipment.second.size(); elink++) { + auto address = equipment.second.at(elink).moduleAddress; + auto asicNr = equipment.second.at(elink).asicNumber; + ss << "\n Equipment " << eqId << " elink " << setw(2) << elink; + ss << " ASIC " << setw(2) << asicNr << " module " << address; + if (address != -1) { + ss << " Unit " << setw(2) << CbmStsAddress::GetElementId(address, kStsUnit); + ss << " Ladd " << setw(2) << CbmStsAddress::GetElementId(address, kStsLadder); + ss << " Hlad " << setw(2) << CbmStsAddress::GetElementId(address, kStsHalfLadder); + ss << " Modu " << setw(2) << CbmStsAddress::GetElementId(address, kStsModule); + } + else + ss << " Inactive"; + } //# elink + } //# component + return ss.str(); +} +// ---------------------------------------------------------------------------- diff --git a/algo/data/sts/ReadoutSetup.h b/algo/data/sts/ReadoutSetup.h new file mode 100644 index 0000000000000000000000000000000000000000..ee09adf1311b7bb2dfff7eca8197aa72a29180b6 --- /dev/null +++ b/algo/data/sts/ReadoutSetup.h @@ -0,0 +1,135 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer], Felix Weiglhofer */ +#ifndef CBM_ALGO_DATA_STS_READOUT_H +#define CBM_ALGO_DATA_STS_READOUT_H + +#include <map> +#include <string> +#include <vector> + +#include "Prelude.h" +#include "config/Property.h" + +namespace cbm::algo::sts +{ + + /** + * @brief Readout setup / Hardware cabling for STS + * Used to create the hardware mapping for the STS unpacker. + */ + struct ReadoutSetup { + + struct Module { + i32 address; + i32 type; + + static constexpr auto Properties = std::make_tuple( + config::Property(&Module::address, "address", "HW address of module", YAML::Hex), + config::Property(&Module::type, "type", + "Type 0 had the connector at the right side, type 1 at the left side. For type 0, the mapping " + "of FEB to module side as above applies, for type 1, it has to be inverted.")); + }; + + struct Component { + u16 equipmentId; + std::vector<std::vector<i16>> feb2module; + std::vector<std::vector<i16>> feb2moduleSide; + std::vector<std::vector<bool>> febIsPulser; + + static constexpr auto Properties = std::make_tuple( + config::Property(&Component::equipmentId, "equipmentId", + "Equipment ID of component. Written to the data stream (MicrosliceDescriptor).", YAML::Hex), + config::Property(&Component::feb2module, "feb2module", + "Mapping of FEB within CROB to module index (-1 = inactive)"), + config::Property(&Component::feb2moduleSide, "feb2moduleSide", + "Mapping of FEB within CROB to module side (0 = left, 1 = right)"), + config::Property(&Component::febIsPulser, "febIsPulser", "Flag if FEB is pulser (true) or not (false)")); + }; + + struct Elink { + i16 toFeb; + u32 toAsicFebA; + u32 toAsicFebB; + + static constexpr auto Properties = std::make_tuple( + config::Property(&Elink::toFeb, "toFeb", "Mapping of elink to FEB within CROB (-1 = inactive)"), + config::Property(&Elink::toAsicFebA, "toAsicFebA", "Mapping of eLink to ASIC for FEB Type A", YAML::Hex), + config::Property(&Elink::toAsicFebB, "toAsicFebB", "Mapping of eLink to ASIC for FEB Type B", YAML::Hex)); + }; + + u16 numAsicsPerFeb; + std::vector<Module> modules; + std::vector<Component> components; + std::vector<Elink> elinks; + + static constexpr auto Properties = + std::make_tuple(config::Property(&ReadoutSetup::numAsicsPerFeb, "numAsicsPerFeb", "Number of ASICs per FEB"), + config::Property(&ReadoutSetup::modules, "modules", "Modules", {}, YAML::Flow), + config::Property(&ReadoutSetup::components, "components", "Components", {}, YAML::Flow), + config::Property(&ReadoutSetup::elinks, "elinks", "Elinks", {}, YAML::Flow)); + }; + + /** @class ReadoutMapping + ** @author Volker Friese <v.friese@gsi.de> + ** @since 3 March 2022 + ** @brief Provides the hardware-to-software address mapping for the CBM-STS + ** + ** The hardware address as provided in the raw data stream is specified in terms of the + ** equipment identifier (specific to one FLES component) and the elink number with in + ** component. This is to be translated into the module address and the ASIC number within + ** the module. + **/ + class ReadoutMapping { + + public: + struct Entry { + i32 moduleAddress; + u16 asicNumber; + bool pulser; + }; + + /** @brief Empty mapping **/ + ReadoutMapping() = default; + + /** @brief Constructor **/ + ReadoutMapping(const ReadoutSetup&); + + /** @brief Equipment in the configuration + ** @return Vector of equipment IDs + **/ + std::vector<u16> GetEquipmentIds(); + + /** @brief Number of elinks of a component + ** @param Equipment ID + ** @return Number of elinks + **/ + size_t GetNumElinks(u16 equipmentId); + + /** @brief Total number of elinks for STS + ** @return Number of elinks + **/ + size_t GetNumElinks(); + + /** @brief API: Mapping from component and elink to address / ASIC number + pulser flag + ** @param equipId Equipment identifier (component) + ** @param elink Elink number within component + ** @return (module address, ASIC number within module) + */ + Entry Map(u16 equipId, u16 elink); + + /** @brief Debug output of readout map **/ + std::string PrintReadoutMap(); + + private: + // --- STS readout map + // --- Map index: (equipment, elink) + std::map<u16, std::vector<Entry>> fReadoutMapping = {}; //! + + /** @brief Initialisation of readout map **/ + void Init(const ReadoutSetup&); + }; + +} // namespace cbm::algo::sts + +#endif // CBM_ALGO_DATA_STS_READOUT_H diff --git a/algo/detectors/sts/StsReadoutConfig.h b/algo/detectors/sts/StsReadoutConfig.h index 76dd79efb5d2c9a1fb9bc1593cef86ccf230de96..b6480d5c87edf183bd66320fcb942880b5def04d 100644 --- a/algo/detectors/sts/StsReadoutConfig.h +++ b/algo/detectors/sts/StsReadoutConfig.h @@ -24,6 +24,8 @@ namespace cbm::algo ** component. This is to be translated into the module address and the ASIC number within ** the module. ** The mapping of the two address spaces is hard-coded in this class. + ** + ** NOTE: This class is deprecated. It's replaced by ReadoutMapping in algo/data/sts. The new class no longer hardcodes the mapping. It can be read from a configuration file instead. **/ class StsReadoutConfig { diff --git a/algo/detectors/sts/StsUnpackChain.cxx b/algo/detectors/sts/StsUnpackChain.cxx index 506813298585ec326a44fb0bad19e864ce718a1f..4dfe0add409b3bfc9abdbf7c47401c71b54e3911 100644 --- a/algo/detectors/sts/StsUnpackChain.cxx +++ b/algo/detectors/sts/StsUnpackChain.cxx @@ -13,7 +13,7 @@ using namespace cbm::algo; -void sts::UnpackChain::Init(StsReadoutConfig config) +void sts::UnpackChain::Init(sts::ReadoutMapping config) { fConfig = config; @@ -33,8 +33,8 @@ void sts::UnpackChain::Init(StsReadoutConfig config) for (size_t elink = 0; elink < numElinks; elink++) { UnpackStsElinkPar elinkPar; auto mapEntry = fConfig->Map(equip, elink); - elinkPar.fAddress = mapEntry.first; // Module address for this elink - elinkPar.fAsicNr = mapEntry.second; // ASIC number within module + elinkPar.fAddress = mapEntry.moduleAddress; // Module address for this elink + elinkPar.fAsicNr = mapEntry.asicNumber; // ASIC number within module elinkPar.fTimeOffset = 0.; elinkPar.fAdcOffset = 1.; elinkPar.fAdcGain = 1.; diff --git a/algo/detectors/sts/StsUnpackChain.h b/algo/detectors/sts/StsUnpackChain.h index e5d7a8375197566290766294d88fb2dc4964a83c..eacba3cb4d9dd614edcd14cf431ee1046725e959 100644 --- a/algo/detectors/sts/StsUnpackChain.h +++ b/algo/detectors/sts/StsUnpackChain.h @@ -12,9 +12,9 @@ #include <yaml-cpp/yaml.h> #include "Prelude.h" -#include "StsReadoutConfig.h" #include "SubChain.h" #include "UnpackSts.h" +#include "sts/ReadoutSetup.h" class CbmStsDigi; namespace fles @@ -28,12 +28,12 @@ namespace cbm::algo::sts class UnpackChain : public SubChain { public: - void Init(StsReadoutConfig config); + void Init(sts::ReadoutMapping config); std::vector<CbmStsDigi> Run(const fles::Timeslice& ts); private: std::unordered_map<u16, UnpackSts> fAlgoSts; - std::optional<StsReadoutConfig> fConfig; + std::optional<sts::ReadoutMapping> fConfig; }; } // namespace cbm::algo::sts diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index bc42367af62f71803f7cc66639e2615759869a0b..1b71db50f1f58e9e48c33205ede3d4b895827b89 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -32,10 +32,11 @@ void Reco::Init(const Options& opts) fContext.recoParams = config::Read<RecoParams>(yaml); // STS Unpacker - // yaml = YAML::LoadFile(opts.ParamsDir() / "StsReadout.yaml"); - // sts::ReadoutPars readoutConfig = config::Read<sts::ReadoutPars>(yaml); - StsReadoutConfig readoutConfig; - fUnpack.Init(readoutConfig); + fs::path stsUnpackParamsPath = opts.ParamsDir() / "StsReadout.yaml"; + yaml = YAML::LoadFile(stsUnpackParamsPath.string()); + sts::ReadoutSetup readoutConfig = config::Read<sts::ReadoutSetup>(yaml); + sts::ReadoutMapping mapping(readoutConfig); + fUnpack.Init(mapping); // STS Hitfinder fs::path stsHitfinderParamsPath = opts.ParamsDir() / "StsHitfinder.yaml"; diff --git a/algo/params/StsReadout.yaml b/algo/params/StsReadout.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0e5dc63e60fcab36b4a845d286c1767fb1d6a2de --- /dev/null +++ b/algo/params/StsReadout.yaml @@ -0,0 +1,67 @@ +--- +numAsicsPerFeb: 8 +modules: + - {address: 0x10008002, type: 0} + - {address: 0x10018002, type: 0} + - {address: 0x10008402, type: 1} + - {address: 0x10018402, type: 1} + - {address: 0x10107c02, type: 1} + - {address: 0x10008412, type: 0} + - {address: 0x10018412, type: 0} + - {address: 0x101ffc02, type: 0} + - {address: 0x10008812, type: 1} + - {address: 0x10018812, type: 1} + - {address: 0x10028812, type: 1} + - {address: 0x10008012, type: 1} + - {address: 0x10018012, type: 1} +components: + - {equipmentId: 0x1003, feb2module: [[-1, 1, 1, 0, 0]], feb2moduleSide: [[-1, 1, 0, 1, 0]], febIsPulser: [[n, n, n, n, n]]} + - {equipmentId: 0x1002, feb2module: [[4, 3, 3, 2, 2]], feb2moduleSide: [[1, 1, 0, 1, 0]], febIsPulser: [[y, n, n, n, n]]} + - {equipmentId: 0x1006, feb2module: [[7, 6, 6, 5, 5]], feb2moduleSide: [[1, 1, 0, 1, 0]], febIsPulser: [[y, n, n, n, n]]} + - {equipmentId: 0x1005, feb2module: [[10, 9, 9, 8, 8]], feb2moduleSide: [[0, 1, 0, 1, 0]], febIsPulser: [[n, n, n, n, n]]} + - {equipmentId: 0x1004, feb2module: [[12, 12, 11, 11, 10]], feb2moduleSide: [[1, 0, 1, 0, 1]], febIsPulser: [[n, n, n, n, n]]} +elinks: + - {toFeb: 4, toAsicFebA: 0x21, toAsicFebB: 0x27} + - {toFeb: 4, toAsicFebA: 0x23, toAsicFebB: 0x25} + - {toFeb: 4, toAsicFebA: 0x25, toAsicFebB: 0x23} + - {toFeb: 4, toAsicFebA: 0x20, toAsicFebB: 0x26} + - {toFeb: 4, toAsicFebA: 0x22, toAsicFebB: 0x24} + - {toFeb: 3, toAsicFebA: 0x18, toAsicFebB: 0x1e} + - {toFeb: 3, toAsicFebA: 0x1a, toAsicFebB: 0x1c} + - {toFeb: 3, toAsicFebA: 0x1c, toAsicFebB: 0x1a} + - {toFeb: 4, toAsicFebA: 0x24, toAsicFebB: 0x22} + - {toFeb: 4, toAsicFebA: 0x27, toAsicFebB: 0x21} + - {toFeb: -1, toAsicFebA: 0xffff, toAsicFebB: 0xffff} + - {toFeb: -1, toAsicFebA: 0xffff, toAsicFebB: 0xffff} + - {toFeb: 4, toAsicFebA: 0x26, toAsicFebB: 0x20} + - {toFeb: 3, toAsicFebA: 0x1e, toAsicFebB: 0x18} + - {toFeb: 2, toAsicFebA: 0x10, toAsicFebB: 0x16} + - {toFeb: 2, toAsicFebA: 0x12, toAsicFebB: 0x14} + - {toFeb: 3, toAsicFebA: 0x19, toAsicFebB: 0x1f} + - {toFeb: 3, toAsicFebA: 0x1b, toAsicFebB: 0x1d} + - {toFeb: 3, toAsicFebA: 0x1f, toAsicFebB: 0x19} + - {toFeb: 1, toAsicFebA: 0xe, toAsicFebB: 0x8} + - {toFeb: 2, toAsicFebA: 0x11, toAsicFebB: 0x17} + - {toFeb: 2, toAsicFebA: 0x13, toAsicFebB: 0x15} + - {toFeb: 1, toAsicFebA: 0xc, toAsicFebB: 0xa} + - {toFeb: 2, toAsicFebA: 0x15, toAsicFebB: 0x13} + - {toFeb: 2, toAsicFebA: 0x17, toAsicFebB: 0x11} + - {toFeb: 2, toAsicFebA: 0x16, toAsicFebB: 0x10} + - {toFeb: 3, toAsicFebA: 0x1d, toAsicFebB: 0x1b} + - {toFeb: 2, toAsicFebA: 0x14, toAsicFebB: 0x12} + - {toFeb: 1, toAsicFebA: 0x9, toAsicFebB: 0xf} + - {toFeb: 1, toAsicFebA: 0xd, toAsicFebB: 0xb} + - {toFeb: 1, toAsicFebA: 0xf, toAsicFebB: 0x9} + - {toFeb: 1, toAsicFebA: 0x8, toAsicFebB: 0xe} + - {toFeb: 1, toAsicFebA: 0xa, toAsicFebB: 0xc} + - {toFeb: 0, toAsicFebA: 0x2, toAsicFebB: 0x4} + - {toFeb: 0, toAsicFebA: 0x4, toAsicFebB: 0x2} + - {toFeb: 0, toAsicFebA: 0x6, toAsicFebB: 0x0} + - {toFeb: 1, toAsicFebA: 0xb, toAsicFebB: 0xd} + - {toFeb: 0, toAsicFebA: 0x5, toAsicFebB: 0x3} + - {toFeb: 0, toAsicFebA: 0x0, toAsicFebB: 0x6} + - {toFeb: 0, toAsicFebA: 0x3, toAsicFebB: 0x5} + - {toFeb: 0, toAsicFebA: 0x7, toAsicFebB: 0x1} + - {toFeb: 0, toAsicFebA: 0x1, toAsicFebB: 0x7} +... +